From 474b9a685ddd86af4368bcc112b6fda4a67c1424 Mon Sep 17 00:00:00 2001 From: Varun Narravula Date: Sun, 14 Dec 2025 16:24:17 -0800 Subject: [PATCH] feat(setup): allow declaring a server setup token through env variable --- server/setup/ensureSetupToken.ts | 60 ++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/server/setup/ensureSetupToken.ts b/server/setup/ensureSetupToken.ts index 64298029..87b86321 100644 --- a/server/setup/ensureSetupToken.ts +++ b/server/setup/ensureSetupToken.ts @@ -16,11 +16,23 @@ function generateToken(): string { return generateRandomString(random, alphabet, 32); } +function validateToken(token: string): boolean { + const tokenRegex = /^[a-z0-9]{32}$/; + return tokenRegex.test(token); +} + function generateId(length: number): string { const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; return generateRandomString(random, alphabet, length); } +function showSetupToken(token: string, source: string): void { + console.log(`=== SETUP TOKEN ${source} ===`); + console.log("Token:", token); + console.log("Use this token on the initial setup page"); + console.log("================================"); +} + export async function ensureSetupToken() { try { // Check if a server admin already exists @@ -38,17 +50,48 @@ export async function ensureSetupToken() { } // Check if a setup token already exists - const existingTokens = await db + const [existingToken] = await db .select() .from(setupTokens) .where(eq(setupTokens.used, false)); + const envSetupToken = process.env.PANGOLIN_SETUP_TOKEN; + console.debug("PANGOLIN_SETUP_TOKEN:", envSetupToken); + if (envSetupToken) { + if (!validateToken(envSetupToken)) { + throw new Error( + "invalid token format for PANGOLIN_SETUP_TOKEN" + ); + } + + if (existingToken?.token !== envSetupToken) { + console.warn( + "Overwriting existing token in DB since PANGOLIN_SETUP_TOKEN is set" + ); + + await db + .update(setupTokens) + .set({ token: envSetupToken }) + .where(eq(setupTokens.tokenId, existingToken.tokenId)); + } else { + const tokenId = generateId(15); + + await db.insert(setupTokens).values({ + tokenId: tokenId, + token: envSetupToken, + used: false, + dateCreated: moment().toISOString(), + dateUsed: null + }); + } + + showSetupToken(envSetupToken, "FROM ENVIRONMENT"); + return; + } + // If unused token exists, display it instead of creating a new one - if (existingTokens.length > 0) { - console.log("=== SETUP TOKEN EXISTS ==="); - console.log("Token:", existingTokens[0].token); - console.log("Use this token on the initial setup page"); - console.log("================================"); + if (existingToken) { + showSetupToken(existingToken.token, "EXISTS"); return; } @@ -64,10 +107,7 @@ export async function ensureSetupToken() { dateUsed: null }); - console.log("=== SETUP TOKEN GENERATED ==="); - console.log("Token:", token); - console.log("Use this token on the initial setup page"); - console.log("================================"); + showSetupToken(token, "GENERATED"); } catch (error) { console.error("Failed to ensure setup token:", error); throw error;