diff --git a/server/routers/gerbil/updateHolePunch.ts b/server/routers/gerbil/updateHolePunch.ts index 68a7282f..26608345 100644 --- a/server/routers/gerbil/updateHolePunch.ts +++ b/server/routers/gerbil/updateHolePunch.ts @@ -7,11 +7,14 @@ import HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; import logger from "@server/logger"; import { fromError } from "zod-validation-error"; +import { validateNewtSessionToken } from "@server/auth/sessions/newt"; +import { validateOlmSessionToken } from "@server/auth/sessions/olm"; // Define Zod schema for request validation const updateHolePunchSchema = z.object({ olmId: z.string().optional(), newtId: z.string().optional(), + token: z.string(), ip: z.string(), port: z.number(), timestamp: z.number() @@ -34,13 +37,28 @@ export async function updateHolePunch( ); } - const { olmId, newtId, ip, port, timestamp } = parsedParams.data; - + const { olmId, newtId, ip, port, timestamp, token } = parsedParams.data; + // logger.debug(`Got hole punch with ip: ${ip}, port: ${port} for olmId: ${olmId} or newtId: ${newtId}`); let site: Site | undefined; if (olmId) { + const { session, olm: olmSession } = + await validateOlmSessionToken(token); + if (!session || !olmSession) { + return next( + createHttpError(HttpCode.UNAUTHORIZED, "Unauthorized") + ); + } + + if (olmId !== olmSession.olmId) { + logger.warn(`Olm ID mismatch: ${olmId} !== ${olmSession.olmId}`); + return next( + createHttpError(HttpCode.UNAUTHORIZED, "Unauthorized") + ); + } + const [olm] = await db .select() .from(olms) @@ -66,7 +84,24 @@ export async function updateHolePunch( .select() .from(sites) .where(eq(sites.siteId, client.siteId)); + } else if (newtId) { + const { session, newt: newtSession } = + await validateNewtSessionToken(token); + + if (!session || !newtSession) { + return next( + createHttpError(HttpCode.UNAUTHORIZED, "Unauthorized") + ); + } + + if (newtId !== newtSession.newtId) { + logger.warn(`Newt ID mismatch: ${newtId} !== ${newtSession.newtId}`); + return next( + createHttpError(HttpCode.UNAUTHORIZED, "Unauthorized") + ); + } + const [newt] = await db .select() .from(newts) @@ -90,10 +125,10 @@ export async function updateHolePunch( } if (!site || !site.endpoint || !site.subnet) { - logger.warn(`Site not found for olmId: ${olmId} or newtId: ${newtId}`); - return next( - createHttpError(HttpCode.NOT_FOUND, "Site not found") + logger.warn( + `Site not found for olmId: ${olmId} or newtId: ${newtId}` ); + return next(createHttpError(HttpCode.NOT_FOUND, "Site not found")); } return res.status(HttpCode.OK).send({ diff --git a/server/routers/olm/handleOlmRegisterMessage.ts b/server/routers/olm/handleOlmRegisterMessage.ts index cf3164be..4bf46744 100644 --- a/server/routers/olm/handleOlmRegisterMessage.ts +++ b/server/routers/olm/handleOlmRegisterMessage.ts @@ -1,6 +1,6 @@ import db from "@server/db"; import { MessageHandler } from "../ws"; -import { clients, Olm, olms, sites } from "@server/db/schema"; +import { clients, exitNodes, Olm, olms, sites } from "@server/db/schema"; import { eq } from "drizzle-orm"; import { addPeer, deletePeer } from "../newt/peers"; import logger from "@server/logger"; @@ -46,27 +46,35 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => { .where(eq(sites.siteId, client.siteId)) .limit(1); - if (!client) { + if (!site) { logger.warn("Site not found or does not have exit node"); return; } + if (!site.exitNodeId) { + logger.warn("Site does not have exit node"); + return; + } + + const [exitNode] = await db + .select() + .from(exitNodes) + .where(eq(exitNodes.exitNodeId, site.exitNodeId)) + .limit(1); + + sendToClient(olm.olmId, { + type: "olm/wg/holepunch", + data: { + serverPubKey: exitNode.publicKey, + } + }); + // make sure we hand endpoints for both the site and the client and the lastHolePunch is not too old if (!site.endpoint || !client.endpoint) { logger.warn("Site or client has no endpoint or listen port"); return; } - sendToClient(olm.olmId, { - type: "olm/wg/holepunch", - data: { - endpoint: site.endpoint, - publicKey: site.publicKey, - serverIP: site.address!.split("/")[0], - tunnelIP: `${client.subnet.split("/")[0]}/${site.address!.split("/")[1]}` // put the client ip in the same subnet as the site. TODO: Is this right? Maybe we need th make .subnet work properly! - } - }); - const now = new Date().getTime() / 1000; if (site.lastHolePunch && now - site.lastHolePunch > 6) { logger.warn("Site last hole punch is too old"); diff --git a/src/app/[orgId]/settings/layout.tsx b/src/app/[orgId]/settings/layout.tsx index 0f9f2ffe..d94da3fb 100644 --- a/src/app/[orgId]/settings/layout.tsx +++ b/src/app/[orgId]/settings/layout.tsx @@ -5,7 +5,8 @@ import { LinkIcon, Settings, Users, - Waypoints + Waypoints, + Workflow } from "lucide-react"; import { Header } from "@app/components/Header"; import { verifySession } from "@app/lib/auth/verifySession";