From f1641c9f3ec9792f46de8aa7e34ce56e79c6e3f3 Mon Sep 17 00:00:00 2001 From: Owen Date: Wed, 27 Aug 2025 11:24:44 -0700 Subject: [PATCH] Dont create exit node on new key Fixes #1347 Fixes #776 Fixes #1090 --- server/routers/gerbil/createExitNode.ts | 58 +++++++++++++++++++++++++ server/routers/gerbil/getConfig.ts | 42 +----------------- 2 files changed, 60 insertions(+), 40 deletions(-) create mode 100644 server/routers/gerbil/createExitNode.ts diff --git a/server/routers/gerbil/createExitNode.ts b/server/routers/gerbil/createExitNode.ts new file mode 100644 index 00000000..b35913db --- /dev/null +++ b/server/routers/gerbil/createExitNode.ts @@ -0,0 +1,58 @@ +import { db, exitNodes } from "@server/db"; +import { getUniqueExitNodeEndpointName } from "@server/db/names"; +import config from "@server/lib/config"; +import { getNextAvailableSubnet } from "@server/lib/exitNodes"; +import logger from "@server/logger"; +import { eq } from "drizzle-orm"; + +export async function createExitNode(publicKey: string, reachableAt: string | undefined) { + // Fetch exit node + const [exitNodeQuery] = await db.select().from(exitNodes).limit(1); + let exitNode; + if (!exitNodeQuery) { + const address = await getNextAvailableSubnet(); + // TODO: eventually we will want to get the next available port so that we can multiple exit nodes + // const listenPort = await getNextAvailablePort(); + const listenPort = config.getRawConfig().gerbil.start_port; + let subEndpoint = ""; + if (config.getRawConfig().gerbil.use_subdomain) { + subEndpoint = await getUniqueExitNodeEndpointName(); + } + + const exitNodeName = + config.getRawConfig().gerbil.exit_node_name || + `Exit Node ${publicKey.slice(0, 8)}`; + + // create a new exit node + exitNode = await db + .insert(exitNodes) + .values({ + publicKey, + endpoint: `${subEndpoint}${subEndpoint != "" ? "." : ""}${config.getRawConfig().gerbil.base_endpoint}`, + address, + listenPort, + reachableAt, + name: exitNodeName + }) + .returning() + .execute(); + + logger.info( + `Created new exit node ${exitNode[0].name} with address ${exitNode[0].address} and port ${exitNode[0].listenPort}` + ); + } else { + // update the existing exit node + exitNode = await db + .update(exitNodes) + .set({ + reachableAt, + publicKey + }) + .where(eq(exitNodes.publicKey, publicKey)) + .returning(); + + logger.info(`Updated exit node`); + } + + return exitNode; +} diff --git a/server/routers/gerbil/getConfig.ts b/server/routers/gerbil/getConfig.ts index 77f7d2e0..6f41b591 100644 --- a/server/routers/gerbil/getConfig.ts +++ b/server/routers/gerbil/getConfig.ts @@ -13,6 +13,7 @@ import { fromError } from "zod-validation-error"; import { getAllowedIps } from "../target/helpers"; import { proxyToRemote } from "@server/lib/remoteProxy"; import { getNextAvailableSubnet } from "@server/lib/exitNodes"; +import { createExitNode } from "./createExitNode"; // Define Zod schema for request validation const getConfigSchema = z.object({ publicKey: z.string(), @@ -53,46 +54,7 @@ export async function getConfig( ); } - // Fetch exit node - const exitNodeQuery = await db - .select() - .from(exitNodes) - .where(eq(exitNodes.publicKey, publicKey)); - let exitNode; - if (exitNodeQuery.length === 0) { - const address = await getNextAvailableSubnet(); - // TODO: eventually we will want to get the next available port so that we can multiple exit nodes - // const listenPort = await getNextAvailablePort(); - const listenPort = config.getRawConfig().gerbil.start_port; - let subEndpoint = ""; - if (config.getRawConfig().gerbil.use_subdomain) { - subEndpoint = await getUniqueExitNodeEndpointName(); - } - - const exitNodeName = - config.getRawConfig().gerbil.exit_node_name || - `Exit Node ${publicKey.slice(0, 8)}`; - - // create a new exit node - exitNode = await db - .insert(exitNodes) - .values({ - publicKey, - endpoint: `${subEndpoint}${subEndpoint != "" ? "." : ""}${config.getRawConfig().gerbil.base_endpoint}`, - address, - listenPort, - reachableAt, - name: exitNodeName - }) - .returning() - .execute(); - - logger.info( - `Created new exit node ${exitNode[0].name} with address ${exitNode[0].address} and port ${exitNode[0].listenPort}` - ); - } else { - exitNode = exitNodeQuery; - } + const exitNode = await createExitNode(publicKey, reachableAt); if (!exitNode) { return next(