use admin key token for admin auth

This commit is contained in:
Evan
2025-03-04 08:43:17 -08:00
parent 62c4887fbb
commit 6a22d58281
5 changed files with 20 additions and 34 deletions
+2
View File
@@ -72,6 +72,8 @@ export interface ServerConfig {
workerPort(gameID: GameID): number;
workerPortByIndex(workerID: number): number;
env(): GameEnv;
adminToken(): string;
adminHeader(): string;
}
export interface Config {
+7 -1
View File
@@ -22,6 +22,12 @@ import { pastelTheme } from "./PastelTheme";
import { pastelThemeDark } from "./PastelThemeDark";
export abstract class DefaultServerConfig implements ServerConfig {
adminHeader(): string {
return "x-admin-key";
}
adminToken(): string {
return process.env.ADMIN_TOKEN;
}
numWorkers(): number {
return 2;
}
@@ -183,7 +189,7 @@ export class DefaultConfig implements Config {
return {
cost: (p: Player) =>
p.type() == PlayerType.Human && this.infiniteGold()
? 0
? 25
: 25_000_000,
territoryBound: false,
};
+5
View File
@@ -5,9 +5,14 @@ import { GameEnv, ServerConfig } from "./Config";
import { DefaultConfig, DefaultServerConfig } from "./DefaultConfig";
export class DevServerConfig extends DefaultServerConfig {
adminToken(): string {
return "WARNING_DEV_ADMIN_KEY_DO_NOT_USE_IN_PRODUCTION";
}
env(): GameEnv {
return GameEnv.Dev;
}
gameCreationRate(highTraffic: boolean): number {
return 5 * 1000;
}
+2 -8
View File
@@ -180,7 +180,6 @@ async function fetchLobbies(): Promise<void> {
async function schedulePublicGame() {
const gameID = generateID();
publicLobbyIDs.add(gameID);
// Create the default public game config (from your GameManager)
const defaultGameConfig = {
gameMap: getNextMap(),
@@ -192,9 +191,7 @@ async function schedulePublicGame() {
disableNPCs: false,
bots: 400,
};
const workerPath = config.workerPath(gameID);
// Send request to the worker to start the game
try {
const response = await fetch(
@@ -203,7 +200,8 @@ async function schedulePublicGame() {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Internal-Request": "true", // Special header for internal requests
"X-Internal-Request": "true",
[config.adminHeader()]: config.adminToken(),
},
body: JSON.stringify({
gameID: gameID,
@@ -211,11 +209,9 @@ async function schedulePublicGame() {
}),
},
);
if (!response.ok) {
throw new Error(`Failed to schedule public game: ${response.statusText}`);
}
const data = await response.json();
} catch (error) {
console.error(
@@ -226,11 +222,9 @@ async function schedulePublicGame() {
}
}
// Map rotation management (moved from GameManager)
let mapsPlaylist: GameMapType[] = [];
const random = new PseudoRandom(123);
// Get the next map in rotation
function getNextMap(): GameMapType {
if (mapsPlaylist.length > 0) {
return mapsPlaylist.shift()!;
+4 -25
View File
@@ -79,9 +79,9 @@ export function startWorker() {
// TODO: if game is public make sure request came from localhohst!!!
const clientIP = req.ip || req.socket.remoteAddress || "unknown";
const gc = req.body?.gameConfig as GameConfig;
if (gc?.gameType == GameType.Public && !isLocalhost(req)) {
if (gc?.gameType == GameType.Public && !isAdmin(req)) {
console.warn(
`cannot create public game ${id}, ip ${clientIP} not localhost`,
`cannot create public game ${id}, ip ${clientIP} not admin`,
);
return res.status(400);
}
@@ -320,27 +320,6 @@ export function startWorker() {
});
}
const isLocalhost = (req: Request): boolean => {
// Get client IP address from various possible sources
const clientIP =
req.ip ||
req.socket.remoteAddress ||
(req.headers["x-forwarded-for"] as string)?.split(",").shift() ||
"unknown";
// Check if the request is from a loopback address
const isLoopbackIP =
// IPv4 localhost
clientIP === "127.0.0.1" ||
// IPv6 localhost
clientIP === "::1" ||
// Full loopback range
clientIP.startsWith("127.");
// Check hostname
const isLocalHostname =
req.hostname === "localhost" || req.headers.host?.startsWith("localhost:");
// Consider request local if either IP is loopback or hostname is localhost
return isLoopbackIP || isLocalHostname;
const isAdmin = (req: Request): boolean => {
return req.headers[config.adminHeader()] === config.adminToken();
};