From 36bcba332c30f9711e483381539df2c97b305c1a Mon Sep 17 00:00:00 2001 From: Fred KISSIE Date: Wed, 11 Mar 2026 05:18:22 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20=20wip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- messages/en-US.json | 1 + server/routers/external.ts | 4 +- server/routers/integration.ts | 4 +- ...sourcePolicy.ts => getResourcePolicies.ts} | 37 ++++++--- server/routers/resource/index.ts | 2 +- .../proxy/[niceId]/authentication/page.tsx | 75 +++++++++++++------ src/lib/queries.ts | 9 ++- 7 files changed, 90 insertions(+), 42 deletions(-) rename server/routers/resource/{getDefaultResourcePolicy.ts => getResourcePolicies.ts} (68%) diff --git a/messages/en-US.json b/messages/en-US.json index 7bd6b9c51..efaf777b5 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -735,6 +735,7 @@ "resourcePolicyOtpEmpty": "No one time password", "resourcePolicyTypeSave": "Save Resource type", "resourcePolicySelect": "Select resource policy", + "resourcePolicyNotFound": "Policy not found", "resourcePolicyRulesEmpty": "No authentication rules", "resourceAuthMethodsDescriptions": "Allow access to the resource via additional auth methods", "resourceAuthSettingsSave": "Saved successfully", diff --git a/server/routers/external.ts b/server/routers/external.ts index a23ec54ad..9ca80dc34 100644 --- a/server/routers/external.ts +++ b/server/routers/external.ts @@ -637,10 +637,10 @@ authenticated.get( ); authenticated.get( - "/resource/:resourceId/default-policy", + "/resource/:resourceId/policies", verifyResourceAccess, verifyUserHasAction(ActionsEnum.getResourcePolicy), - resource.getDefaultResourcePolicy + resource.getResourcePolicies ); authenticated.put( diff --git a/server/routers/integration.ts b/server/routers/integration.ts index 56dec9dee..6b682bff7 100644 --- a/server/routers/integration.ts +++ b/server/routers/integration.ts @@ -454,10 +454,10 @@ authenticated.get( ); authenticated.get( - "/resource/:resourceId/default-policy", + "/resource/:resourceId/policies", verifyApiKeyResourceAccess, verifyApiKeyHasAction(ActionsEnum.getResourcePolicy), - resource.getDefaultResourcePolicy + resource.getResourcePolicies ); authenticated.post( diff --git a/server/routers/resource/getDefaultResourcePolicy.ts b/server/routers/resource/getResourcePolicies.ts similarity index 68% rename from server/routers/resource/getDefaultResourcePolicy.ts rename to server/routers/resource/getResourcePolicies.ts index 39621c2ea..6742a0bd5 100644 --- a/server/routers/resource/getDefaultResourcePolicy.ts +++ b/server/routers/resource/getResourcePolicies.ts @@ -17,12 +17,15 @@ const getResourcePoliciesParamsSchema = z.strictObject({ resourceId: z.string().transform(Number).pipe(z.int().positive()) }); -export type GetDefaultResourcePolicyResponse = GetResourcePolicyResponse; +export type GetResourcePoliciesResponse = { + defaultPolicy: GetResourcePolicyResponse; + sharedPolicy: GetResourcePolicyResponse | null; +}; registry.registerPath({ method: "get", - path: "/resource/{resourceId}/default-policy", - description: "Get the default policy for a resource.", + path: "/resource/{resourceId}/policies", + description: "Get the inline and shared policies associated with a resource.", tags: [OpenAPITags.PublicResource, OpenAPITags.Policy], request: { params: getResourcePoliciesParamsSchema @@ -30,7 +33,7 @@ registry.registerPath({ responses: {} }); -export async function getDefaultResourcePolicy( +export async function getResourcePolicies( req: Request, res: Response, next: NextFunction @@ -52,7 +55,8 @@ export async function getDefaultResourcePolicy( const [resource] = await db .select({ - defaultResourcePolicyId: resources.defaultResourcePolicyId + defaultResourcePolicyId: resources.defaultResourcePolicyId, + resourcePolicyId: resources.resourcePolicyId }) .from(resources) .where(eq(resources.resourceId, resourceId)) @@ -73,11 +77,24 @@ export async function getDefaultResourcePolicy( ); } - const defaultPolicy = await queryResourcePolicy({ - resourcePolicyId: resource.defaultResourcePolicyId - }); - return response(res, { - data: defaultPolicy, + const [defaultPolicy, sharedPolicy] = await Promise.all([ + queryResourcePolicy({ + resourcePolicyId: resource.defaultResourcePolicyId + }), + resource.resourcePolicyId + ? queryResourcePolicy({ + resourcePolicyId: resource.resourcePolicyId + }) + : null + ]); + + return response(res, { + data: { + defaultPolicy: + // the policy will always be non nullable + defaultPolicy as unknown as GetResourcePolicyResponse, + sharedPolicy + }, success: true, error: false, message: "Resource policies retrieved successfully", diff --git a/server/routers/resource/index.ts b/server/routers/resource/index.ts index e602932f0..78803105f 100644 --- a/server/routers/resource/index.ts +++ b/server/routers/resource/index.ts @@ -31,4 +31,4 @@ export * from "./addUserToResource"; export * from "./removeUserFromResource"; export * from "./listAllResourceNames"; export * from "./removeEmailFromResourceWhitelist"; -export * from "./getDefaultResourcePolicy"; +export * from "./getResourcePolicies"; diff --git a/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx b/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx index 414133c86..c1eadf5f3 100644 --- a/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx +++ b/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx @@ -79,7 +79,7 @@ import SetResourcePasswordForm from "components/SetResourcePasswordForm"; import { Binary, Bot, CheckIcon, InfoIcon, Key } from "lucide-react"; import { useTranslations } from "next-intl"; import { useRouter } from "next/navigation"; -import { +import React, { useActionState, useEffect, useMemo, @@ -105,8 +105,7 @@ type ResourcePolicyType = StrategyOption<"inline" | "shared">; export default function ResourceAuthenticationPage() { const { org } = useOrgContext(); - const { resource, updateResource, authInfo, updateAuthInfo } = - useResourceContext(); + const { resource, updateResource } = useResourceContext(); const { env } = useEnvContext(); @@ -125,7 +124,7 @@ export default function ResourceAuthenticationPage() { const form = useForm({ resolver: zodResolver(resourceTypeSchema), defaultValues: { - type: "inline" + type: resource.resourcePolicyId ? "shared" : "inline" } }); @@ -145,7 +144,7 @@ export default function ResourceAuthenticationPage() { enabled: selectedResourceType === "shared" }); - const { data: sharedPolicy } = useQuery({ + const { data: sharedPolicy, isLoading: isLoadingSharedPolicy } = useQuery({ ...resourcePolicyQueries.single({ resourcePolicyId: resource.resourcePolicyId ?? 1 }), @@ -157,17 +156,6 @@ export default function ResourceAuthenticationPage() { id: number; } | null>(null); - const pageLoading = isLoadingPolicies || !defaultPolicy; - - const [ - loadingRemoveResourceHeaderAuth, - setLoadingRemoveResourceHeaderAuth - ] = useState(false); - - const [isSetPasswordOpen, setIsSetPasswordOpen] = useState(false); - const [isSetPincodeOpen, setIsSetPincodeOpen] = useState(false); - const [isSetHeaderAuthOpen, setIsSetHeaderAuthOpen] = useState(false); - const resourcePolicyTypes: Array = [ { id: "inline", @@ -181,6 +169,49 @@ export default function ResourceAuthenticationPage() { } ]; + useEffect(() => { + if (!isLoadingSharedPolicy && sharedPolicy) { + setSelectedPolicy({ + id: sharedPolicy.resourcePolicyId, + name: sharedPolicy.name + }); + } + }, [isLoadingSharedPolicy, sharedPolicy]); + + const [isUpdatingResource, startTransition] = useTransition(); + + async function handleSaveResourcePolicyType() { + try { + if (selectedResourceType === "inline") { + await api.post(`/resource/${resource.resourceId}`, { + resourcePolicyId: null + }); + } else { + if (!selectedPolicy) { + toast({ + title: t("error"), + description: t("resourcePolicySelectError"), + variant: "destructive" + }); + return; + } + await api.post(`/resource/${resource.resourceId}`, { + resourcePolicyId: selectedPolicy.id + }); + } + router.refresh(); + } catch (e) { + toast({ + title: t("error"), + description: formatAxiosError(e), + variant: "destructive" + }); + } + } + + const pageLoading = + isLoadingPolicies || !defaultPolicy || isLoadingSharedPolicy; + if (pageLoading) { return <>; } @@ -214,9 +245,6 @@ export default function ResourceAuthenticationPage() { role="combobox" className={ "w-full md:w-1/2 justify-between" - // "w-45 justify-between text-sm border-r pr-4 rounded-none h-8 hover:bg-transparent", - // "rounded-l-md rounded-r-xs" - // !proxyTarget.siteId && "text-muted-foreground" } > @@ -238,7 +266,7 @@ export default function ResourceAuthenticationPage() { /> - {t("siteNotFound")} + {t("resourcePolicyNotFound")} {policiesList.map((policy) => ( @@ -275,9 +303,10 @@ export default function ResourceAuthenticationPage() { diff --git a/src/lib/queries.ts b/src/lib/queries.ts index 022239006..36e66ca8a 100644 --- a/src/lib/queries.ts +++ b/src/lib/queries.ts @@ -4,7 +4,7 @@ import type { ListClientsResponse } from "@server/routers/client"; import type { ListDomainsResponse } from "@server/routers/domain"; import type { GetResourceWhitelistResponse, - GetDefaultResourcePolicyResponse, + GetResourcePoliciesResponse, ListResourceNamesResponse, ListResourcesResponse, ListResourceRolesResponse, @@ -31,6 +31,7 @@ import { remote } from "./api"; import { durationToMs } from "./durationToMs"; import { wait } from "./wait"; import type { ListResourcePoliciesResponse } from "@server/routers/resource/types"; +import type { GetResourcePolicyResponse } from "@server/routers/policy"; export type ProductUpdate = { link: string | null; @@ -227,7 +228,7 @@ export const resourcePolicyQueries = { queryKey: ["RESOURCE_POLICIES", resourcePolicyId] as const, queryFn: async ({ signal, meta }) => { const res = await meta!.api.get< - AxiosResponse + AxiosResponse >(`/resource-policy/${resourcePolicyId}`, { signal }); return res.data.data; @@ -364,8 +365,8 @@ export const resourceQueries = { queryKey: ["RESOURCES", resourceId, "DEFAULT_POLICY"] as const, queryFn: async ({ signal, meta }) => { const res = await meta!.api.get< - AxiosResponse - >(`/resource/${resourceId}/default-policy`, { signal }); + AxiosResponse + >(`/resource/${resourceId}/policies`, { signal }); return res.data.data; }