From 3f3e9cf1bb8fd280482db6e68661f516e6650858 Mon Sep 17 00:00:00 2001 From: Pallavi Kumari Date: Mon, 6 Oct 2025 21:00:07 +0530 Subject: [PATCH] add cert resolver --- messages/en-US.json | 6 +- server/db/sqlite/schema/schema.ts | 4 +- server/routers/domain/createOrgDomain.ts | 17 +++-- server/routers/domain/listDomains.ts | 4 +- src/components/CreateDomainForm.tsx | 83 +++++++++++++++++++----- 5 files changed, 92 insertions(+), 22 deletions(-) diff --git a/messages/en-US.json b/messages/en-US.json index 4cffaf98..2f7fd3e0 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1891,5 +1891,9 @@ "cannotbeUndone": "This can not be undone.", "toConfirm": "to confirm", "deleteClientQuestion": "Are you sure you want to remove the client from the site and organization?", - "clientMessageRemove": "Once removed, the client will no longer be able to connect to the site." + "clientMessageRemove": "Once removed, the client will no longer be able to connect to the site.", + "certResolver": "Certificate Resolver", + "certResolverDescription": "Select the certificate resolver to use for this resource.", + "selectCertResolver": "Select Certificate Resolver", + "enterCustomResolver": "Enter Custom Resolver" } diff --git a/server/db/sqlite/schema/schema.ts b/server/db/sqlite/schema/schema.ts index 3d6c6b0d..d0d972ff 100644 --- a/server/db/sqlite/schema/schema.ts +++ b/server/db/sqlite/schema/schema.ts @@ -11,7 +11,9 @@ export const domains = sqliteTable("domains", { type: text("type"), // "ns", "cname", "wildcard" verified: integer("verified", { mode: "boolean" }).notNull().default(false), failed: integer("failed", { mode: "boolean" }).notNull().default(false), - tries: integer("tries").notNull().default(0) + tries: integer("tries").notNull().default(0), + certResolver: text("certResolver").default("letsencrypt"), + customCertResolver: text("customCertResolver") }); export const orgs = sqliteTable("orgs", { diff --git a/server/routers/domain/createOrgDomain.ts b/server/routers/domain/createOrgDomain.ts index d0e8a72b..54cad172 100644 --- a/server/routers/domain/createOrgDomain.ts +++ b/server/routers/domain/createOrgDomain.ts @@ -24,16 +24,21 @@ const paramsSchema = z const bodySchema = z .object({ type: z.enum(["ns", "cname", "wildcard"]), - baseDomain: subdomainSchema + baseDomain: subdomainSchema, + certResolver: z.enum(["letsencrypt", "custom"]).optional(), // optional, only for wildcard + customCertResolver: z.string().optional() // required if certResolver === "custom" }) .strict(); + export type CreateDomainResponse = { domainId: string; nsRecords?: string[]; cnameRecords?: { baseDomain: string; value: string }[]; aRecords?: { baseDomain: string; value: string }[]; txtRecords?: { baseDomain: string; value: string }[]; + certResolver?: string | null; + customCertResolver?: string | null; }; // Helper to check if a domain is a subdomain or equal to another domain @@ -71,7 +76,7 @@ export async function createOrgDomain( } const { orgId } = parsedParams.data; - const { type, baseDomain } = parsedBody.data; + const { type, baseDomain, certResolver, customCertResolver } = parsedBody.data; if (build == "oss") { if (type !== "wildcard") { @@ -254,7 +259,9 @@ export async function createOrgDomain( domainId, baseDomain, type, - verified: type === "wildcard" ? true : false + verified: type === "wildcard" ? true : false, + certResolver: certResolver || null, + customCertResolver: customCertResolver || null }) .returning(); @@ -325,7 +332,9 @@ export async function createOrgDomain( cnameRecords, txtRecords, nsRecords, - aRecords + aRecords, + certResolver: returned.certResolver, + customCertResolver: returned.customCertResolver }, success: true, error: false, diff --git a/server/routers/domain/listDomains.ts b/server/routers/domain/listDomains.ts index fe51cde6..85bc3caa 100644 --- a/server/routers/domain/listDomains.ts +++ b/server/routers/domain/listDomains.ts @@ -42,7 +42,9 @@ async function queryDomains(orgId: string, limit: number, offset: number) { type: domains.type, failed: domains.failed, tries: domains.tries, - configManaged: domains.configManaged + configManaged: domains.configManaged, + certResolver: domains.certResolver, + customCertResolver: domains.customCertResolver, }) .from(orgDomains) .where(eq(orgDomains.orgId, orgId)) diff --git a/src/components/CreateDomainForm.tsx b/src/components/CreateDomainForm.tsx index 258aee49..24b1d466 100644 --- a/src/components/CreateDomainForm.tsx +++ b/src/components/CreateDomainForm.tsx @@ -45,6 +45,7 @@ import { import { useOrgContext } from "@app/hooks/useOrgContext"; import { build } from "@server/build"; import { toASCII, toUnicode } from 'punycode'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select"; // Helper functions for Unicode domain handling @@ -96,7 +97,9 @@ const formSchema = z.object({ .min(1, "Domain is required") .refine((val) => isValidDomainFormat(val), "Invalid domain format") .transform((val) => toPunycode(val)), - type: z.enum(["ns", "cname", "wildcard"]) + type: z.enum(["ns", "cname", "wildcard"]), + certResolver: z.string().optional(), + customCertResolver: z.string().optional() }); type FormValues = z.infer; @@ -107,6 +110,12 @@ type CreateDomainFormProps = { onCreated?: (domain: CreateDomainResponse) => void; }; +// Example cert resolver options (replace with real API/fetch if needed) +const certResolverOptions = [ + { id: "letsencrypt", title: "Let's Encrypt" }, + { id: "custom", title: "Custom Resolver" } +]; + export default function CreateDomainForm({ open, setOpen, @@ -125,15 +134,26 @@ export default function CreateDomainForm({ resolver: zodResolver(formSchema), defaultValues: { baseDomain: "", - type: build == "oss" || !env.flags.usePangolinDns ? "wildcard" : "ns" + type: build == "oss" || !env.flags.usePangolinDns ? "wildcard" : "ns", + certResolver: "", + customCertResolver: "" } }); - function reset() { + const baseDomain = form.watch("baseDomain"); + const domainType = form.watch("type"); + + const punycodePreview = useMemo(() => { + if (!baseDomain) return ""; + const punycode = toPunycode(baseDomain); + return punycode !== baseDomain.toLowerCase() ? punycode : ""; + }, [baseDomain]); + + const reset = () => { form.reset(); setLoading(false); setCreatedDomain(null); - } + }; async function onSubmit(values: FormValues) { setLoading(true); @@ -158,17 +178,9 @@ export default function CreateDomainForm({ } finally { setLoading(false); } - } - - const baseDomain = form.watch("baseDomain"); - const domainInputValue = form.watch("baseDomain") || ""; - - const punycodePreview = useMemo(() => { - if (!domainInputValue) return ""; - const punycode = toPunycode(domainInputValue); - return punycode !== domainInputValue.toLowerCase() ? punycode : ""; - }, [domainInputValue]); + }; + // Domain type options let domainOptions: any = []; if (build != "oss" && env.flags.usePangolinDns) { domainOptions = [ @@ -250,7 +262,7 @@ export default function CreateDomainForm({ {t("internationaldomaindetected")}
-

{t("willbestoredas")} {punycodePreview}

+

{t("willbestoredas")} {punycodePreview}

@@ -260,6 +272,47 @@ export default function CreateDomainForm({ )} /> + {domainType === "wildcard" && ( + ( + + {t("certResolver")} + + + + + {field.value === "custom" && ( + + + form.setValue("customCertResolver", e.target.value) + } + /> + + )} + + )} + /> + + )} ) : (