diff --git a/server/lib/exitNodes/index.ts b/server/lib/exitNodes/index.ts index caae390a..8889bc35 100644 --- a/server/lib/exitNodes/index.ts +++ b/server/lib/exitNodes/index.ts @@ -1 +1,2 @@ -export * from "./exitNodes"; \ No newline at end of file +export * from "./exitNodes"; +export * from "./shared"; \ No newline at end of file diff --git a/server/lib/exitNodes/shared.ts b/server/lib/exitNodes/shared.ts new file mode 100644 index 00000000..c06f1d05 --- /dev/null +++ b/server/lib/exitNodes/shared.ts @@ -0,0 +1,30 @@ +import { db, exitNodes } from "@server/db"; +import config from "@server/lib/config"; +import { findNextAvailableCidr } from "@server/lib/ip"; + +export async function getNextAvailableSubnet(): Promise { + // Get all existing subnets from routes table + const existingAddresses = await db + .select({ + address: exitNodes.address + }) + .from(exitNodes); + + const addresses = existingAddresses.map((a) => a.address); + let subnet = findNextAvailableCidr( + addresses, + config.getRawConfig().gerbil.block_size, + config.getRawConfig().gerbil.subnet_group + ); + if (!subnet) { + throw new Error("No available subnets remaining in space"); + } + + // replace the last octet with 1 + subnet = + subnet.split(".").slice(0, 3).join(".") + + ".1" + + "/" + + subnet.split("/")[1]; + return subnet; +} \ No newline at end of file diff --git a/server/lib/remoteTraefikConfig.ts b/server/lib/remoteTraefikConfig.ts index e192ab67..d6289dea 100644 --- a/server/lib/remoteTraefikConfig.ts +++ b/server/lib/remoteTraefikConfig.ts @@ -155,14 +155,11 @@ export class TraefikConfigManager { method: error.config?.method }); } else { - logger.error( - "Error updating local SNI:", - error - ); + logger.error("Error updating local SNI:", error); } } } else { - logger.error("No exit node found"); + logger.error("No exit node found. Has gerbil registered yet?"); } } catch (err) { logger.error("Failed to post domains to SNI proxy:", err); @@ -213,35 +210,39 @@ export class TraefikConfigManager { } } - const badgerMiddlewareName = "badger"; - traefikConfig.http.middlewares[badgerMiddlewareName] = { - plugin: { - [badgerMiddlewareName]: { - apiBaseUrl: new URL( - "/api/v1", - `http://${ - config.getRawConfig().server.internal_hostname - }:${config.getRawConfig().server.internal_port}` - ).href, - userSessionCookieName: - config.getRawConfig().server.session_cookie_name, - - // deprecated - accessTokenQueryParam: - config.getRawConfig().server - .resource_access_token_param, - - resourceSessionRequestParam: - config.getRawConfig().server - .resource_session_request_param - } - } - }; - // logger.debug( // `Successfully retrieved traefik config: ${JSON.stringify(traefikConfig)}` // ); + const badgerMiddlewareName = "badger"; + if (traefikConfig?.http?.middlewares) { + traefikConfig.http.middlewares[badgerMiddlewareName] = { + plugin: { + [badgerMiddlewareName]: { + apiBaseUrl: new URL( + "/api/v1", + `http://${ + config.getRawConfig().server + .internal_hostname + }:${config.getRawConfig().server.internal_port}` + ).href, + userSessionCookieName: + config.getRawConfig().server + .session_cookie_name, + + // deprecated + accessTokenQueryParam: + config.getRawConfig().server + .resource_access_token_param, + + resourceSessionRequestParam: + config.getRawConfig().server + .resource_session_request_param + } + } + }; + } + return { domains, traefikConfig }; } catch (error) { // pull data out of the axios error to log diff --git a/server/lib/tokenManager.ts b/server/lib/tokenManager.ts index 8abfd969..99330a3c 100644 --- a/server/lib/tokenManager.ts +++ b/server/lib/tokenManager.ts @@ -150,25 +150,20 @@ export class TokenManager { this.token = response.data.data.token; logger.debug("Token refreshed successfully"); } catch (error) { - logger.error("Failed to refresh token:", error); - if (axios.isAxiosError(error)) { - if (error.response) { - throw new Error( - `Failed to get token with status code: ${error.response.status}` - ); - } else if (error.request) { - throw new Error( - "Failed to request new token: No response received" - ); - } else { - throw new Error( - `Failed to request new token: ${error.message}` - ); - } + logger.error("Error updating proxy mapping:", { + message: error.message, + code: error.code, + status: error.response?.status, + statusText: error.response?.statusText, + url: error.config?.url, + method: error.config?.method + }); } else { - throw new Error(`Failed to get token: ${error}`); + logger.error("Error updating proxy mapping:", error); } + + throw new Error("Failed to refresh token"); } finally { this.isRefreshing = false; } diff --git a/server/routers/gerbil/getConfig.ts b/server/routers/gerbil/getConfig.ts index d8f4c56e..7cf69245 100644 --- a/server/routers/gerbil/getConfig.ts +++ b/server/routers/gerbil/getConfig.ts @@ -12,6 +12,7 @@ import { findNextAvailableCidr } from "@server/lib/ip"; import { fromError } from "zod-validation-error"; import { getAllowedIps } from "../target/helpers"; import { proxyToRemote } from "@server/lib/remoteProxy"; +import { getNextAvailableSubnet } from "@server/lib/exitNodes"; // Define Zod schema for request validation const getConfigSchema = z.object({ publicKey: z.string(), @@ -104,6 +105,11 @@ export async function getConfig( // STOP HERE IN HYBRID MODE if (config.isHybridMode()) { + req.body = { + ...req.body, + endpoint: exitNode[0].endpoint, + listenPort: exitNode[0].listenPort + } return proxyToRemote(req, res, next, "hybrid/gerbil/get-config"); } @@ -164,33 +170,6 @@ export async function generateGerbilConfig(exitNode: ExitNode) { return configResponse; } -async function getNextAvailableSubnet(): Promise { - // Get all existing subnets from routes table - const existingAddresses = await db - .select({ - address: exitNodes.address - }) - .from(exitNodes); - - const addresses = existingAddresses.map((a) => a.address); - let subnet = findNextAvailableCidr( - addresses, - config.getRawConfig().gerbil.block_size, - config.getRawConfig().gerbil.subnet_group - ); - if (!subnet) { - throw new Error("No available subnets remaining in space"); - } - - // replace the last octet with 1 - subnet = - subnet.split(".").slice(0, 3).join(".") + - ".1" + - "/" + - subnet.split("/")[1]; - return subnet; -} - async function getNextAvailablePort(): Promise { // Get all existing ports from exitNodes table const existingPorts = await db