Skip to content

Commit 441c2c5

Browse files
committed
Generate token when connecting to a server, not when fetching the list.
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.
1 parent 7e58656 commit 441c2c5

10 files changed

+196
-70
lines changed

include/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ noinst_HEADERS = \
102102
SceneDatabase.h \
103103
SceneNode.h \
104104
SceneRenderer.h \
105+
ServerAuth.h \
105106
ServerItem.h \
106107
ServerList.h \
107108
ServerListCache.h \

include/ServerAuth.h

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* bzflag
2+
* Copyright (c) 1993-2024 Tim Riker
3+
*
4+
* This package is free software; you can redistribute it and/or
5+
* modify it under the terms of the license found in the file
6+
* named COPYING that should have accompanied this file.
7+
*
8+
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9+
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11+
*/
12+
13+
#ifndef BZF_SERVERAUTH_H
14+
#define BZF_SERVERAUTH_H
15+
16+
#include "common.h"
17+
18+
/* system interface headers */
19+
#include <vector>
20+
21+
/* common interface headers */
22+
#include "StartupInfo.h"
23+
#include "cURLManager.h"
24+
25+
class ServerAuth : cURLManager
26+
{
27+
public:
28+
ServerAuth();
29+
virtual ~ServerAuth();
30+
31+
void requestToken(StartupInfo *info);
32+
void finalization(char *data, unsigned int length, bool good);
33+
34+
private:
35+
StartupInfo *startupInfo;
36+
};
37+
38+
#endif // BZF_SERVERAUTH_H

include/cURLManager.h

-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ class cURLManager
4646
void setPostMode(std::string postData);
4747
void setRequestFileTime(bool request);
4848
void setURL(const std::string &url);
49-
void setURLwithNonce(const std::string &url);
5049
void setProgressFunction(curl_xferinfo_callback func, const void* data);
5150
void setTimeCondition(timeCondition condition, time_t &t);
5251
void setInterface(const std::string &interfaceIP);

src/bzadmin/BZAdminClient.cxx

+19-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "TextUtils.h"
3131
#include "version.h"
3232
#include "Team.h"
33+
#include "ServerAuth.h"
3334
#include "ServerList.h"
3435
#include "ErrorHandler.h"
3536
#include "cURLManager.h"
@@ -73,10 +74,25 @@ BZAdminClient::BZAdminClient(BZAdminUI* bzInterface)
7374
std::cout << std::endl;
7475
return;
7576
}
76-
if ((startupInfo.token[0] == '\0') && (startupInfo.password[0] != '\0'))
77+
78+
// If a password was provided, get a token
79+
if (startupInfo.password[0] != '\0')
7780
{
78-
// won't really output anything, just gets token
79-
outputServerList();
81+
ServerAuth* serverAuth = new ServerAuth;
82+
serverAuth->requestToken(&startupInfo);
83+
// wait no more than 10 seconds for a token
84+
for (int j = 0; j < 40; j++)
85+
{
86+
cURLManager::perform();
87+
if (startupInfo.token[0] != '\0') break;
88+
TimeKeeper::sleep(0.25f);
89+
}
90+
delete serverAuth;
91+
92+
// don't let the bad token specifier slip through to the server,
93+
// just erase it
94+
if (strcmp(startupInfo.token, "badtoken") == 0)
95+
startupInfo.token[0] = '\0';
8096
}
8197
sLink.sendEnter(TankPlayer, myTeam, startupInfo.callsign, "bzadmin", startupInfo.token);
8298
if (sLink.getState() != ServerLink::Okay)

src/bzflag/playing.cxx

+14-12
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
#include "PhysicsDriver.h"
5353
#include "PlatformFactory.h"
5454
#include "QuadWallSceneNode.h"
55-
#include "ServerList.h"
55+
#include "ServerAuth.h"
5656
#include "SphereSceneNode.h"
5757
#include "TankGeometryMgr.h"
5858
#include "Team.h"
@@ -7007,26 +7007,28 @@ static void playingLoop()
70077007
// if already connected to a game then first sign off
70087008
if (myTank) leaveGame();
70097009

