mirror of
https://github.com/outbackdingo/pangolin.git
synced 2026-01-27 18:20:04 +00:00
Copy in config to db, remove 2nd column, + prefer
This commit is contained in:
@@ -1895,5 +1895,6 @@
|
||||
"certResolver": "Certificate Resolver",
|
||||
"certResolverDescription": "Select the certificate resolver to use for this resource.",
|
||||
"selectCertResolver": "Select Certificate Resolver",
|
||||
"enterCustomResolver": "Enter Custom Resolver"
|
||||
"enterCustomResolver": "Enter Custom Resolver",
|
||||
"preferWildcardCert": "Prefer Wildcard Certificate"
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ export const domains = pgTable("domains", {
|
||||
failed: boolean("failed").notNull().default(false),
|
||||
tries: integer("tries").notNull().default(0),
|
||||
certResolver: varchar("certResolver"),
|
||||
customCertResolver: varchar("customCertResolver")
|
||||
customCertResolver: varchar("customCertResolver"),
|
||||
preferWildcardCert: boolean("preferWildcardCert")
|
||||
});
|
||||
|
||||
export const orgs = pgTable("orgs", {
|
||||
|
||||
@@ -13,7 +13,7 @@ export const domains = sqliteTable("domains", {
|
||||
failed: integer("failed", { mode: "boolean" }).notNull().default(false),
|
||||
tries: integer("tries").notNull().default(0),
|
||||
certResolver: text("certResolver"),
|
||||
customCertResolver: text("customCertResolver")
|
||||
preferWildcardCert: integer("preferWildcardCert", { mode: "boolean" })
|
||||
});
|
||||
|
||||
export const orgs = sqliteTable("orgs", {
|
||||
|
||||
@@ -77,8 +77,7 @@ export async function getTraefikConfig(
|
||||
subnet: sites.subnet,
|
||||
exitNodeId: sites.exitNodeId,
|
||||
// Domain cert resolver fields
|
||||
domainCertResolver: domains.certResolver,
|
||||
domainCustomCertResolver: domains.customCertResolver
|
||||
domainCertResolver: domains.certResolver
|
||||
})
|
||||
.from(sites)
|
||||
.innerJoin(targets, eq(targets.siteId, sites.siteId))
|
||||
@@ -167,8 +166,7 @@ export async function getTraefikConfig(
|
||||
rewritePathType: row.rewritePathType,
|
||||
priority: priority,
|
||||
// Store domain cert resolver fields
|
||||
domainCertResolver: row.domainCertResolver,
|
||||
domainCustomCertResolver: row.domainCustomCertResolver
|
||||
domainCertResolver: row.domainCertResolver
|
||||
});
|
||||
}
|
||||
|
||||
@@ -247,42 +245,47 @@ export async function getTraefikConfig(
|
||||
wildCard = resource.fullDomain;
|
||||
}
|
||||
|
||||
const configDomain = config.getDomain(resource.domainId);
|
||||
const rawTraefikCfg = config.getRawConfig().traefik || {};
|
||||
const globalDefaultResolver = rawTraefikCfg.cert_resolver;
|
||||
const globalDefaultResolver =
|
||||
config.getRawConfig().traefik.cert_resolver;
|
||||
const globalDefaultPreferWildcard =
|
||||
config.getRawConfig().traefik.prefer_wildcard_cert;
|
||||
|
||||
|
||||
const domainCertResolver =
|
||||
resource.domainCertResolver ?? configDomain?.cert_resolver;
|
||||
const domainCustomResolver =
|
||||
resource.domainCustomCertResolver;
|
||||
const preferWildcardCert =
|
||||
resource.preferWildcardCert ?? configDomain?.prefer_wildcard_cert ?? false;
|
||||
const domainCertResolver = resource.domainCertResolver;
|
||||
const preferWildcardCert = resource.preferWildcardCert;
|
||||
|
||||
let resolverName: string | undefined;
|
||||
|
||||
let preferWildcard: boolean | undefined;
|
||||
// Handle both letsencrypt & custom cases
|
||||
if (domainCertResolver === "custom") {
|
||||
resolverName = domainCustomResolver?.trim();
|
||||
} else if (domainCertResolver) {
|
||||
resolverName = domainCertResolver;
|
||||
if (domainCertResolver) {
|
||||
resolverName = domainCertResolver.trim();
|
||||
} else {
|
||||
resolverName = globalDefaultResolver;
|
||||
}
|
||||
|
||||
const tls = {
|
||||
certResolver: resolverName,
|
||||
...(preferWildcardCert
|
||||
? {
|
||||
domains: [
|
||||
{
|
||||
main: wildCard
|
||||
}
|
||||
]
|
||||
}
|
||||
: {})
|
||||
};
|
||||
if (
|
||||
preferWildcardCert !== undefined &&
|
||||
preferWildcardCert !== null
|
||||
) {
|
||||
preferWildcard = preferWildcardCert;
|
||||
} else {
|
||||
preferWildcard = globalDefaultPreferWildcard;
|
||||
}
|
||||
|
||||
let tls = {};
|
||||
if (build == "oss") {
|
||||
tls = {
|
||||
certResolver: resolverName,
|
||||
...(preferWildcard
|
||||
? {
|
||||
domains: [
|
||||
{
|
||||
main: wildCard
|
||||
}
|
||||
]
|
||||
}
|
||||
: {})
|
||||
};
|
||||
}
|
||||
|
||||
const additionalMiddlewares =
|
||||
config.getRawConfig().traefik.additional_middlewares || [];
|
||||
|
||||
@@ -108,7 +108,6 @@ export async function getTraefikConfig(
|
||||
// Certificate
|
||||
certificateStatus: certificates.status,
|
||||
domainCertResolver: domains.certResolver,
|
||||
domainCustomCertResolver: domains.customCertResolver
|
||||
})
|
||||
.from(sites)
|
||||
.innerJoin(targets, eq(targets.siteId, sites.siteId))
|
||||
@@ -206,7 +205,6 @@ export async function getTraefikConfig(
|
||||
rewritePathType: row.rewritePathType,
|
||||
priority: priority, // may be null, we fallback later
|
||||
domainCertResolver: row.domainCertResolver,
|
||||
domainCustomCertResolver: row.domainCustomCertResolver
|
||||
});
|
||||
}
|
||||
|
||||
@@ -306,29 +304,6 @@ export async function getTraefikConfig(
|
||||
wildCard = resource.fullDomain;
|
||||
}
|
||||
|
||||
const configDomain = config.getDomain(resource.domainId);
|
||||
const rawTraefikCfg = config.getRawConfig().traefik || {};
|
||||
const globalDefaultResolver = rawTraefikCfg.cert_resolver;
|
||||
|
||||
|
||||
const domainCertResolver =
|
||||
resource.domainCertResolver ?? configDomain?.cert_resolver;
|
||||
const domainCustomResolver =
|
||||
resource.domainCustomCertResolver;
|
||||
const preferWildcardCert =
|
||||
resource.preferWildcardCert ?? configDomain?.prefer_wildcard_cert ?? false;
|
||||
|
||||
let resolverName: string | undefined;
|
||||
|
||||
// Handle both letsencrypt & custom cases
|
||||
if (domainCertResolver === "custom") {
|
||||
resolverName = domainCustomResolver?.trim();
|
||||
} else if (domainCertResolver) {
|
||||
resolverName = domainCertResolver;
|
||||
} else {
|
||||
resolverName = globalDefaultResolver;
|
||||
}
|
||||
|
||||
let tls = {};
|
||||
if (!privateConfig.getRawPrivateConfig().flags.use_pangolin_dns) {
|
||||
const domainParts = fullDomain.split(".");
|
||||
|
||||
@@ -25,8 +25,8 @@ const bodySchema = z
|
||||
.object({
|
||||
type: z.enum(["ns", "cname", "wildcard"]),
|
||||
baseDomain: subdomainSchema,
|
||||
certResolver: z.enum(["letsencrypt", "custom"]).optional(), // optional, only for wildcard
|
||||
customCertResolver: z.string().optional() // required if certResolver === "custom"
|
||||
certResolver: z.string().optional().nullable(),
|
||||
preferWildcardCert: z.boolean().optional().nullable() // optional, only for wildcard
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -38,7 +38,7 @@ export type CreateDomainResponse = {
|
||||
aRecords?: { baseDomain: string; value: string }[];
|
||||
txtRecords?: { baseDomain: string; value: string }[];
|
||||
certResolver?: string | null;
|
||||
customCertResolver?: string | null;
|
||||
preferWildcardCert?: boolean;
|
||||
};
|
||||
|
||||
// Helper to check if a domain is a subdomain or equal to another domain
|
||||
@@ -76,7 +76,7 @@ export async function createOrgDomain(
|
||||
}
|
||||
|
||||
const { orgId } = parsedParams.data;
|
||||
const { type, baseDomain, certResolver, customCertResolver } = parsedBody.data;
|
||||
const { type, baseDomain, certResolver, preferWildcardCert } = parsedBody.data;
|
||||
|
||||
if (build == "oss") {
|
||||
if (type !== "wildcard") {
|
||||
@@ -261,7 +261,7 @@ export async function createOrgDomain(
|
||||
type,
|
||||
verified: type === "wildcard" ? true : false,
|
||||
certResolver: certResolver || null,
|
||||
customCertResolver: customCertResolver || null
|
||||
preferWildcardCert: preferWildcardCert || false
|
||||
})
|
||||
.returning();
|
||||
|
||||
@@ -334,7 +334,7 @@ export async function createOrgDomain(
|
||||
nsRecords,
|
||||
aRecords,
|
||||
certResolver: returned.certResolver,
|
||||
customCertResolver: returned.customCertResolver
|
||||
preferWildcardCert: returned.preferWildcardCert
|
||||
},
|
||||
success: true,
|
||||
error: false,
|
||||
|
||||
@@ -44,7 +44,7 @@ async function queryDomains(orgId: string, limit: number, offset: number) {
|
||||
tries: domains.tries,
|
||||
configManaged: domains.configManaged,
|
||||
certResolver: domains.certResolver,
|
||||
customCertResolver: domains.customCertResolver,
|
||||
preferWildcardCert: domains.preferWildcardCert
|
||||
})
|
||||
.from(orgDomains)
|
||||
.where(eq(orgDomains.orgId, orgId))
|
||||
|
||||
@@ -37,7 +37,9 @@ async function copyInDomains() {
|
||||
const configDomains = Object.entries(rawDomains).map(
|
||||
([key, value]) => ({
|
||||
domainId: key,
|
||||
baseDomain: value.base_domain.toLowerCase()
|
||||
baseDomain: value.base_domain.toLowerCase(),
|
||||
certResolver: value.cert_resolver || null,
|
||||
preferWildcardCert: value.prefer_wildcard_cert || null
|
||||
})
|
||||
);
|
||||
|
||||
@@ -59,11 +61,11 @@ async function copyInDomains() {
|
||||
}
|
||||
}
|
||||
|
||||
for (const { domainId, baseDomain } of configDomains) {
|
||||
for (const { domainId, baseDomain, certResolver, preferWildcardCert } of configDomains) {
|
||||
if (existingDomainKeys.has(domainId)) {
|
||||
await trx
|
||||
.update(domains)
|
||||
.set({ baseDomain, verified: true, type: "wildcard" })
|
||||
.set({ baseDomain, verified: true, type: "wildcard", certResolver, preferWildcardCert })
|
||||
.where(eq(domains.domainId, domainId))
|
||||
.execute();
|
||||
} else {
|
||||
@@ -74,7 +76,9 @@ async function copyInDomains() {
|
||||
baseDomain,
|
||||
configManaged: true,
|
||||
type: "wildcard",
|
||||
verified: true
|
||||
verified: true,
|
||||
certResolver,
|
||||
preferWildcardCert
|
||||
})
|
||||
.execute();
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
FormDescription
|
||||
} from "@app/components/ui/form";
|
||||
import { Input } from "@app/components/ui/input";
|
||||
import { Checkbox, CheckboxWithLabel } from "@app/components/ui/checkbox";
|
||||
import { useToast } from "@app/hooks/useToast";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useState, useMemo } from "react";
|
||||
@@ -98,8 +99,8 @@ const formSchema = z.object({
|
||||
.refine((val) => isValidDomainFormat(val), "Invalid domain format")
|
||||
.transform((val) => toPunycode(val)),
|
||||
type: z.enum(["ns", "cname", "wildcard"]),
|
||||
certResolver: z.string().optional(),
|
||||
customCertResolver: z.string().optional()
|
||||
certResolver: z.string().nullable().optional(),
|
||||
preferWildcardCert: z.boolean().optional()
|
||||
});
|
||||
|
||||
type FormValues = z.infer<typeof formSchema>;
|
||||
@@ -112,7 +113,7 @@ type CreateDomainFormProps = {
|
||||
|
||||
// Example cert resolver options (replace with real API/fetch if needed)
|
||||
const certResolverOptions = [
|
||||
{ id: "letsencrypt", title: "Let's Encrypt" },
|
||||
{ id: "default", title: "Default" },
|
||||
{ id: "custom", title: "Custom Resolver" }
|
||||
];
|
||||
|
||||
@@ -135,8 +136,8 @@ export default function CreateDomainForm({
|
||||
defaultValues: {
|
||||
baseDomain: "",
|
||||
type: build == "oss" || !env.flags.usePangolinDns ? "wildcard" : "ns",
|
||||
certResolver: "",
|
||||
customCertResolver: ""
|
||||
certResolver: null,
|
||||
preferWildcardCert: false
|
||||
}
|
||||
});
|
||||
|
||||
@@ -281,8 +282,20 @@ export default function CreateDomainForm({
|
||||
<FormLabel>{t("certResolver")}</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
value={field.value}
|
||||
onValueChange={(val) => field.onChange(val)}
|
||||
value={
|
||||
field.value === null ? "default" :
|
||||
(field.value === "" || (field.value && field.value !== "default")) ? "custom" :
|
||||
"default"
|
||||
}
|
||||
onValueChange={(val) => {
|
||||
if (val === "default") {
|
||||
field.onChange(null);
|
||||
} else if (val === "custom") {
|
||||
field.onChange("");
|
||||
} else {
|
||||
field.onChange(val);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("selectCertResolver")} />
|
||||
@@ -297,21 +310,40 @@ export default function CreateDomainForm({
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
{field.value === "custom" && (
|
||||
<FormControl className="mt-2">
|
||||
<Input
|
||||
placeholder={t("enterCustomResolver")}
|
||||
value={form.watch("customCertResolver") || ""}
|
||||
onChange={(e) =>
|
||||
form.setValue("customCertResolver", e.target.value)
|
||||
}
|
||||
{field.value !== null && field.value !== "default" && (
|
||||
<div className="space-y-2 mt-2">
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={t("enterCustomResolver")}
|
||||
value={field.value || ""}
|
||||
onChange={(e) => field.onChange(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="preferWildcardCert"
|
||||
render={({ field: checkboxField }) => (
|
||||
<FormItem className="flex flex-row items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<CheckboxWithLabel
|
||||
label={t("preferWildcardCert")}
|
||||
checked={checkboxField.value}
|
||||
onCheckedChange={checkboxField.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
{/* <div className="space-y-1 leading-none">
|
||||
<FormLabel>
|
||||
{t("preferWildcardCert")}
|
||||
</FormLabel>
|
||||
</div> */}
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
)}
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
Reference in New Issue
Block a user