Initial commit

This commit is contained in:
Brian Beck 2025-09-11 16:56:30 -07:00
parent 2211ed7650
commit ebb3dc9cdd
10121 changed files with 801 additions and 4 deletions

View file

@ -0,0 +1,8 @@
if (!isObject(ServerGroup))
{
exec("tournament/settings.cs");
exec("tournament/login.cs");
tn_community_login_initiate();
exec("tournament/browser.cs");
}

View file

@ -0,0 +1,143 @@
// TribesNext Project
// http://www.tribesnext.com/
// Copyright 2011
// Tribes 2 Community System
// Robot Browser Client - Prototype
$TribesNext::Community::Browser::Active = 0;
function CommunityBrowserInterface::onConnected(%this)
{
//echo("Browser-Sending: " @ %this.data);
%this.primed = 0;
%this.send(%this.data);
}
function CommunityBrowserInterface::onDisconnect(%this)
{
$TribesNext::Community::Browser::Active = 0;
tn_community_Browser_executeNextRequest();
}
function CommunityBrowserInterface::onLine(%this, %line)
{
if (trim(%line) $= "")
{
%this.primed = 1;
return;
}
if (!%this.primed)
return;
//warn("Browser: " @ %line);
%message = getField(%line, 0);
switch$ (%message)
{
// display errors to the user -- some of these should never actually happen
case "ERR":
if (getField(%line, 1) $= "BROWSER")
{
%type = getField(%line, 2);
switch$ (%type)
{
// TODO -- implement different message types
case "BLAH":
%message = "Blah!";
default:
%message = "Unknown error in browser system: " @ %line;
}
schedule(500, 0, MessageBoxOK, "ERROR", %message);
}
case "DCE":
%dceCert = collapseEscape(getField(%line, 1));
%index = getField(%dceCert, 1);
$T2CSRI::ClientDCESupport::DCECert[%index] = %dceCert;
case "CEC":
$T2CSRI::CommunityCertificate = collapseEscape(getField(%line, 1));
// schedule a refresh
%expire = getField($T2CSRI::CommunityCertificate, 2);
rubyEval("tsEval '$temp=\"' + (" @ %expire @ " - Time.now().to_i).to_s + '\";'");
%expire = $temp - 60;
if (%expire > 0)
{
if (isEventPending($TribesNext::Browser::CertRefreshSch))
cancel($TribesNext::Browser::CertRefreshSch);
$TribesNext::Browser::CertRefreshSch = schedule(1000 * %expire, 0, tn_community_Browser_request_cert);
}
else
{
schedule(500, 0, MessageBoxOK, "ERROR", "Received expired certificate from community server. Is your computer's clock set correctly?");
}
}
}
function tn_community_browser_initQueue()
{
if (isObject($BrowserRequestQueue))
$BrowserRequestQueue.delete();
$BrowserRequestQueue = new MessageVector();
}
tn_community_browser_initQueue();
function tn_community_browser_processRequest(%request, %payload)
{
if (%request !$= "")
{
%request = "?guid=" @ getField($LoginCertificate, 1) @ "&uuid=" @ $TribesNext::Community::UUID @ "&" @ %request;
}
if (%payload $= "")
{
%data = "GET " @ $TribesNext::Community::BaseURL @ $TribesNext::Community::BrowserScript @ %request;
%data = %data @ " HTTP/1.1\r\nHost: " @ $TribesNext::Community::Host @ "\r\nUser-Agent: Tribes 2\r\nConnection: close\r\n\r\n";
}
else
{
%data = "POST " @ $TribesNext::Community::BaseURL @ $TribesNext::Community::BrowserScript @ " HTTP/1.1\r\n";
%data = %data @ "Host: " @ $TribesNext::Community::Host @ "\r\nUser-Agent: Tribes 2\r\nConnection: close\r\n";
%data = %data @ %payload;
}
$BrowserRequestQueue.pushBackLine(%data);
if (!$TribesNext::Community::Browser::Active)
tn_community_browser_executeNextRequest();
}
function tn_community_browser_executeNextRequest()
{
if ($BrowserRequestQueue.getNumLines() <= 0)
return;
%data = $BrowserRequestQueue.getLineText(0);
$BrowserRequestQueue.popFrontLine();
$TribesNext::Community::Browser::Active = 1;
if (isObject(CommunityBrowserInterface))
{
CommunityBrowserInterface.disconnect();
}
else
{
new TCPObject(CommunityBrowserInterface);
}
CommunityBrowserInterface.data = %data;
CommunityBrowserInterface.connect($TribesNext::Community::Host @ ":" @ $TribesNext::Community::Port);
}
// implementation of API requests
function tn_community_Browser_request_cert()
{
if ($TribesNext::Community::UUID $= "")
{
schedule(3000, 0, tn_community_Browser_request_cert);
return;
}
//error("Browser: Downloading enhanced certificate from community server.");
tn_community_Browser_processRequest("method=cert");
}
schedule(3000, 0, tn_community_Browser_request_cert);