7010-
// get token if we need to (have a password but no token)
7011-
if ((startupInfo.token[0] == '\0')
7012-
&& (startupInfo.password[0] != '\0'))
7010+
// Erase any existing token
7011+
startupInfo.token[0] = '\0';
7012+
7013+
// get token if we have a password
7014+
if (startupInfo.password[0] != '\0')
70137015
{
7014-
ServerList* serverList = new ServerList;
7015-
serverList->startServerPings(&startupInfo);
7016+
ServerAuth* serverAuth = new ServerAuth;
7017+
serverAuth->requestToken(&startupInfo);
70167018
// wait no more than 10 seconds for a token
70177019
for (int j = 0; j < 40; j++)
70187020
{
7019-
serverList->checkEchos(getStartupInfo());
70207021
cURLManager::perform();
70217022
if (startupInfo.token[0] != '\0') break;
70227023
TimeKeeper::sleep(0.25f);
70237024
}
7024-
delete serverList;
7025+
delete serverAuth;
7026+
7027+
// don't let the bad token specifier slip through to the server,
7028+
// just erase it
7029+
if (strcmp(startupInfo.token, "badtoken") == 0)
7030+
startupInfo.token[0] = '\0';
70257031
}
7026-
// don't let the bad token specifier slip through to the server,
7027-
// just erase it
7028-
if (strcmp(startupInfo.token, "badtoken") == 0)
7029-
startupInfo.token[0] = '\0';
70307032

70317033
ares->queryHost(startupInfo.serverName);
70327034
waitingDNS = true;

src/bzfs/ListServerConnection.cxx

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ ListServerLink::ListServerLink(std::string listServerURL,
4343
std::string bzfsUserAgent = "bzfs ";
4444
bzfsUserAgent += getAppVersion();
4545

46-
setURLwithNonce(listServerURL);
46+
setURL(listServerURL);
4747
setUserAgent(bzfsUserAgent);
4848
setTimeout(10);
4949

src/common/cURLManager.cxx

-8
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,6 @@ void cURLManager::setURL(const std::string &url)
186186
logDebugMessage(1,"CURLOPT_URL error %d : %s\n", result, errorBuffer);
187187
}
188188

