Skip to content

Commit

Permalink
Generate token when connecting to a server, not when fetching the list.
Browse files Browse the repository at this point in the history
Generating a token no longer fetches the entire server list. This also
instructs the list server to not generate a token for the LIST action,
since we're now trying to restrict tokens to a specific server host/port
instead of the player IP.
  • Loading branch information
blast007 committed May 19, 2024
1 parent 3f3d875 commit 2e895d8
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 70 deletions.
1 change: 1 addition & 0 deletions include/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ noinst_HEADERS = \
SceneDatabase.h \
SceneNode.h \
SceneRenderer.h \
ServerAuth.h \
ServerItem.h \
ServerList.h \
ServerListCache.h \
Expand Down
38 changes: 38 additions & 0 deletions include/ServerAuth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* bzflag
* Copyright (c) 1993-2024 Tim Riker
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#ifndef BZF_SERVERAUTH_H
#define BZF_SERVERAUTH_H

#include "common.h"

/* system interface headers */
#include <vector>

/* common interface headers */
#include "StartupInfo.h"
#include "cURLManager.h"

class ServerAuth : cURLManager
{
public:
ServerAuth();
virtual ~ServerAuth();

void requestToken(StartupInfo *info);
void finalization(char *data, unsigned int length, bool good);

private:
StartupInfo *startupInfo;
};

#endif // BZF_SERVERAUTH_H
1 change: 0 additions & 1 deletion include/cURLManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class cURLManager
void setPostMode(std::string postData);
void setRequestFileTime(bool request);
void setURL(const std::string &url);
void setURLwithNonce(const std::string &url);
void setProgressFunction(curl_xferinfo_callback func, const void* data);
void setTimeCondition(timeCondition condition, time_t &t);
void setInterface(const std::string &interfaceIP);
Expand Down
22 changes: 19 additions & 3 deletions src/bzadmin/BZAdminClient.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "TextUtils.h"
#include "version.h"
#include "Team.h"
#include "ServerAuth.h"
#include "ServerList.h"
#include "ErrorHandler.h"
#include "cURLManager.h"
Expand Down Expand Up @@ -73,10 +74,25 @@ BZAdminClient::BZAdminClient(BZAdminUI* bzInterface)
std::cout << std::endl;
return;
}
if ((startupInfo.token[0] == '\0') && (startupInfo.password[0] != '\0'))

// If a password was provided, get a token
if (startupInfo.password[0] != '\0')
{
// won't really output anything, just gets token
outputServerList();
ServerAuth* serverAuth = new ServerAuth;
serverAuth->requestToken(&startupInfo);
// wait no more than 10 seconds for a token
for (int j = 0; j < 40; j++)
{
cURLManager::perform();
if (startupInfo.token[0] != '\0') break;
TimeKeeper::sleep(0.25f);
}
delete serverAuth;

// don't let the bad token specifier slip through to the server,
// just erase it
if (strcmp(startupInfo.token, "badtoken") == 0)
startupInfo.token[0] = '\0';
}
sLink.sendEnter(TankPlayer, myTeam, startupInfo.callsign, "bzadmin", startupInfo.token);
if (sLink.getState() != ServerLink::Okay)
Expand Down
26 changes: 14 additions & 12 deletions src/bzflag/playing.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
#include "PhysicsDriver.h"
#include "PlatformFactory.h"
#include "QuadWallSceneNode.h"
#include "ServerList.h"
#include "ServerAuth.h"
#include "SphereSceneNode.h"
#include "TankGeometryMgr.h"
#include "Team.h"
Expand Down Expand Up @@ -7007,26 +7007,28 @@ static void playingLoop()
// if already connected to a game then first sign off
if (myTank) leaveGame();

// get token if we need to (have a password but no token)
if ((startupInfo.token[0] == '\0')
&& (startupInfo.password[0] != '\0'))
// Erase any existing token
startupInfo.token[0] = '\0';

