diff --git a/server/routers/client/listClients.ts b/server/routers/client/listClients.ts index d76c8b9..6a0610a 100644 --- a/server/routers/client/listClients.ts +++ b/server/routers/client/listClients.ts @@ -54,7 +54,6 @@ function queryClients(orgId: string, accessibleClientIds: number[]) { }) .from(clients) .leftJoin(orgs, eq(clients.orgId, orgs.orgId)) - .leftJoin(orgs, eq(clients.orgId, orgs.orgId)) .where( and( inArray(clients.clientId, accessibleClientIds), diff --git a/server/routers/client/updateClient.ts b/server/routers/client/updateClient.ts index f3f00c4..f1d827c 100644 --- a/server/routers/client/updateClient.ts +++ b/server/routers/client/updateClient.ts @@ -1,10 +1,7 @@ import { Request, Response, NextFunction } from "express"; import { z } from "zod"; import { db } from "@server/db"; -import { - clients, - clientSites -} from "@server/db/schemas"; +import { clients, clientSites } from "@server/db/schemas"; import response from "@server/lib/response"; import HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; @@ -12,6 +9,14 @@ import logger from "@server/logger"; import { eq, and } from "drizzle-orm"; import { fromError } from "zod-validation-error"; import { OpenAPITags, registry } from "@server/openApi"; +import { + addPeer as newtAddPeer, + deletePeer as newtDeletePeer +} from "../newt/peers"; +import { + addPeer as olmAddPeer, + deletePeer as olmDeletePeer +} from "../olm/peers"; const updateClientParamsSchema = z .object({ @@ -22,7 +27,9 @@ const updateClientParamsSchema = z const updateClientSchema = z .object({ name: z.string().min(1).max(255).optional(), - siteIds: z.array(z.string().transform(Number).pipe(z.number())).optional() + siteIds: z + .array(z.string().transform(Number).pipe(z.number())) + .optional() }) .strict(); @@ -92,6 +99,81 @@ export async function updateClient( ); } + if (siteIds) { + let sitesAdded = []; + let sitesRemoved = []; + + // Fetch existing site associations + const existingSites = await db + .select({ siteId: clientSites.siteId }) + .from(clientSites) + .where(eq(clientSites.clientId, clientId)); + + const existingSiteIds = existingSites.map((site) => site.siteId); + + // Determine which sites were added and removed + sitesAdded = siteIds.filter( + (siteId) => !existingSiteIds.includes(siteId) + ); + sitesRemoved = existingSiteIds.filter( + (siteId) => !siteIds.includes(siteId) + ); + + logger.info( + `Adding ${sitesAdded.length} new sites to client ${client.clientId}` + ); + for (const siteId of sitesAdded) { + if (!client.subnet || !client.pubKey || !client.endpoint) { + logger.debug("Client subnet, pubKey or endpoint is not set"); + continue; + } + + const site = await newtAddPeer(siteId, { + publicKey: client.pubKey, + allowedIps: [`${client.subnet.split("/")[0]}/32`], // we want to only allow from that client + endpoint: client.endpoint + }); + if (!site) { + logger.debug("Failed to add peer to newt - missing site"); + continue; + } + + if (!site.endpoint || !site.publicKey) { + logger.debug("Site endpoint or publicKey is not set"); + continue; + } + await olmAddPeer(client.clientId, { + siteId: siteId, + endpoint: site.endpoint, + publicKey: site.publicKey, + serverIP: site.address, + serverPort: site.listenPort + }); + } + + logger.info( + `Removing ${sitesRemoved.length} sites from client ${client.clientId}` + ); + for (const siteId of sitesRemoved) { + if (!client.pubKey) { + logger.debug("Client pubKey is not set"); + continue; + } + const site = await newtDeletePeer(siteId, client.pubKey); + if (!site) { + logger.debug( + "Failed to delete peer from newt - missing site" + ); + continue; + } + if (!site.endpoint || !site.publicKey) { + logger.debug("Site endpoint or publicKey is not set"); + continue; + } + await olmDeletePeer(client.clientId, site.siteId, site.publicKey); + } + } + await db.transaction(async (trx) => { // Update client name if provided if (name) { @@ -111,7 +193,7 @@ export async function updateClient( // Create new site associations if (siteIds.length > 0) { await trx.insert(clientSites).values( - siteIds.map(siteId => ({ + siteIds.map((siteId) => ({ clientId, siteId })) diff --git a/server/routers/newt/peers.ts b/server/routers/newt/peers.ts index 18afd1e..d81fabf 100644 --- a/server/routers/newt/peers.ts +++ b/server/routers/newt/peers.ts @@ -37,6 +37,8 @@ export async function addPeer( }); logger.info(`Added peer ${peer.publicKey} to newt ${newt.newtId}`); + + return site; } export async function deletePeer(siteId: number, publicKey: string) { @@ -67,6 +69,8 @@ export async function deletePeer(siteId: number, publicKey: string) { }); logger.info(`Deleted peer ${publicKey} from newt ${newt.newtId}`); + + return site; } export async function updatePeer( @@ -105,4 +109,6 @@ export async function updatePeer( }); logger.info(`Updated peer ${publicKey} on newt ${newt.newtId}`); + + return site; } diff --git a/server/routers/olm/peers.ts b/server/routers/olm/peers.ts index 7af1e35..9d42a29 100644 --- a/server/routers/olm/peers.ts +++ b/server/routers/olm/peers.ts @@ -1,5 +1,5 @@ import db from "@server/db"; -import { clients, olms, newts } from "@server/db/schemas"; +import { clients, olms, newts, sites } from "@server/db/schemas"; import { eq } from "drizzle-orm"; import { sendToClient } from "../ws"; import logger from "@server/logger"; @@ -37,7 +37,7 @@ export async function addPeer( logger.info(`Added peer ${peer.publicKey} to olm ${olm.olmId}`); } -export async function deletePeer(clientId: number, publicKey: string) { +export async function deletePeer(clientId: number, siteId: number, publicKey: string) { const [olm] = await db .select() .from(olms) @@ -50,7 +50,8 @@ export async function deletePeer(clientId: number, publicKey: string) { sendToClient(olm.olmId, { type: "olm/wg/peer/remove", data: { - publicKey + publicKey, + siteId: siteId } });