189-
void cURLManager::setURLwithNonce(const std::string &url)
190-
{
191-
// only the default list server is known to support the nonce parameter
192-
const std::string nonce = (strcasecmp(url.c_str(), DefaultListServerURL) == 0) ? TextUtils::format("?nocache=%lu",
193-
time(0)) : "";
194-
setURL(url + nonce);
195-
}
196-
197189
void cURLManager::setProgressFunction(curl_xferinfo_callback func, const void* data)
198190
{
199191
CURLcode result;

src/game/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ libGame_la_SOURCES = \
2626
PlayerInfo.cxx \
2727
Ray.cxx \
2828
ServerItem.cxx \
29+
ServerAuth.cxx \
2930
ServerList.cxx \
3031
ServerListCache.cxx \
3132
StartupInfo.cxx \

src/game/ServerAuth.cxx

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/* bzflag
2+
* Copyright (c) 1993-2024 Tim Riker
3+
*
4+
* This package is free software; you can redistribute it and/or
5+
* modify it under the terms of the license found in the file
6+
* named COPYING that should have accompanied this file.
7+
*
8+
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9+
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11+
*/
12+
13+
/* interface header */
14+
#include "ServerAuth.h"
15+
16+
/* system headers */
17+
#include <cstring>
18+
19+
/* common implementation headers */
20+
#include "TextUtils.h"
21+
#include "ErrorHandler.h"
22+
23+
ServerAuth::ServerAuth()
24+
{
25+
}
26+
27+
ServerAuth::~ServerAuth()
28+
{
29+
}
30+
31+
void ServerAuth::requestToken(StartupInfo *info)
32+
{
33+
startupInfo = info;
34+
35+
std::string url = info->listServerURL;
36+
37+
std::string msg = "action=GETTOKEN&callsign=";
38+
msg += TextUtils::url_encode(info->callsign);
39+
msg += "&password=";
40+
msg += TextUtils::url_encode(info->password);
41+
if (info->serverName[0] != '\0')
42+
{
43+
msg += "&nameport=";
44+
msg += info->serverName;
45+
msg += ':';
46+
msg += std::to_string(info->serverPort);
47+
}
48+
setPostMode(msg);
49+
setURL(url);
50+
addHandle();
51+
}
52+
53+
void ServerAuth::finalization(char *_data, unsigned int length, bool good)
54+
{
55+
if (good)
56+
{
57+
char *base = (char *)_data;
58+
char *endS = base + length;
59+
const char tokenIdentifier[] = "TOKEN: ";
60+
const char noTokenIdentifier[] = "NOTOK: ";
61+
const char errorIdentifier[] = "ERROR: ";
62+
const char noticeIdentifier[] = "NOTICE: ";
63+
64+
while (base < endS)
65+
{
66+
// find next newline
67+
char* scan = base;
68+
while (scan < endS && *scan != '\n')
69+
scan++;
70+
71+
// if no newline then no more complete replies
72+
if (scan >= endS)
73+
break;
74+
*scan++ = '\0';
75+
76+
// look for TOKEN: and save token if found also look for NOTOK:
77+
// and record "badtoken" into the token string and print an
78+
// error
79+
if (strncmp(base, tokenIdentifier, strlen(tokenIdentifier)) == 0)
80+
{
81+
strncpy(startupInfo->token, (char *)(base + strlen(tokenIdentifier)),
82+
TokenLen - 1);
83+
startupInfo->token[TokenLen - 1] = '\0';
84+
#ifdef DEBUG
85+
std::vector<std::string> args;
86+
args.push_back(startupInfo->token);
87+
printError("got token: {1}", &args);
88+
#endif
89+
}
90+
else if (!strncmp(base, noTokenIdentifier,
91+
strlen(noTokenIdentifier)))
92+
{
93+
printError("ERROR: did not get token:");
94+
printError(base);
95+
strcpy(startupInfo->token, "badtoken\0");
96+
}
97+
else if (!strncmp(base, errorIdentifier, strlen(errorIdentifier)))
98+
{
99+
printError(base);
100+
strcpy(startupInfo->token, "badtoken\0");
101+
}
102+
else if (!strncmp(base, noticeIdentifier, strlen(noticeIdentifier)))
103+
printError(base);
104+
105+
// next reply
106+
base = scan;
107+
}
108+
}
109+
else
110+
strcpy(startupInfo->token, "badtoken\0");
111+
}

src/game/ServerList.cxx

+11-45
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,6 @@ void ServerList::readServerList()
6464
{
6565
char *base = (char *)theData;
6666
char *endS = base + theLen;
67-
const char tokenIdentifier[] = "TOKEN: ";
68-
const char noTokenIdentifier[] = "NOTOK: ";
69-
const char errorIdentifier[] = "ERROR: ";
7067
const char noticeIdentifier[] = "NOTICE: ";
7168
// walks entire reply including HTTP headers
7269
while (base < endS)
@@ -81,38 +78,7 @@ void ServerList::readServerList()
8178
break;
8279
*scan++ = '\0';
8380

84-
// look for TOKEN: and save token if found also look for NOTOK:
85-
// and record "badtoken" into the token string and print an
86-
// error
87-
if (strncmp(base, tokenIdentifier, strlen(tokenIdentifier)) == 0)
88-
{
89-
strncpy(startupInfo->token, (char *)(base + strlen(tokenIdentifier)),
90-
TokenLen - 1);
91-
startupInfo->token[TokenLen - 1] = '\0';
92-
#ifdef DEBUG
93-
printError("got token:");
94-
printError(startupInfo->token);
95-
#endif
96-
base = scan;
97-
continue;
98-
}
99-
else if (!strncmp(base, noTokenIdentifier,
100-
strlen(noTokenIdentifier)))
101-
{
102-
printError("ERROR: did not get token:");
103-
printError(base);
104-
strcpy(startupInfo->token, "badtoken\0");
105-
base = scan;
106-
continue;
107-
}
108-
else if (!strncmp(base, errorIdentifier, strlen(errorIdentifier)))
109-
{
110-
printError(base);
111-
strcpy(startupInfo->token, "badtoken\0");
112-
base = scan;
113-
continue;
114-
}
115-
else if (!strncmp(base, noticeIdentifier, strlen(noticeIdentifier)))
81+
if (!strncmp(base, noticeIdentifier, strlen(noticeIdentifier)))
11682
{
11783
printError(base);
11884
base = scan;
@@ -306,19 +272,19 @@ void ServerList::checkEchos(StartupInfo *info)
306272

307273
std::string msg = "action=LIST&version=";
308274
msg += getServerVersion();
309-
msg += "&callsign=";
310-
msg += TextUtils::url_encode(info->callsign);
311-
msg += "&password=";
312-
msg += TextUtils::url_encode(info->password);
313-
if (info->serverName[0] != '\0')
275+
// Send callsign/password only if the password is set
276+
if (info->password[0] != '\0')
314277
{
315-
msg += "&nameport=";
316-
msg += info->serverName;
317-
msg += ':';
318-
msg += std::to_string(info->serverPort);
278+
msg += "&callsign=";
279+
msg += TextUtils::url_encode(info->callsign);
280+
msg += "&password=";
281+
msg += TextUtils::url_encode(info->password);
282+
// Since tokens are now tied to a game server host/port instead of the player IP, we will skip generating
283+
// a token during the LIST operation.
284+
msg += "&skiptoken=1";
319285
}
320286
setPostMode(msg);
321-
setURLwithNonce(url);
287+
setURL(url);
322288
addHandle();
323289

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

0 commit comments

Comments
 (0)