// get token if we have a password
if (startupInfo.password[0] != '\0')
{
ServerList* serverList = new ServerList;
serverList->startServerPings(&startupInfo);
ServerAuth* serverAuth = new ServerAuth;
serverAuth->requestToken(&startupInfo);
// wait no more than 10 seconds for a token
for (int j = 0; j < 40; j++)
{
serverList->checkEchos(getStartupInfo());
cURLManager::perform();
if (startupInfo.token[0] != '\0') break;
TimeKeeper::sleep(0.25f);
}
delete serverList;
delete serverAuth;

// don't let the bad token specifier slip through to the server,
// just erase it
if (strcmp(startupInfo.token, "badtoken") == 0)
startupInfo.token[0] = '\0';
}
// don't let the bad token specifier slip through to the server,
// just erase it
if (strcmp(startupInfo.token, "badtoken") == 0)
startupInfo.token[0] = '\0';

ares->queryHost(startupInfo.serverName);
waitingDNS = true;
Expand Down
2 changes: 1 addition & 1 deletion src/bzfs/ListServerConnection.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ ListServerLink::ListServerLink(std::string listServerURL,
std::string bzfsUserAgent = "bzfs ";
bzfsUserAgent += getAppVersion();

setURLwithNonce(listServerURL);
setURL(listServerURL);
setUserAgent(bzfsUserAgent);
setTimeout(10);

Expand Down
8 changes: 0 additions & 8 deletions src/common/cURLManager.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,6 @@ void cURLManager::setURL(const std::string &url)
logDebugMessage(1,"CURLOPT_URL error %d : %s\n", result, errorBuffer);
}

void cURLManager::setURLwithNonce(const std::string &url)
{
// only the default list server is known to support the nonce parameter
const std::string nonce = (strcasecmp(url.c_str(), DefaultListServerURL) == 0) ? TextUtils::format("?nocache=%lu",
time(0)) : "";
setURL(url + nonce);
}