View file

@ -0,0 +1,185 @@
// TribesNext Project
// http://www.tribesnext.com/
// Copyright 2011
// Tribes 2 Community System
// Robot Session Client
// Since the game itself does not store the users' passwords for any longer than is required
// to decrypt their RSA private keys, the "robot" client must negotiate sessions through an
// RSA challenge/response.
// The robot client issues a challenge request by sending the user's GUID and a random nonce.
// The DCE issues a challenge that is encrypted with the user's public key. The challenge is
// valid for a server configured lifetime, during which any challenge request by the same GUID
// would return the same challenge. The client sends the decrypted challenge back to the DCE, and
// if it is a match, a session is initiated, and a session UUID is returned to the robot client,
// which it uses to verify its identity for all authenticated requests. The challenge lifetime is
// sufficiently generous to allow an RSA decryption and heavy network latency.
// The client will refresh periodically (every 10 minutes by default) to keep the session alive.
function CommunitySessionInterface::onLine(%this, %line)
{
//warn("SInterf: " @ %line);
if (trim(%line) $= "")
{
%this.primed = 1;
return;
}
if (%this.primed)
{
echo(%line);
if (getSubStr(%line, 0, 11) $= "CHALLENGE: ")
{
$TribesNext::Community::SessionErrors = 0;
$TribesNext::Community::Challenge = getSubStr(%line, 11, strlen(%line));
//error("Challenge set: " @ $TribesNext::Community::Challenge);
cancel($TribesNext::Community::SessionSchedule);
$TribesNext::Community::SessionSchedule = schedule(200, 0, tn_community_login_initiate);
}
else if (getSubStr(%line, 0, 6) $= "UUID: ")
{
$TribesNext::Community::SessionErrors = 0;
$TribesNext::Community::UUID = getSubStr(%line, 6, strlen(%line));
$TribesNext::Community::Challenge = "";
//error("UUID set: " @ $TribesNext::Community::UUID);
cancel($TribesNext::Community::SessionSchedule);
$TribesNext::Community::SessionSchedule = schedule($TribesNext::Community::SessionRefresh * 1000, 0, tn_community_login_initiate);
}
else if (getSubStr(%line, 0, 5) $= "ERR: ")
{
error("Session negotiation error: " @ getSubStr(%line, 5, strlen(%line)));
$TribesNext::Community::UUID = "";
$TribesNext::Community::Challenge = "";
// add schedule with backoff, up to about 15 minutes
$TribesNext::Community::SessionErrors++;
if ($TribesNext::Community::SessionErrors > 66)
$TribesNext::Community::SessionErrors = 66;
$TribesNext::Community::SessionSchedule = schedule(200 * ($TribesNext::Community::SessionErrors * $TribesNext::Community::SessionErrors), 0, tn_community_login_initiate);
}
else if (getSubStr(%line, 0, 9) $= "REFRESHED")
{
$TribesNext::Community::SessionErrors = 0;
//error("Session refreshed. Scheduling next ping.");
cancel($TribesNext::Community::SessionSchedule);
$TribesNext::Community::SessionSchedule = schedule($TribesNext::Community::SessionRefresh * 1000, 0, tn_community_login_initiate);
}
else if (getSubStr(%line, 0, 7) $= "TIMEOUT")
{
$TribesNext::Community::SessionErrors = 0;
//error("Session timed out. Refreshing.");
$TribesNext::Community::UUID = "";
$TribesNext::Community::Challenge = "";
cancel($TribesNext::Community::SessionSchedule);
$TribesNext::Community::SessionSchedule = schedule(200, 0, tn_community_login_initiate);
}
}
}
function CommunitySessionInterface::onConnected(%this)
{
//echo("Sending: " @ %this.data);
%this.primed = 0;
%this.send(%this.data);
}
// initiates the session negotiation process
function tn_community_login_initiate()
{
if (isEventPending($TribesNext::Community::SessionSchedule))
{
cancel($TribesNext::Community::SessionSchedule);
}
%payload = "GET " @ $TribesNext::Community::BaseURL @ $TribesNext::Community::LoginScript @ "?guid=" @ getField($LoginCertificate, 1) @ "&";
// is there an existing session?
if ($TribesNext::Community::UUID !$= "")
{
// try to refresh it
%payload = %payload @ "uuid=" @ $TribesNext::Community::UUID;
}
else
{
// no session -- either expired, or never had one
// is a challenge present
if ($TribesNext::Community::Challenge $= "")
{
// no challenge present... ask for one:
// create a random nonce half of the length of the active RSA key modulus
%length = strlen(getField($LoginCertificate, 3)) / 2;
%nonce = "1"; // start with a one to prevent truncation issues
for (%i = 1; %i < %length; %i++)
{
%nibble = getRandom(0, 15);
if (%nibble == 10)
%nibble = "a";
else if (%nibble == 11)
%nibble = "b";
else if (%nibble == 12)
%nibble = "c";
else if (%nibble == 13)
%nibble = "d";
else if (%nibble == 14)
%nibble = "e";
else if (%nibble >= 15)
%nibble = "f";
%nonce = %nonce @ %nibble;
}
$TribesNext::Community::Nonce = %nonce;
// transmit the request to the community server
%payload = %payload @ "nonce=" @ %nonce;
}
else
{
%challenge = strlwr($TribesNext::Community::Challenge);
for (%i = 0; %i < strlen(%challenge); %i++)
{
%char = strcmp(getSubStr(%challenge, %i, 1), "");
if ((%char < 48 || %char > 102) || (%char > 57 && %char < 97))
{
// non-hex characters in the challenge!
error("TNCommunity: Hostile challenge payload returned by server!");
$TribesNext::Community::Challenge = "";
tn_community_login_initiate();
return;
}
}
// challenge is present... decrypt it and transmit it to the community server
rubyEval("tsEval '$decryptedChallenge=\"' + $accountKey.decrypt('" @ %challenge @ "'.to_i(16)).to_s(16) + '\";'");
%verifiedNonce = getSubStr($decryptedChallenge, 0, strLen($TribesNext::Community::Nonce));
if (%verifiedNonce !$= $TribesNext::Community::Nonce)
{
// this is not the nonce we sent to the community server, try again
error("TNCommunity: Unmatched nonce in challenge returned by server!");
$TribesNext::Community::Challenge = "";
tn_community_login_initiate();
return;
}
else
{
%response = getSubStr($decryptedChallenge, strLen($TribesNext::Community::Nonce), strlen($decryptedChallenge));
%payload = %payload @ "response=" @ %response;
}
}
}
%payload = %payload @ " HTTP/1.1\r\nHost: " @ $TribesNext::Community::Host @ "\r\nUser-Agent: Tribes 2\r\nConnection: close\r\n\r\n";
if (isObject(CommunitySessionInterface))
{
CommunitySessionInterface.disconnect();
}
else
{
new TCPObject(CommunitySessionInterface);
}
CommunitySessionInterface.data = %payload;
CommunitySessionInterface.connect($TribesNext::Community::Host @ ":" @ $TribesNext::Community::Port);
}

View file

@ -0,0 +1,19 @@
// TribesNext Project
// http://www.tribesnext.com/
// Copyright 2011-2017
// Tribes 2 Community System
// Robot Client Settings
// Tournament Version
// This file contains the URL and server settings for the community system.
$TribesNext::Community::Host = "tribesnext.thyth.com";
$TribesNext::Community::Port = 80;
$TribesNext::Community::BaseURL = "/tn/robot/";
$TribesNext::Community::LoginScript = "robot_login.php";
$TribesNext::Community::MailScript = "robot_mail.php";
$TribesNext::Community::BrowserScript = "robot_browser.php";
$TribesNext::Community::SessionRefresh = 10*60;