Files
certd/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts

175 lines
4.8 KiB
TypeScript
Raw Normal View History

import { Decorator, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
2024-07-15 00:30:33 +08:00
import type { CertInfo, SSLProvider } from "./acme.js";
2024-07-18 21:10:13 +08:00
import { AcmeService } from "./acme.js";
2024-07-15 00:30:33 +08:00
import _ from "lodash-es";
import { DnsProviderContext, DnsProviderDefine, dnsProviderRegistry } from "../../dns-provider/index.js";
import { CertReader } from "./cert-reader.js";
2024-07-18 21:10:13 +08:00
import { CertApplyBasePlugin } from "./base.js";
export { CertReader };
export type { CertInfo };
2023-01-11 20:39:48 +08:00
2022-12-29 23:52:51 +08:00
@IsTaskPlugin({
name: "CertApply",
title: "证书申请JS版",
group: pluginGroups.cert.key,
2022-12-29 23:52:51 +08:00
desc: "免费通配符域名证书申请,支持多个域名打到同一个证书上",
default: {
2022-11-08 22:10:42 +08:00
input: {
2022-12-29 23:52:51 +08:00
renewDays: 20,
forceUpdate: false,
2022-11-08 22:10:42 +08:00
},
2022-12-29 23:52:51 +08:00
strategy: {
runStrategy: RunStrategy.AlwaysRun,
2022-11-08 22:10:42 +08:00
},
2022-12-29 23:52:51 +08:00
},
2022-11-08 22:10:42 +08:00
})
2024-07-18 21:10:13 +08:00
export class CertApplyPlugin extends CertApplyBasePlugin {
2024-07-04 01:14:09 +08:00
@TaskInput({
title: "证书提供商",
value: "letsencrypt",
2024-07-04 01:14:09 +08:00
component: {
name: "a-select",
vModel: "value",
options: [
{ value: "letsencrypt", label: "Let's Encrypt" },
2024-07-24 02:11:38 +08:00
// { value: "letsencrypt-proxy", label: "Let's Encrypt代理letsencrypt.org无法访问时使用" },
2024-08-23 13:15:06 +08:00
{ value: "google", label: "Google" },
2024-07-04 01:14:09 +08:00
{ value: "zerossl", label: "ZeroSSL" },
],
},
required: true,
})
sslProvider!: SSLProvider;
@TaskInput({
title: "EAB授权",
component: {
name: "pi-access-selector",
type: "eab",
},
maybeNeed: true,
2024-07-04 01:14:09 +08:00
helper: "如果使用ZeroSSL证书需要提供EAB授权 请前往 https://app.zerossl.com/developer 生成 'EAB Credentials for ACME Clients' ",
})
eabAccessId!: number;
2022-12-29 23:52:51 +08:00
@TaskInput({
title: "DNS提供商",
component: {
name: "pi-dns-provider-selector",
},
required: true,
helper: "请选择dns解析提供商",
})
dnsProviderType!: string;
@TaskInput({
title: "DNS解析授权",
component: {
name: "pi-access-selector",
},
required: true,
helper: "请选择dns解析提供商授权",
2023-06-25 16:25:23 +08:00
reference: [
{
src: "form.dnsProviderType",
dest: "component.type",
type: "computed",
},
],
2022-12-29 23:52:51 +08:00
})
dnsProviderAccess!: string;
@TaskInput({
title: "使用代理",
value: false,
component: {
name: "a-switch",
vModel: "checked",
},
helper: "如果acme-v02.api.letsencrypt.org被墙无法连接访问请尝试开启此选项",
})
useProxy = false;
@TaskInput({
2024-07-08 15:47:36 +08:00
title: "跳过本地校验DNS",
value: false,
component: {
name: "a-switch",
vModel: "checked",
},
helper: "如果重试多次出现Authorization not found TXT record导致无法申请成功请尝试开启此选项",
})
skipLocalVerify = false;
2023-06-25 23:25:56 +08:00
acme!: AcmeService;
2024-07-18 21:10:13 +08:00
async onInit() {
2024-07-04 01:14:09 +08:00
let eab: any = null;
if (this.eabAccessId) {
eab = await this.ctx.accessService.getById(this.eabAccessId);
}
this.acme = new AcmeService({
userContext: this.userContext,
logger: this.logger,
sslProvider: this.sslProvider,
eab,
skipLocalVerify: this.skipLocalVerify,
useMappingProxy: this.useProxy,
});
2022-11-08 22:10:42 +08:00
}
2022-12-29 23:52:51 +08:00
async doCertApply() {
const email = this["email"];
const domains = this["domains"];
const dnsProviderType = this["dnsProviderType"];
const dnsProviderAccessId = this["dnsProviderAccess"];
2022-11-08 22:10:42 +08:00
const csrInfo = _.merge(
{
country: "CN",
state: "GuangDong",
locality: "ShengZhen",
organization: "CertD Org.",
organizationUnit: "IT Department",
emailAddress: email,
},
2024-06-15 02:17:34 +08:00
this.csrInfo ? JSON.parse(this.csrInfo) : {}
2022-11-08 22:10:42 +08:00
);
this.logger.info("开始申请证书,", email, domains);
2023-01-11 20:39:48 +08:00
const dnsProviderPlugin = dnsProviderRegistry.get(dnsProviderType);
const DnsProviderClass = dnsProviderPlugin.target;
const dnsProviderDefine = dnsProviderPlugin.define as DnsProviderDefine;
2022-11-08 22:10:42 +08:00
const access = await this.accessService.getById(dnsProviderAccessId);
2023-01-11 20:39:48 +08:00
2022-11-08 22:10:42 +08:00
// @ts-ignore
2023-01-11 20:39:48 +08:00
const dnsProvider: IDnsProvider = new DnsProviderClass();
const context: DnsProviderContext = { access, logger: this.logger, http: this.http };
2023-01-11 20:39:48 +08:00
Decorator.inject(dnsProviderDefine.autowire, dnsProvider, context);
dnsProvider.setCtx(context);
2023-05-09 10:16:49 +08:00
await dnsProvider.onInstance();
2022-11-08 22:10:42 +08:00
2024-07-18 11:17:13 +08:00
try {
const cert = await this.acme.order({
email,
domains,
dnsProvider,
csrInfo,
isTest: false,
});
const certInfo = this.formatCerts(cert);
return new CertReader(certInfo);
} catch (e: any) {
const message: string = e.message;
if (message.indexOf("redundant with a wildcard domain in the same request") >= 0) {
this.logger.error(e);
throw new Error(`通配符域名已经包含了普通域名,请删除其中一个(${message}`);
}
throw e;
}
2022-11-08 22:10:42 +08:00
}
}
2023-05-09 09:56:31 +08:00
new CertApplyPlugin();