mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Client token authentication implementation
The game internally obtains a auth token from Origin. On connect to a gameserver, it will send it to the masterserver. The master server will create a JWT token and send this back to the client. The client stores this token in 3 userinfo cvars (token, sig1, sig2). the sig1 and sig2 cvars are there to compensate for the truncation caused by sending the cvar, as each cvar string length could be up to 255 (byte max). The server verifies this token (the signature, timestamp, expiry); if they are valid, the has successfully authenticated and will connect.
This commit is contained in:
parent
6b344ad52f
commit
59fab7ac93
@ -15,6 +15,7 @@
|
||||
#ifndef DEDICATED
|
||||
#include "engine/client/cl_rcon.h"
|
||||
#include "engine/client/cdll_engine_int.h"
|
||||
#include "engine/client/clientstate.h"
|
||||
#endif // !DEDICATED
|
||||
#include "engine/client/client.h"
|
||||
#include "engine/net.h"
|
||||
@ -808,6 +809,7 @@ SIG_GetAdr_f
|
||||
*/
|
||||
void SIG_GetAdr_f(const CCommand& args)
|
||||
{
|
||||
if (!IsCert() && !IsRetail())
|
||||
DetourAddress();
|
||||
}
|
||||
|
||||
@ -1458,13 +1460,16 @@ CC_CreateFakePlayer_f
|
||||
#ifndef CLIENT_DLL
|
||||
void CC_CreateFakePlayer_f(const CCommand& args)
|
||||
{
|
||||
if (!g_pServer->IsActive())
|
||||
return;
|
||||
|
||||
if (args.ArgC() < 3)
|
||||
{
|
||||
Msg(eDLL_T::SERVER, "usage 'sv_addbot': name(string) teamid(int)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int numPlayers = g_pServer->GetNumClients();
|
||||
const int numPlayers = g_pServer->GetNumClients();
|
||||
|
||||
// Already at max, don't create.
|
||||
if (numPlayers >= g_ServerGlobalVariables->m_nMaxClients)
|
||||
@ -1473,7 +1478,7 @@ void CC_CreateFakePlayer_f(const CCommand& args)
|
||||
const char* playerName = args.Arg(1);
|
||||
|
||||
int teamNum = atoi(args.Arg(2));
|
||||
int maxTeams = int(g_pServer->GetMaxTeams()) + 1;
|
||||
const int maxTeams = int(g_pServer->GetMaxTeams()) + 1;
|
||||
|
||||
// Clamp team count, going above the limit will
|
||||
// cause a crash. Going below 0 means that the
|
||||
@ -1483,9 +1488,44 @@ void CC_CreateFakePlayer_f(const CCommand& args)
|
||||
|
||||
g_pEngineServer->LockNetworkStringTables(true);
|
||||
|
||||
edict_t nHandle = g_pEngineServer->CreateFakeClient(playerName, teamNum);
|
||||
const edict_t nHandle = g_pEngineServer->CreateFakeClient(playerName, teamNum);
|
||||
g_pServerGameClients->ClientFullyConnect(nHandle, false);
|
||||
|
||||
g_pEngineServer->LockNetworkStringTables(false);
|
||||
}
|
||||
#endif // !CLIENT_DLL
|
||||
|
||||
/*
|
||||
=====================
|
||||
Cmd_Exec_f
|
||||
|
||||
executes a cfg file
|
||||
=====================
|
||||
*/
|
||||
void Cmd_Exec_f(const CCommand& args)
|
||||
{
|
||||
#ifndef DEDICATED
|
||||
// Prevent users from running neo strafe commands and other quick hacks.
|
||||
// TODO: when reBar becomes a thing, we should verify this function and
|
||||
// flag users that patch them out.
|
||||
if (!ThreadInServerFrameThread() && (!sv_cheats->GetBool() && g_pClientState->IsActive()))
|
||||
{
|
||||
DevWarning(eDLL_T::ENGINE, "Client is simulating and %s = false; dropped exec command: %s\n",
|
||||
sv_cheats->GetName(), args.ArgS());
|
||||
|
||||
return;
|
||||
}
|
||||
#endif // !DEDICATED
|
||||
_Cmd_Exec_f(args);
|
||||
}
|
||||
|
||||
|
||||
void VCallback::Attach() const
|
||||
{
|
||||
DetourAttach(&_Cmd_Exec_f, &Cmd_Exec_f);
|
||||
}
|
||||
|
||||
void VCallback::Detach() const
|
||||
{
|
||||
DetourDetach(&_Cmd_Exec_f, &Cmd_Exec_f);
|
||||
}
|
||||
|
@ -7,6 +7,9 @@ inline bool(*SetupGamemode)(const char* pszPlayList);
|
||||
inline CMemory p_DownloadPlaylists_f;
|
||||
inline void(*_DownloadPlaylists_f)(void);
|
||||
|
||||
inline CMemory p_Cmd_Exec_f;
|
||||
inline void(*_Cmd_Exec_f)(const CCommand& args);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue);
|
||||
void MP_HostName_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue);
|
||||
@ -87,18 +90,21 @@ class VCallback : public IDetour
|
||||
{
|
||||
LogFunAdr("SetupGamemode", p_SetupGamemode.GetPtr());
|
||||
LogFunAdr("DownloadPlaylist_f", p_DownloadPlaylists_f.GetPtr());
|
||||
LogFunAdr("Cmd_Exec_f", p_Cmd_Exec_f.GetPtr());
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
p_SetupGamemode = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 8B D9 48 C7 C0 ?? ?? ?? ??");
|
||||
p_DownloadPlaylists_f = g_GameDll.FindPatternSIMD("33 C9 C6 05 ?? ?? ?? ?? ?? E9 ?? ?? ?? ??");
|
||||
p_Cmd_Exec_f = g_GameDll.FindPatternSIMD("40 55 53 48 8D AC 24 ?? ?? ?? ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B D9");
|
||||
|
||||
SetupGamemode = p_SetupGamemode.RCast<bool(*)(const char*)>(); /*40 53 48 83 EC 20 48 8B D9 48 C7 C0 ?? ?? ?? ??*/
|
||||
_DownloadPlaylists_f = p_DownloadPlaylists_f.RCast<void(*)(void)>(); /*33 C9 C6 05 ?? ?? ?? ?? ?? E9 ?? ?? ?? ??*/
|
||||
SetupGamemode = p_SetupGamemode.RCast<bool(*)(const char*)>();
|
||||
_DownloadPlaylists_f = p_DownloadPlaylists_f.RCast<void(*)(void)>();
|
||||
_Cmd_Exec_f = p_Cmd_Exec_f.RCast<void(*)(const CCommand& args)>();
|
||||
}
|
||||
virtual void GetVar(void) const { }
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Attach(void) const { }
|
||||
virtual void Detach(void) const { }
|
||||
virtual void Attach(void) const;
|
||||
virtual void Detach(void) const;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -195,6 +195,10 @@ ConVar* cl_threaded_bone_setup = nullptr;
|
||||
|
||||
ConVar* cl_language = nullptr;
|
||||
|
||||
ConVar* cl_onlineAuthToken = nullptr;
|
||||
ConVar* cl_onlineAuthTokenSignature1 = nullptr;
|
||||
ConVar* cl_onlineAuthTokenSignature2 = nullptr;
|
||||
|
||||
ConVar* con_drawnotify = nullptr;
|
||||
ConVar* con_notifylines = nullptr;
|
||||
ConVar* con_notifytime = nullptr;
|
||||
@ -403,6 +407,10 @@ void ConVar_StaticInit(void)
|
||||
cl_materialinfo_offset_x = ConVar::StaticCreate("cl_materialinfo_offset_x", "0" , FCVAR_DEVELOPMENTONLY, "X offset for material debug info overlay.", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
cl_materialinfo_offset_y = ConVar::StaticCreate("cl_materialinfo_offset_y", "420", FCVAR_DEVELOPMENTONLY, "Y offset for material debug info overlay.", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
|
||||
cl_onlineAuthToken = ConVar::StaticCreate("cl_onlineAuthToken", "", FCVAR_HIDDEN | FCVAR_USERINFO | FCVAR_DONTRECORD | FCVAR_SERVER_CANNOT_QUERY | FCVAR_PLATFORM_SYSTEM, "", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
cl_onlineAuthTokenSignature1 = ConVar::StaticCreate("cl_onlineAuthTokenSignature1", "", FCVAR_HIDDEN | FCVAR_USERINFO | FCVAR_DONTRECORD | FCVAR_SERVER_CANNOT_QUERY | FCVAR_PLATFORM_SYSTEM, "", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
cl_onlineAuthTokenSignature2 = ConVar::StaticCreate("cl_onlineAuthTokenSignature2", "", FCVAR_HIDDEN | FCVAR_USERINFO | FCVAR_DONTRECORD | FCVAR_SERVER_CANNOT_QUERY | FCVAR_PLATFORM_SYSTEM, "", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
|
||||
con_drawnotify = ConVar::StaticCreate("con_drawnotify", "0", FCVAR_RELEASE, "Draws the RUI console to the hud.", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
con_notifylines = ConVar::StaticCreate("con_notifylines" , "3" , FCVAR_MATERIAL_SYSTEM_THREAD, "Number of console lines to overlay for debugging.", true, 1.f, false, 0.f, nullptr, nullptr);
|
||||
con_notifytime = ConVar::StaticCreate("con_notifytime" , "6" , FCVAR_MATERIAL_SYSTEM_THREAD, "How long to display recent console text to the upper part of the game window.", false, 1.f, false, 50.f, nullptr, nullptr);
|
||||
@ -473,7 +481,7 @@ void ConVar_StaticInit(void)
|
||||
net_processTimeBudget = ConVar::StaticCreate("net_processTimeBudget" ,"200" , FCVAR_RELEASE , "Net message process time budget in milliseconds (removing netchannel if exceeded).", true, 0.f, false, 0.f, nullptr, "0 = disabled");
|
||||
//-------------------------------------------------------------------------
|
||||
// NETWORKSYSTEM |
|
||||
pylon_matchmaking_hostname = ConVar::StaticCreate("pylon_matchmaking_hostname", "ms.r5reloaded.com", FCVAR_RELEASE, "Holds the pylon matchmaking hostname.", false, 0.f, false, 0.f, &MP_HostName_Changed_f, nullptr);
|
||||
pylon_matchmaking_hostname = ConVar::StaticCreate("pylon_matchmaking_hostname", "ms-dev.r5reloaded.com", FCVAR_RELEASE, "Holds the pylon matchmaking hostname.", false, 0.f, false, 0.f, &MP_HostName_Changed_f, nullptr);
|
||||
pylon_host_update_interval = ConVar::StaticCreate("pylon_host_update_interval", "5" , FCVAR_RELEASE, "Length of time in seconds between each status update interval to master server.", true, 5.f, false, 0.f, nullptr, nullptr);
|
||||
pylon_showdebuginfo = ConVar::StaticCreate("pylon_showdebuginfo" , "0" , FCVAR_RELEASE, "Shows debug output for pylon.", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
//-------------------------------------------------------------------------
|
||||
@ -737,6 +745,7 @@ void ConCommand_StaticInit(void)
|
||||
ConCommand::StaticCreate("net_generatekey", "Generates and sets a random base64 net key.", nullptr, FCVAR_RELEASE, NET_GenerateKey_f, nullptr);
|
||||
//-------------------------------------------------------------------------
|
||||
// TIER0 |
|
||||
if (!IsCert() && !IsRetail())
|
||||
ConCommand::StaticCreate("sig_getadr", "Logs the sigscan results to the console.", nullptr, FCVAR_DEVELOPMENTONLY | FCVAR_HIDDEN, SIG_GetAdr_f, nullptr);
|
||||
}
|
||||
|
||||
|
@ -185,6 +185,11 @@ extern ConVar* cl_threaded_bone_setup;
|
||||
|
||||
extern ConVar* cl_language;
|
||||
|
||||
extern ConVar* cl_onlineAuthToken;
|
||||
extern ConVar* cl_onlineAuthTokenSignature1;
|
||||
extern ConVar* cl_onlineAuthTokenSignature2;
|
||||
|
||||
|
||||
extern ConVar* con_drawnotify;
|
||||
extern ConVar* con_notifylines;
|
||||
extern ConVar* con_notifytime;
|
||||
|
@ -103,6 +103,15 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE
|
||||
)
|
||||
endif()
|
||||
|
||||
if( NOT ${PROJECT_NAME} STREQUAL "client" )
|
||||
target_link_libraries( ${PROJECT_NAME} PRIVATE
|
||||
"libmbedcrypto"
|
||||
"libmbedtls"
|
||||
"libmbedx509"
|
||||
"libjwt"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Determine the compiler definitions and link libraries per project.
|
||||
if( ${PROJECT_NAME} STREQUAL "gamesdk" )
|
||||
end_sources()
|
||||
|
@ -11,8 +11,12 @@
|
||||
#include "core/stdafx.h"
|
||||
#include "tier1/cvar.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "mathlib/sha256.h"
|
||||
#include "engine/server/server.h"
|
||||
#include "engine/client/client.h"
|
||||
#ifndef CLIENT_DLL
|
||||
#include "jwt/include/decode.h"
|
||||
#endif
|
||||
|
||||
// Absolute max string cmd length, any character past this will be NULLED.
|
||||
#define STRINGCMD_MAX_LEN 512
|
||||
@ -37,22 +41,156 @@ void CClient::VClear(CClient* pClient)
|
||||
pClient->Clear();
|
||||
}
|
||||
|
||||
static const char JWT_PUBLIC_KEY[] =
|
||||
"-----BEGIN PUBLIC KEY-----\n"
|
||||
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2/335exIZ6LE8pYi6e50\n"
|
||||
"7tH19tXaeeEJVF5XXpTCXpndXIIWVimvg6xQ381eajySDw93wvG1DzW3U/6LHzyt\n"
|
||||
"Q++N8w7N+FwnXyoDUD5Y8hheTZv6jjLoYT8ZtsMl20k9UosrbFBTMUhgmIT2dVth\n"
|
||||
"LH+rT9ohpUNwQXHJvTOs9eY74GyfFw93+32LANBPZ8b+S8S3oZnKFVeCxRkYKsV0\n"
|
||||
"b34POHVBbXNw6Kt163gR5zaiCfJJtRto9AA7MV2t9pfy8CChs3uJ+Xn7QVHD5cqt\n"
|
||||
"Msg9MBac2Pvs2j+8wJ/igAVL5L81z3FXVt04id59TfPMUbYhRfY8pk7FB0MCigOH\n"
|
||||
"dwIDAQAB\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
|
||||
|
||||
bool CClient::Authenticate(const char* const playerName, char* const reasonBuf, const size_t reasonBufLen)
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
// don't bother checking origin auth on bots or local clients
|
||||
if (IsFakeClient() || GetNetChan()->GetRemoteAddress().IsLoopback())
|
||||
return true;
|
||||
|
||||
#define FORMAT_ERROR_REASON(fmt, ...) V_snprintf(reasonBuf, reasonBufLen, fmt, ##__VA_ARGS__);
|
||||
|
||||
KeyValues* cl_onlineAuthTokenKv = this->m_ConVars->FindKey("cl_onlineAuthToken");
|
||||
KeyValues* cl_onlineAuthTokenSignature1Kv = this->m_ConVars->FindKey("cl_onlineAuthTokenSignature1");
|
||||
KeyValues* cl_onlineAuthTokenSignature2Kv = this->m_ConVars->FindKey("cl_onlineAuthTokenSignature2");
|
||||
|
||||
if (!cl_onlineAuthTokenKv || !cl_onlineAuthTokenSignature1Kv)
|
||||
{
|
||||
FORMAT_ERROR_REASON("Missing token");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* onlineAuthToken = cl_onlineAuthTokenKv->GetString();
|
||||
const char* onlineAuthTokenSignature1 = cl_onlineAuthTokenSignature1Kv->GetString();
|
||||
const char* onlineAuthTokenSignature2 = cl_onlineAuthTokenSignature2Kv->GetString();
|
||||
|
||||
const std::string fullToken = Format("%s.%s%s", onlineAuthToken, onlineAuthTokenSignature1, onlineAuthTokenSignature2);
|
||||
|
||||
struct l8w8jwt_decoding_params params;
|
||||
l8w8jwt_decoding_params_init(¶ms);
|
||||
|
||||
params.alg = L8W8JWT_ALG_RS256;
|
||||
|
||||
params.jwt = (char*)fullToken.c_str();
|
||||
params.jwt_length = fullToken.length();
|
||||
|
||||
params.verification_key = (unsigned char*)JWT_PUBLIC_KEY;
|
||||
params.verification_key_length = strlen(JWT_PUBLIC_KEY);
|
||||
|
||||
params.validate_exp = 1;
|
||||
params.exp_tolerance_seconds = 1;
|
||||
|
||||
params.validate_iat = 1;
|
||||
params.iat_tolerance_seconds = 30;
|
||||
|
||||
l8w8jwt_claim* claims = nullptr;
|
||||
size_t numClaims = 0;
|
||||
|
||||
enum l8w8jwt_validation_result validation_result;
|
||||
const int r = l8w8jwt_decode(¶ms, &validation_result, &claims, &numClaims);
|
||||
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
FORMAT_ERROR_REASON("Code %i", r);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (validation_result != L8W8JWT_VALID)
|
||||
{
|
||||
char reasonBuffer[256];
|
||||
l8w8jwt_get_validation_result_desc(validation_result, reasonBuffer, sizeof(reasonBuffer));
|
||||
|
||||
FORMAT_ERROR_REASON("%s", reasonBuffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool foundSessionId = false;
|
||||
for (size_t i = 0; i < numClaims; ++i)
|
||||
{
|
||||
// session id
|
||||
if (!strcmp(claims[i].key, "sessionId"))
|
||||
{
|
||||
const char* const sessionId = claims[i].value;
|
||||
|
||||
const std::string newId = Format(
|
||||
"%lld-%s-%s",
|
||||
this->m_DataBlock.userData,
|
||||
playerName,
|
||||
g_pMasterServer->GetHostIP().c_str()
|
||||
);
|
||||
|
||||
DevMsg(eDLL_T::SERVER, "%s: newId=%s\n", __FUNCTION__, newId.c_str());
|
||||
const std::string hashedNewId = sha256(newId);
|
||||
|
||||
if (hashedNewId.compare(sessionId) != 0)
|
||||
{
|
||||
FORMAT_ERROR_REASON("Token is not authorized for the connecting client");
|
||||
return false;
|
||||
}
|
||||
|
||||
foundSessionId = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundSessionId)
|
||||
{
|
||||
FORMAT_ERROR_REASON("No session ID");
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef REJECT_CONNECTION
|
||||
#endif // !CLIENT_DLL
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: connect new client
|
||||
// Input : *szName -
|
||||
// *pNetChannel -
|
||||
// bFakePlayer -
|
||||
// *a5 -
|
||||
// *conVars -
|
||||
// *szMessage -
|
||||
// nMessageSize -
|
||||
// Output : true if connection was successful, false otherwise
|
||||
//---------------------------------------------------------------------------------
|
||||
bool CClient::Connect(const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize)
|
||||
bool CClient::Connect(const char* szName, void* pNetChannel, bool bFakePlayer,
|
||||
CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize)
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
g_ServerPlayer[GetUserID()].Reset(); // Reset ServerPlayer slot.
|
||||
#endif
|
||||
|
||||
if (!v_CClient_Connect(this, szName, pNetChannel, bFakePlayer, conVars, szMessage, nMessageSize))
|
||||
return false;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
#define REJECT_CONNECTION(fmt, ...) V_snprintf(szMessage, nMessageSize, fmt, ##__VA_ARGS__);
|
||||
|
||||
char authFailReason[512];
|
||||
if (!Authenticate(szName, authFailReason, sizeof(authFailReason)))
|
||||
{
|
||||
REJECT_CONNECTION("Failed to verify authentication token [%s]", authFailReason);
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef REJECT_CONNECTION
|
||||
#endif // !CLIENT_DLL
|
||||
return v_CClient_Connect(this, szName, pNetChannel, bFakePlayer, a5, szMessage, nMessageSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
@ -66,9 +204,10 @@ bool CClient::Connect(const char* szName, void* pNetChannel, bool bFakePlayer, v
|
||||
// nMessageSize -
|
||||
// Output : true if connection was successful, false otherwise
|
||||
//---------------------------------------------------------------------------------
|
||||
bool CClient::VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize)
|
||||
bool CClient::VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer,
|
||||
CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize)
|
||||
{
|
||||
return pClient->Connect(szName, pNetChannel, bFakePlayer, a5, szMessage, nMessageSize);;
|
||||
return pClient->Connect(szName, pNetChannel, bFakePlayer, conVars, szMessage, nMessageSize);;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
@ -258,8 +397,8 @@ bool CClient::VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg)
|
||||
bool CClient::VProcessSetConVar(CClient* pClient, NET_SetConVar* pMsg)
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
CClient* pAdj = AdjustShiftedThisPointer(pClient);
|
||||
ServerPlayer_t* pSlot = &g_ServerPlayer[pAdj->GetUserID()];
|
||||
CClient* const pAdj = AdjustShiftedThisPointer(pClient);
|
||||
ServerPlayer_t* const pSlot = &g_ServerPlayer[pAdj->GetUserID()];
|
||||
|
||||
// This loop never exceeds 255 iterations, NET_SetConVar::ReadFromBuffer(...)
|
||||
// reads and inserts up to 255 entries in the vector (reads a byte for size).
|
||||
@ -297,6 +436,7 @@ bool CClient::VProcessSetConVar(CClient* pClient, NET_SetConVar* pMsg)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add ConVar to list and set string.
|
||||
pAdj->m_ConVars->SetString(name, value);
|
||||
DevMsg(eDLL_T::SERVER, "UserInfo update from \"%s\": %s = %s\n", pAdj->GetClientName(), name, value);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "common/protocol.h"
|
||||
#include "engine/net.h"
|
||||
#include "engine/net_chan.h"
|
||||
#include "public/edict.h"
|
||||
#include "engine/server/datablock_sender.h"
|
||||
@ -93,13 +94,18 @@ public:
|
||||
inline bool IsHumanPlayer(void) const { if (!IsConnected() || IsFakeClient()) { return false; } return true; }
|
||||
|
||||
bool SendNetMsgEx(CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice);
|
||||
bool Connect(const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize);
|
||||
|
||||
bool Authenticate(const char* const playerName, char* const reasonBuf, const size_t reasonBufLen);
|
||||
bool Connect(const char* szName, void* pNetChannel, bool bFakePlayer,
|
||||
CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize);
|
||||
void Disconnect(const Reputation_t nRepLvl, const char* szReason, ...);
|
||||
static bool VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize);
|
||||
void Clear(void);
|
||||
|
||||
public: // Hook statics:
|
||||
static void VClear(CClient* pClient);
|
||||
static bool VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer,
|
||||
CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize);
|
||||
|
||||
static void VActivatePlayer(CClient* pClient);
|
||||
static void* VSendSnapshot(CClient* pClient, CClientFrame* pFrame, int nTick, int nTickAck);
|
||||
static bool VSendNetMsgEx(CClient* pClient, CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice);
|
||||
@ -204,7 +210,7 @@ static_assert(sizeof(CClient) == 0x4A4C0);
|
||||
|
||||
/* ==== CBASECLIENT ===================================================================================================================================================== */
|
||||
inline CMemory p_CClient_Connect;
|
||||
inline bool(*v_CClient_Connect)(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize);
|
||||
inline bool(*v_CClient_Connect)(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize);
|
||||
|
||||
inline CMemory p_CClient_Disconnect;
|
||||
inline bool(*v_CClient_Disconnect)(CClient* pClient, const Reputation_t nRepLvl, const char* szReason, ...);
|
||||
@ -269,7 +275,7 @@ class VClient : public IDetour
|
||||
p_CClient_ProcessSetConVar = g_GameDll.FindPatternSIMD("48 83 EC 28 48 83 C2 20");
|
||||
p_CClient_SetSignonState = g_GameDll.FindPatternSIMD("48 8B C4 48 89 58 10 48 89 70 18 57 48 81 EC ?? ?? ?? ?? 0F 29 70 E8 8B F2");
|
||||
|
||||
v_CClient_Connect = p_CClient_Connect.RCast<bool (*)(CClient*, const char*, void*, bool, void*, char*, int)>();
|
||||
v_CClient_Connect = p_CClient_Connect.RCast<bool (*)(CClient*, const char*, void*, bool, CUtlVector<NET_SetConVar::cvar_t>*, char*, int)>();
|
||||
v_CClient_Disconnect = p_CClient_Disconnect.RCast<bool (*)(CClient*, const Reputation_t, const char*, ...)>();
|
||||
v_CClient_Clear = p_CClient_Clear.RCast<void (*)(CClient*)>();
|
||||
v_CClient_ActivatePlayer = p_CClient_ActivatePlayer.RCast<void (*)(CClient* pClient)>();
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "common/callback.h"
|
||||
#include "cdll_engine_int.h"
|
||||
#include "vgui/vgui_baseui_interface.h"
|
||||
#include <ebisusdk/EbisuSDK.h>
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -163,16 +164,76 @@ bool CClientState::VProcessServerTick(CClientState* pClientState, SVC_ServerTick
|
||||
}
|
||||
}
|
||||
|
||||
bool CClientState::Authenticate(connectparams_t* connectParams) const
|
||||
{
|
||||
string msToken; // token returned by the masterserver authorising the client to play online
|
||||
string message; // message returned by the masterserver about the result of the auth
|
||||
|
||||
// verify that the client is not lying about their account identity
|
||||
// code is immediately discarded upon verification
|
||||
|
||||
const bool ret = g_pMasterServer->AuthForConnection(*g_NucleusID, connectParams->netAdr, g_OriginAuthCode, msToken, message);
|
||||
if (!ret)
|
||||
{
|
||||
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to authenticate for online play: %s\n", message.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// get full token
|
||||
const char* token = msToken.c_str();
|
||||
|
||||
// get a pointer to the delimiter that begins the token's signature
|
||||
const char* tokenSignatureDelim = strrchr(token, '.');
|
||||
|
||||
if (!tokenSignatureDelim)
|
||||
{
|
||||
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to authenticate for online play: %s\n", "Invalid token returned by MS");
|
||||
return false;
|
||||
}
|
||||
|
||||
// replace the delimiter with a null char so the first cvar only takes the header and payload data
|
||||
*(char*)tokenSignatureDelim = '\0';
|
||||
const size_t sigLength = strlen(tokenSignatureDelim) - 1;
|
||||
|
||||
cl_onlineAuthToken->SetValue(token);
|
||||
|
||||
if (sigLength > 0)
|
||||
{
|
||||
// get a pointer to the first part of the token signature to store in cl_onlineAuthTokenSignature1
|
||||
const char* tokenSignaturePart1 = tokenSignatureDelim + 1;
|
||||
|
||||
cl_onlineAuthTokenSignature1->SetValue(tokenSignaturePart1);
|
||||
|
||||
if (sigLength > 255)
|
||||
{
|
||||
// get a pointer to the rest of the token signature to store in cl_onlineAuthTokenSignature2
|
||||
const char* tokenSignaturePart2 = tokenSignaturePart1 + 255;
|
||||
|
||||
cl_onlineAuthTokenSignature2->SetValue(tokenSignaturePart2);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CClientState::VConnect(CClientState* thisptr, connectparams_t* connectParams)
|
||||
{
|
||||
thisptr->Authenticate(connectParams);
|
||||
CClientState__Connect(thisptr, connectParams);
|
||||
}
|
||||
|
||||
void VClientState::Attach() const
|
||||
{
|
||||
DetourAttach(&CClientState__ConnectionClosing, &CClientState::VConnectionClosing);
|
||||
DetourAttach(&CClientState__ProcessServerTick, &CClientState::VProcessServerTick);
|
||||
DetourAttach(&CClientState__Connect, &CClientState::VConnect);
|
||||
}
|
||||
|
||||
void VClientState::Detach() const
|
||||
{
|
||||
DetourDetach(&CClientState__ConnectionClosing, &CClientState::VConnectionClosing);
|
||||
DetourDetach(&CClientState__ProcessServerTick, &CClientState::VProcessServerTick);
|
||||
DetourDetach(&CClientState__Connect, &CClientState::VConnect);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -11,6 +11,16 @@
|
||||
#include "engine/packed_entity.h"
|
||||
#include "datablock_receiver.h"
|
||||
|
||||
struct connectparams_t
|
||||
{
|
||||
const char* netAdr;
|
||||
const char* netKey;
|
||||
int unkReconnect;
|
||||
int unk;
|
||||
bool challengeRequest;
|
||||
bool asSpectator_MAYBE;
|
||||
};
|
||||
|
||||
class CClientSnapshotManager : public IClientSnapshotManager
|
||||
{
|
||||
public:
|
||||
@ -27,6 +37,7 @@ class CClientState : CS_INetChannelHandler, IConnectionlessPacketHandler, IServe
|
||||
public: // Hook statics.
|
||||
static void VConnectionClosing(CClientState* thisptr, const char* szReason);
|
||||
static bool VProcessServerTick(CClientState* thisptr, SVC_ServerTick* msg);
|
||||
static void VConnect(CClientState* thisptr, connectparams_t* connectParams);
|
||||
|
||||
public:
|
||||
bool IsPaused() const;
|
||||
@ -46,6 +57,8 @@ public:
|
||||
|
||||
float GetFrameTime(void) const;
|
||||
|
||||
bool Authenticate(connectparams_t* connectParams) const;
|
||||
|
||||
int m_Socket;
|
||||
int _padding_maybe;
|
||||
CNetChan* m_NetChannel;
|
||||
@ -199,6 +212,9 @@ extern CClientState** g_pClientState_Shifted; // Shifted by 0x10 forward!
|
||||
inline CMemory p_CClientState__RunFrame;
|
||||
inline void(*CClientState__RunFrame)(CClientState* thisptr);
|
||||
|
||||
inline CMemory p_CClientState__Connect;
|
||||
inline void(*CClientState__Connect)(CClientState* thisptr, connectparams_t* connectParams);
|
||||
|
||||
inline CMemory p_CClientState__Disconnect;
|
||||
inline void(*CClientState__Disconnect)(CClientState* thisptr, bool bSendTrackingContext);
|
||||
|
||||
@ -214,6 +230,7 @@ class VClientState : public IDetour
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("CClientState::RunFrame", p_CClientState__RunFrame.GetPtr());
|
||||
LogFunAdr("CClientState::Connect", p_CClientState__Connect.GetPtr());
|
||||
LogFunAdr("CClientState::Disconnect", p_CClientState__Disconnect.GetPtr());
|
||||
LogFunAdr("CClientState::ConnectionClosing", p_CClientState__ConnectionClosing.GetPtr());
|
||||
LogFunAdr("CClientState::ProcessServerTick", p_CClientState__ProcessServerTick.GetPtr());
|
||||
@ -234,7 +251,11 @@ class VClientState : public IDetour
|
||||
#endif
|
||||
p_CClientState__ProcessServerTick = g_GameDll.FindPatternSIMD("40 57 48 83 EC 20 83 B9 ?? ?? ?? ?? ?? 48 8B F9 7C 66");
|
||||
|
||||
p_CClientState__Connect = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 81 EC ?? ?? ?? ?? 48 8B 32");
|
||||
|
||||
|
||||
CClientState__RunFrame = p_CClientState__RunFrame.RCast<void(*)(CClientState*)>();
|
||||
CClientState__Connect = p_CClientState__Connect.RCast<void(*)(CClientState*, connectparams_t*)>();
|
||||
CClientState__Disconnect = p_CClientState__Disconnect.RCast<void(*)(CClientState*, bool)>();
|
||||
CClientState__ConnectionClosing = p_CClientState__ConnectionClosing.RCast<void(*)(CClientState*, const char*)>();
|
||||
CClientState__ProcessServerTick = p_CClientState__ProcessServerTick.RCast<bool(*)(CClientState*, SVC_ServerTick*)>();
|
||||
|
@ -69,8 +69,9 @@ bool HostState_KeepAlive(const NetGameServer_t& netGameServer)
|
||||
|
||||
string errorMsg;
|
||||
string hostToken;
|
||||
string hostIp;
|
||||
|
||||
const bool result = g_pMasterServer->PostServerHost(errorMsg, hostToken, netGameServer);
|
||||
const bool result = g_pMasterServer->PostServerHost(errorMsg, hostToken, hostIp, netGameServer);
|
||||
if (!result)
|
||||
{
|
||||
if (!errorMsg.empty() && g_pMasterServer->GetCurrentError().compare(errorMsg) != NULL)
|
||||
@ -90,6 +91,9 @@ bool HostState_KeepAlive(const NetGameServer_t& netGameServer)
|
||||
}
|
||||
}
|
||||
|
||||
if (hostIp.length() != 0)
|
||||
g_pMasterServer->SetHostIP(hostIp);
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif // !CLIENT_DLL
|
||||
|
@ -46,8 +46,8 @@ protected:
|
||||
|
||||
struct ServerDataBlock
|
||||
{
|
||||
char SnapshotBuffer[295312]; // this might be wrong !!!
|
||||
void* pUnkBlockStruct;
|
||||
char blockBuffer[295312]; // this might be wrong !!!
|
||||
void* userData;
|
||||
char gapC0008[56];
|
||||
ServerDataBlockSender sender;
|
||||
};
|
||||
|
@ -778,13 +778,18 @@ void CBrowser::SendHostingPostRequest(const NetGameServer_t& gameServer)
|
||||
#ifndef CLIENT_DLL
|
||||
string svHostRequestMessage;
|
||||
string svHostToken;
|
||||
bool result = g_pMasterServer->PostServerHost(svHostRequestMessage, svHostToken, gameServer);
|
||||
string svHostIp;
|
||||
|
||||
bool result = g_pMasterServer->PostServerHost(svHostRequestMessage, svHostToken, svHostIp, gameServer);
|
||||
|
||||
std::lock_guard<std::mutex> l(m_Mutex);
|
||||
|
||||
m_svHostRequestMessage = svHostRequestMessage;
|
||||
m_svHostToken = svHostToken;
|
||||
|
||||
if(svHostIp.length() != 0)
|
||||
g_pMasterServer->SetHostIP(svHostIp);
|
||||
|
||||
if (result)
|
||||
{
|
||||
m_HostRequestMessageColor = ImVec4(0.00f, 1.00f, 0.00f, 1.00f);
|
||||
|
@ -169,7 +169,7 @@ bool CPylon::GetServerByToken(NetGameServer_t& outGameServer,
|
||||
// &netGameServer -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPylon::PostServerHost(string& outMessage, string& outToken, const NetGameServer_t& netGameServer) const
|
||||
bool CPylon::PostServerHost(string& outMessage, string& outToken, string& outHostIp, const NetGameServer_t& netGameServer) const
|
||||
{
|
||||
rapidjson::Document requestJson;
|
||||
requestJson.SetObject();
|
||||
@ -210,6 +210,13 @@ bool CPylon::PostServerHost(string& outMessage, string& outToken, const NetGameS
|
||||
outToken = responseJson["token"].GetString();
|
||||
}
|
||||
|
||||
if (responseJson.HasMember("ip") && responseJson["ip"].IsString() &&
|
||||
responseJson.HasMember("port") && responseJson["port"].IsInt())
|
||||
{
|
||||
outHostIp = Format("[%s]:%i",
|
||||
responseJson["ip"].GetString(), responseJson["port"].GetInt());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -304,6 +311,35 @@ bool CPylon::CheckForBan(const string& ipAddress, const uint64_t nucleusId, cons
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPylon::AuthForConnection(const uint64_t nucleusId, const char* ipAddress, const char* authCode, string& outToken, string& outMessage) const
|
||||
{
|
||||
rapidjson::Document requestJson;
|
||||
requestJson.SetObject();
|
||||
|
||||
rapidjson::Document::AllocatorType& allocator = requestJson.GetAllocator();
|
||||
|
||||
requestJson.AddMember("id", nucleusId, allocator);
|
||||
requestJson.AddMember("ip", rapidjson::Value(ipAddress, allocator), allocator);
|
||||
requestJson.AddMember("code", rapidjson::Value(authCode, allocator), allocator);
|
||||
|
||||
rapidjson::Document responseJson;
|
||||
|
||||
CURLINFO status;
|
||||
|
||||
if (!SendRequest("/client/authenticate", requestJson, responseJson, outMessage, status, "origin auth error"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseJson.HasMember("token") && responseJson["token"].IsString())
|
||||
{
|
||||
outToken = responseJson["token"].GetString();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sends request to Pylon Master Server.
|
||||
// Input : *endpoint -
|
||||
|
@ -11,11 +11,13 @@ public:
|
||||
|
||||
vector<NetGameServer_t> GetServerList(string& outMessage) const;
|
||||
bool GetServerByToken(NetGameServer_t& slOutServer, string& outMessage, const string& svToken) const;
|
||||
bool PostServerHost(string& outMessage, string& svOutToken, const NetGameServer_t& netGameServer) const;
|
||||
bool PostServerHost(string& outMessage, string& svOutToken, string& outHostIp, const NetGameServer_t& netGameServer) const;
|
||||
|
||||
bool GetBannedList(const CBanSystem::BannedList_t& inBannedVec, CBanSystem::BannedList_t& outBannedVec) const;
|
||||
bool CheckForBan(const string& ipAddress, const uint64_t nucleusId, const string& personaName, string& outReason) const;
|
||||
|
||||
bool AuthForConnection(const uint64_t nucleusId, const char* ipAddress, const char* authCode, string& outToken, string& outMessage) const;
|
||||
|
||||
void ExtractError(const rapidjson::Document& resultBody, string& outMessage, CURLINFO status, const char* errorText = nullptr) const;
|
||||
void ExtractError(const string& response, string& outMessage, CURLINFO status, const char* messageText = nullptr) const;
|
||||
|
||||
@ -26,14 +28,19 @@ public:
|
||||
inline const string& GetCurrentToken() const { return m_Token; }
|
||||
inline const string& GetCurrentError() const { return m_ErrorMsg; }
|
||||
|
||||
inline const string& GetHostIP() const { return m_HostIP; };
|
||||
|
||||
inline void SetCurrentToken(const string& token) { m_Token = token; }
|
||||
inline void SetCurrentError(const string& error) { m_ErrorMsg = error; }
|
||||
|
||||
inline void SetHostIP(const string& ip) { m_HostIP = ip; };
|
||||
|
||||
inline void SetLanguage(const char* lang) { m_Language = lang; };
|
||||
|
||||
private:
|
||||
string m_Token;
|
||||
string m_ErrorMsg;
|
||||
string m_HostIP;
|
||||
string m_Language;
|
||||
};
|
||||
extern CPylon* g_pMasterServer;
|
||||
|
26
src/thirdparty/jwt/include/decode.h
vendored
26
src/thirdparty/jwt/include/decode.h
vendored
@ -34,6 +34,7 @@ extern "C" {
|
||||
#include <time.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef L8W8JWT_MAX_KEY_SIZE
|
||||
#define L8W8JWT_MAX_KEY_SIZE 8192
|
||||
@ -94,6 +95,31 @@ enum l8w8jwt_validation_result {
|
||||
L8W8JWT_TYP_FAILURE = (unsigned)1 << (unsigned)8
|
||||
};
|
||||
|
||||
static void l8w8jwt_get_validation_result_desc(enum l8w8jwt_validation_result res, char* out_buffer, size_t buffer_size)
|
||||
{
|
||||
#define JWT_OUTPUT_MSG(msg) snprintf(out_buffer, buffer_size, "%s", msg)
|
||||
#define JWT_FLAG_STATUS(flag, msg) if(res & flag) { JWT_OUTPUT_MSG(msg); return; }
|
||||
|
||||
if (res == L8W8JWT_VALID)
|
||||
{
|
||||
JWT_OUTPUT_MSG("Success");
|
||||
return;
|
||||
}
|
||||
|
||||
JWT_FLAG_STATUS(L8W8JWT_ISS_FAILURE, "Issuer claim is invalid");
|
||||
JWT_FLAG_STATUS(L8W8JWT_SUB_FAILURE, "Subject claim is invalid");
|
||||
JWT_FLAG_STATUS(L8W8JWT_AUD_FAILURE, "Audience claim is invalid");
|
||||
JWT_FLAG_STATUS(L8W8JWT_JTI_FAILURE, "JWT ID claim is invalid");
|
||||
JWT_FLAG_STATUS(L8W8JWT_EXP_FAILURE, "Token has expired");
|
||||
JWT_FLAG_STATUS(L8W8JWT_NBF_FAILURE, "Token is not yet valid");
|
||||
JWT_FLAG_STATUS(L8W8JWT_IAT_FAILURE, "Token has not been issued yet");
|
||||
JWT_FLAG_STATUS(L8W8JWT_SIGNATURE_VERIFICATION_FAILURE, "Token signature is invalid");
|
||||
JWT_FLAG_STATUS(L8W8JWT_TYP_FAILURE, "Token type is invalid");
|
||||
|
||||
#undef JWT_OUTPUT_MSG
|
||||
#undef JWT_FLAG_STATUS
|
||||
}
|
||||
|
||||
/**
|
||||
* Struct containing the parameters to use for decoding and validating a JWT.
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user