From 33fad57bf7758ec479c8e9ec3ab34fc4fca60f16 Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 2 Jun 2026 16:38:04 -0700 Subject: [PATCH] Restrict the number of sites in the api --- .../siteResource/createSiteResource.ts | 19 +++++++ .../siteResource/updateSiteResource.ts | 19 +++++++ src/components/PrivateResourceForm.tsx | 53 +++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/server/routers/siteResource/createSiteResource.ts b/server/routers/siteResource/createSiteResource.ts index a15b10555..0d012bf25 100644 --- a/server/routers/siteResource/createSiteResource.ts +++ b/server/routers/siteResource/createSiteResource.ts @@ -173,6 +173,25 @@ const createSiteResourceSchema = z { message: "At least one of siteIds or siteId must be provided" } + ) + .refine( + (data) => { + if (data.mode !== "ssh") return true; + const isSingleSiteMode = + data.authDaemonMode === "native" || + (data.pamMode === "push" && data.authDaemonMode === "site") || + (data.pamMode === "push" && data.authDaemonMode === undefined); + if (!isSingleSiteMode) return true; + const effectiveSiteIds = [ + ...(data.siteIds ?? []), + ...(data.siteId !== undefined ? [data.siteId] : []) + ]; + const uniqueSiteIds = new Set(effectiveSiteIds); + return uniqueSiteIds.size <= 1; + }, + { + message: "Only one site is allowed for this SSH daemon mode" + } ); export type CreateSiteResourceBody = z.infer; diff --git a/server/routers/siteResource/updateSiteResource.ts b/server/routers/siteResource/updateSiteResource.ts index a52d15d6a..ffdf51f35 100644 --- a/server/routers/siteResource/updateSiteResource.ts +++ b/server/routers/siteResource/updateSiteResource.ts @@ -181,6 +181,25 @@ const updateSiteResourceSchema = z { message: "At least one of siteIds or siteId must be provided" } + ) + .refine( + (data) => { + if (data.mode !== "ssh") return true; + const isSingleSiteMode = + data.authDaemonMode === "native" || + (data.pamMode === "push" && data.authDaemonMode === "site") || + (data.pamMode === "push" && data.authDaemonMode === undefined); + if (!isSingleSiteMode) return true; + const effectiveSiteIds = [ + ...(data.siteIds ?? []), + ...(data.siteId !== undefined ? [data.siteId] : []) + ]; + const uniqueSiteIds = new Set(effectiveSiteIds); + return uniqueSiteIds.size <= 1; + }, + { + message: "Only one site is allowed for this SSH daemon mode" + } ); export type UpdateSiteResourceBody = z.infer; diff --git a/src/components/PrivateResourceForm.tsx b/src/components/PrivateResourceForm.tsx index adbbc5f22..fb80e0ce0 100644 --- a/src/components/PrivateResourceForm.tsx +++ b/src/components/PrivateResourceForm.tsx @@ -1885,6 +1885,36 @@ export function PrivateResourceForm({ "authDaemonPort", null ); + } else if ( + v === "push" + ) { + // push + site (default) = single site + const curAuthMode = + form.getValues( + "authDaemonMode" + ); + if ( + curAuthMode !== + "remote" && + selectedSites.length > + 1 + ) { + const first = + selectedSites.slice( + 0, + 1 + ); + setSelectedSites( + first + ); + form.setValue( + "siteIds", + first.map( + (s) => + s.siteId + ) + ); + } } }} cols={2} @@ -1952,6 +1982,29 @@ export function PrivateResourceForm({ "authDaemonPort", null ); + // site daemon = single site + if ( + selectedSites.length > + 1 + ) { + const first = + selectedSites.slice( + 0, + 1 + ); + setSelectedSites( + first + ); + form.setValue( + "siteIds", + first.map( + ( + s + ) => + s.siteId + ) + ); + } } }} cols={2}