void cURLManager::setProgressFunction(curl_xferinfo_callback func, const void* data)
{
CURLcode result;
Expand Down
1 change: 1 addition & 0 deletions src/game/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ libGame_la_SOURCES = \
PlayerInfo.cxx \
Ray.cxx \
ServerItem.cxx \
ServerAuth.cxx \
ServerList.cxx \
ServerListCache.cxx \
StartupInfo.cxx \
Expand Down
111 changes: 111 additions & 0 deletions src/game/ServerAuth.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* bzflag
* Copyright (c) 1993-2024 Tim Riker
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

/* interface header */
#include "ServerAuth.h"

/* system headers */
#include <cstring>

/* common implementation headers */
#include "TextUtils.h"
#include "ErrorHandler.h"

ServerAuth::ServerAuth()
{
}

ServerAuth::~ServerAuth()
{
}

void ServerAuth::requestToken(StartupInfo *info)
{
startupInfo = info;

std::string url = info->listServerURL;

std::string msg = "action=GETTOKEN&callsign=";
msg += TextUtils::url_encode(info->callsign);
msg += "&password=";
msg += TextUtils::url_encode(info->password);
if (info->serverName[0] != '\0')
{
msg += "&nameport=";
msg += info->serverName;
msg += ':';
msg += std::to_string(info->serverPort);
}
setPostMode(msg);
setURL(url);
addHandle();
}

void ServerAuth::finalization(char *_data, unsigned int length, bool good)
{
if (good)
{
char *base = (char *)_data;
char *endS = base + length;
const char tokenIdentifier[] = "TOKEN: ";
const char noTokenIdentifier[] = "NOTOK: ";
const char errorIdentifier[] = "ERROR: ";
const char noticeIdentifier[] = "NOTICE: ";

while (base < endS)
{
// find next newline
char* scan = base;
while (scan < endS && *scan != '\n')
scan++;

// if no newline then no more complete replies
if (scan >= endS)
break;
*scan++ = '\0';

// look for TOKEN: and save token if found also look for NOTOK:
// and record "badtoken" into the token string and print an
// error
if (strncmp(base, tokenIdentifier, strlen(tokenIdentifier)) == 0)
{
strncpy(startupInfo->token, (char *)(base + strlen(tokenIdentifier)),
TokenLen - 1);
startupInfo->token[TokenLen - 1] = '\0';
#ifdef DEBUG
std::vector<std::string> args;
args.push_back(startupInfo->token);
printError("got token: {1}", &args);
#endif
}
else if (!strncmp(base, noTokenIdentifier,
strlen(noTokenIdentifier)))
{
printError("ERROR: did not get token:");
printError(base);
strcpy(startupInfo->token, "badtoken\0");
}
else if (!strncmp(base, errorIdentifier, strlen(errorIdentifier)))
{
printError(base);
strcpy(startupInfo->token, "badtoken\0");
}
else if (!strncmp(base, noticeIdentifier, strlen(noticeIdentifier)))
printError(base);

// next reply
base = scan;
}
}
else
strcpy(startupInfo->token, "badtoken\0");
}
56 changes: 11 additions & 45 deletions src/game/ServerList.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ void ServerList::readServerList()
{
char *base = (char *)theData;
char *endS = base + theLen;
const char tokenIdentifier[] = "TOKEN: ";
const char noTokenIdentifier[] = "NOTOK: ";
const char errorIdentifier[] = "ERROR: ";
const char noticeIdentifier[] = "NOTICE: ";
// walks entire reply including HTTP headers
while (base < endS)
Expand All @@ -81,38 +78,7 @@ void ServerList::readServerList()
break;
*scan++ = '\0';

// look for TOKEN: and save token if found also look for NOTOK:
// and record "badtoken" into the token string and print an
// error
if (strncmp(base, tokenIdentifier, strlen(tokenIdentifier)) == 0)
{
strncpy(startupInfo->token, (char *)(base + strlen(tokenIdentifier)),
TokenLen - 1);
startupInfo->token[TokenLen - 1] = '\0';
#ifdef DEBUG
printError("got token:");
printError(startupInfo->token);
#endif
base = scan;
continue;
}
else if (!strncmp(base, noTokenIdentifier,
strlen(noTokenIdentifier)))
{
printError("ERROR: did not get token:");
printError(base);
strcpy(startupInfo->token, "badtoken\0");
base = scan;
continue;
}
else if (!strncmp(base, errorIdentifier, strlen(errorIdentifier)))
{
printError(base);
strcpy(startupInfo->token, "badtoken\0");
base = scan;
continue;
}
else if (!strncmp(base, noticeIdentifier, strlen(noticeIdentifier)))
if (!strncmp(base, noticeIdentifier, strlen(noticeIdentifier)))
{
printError(base);
base = scan;
Expand Down Expand Up @@ -306,19 +272,19 @@ void ServerList::checkEchos(StartupInfo *info)

std::string msg = "action=LIST&version=";
msg += getServerVersion();
msg += "&callsign=";
msg += TextUtils::url_encode(info->callsign);
msg += "&password=";
msg += TextUtils::url_encode(info->password);
if (info->serverName[0] != '\0')
// Send callsign/password only if the password is set
if (info->password[0] != '\0')
{
msg += "&nameport=";
msg += info->serverName;
msg += ':';
msg += std::to_string(info->serverPort);
msg += "&callsign=";
msg += TextUtils::url_encode(info->callsign);
msg += "&password=";
msg += TextUtils::url_encode(info->password);
// Since tokens are now tied to a game server host/port instead of the player IP, we will skip generating
// a token during the LIST operation.
msg += "&skiptoken=1";
}
setPostMode(msg);
setURLwithNonce(url);
setURL(url);
addHandle();

// do phase 1 only if we found a valid list server url
Expand Down

0 comments on commit 2e895d8

Please sign in to comment.