Add zerossl provider

This commit is contained in:
yoan
2024-09-26 16:07:51 +08:00
parent a9fdceca6f
commit 363fbdee00
16 changed files with 705 additions and 319 deletions

View File

@@ -1,7 +1,11 @@
export type Setting = {
id?: string;
name?: string;
content?: EmailsSetting | NotifyTemplates | NotifyChannels;
content?:
| EmailsSetting
| NotifyTemplates
| NotifyChannels
| SSLProviderSetting;
};
export type EmailsSetting = {
@@ -49,3 +53,14 @@ export const defaultNotifyTemplate: NotifyTemplate = {
title: "您有{COUNT}张证书即将过期",
content: "有{COUNT}张证书即将过期,域名分别为{DOMAINS},请保持关注!",
};
export type SSLProvider = "letsencrypt" | "zerossl";
export type SSLProviderSetting = {
provider: SSLProvider;
config: {
[key: string]: {
[key: string]: string;
};
};
};

View File

@@ -1,6 +1,6 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Toaster } from "@/components/ui/toaster";
import { KeyRound, Megaphone, UserRound } from "lucide-react";
import { KeyRound, Megaphone, ShieldCheck, UserRound } from "lucide-react";
import { useEffect, useState } from "react";
import { Outlet, useLocation, useNavigate } from "react-router-dom";
@@ -56,6 +56,16 @@ const SettingLayout = () => {
<Megaphone size={14} />
<div className="ml-1"></div>
</TabsTrigger>
<TabsTrigger
value="ssl-provider"
onClick={() => {
navigate("/setting/ssl-provider");
}}
className="px-5"
>
<ShieldCheck size={14} />
<div className="ml-1"></div>
</TabsTrigger>
</TabsList>
<TabsContent value={tabValue}>
<div className="mt-5 w-full md:w-[45em]">

View File

@@ -0,0 +1,247 @@
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { useToast } from "@/components/ui/use-toast";
import {
SSLProvider as SSLProviderType,
SSLProviderSetting,
Setting,
} from "@/domain/settings";
import { getErrMessage } from "@/lib/error";
import { cn } from "@/lib/utils";
import { getSetting, update } from "@/repository/settings";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
const formSchema = z.object({
provider: z.enum(["letsencrypt", "zerossl"], {
message: "请选择SSL提供商",
}),
eabKid: z.string().optional(),
eabHmacKey: z.string().optional(),
});
const SSLProvider = () => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
provider: "letsencrypt",
},
});
const [provider, setProvider] = useState("letsencrypt");
const [config, setConfig] = useState<Setting>();
const { toast } = useToast();
useEffect(() => {
const fetchData = async () => {
const setting = await getSetting("ssl-provider");
if (setting) {
setConfig(setting);
const content = setting.content as SSLProviderSetting;
form.setValue("provider", content.provider);
form.setValue("eabKid", content.config[content.provider].eabKid);
form.setValue(
"eabHmacKey",
content.config[content.provider].eabHmacKey
);
setProvider(content.provider);
} else {
form.setValue("provider", "letsencrypt");
setProvider("letsencrypt");
}
};
fetchData();
}, []);
const getOptionCls = (val: string) => {
if (provider === val) {
return "border-primary";
}
return "";
};
const onSubmit = async (values: z.infer<typeof formSchema>) => {
if (values.provider === "zerossl") {
if (!values.eabKid) {
form.setError("eabKid", {
message: "请输入EAB_KID和EAB_HMAC_KEY",
});
}
if (!values.eabHmacKey) {
form.setError("eabHmacKey", {
message: "请输入EAB_KID和EAB_HMAC_KEY",
});
}
if (!values.eabKid || !values.eabHmacKey) {
return;
}
}
const setting: Setting = {
id: config?.id,
name: "ssl-provider",
content: {
provider: values.provider,
config: {
letsencrypt: {},
zerossl: {
eabKid: values.eabKid ?? "",
eabHmacKey: values.eabHmacKey ?? "",
},
},
},
};
try {
await update(setting);
toast({
title: "修改成功",
description: "修改成功",
});
} catch (e) {
const message = getErrMessage(e);
toast({
title: "修改失败",
description: message,
variant: "destructive",
});
}
};
return (
<>
<div className="w-full md:max-w-[35em]">
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8 dark:text-stone-200"
>
<FormField
control={form.control}
name="provider"
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<FormControl>
<RadioGroup
{...field}
className="flex"
onValueChange={(val) => {
setProvider(val);
form.setValue("provider", val as SSLProviderType);
}}
value={provider}
>
<div className="flex items-center space-x-2">
<RadioGroupItem value="letsencrypt" id="letsencrypt" />
<Label htmlFor="letsencrypt">
<div
className={cn(
"flex items-center space-x-2 border p-2 rounded cursor-pointer",
getOptionCls("letsencrypt")
)}
>
<img
src={"/imgs/providers/letsencrypt.svg"}
className="h-6"
/>
<div>{"Let's Encrypt"}</div>
</div>
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="zerossl" id="zerossl" />
<Label htmlFor="zerossl">
<div
className={cn(
"flex items-center space-x-2 border p-2 rounded cursor-pointer",
getOptionCls("zerossl")
)}
>
<img
src={"/imgs/providers/zerossl.svg"}
className="h-6"
/>
<div>{"ZeroSSL"}</div>
</div>
</Label>
</div>
</RadioGroup>
</FormControl>
<FormField
control={form.control}
name="eabKid"
render={({ field }) => (
<FormItem hidden={provider !== "zerossl"}>
<FormLabel>EAB_KID</FormLabel>
<FormControl>
<Input
placeholder="请输入EAB_KID"
{...field}
type="text"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="eabHmacKey"
render={({ field }) => (
<FormItem hidden={provider !== "zerossl"}>
<FormLabel>EAB_HMAC_KEY</FormLabel>
<FormControl>
<Input
placeholder="请输入EAB_HMAC_KEY"
{...field}
type="text"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-end">
<Button type="submit"></Button>
</div>
</form>
</Form>
</div>
</>
);
};
export default SSLProvider;

View File

@@ -12,6 +12,7 @@ import SettingLayout from "./pages/SettingLayout";
import Dashboard from "./pages/dashboard/Dashboard";
import Account from "./pages/setting/Account";
import Notify from "./pages/setting/Notify";
import SSLProvider from "./pages/setting/SSLProvider";
export const router = createHashRouter([
{
@@ -54,6 +55,10 @@ export const router = createHashRouter([
path: "/setting/notify",
element: <Notify />,
},
{
path: "/setting/ssl-provider",
element: <SSLProvider />,
},
],
},
],