feat(Core/RBAC): Role Based Access Controls (#24641)
Co-authored-by: blinkysc <blinkysc@users.noreply.github.com> Co-authored-by: Spp <spp@jorge.gr> Co-authored-by: Spp <spp@tc.plus> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Andrew <47818697+Nyeriah@users.noreply.github.com>
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
#include "PacketUtilities.h"
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
#include "Realm.h"
|
||||
#include "QueryHolder.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SocialMgr.h"
|
||||
@@ -115,6 +116,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 accountFlags, s
|
||||
_security(sec),
|
||||
_skipQueue(skipQueue),
|
||||
_accountId(id),
|
||||
_RBACData(nullptr),
|
||||
_accountName(std::move(name)),
|
||||
_accountFlags(accountFlags),
|
||||
m_expansion(expansion),
|
||||
@@ -171,6 +173,8 @@ WorldSession::~WorldSession()
|
||||
m_Socket = nullptr;
|
||||
}
|
||||
|
||||
delete _RBACData;
|
||||
|
||||
///- empty incoming packet queue
|
||||
WorldPacket* packet = nullptr;
|
||||
while (_recvQueue.next(packet))
|
||||
@@ -360,7 +364,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
///- Before we process anything:
|
||||
/// If necessary, kick the player because the client didn't send anything for too long
|
||||
/// (or they've been idling in character select)
|
||||
if (sWorld->getBoolConfig(CONFIG_CLOSE_IDLE_CONNECTIONS) && IsConnectionIdle() && m_Socket)
|
||||
if (IsConnectionIdle() && !HasPermission(rbac::RBAC_PERM_IGNORE_IDLE_CONNECTION))
|
||||
m_Socket->CloseSocket();
|
||||
|
||||
if (updater.ProcessUnsafe())
|
||||
@@ -1519,3 +1523,54 @@ void WorldSession::SetPacketLogging(bool state)
|
||||
if (m_Socket)
|
||||
m_Socket->SetPacketLogging(state);
|
||||
}
|
||||
|
||||
void WorldSession::LoadPermissions()
|
||||
{
|
||||
uint32 id = GetAccountId();
|
||||
uint8 secLevel = GetSecurity();
|
||||
|
||||
LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: {}, Name: {}, realmId: {}, secLevel: {}]",
|
||||
id, _accountName, realm.Id.Realm, secLevel);
|
||||
|
||||
_RBACData = new rbac::RBACData(id, _accountName, realm.Id.Realm, secLevel);
|
||||
_RBACData->LoadFromDB();
|
||||
}
|
||||
|
||||
QueryCallback WorldSession::LoadPermissionsAsync()
|
||||
{
|
||||
uint32 id = GetAccountId();
|
||||
uint8 secLevel = GetSecurity();
|
||||
|
||||
LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: {}, Name: {}, realmId: {}, secLevel: {}]",
|
||||
id, _accountName, realm.Id.Realm, secLevel);
|
||||
|
||||
_RBACData = new rbac::RBACData(id, _accountName, realm.Id.Realm, secLevel);
|
||||
return _RBACData->LoadFromDBAsync();
|
||||
}
|
||||
|
||||
bool WorldSession::HasPermission(uint32 permission)
|
||||
{
|
||||
if (!_RBACData)
|
||||
LoadPermissions();
|
||||
|
||||
bool hasPermission = _RBACData->HasPermission(permission);
|
||||
LOG_DEBUG("rbac", "WorldSession::HasPermission [AccountId: {}, Name: {}, realmId: {}]",
|
||||
_RBACData->GetId(), _RBACData->GetName(), realm.Id.Realm);
|
||||
|
||||
return hasPermission;
|
||||
}
|
||||
|
||||
void WorldSession::InvalidateRBACData()
|
||||
{
|
||||
LOG_DEBUG("rbac", "WorldSession::InvalidateRBACData [AccountId: {}, Name: {}, realmId: {}]",
|
||||
_RBACData->GetId(), _RBACData->GetName(), realm.Id.Realm);
|
||||
delete _RBACData;
|
||||
_RBACData = nullptr;
|
||||
}
|
||||
|
||||
void WorldSession::InitRBACDataForTest()
|
||||
{
|
||||
delete _RBACData;
|
||||
_RBACData = new rbac::RBACData(_accountId, _accountName, realm.Id.Realm, _security);
|
||||
_RBACData->LoadFromDBCallback(nullptr);
|
||||
}
|
||||
|
||||
@@ -440,6 +440,16 @@ public:
|
||||
|
||||
AccountTypes GetSecurity() const { return _security; }
|
||||
bool CanSkipQueue() const { return _skipQueue; }
|
||||
|
||||
// RBAC
|
||||
rbac::RBACData* GetRBACData() const { return _RBACData; }
|
||||
bool HasPermission(uint32 permissionId);
|
||||
void LoadPermissions();
|
||||
QueryCallback LoadPermissionsAsync();
|
||||
void InvalidateRBACData();
|
||||
|
||||
/// For unit testing - initializes RBAC data without database access
|
||||
void InitRBACDataForTest();
|
||||
uint32 GetAccountId() const { return _accountId; }
|
||||
Player* GetPlayer() const { return _player; }
|
||||
std::string const& GetPlayerName() const;
|
||||
@@ -1224,6 +1234,7 @@ private:
|
||||
AccountTypes _security;
|
||||
bool _skipQueue;
|
||||
uint32 _accountId;
|
||||
rbac::RBACData* _RBACData;
|
||||
std::string _accountName;
|
||||
uint32 _accountFlags;
|
||||
uint8 m_expansion;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "Chat.h"
|
||||
#include "ChatPackets.h"
|
||||
#include "RBAC.h"
|
||||
#include "GameTime.h"
|
||||
#include "Metric.h"
|
||||
#include "Player.h"
|
||||
@@ -323,7 +324,7 @@ void WorldSessionMgr::AddSession_(WorldSession* session)
|
||||
// don't count this session when checking player limit
|
||||
--Sessions;
|
||||
|
||||
if (pLimit > 0 && Sessions >= pLimit && AccountMgr::IsPlayerAccount(session->GetSecurity()) && !session->CanSkipQueue() && !HasRecentlyDisconnected(session))
|
||||
if (pLimit > 0 && Sessions >= pLimit && !session->HasPermission(rbac::RBAC_PERM_SKIP_QUEUE) && !session->CanSkipQueue() && !HasRecentlyDisconnected(session))
|
||||
{
|
||||
AddQueuedPlayer(session);
|
||||
UpdateMaxSessionCounters();
|
||||
@@ -390,7 +391,7 @@ void WorldSessionMgr::SendGlobalGMMessage(WorldPacket const* packet, WorldSessio
|
||||
itr->second->GetPlayer() &&
|
||||
itr->second->GetPlayer()->IsInWorld() &&
|
||||
itr->second != self &&
|
||||
!AccountMgr::IsPlayerAccount(itr->second->GetSecurity()) &&
|
||||
itr->second->HasPermission(rbac::RBAC_PERM_RECEIVE_GLOBAL_GM_TEXTMESSAGE) &&
|
||||
(teamId == TEAM_NEUTRAL || itr->second->GetPlayer()->GetTeamId() == teamId))
|
||||
{
|
||||
itr->second->SendPacket(packet);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
#include "RBAC.h"
|
||||
#include "zlib.h"
|
||||
#include <memory>
|
||||
|
||||
@@ -763,7 +764,7 @@ bool WorldSocket::HandlePing(WorldPacket& recvPacket)
|
||||
{
|
||||
std::unique_lock<std::mutex> sessionGuard(_worldSessionLock);
|
||||
|
||||
if (_worldSession && AccountMgr::IsPlayerAccount(_worldSession->GetSecurity()))
|
||||
if (_worldSession && !_worldSession->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_OVERSPEED_PING))
|
||||
{
|
||||
LOG_ERROR("network", "WorldSocket::HandlePing: {} kicked for over-speed pings (address: {})",
|
||||
_worldSession->GetPlayerInfo(), GetRemoteIpAddress().to_string());
|
||||
|
||||
Reference in New Issue
Block a user