perf: 支持ssl.com证书颁发机构

v2-dev
xiaojunnuo 2025-09-04 23:42:03 +08:00
parent 204cbd0209
commit 27b6dfa4d2
7 changed files with 55 additions and 36 deletions

View File

@ -25,6 +25,10 @@ export const directory = {
staging: 'https://acme.zerossl.com/v2/DV90', staging: 'https://acme.zerossl.com/v2/DV90',
production: 'https://acme.zerossl.com/v2/DV90', production: 'https://acme.zerossl.com/v2/DV90',
}, },
sslcom:{
staging: 'https://acme.ssl.com/sslcom-dv-rsa',
production: 'https://acme.ssl.com/sslcom-dv-rsa',
}
}; };
/** /**

View File

@ -253,9 +253,9 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
return name + "_" + dayjs().format("YYYYMMDDHHmmssSSS"); return name + "_" + dayjs().format("YYYYMMDDHHmmssSSS");
} }
buildCertName(domain: string) { buildCertName(domain: string, prefix = "") {
domain = domain.replaceAll("*", "_").replaceAll(".", "_"); domain = domain.replaceAll("*", "_").replaceAll(".", "_");
return `${domain}_${dayjs().format("YYYYMMDDHHmmssSSS")}`; return `${prefix}_${domain}_${dayjs().format("YYYYMMDDHHmmssSSS")}`;
} }
async onRequest(req: PluginRequestHandleReq<any>) { async onRequest(req: PluginRequestHandleReq<any>) {

View File

@ -12,7 +12,7 @@ export class EabAccess extends BaseAccess {
component: { component: {
placeholder: "kid / keyId", placeholder: "kid / keyId",
}, },
helper: "EAB KID google的叫 keyId", helper: "EAB KID google的叫 keyIdssl.com的叫Account/ACME Key",
required: true, required: true,
encrypt: true, encrypt: true,
}) })

View File

@ -50,7 +50,7 @@ export type CertInfo = {
one?: string; one?: string;
p7b?: string; p7b?: string;
}; };
export type SSLProvider = "letsencrypt" | "google" | "zerossl"; export type SSLProvider = "letsencrypt" | "google" | "zerossl" | "sslcom";
export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521"; export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521";
type AcmeServiceOptions = { type AcmeServiceOptions = {
userContext: IContext; userContext: IContext;
@ -373,6 +373,7 @@ export class AcmeService {
commonName, commonName,
...csrInfo, ...csrInfo,
altNames, altNames,
emailAddress: email,
}, },
privateKey privateKey
); );

View File

@ -221,10 +221,10 @@ export class CertReader {
return `${prefix}_${domain}_${timeStr}.${suffix}`; return `${prefix}_${domain}_${timeStr}.${suffix}`;
} }
buildCertName() { buildCertName(prefix: string = "") {
let domain = this.getMainDomain(); let domain = this.getMainDomain();
domain = domain.replaceAll(".", "_").replaceAll("*", "_"); domain = domain.replaceAll(".", "_").replaceAll("*", "_");
return `${domain}_${dayjs().format("YYYYMMDDHHmmssSSS")}`; return `${prefix}_${domain}_${dayjs().format("YYYYMMDDHHmmssSSS")}`;
} }
static appendTimeSuffix(name?: string) { static appendTimeSuffix(name?: string) {

View File

@ -89,6 +89,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
{ value: "letsencrypt", label: "Let's Encrypt", icon: "simple-icons:letsencrypt" }, { value: "letsencrypt", label: "Let's Encrypt", icon: "simple-icons:letsencrypt" },
{ value: "google", label: "Google", icon: "flat-color-icons:google" }, { value: "google", label: "Google", icon: "flat-color-icons:google" },
{ value: "zerossl", label: "ZeroSSL", icon: "emojione:digit-zero" }, { value: "zerossl", label: "ZeroSSL", icon: "emojione:digit-zero" },
{ value: "sslcom", label: "SSL.com", icon: "la:expeditedssl" },
], ],
}, },
helper: "Let's Encrypt申请最简单\nGoogle大厂光环兼容性好仅首次需要翻墙获取EAB授权\nZeroSSL需要EAB授权无需翻墙", helper: "Let's Encrypt申请最简单\nGoogle大厂光环兼容性好仅首次需要翻墙获取EAB授权\nZeroSSL需要EAB授权无需翻墙",
@ -194,6 +195,13 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
}) })
zerosslCommonEabAccessId!: number; zerosslCommonEabAccessId!: number;
@TaskInput({
title: "SSL.com公共EAB授权",
isSys: true,
show: false,
})
sslcomCommonEabAccessId!: number;
@TaskInput({ @TaskInput({
title: "EAB授权", title: "EAB授权",
component: { component: {
@ -203,11 +211,16 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
maybeNeed: true, maybeNeed: true,
required: false, required: false,
helper: helper:
"需要提供EAB授权\nZeroSSL请前往[zerossl开发者中心](https://app.zerossl.com/developer),生成 'EAB Credentials'\n Google:请查看[google获取eab帮助文档](https://certd.docmirror.cn/guide/use/google/)用过一次后会绑定邮箱后续复用EAB要用同一个邮箱", "需要提供EAB授权" +
"\nZeroSSL请前往[zerossl开发者中心](https://app.zerossl.com/developer),生成 'EAB Credentials'" +
"\nGoogle:请查看[google获取eab帮助文档](https://certd.docmirror.cn/guide/use/google/)用过一次后会绑定邮箱后续复用EAB要用同一个邮箱" +
"\nSSL.com:[SSL.com账号页面](https://secure.ssl.com/account),然后点击api credentials链接然后点击编辑按钮查看Secret key和HMAC key",
mergeScript: ` mergeScript: `
return { return {
show: ctx.compute(({form})=>{ show: ctx.compute(({form})=>{
return (form.sslProvider === 'zerossl' && !form.zerosslCommonEabAccessId) || (form.sslProvider === 'google' && !form.googleCommonEabAccessId) return (form.sslProvider === 'zerossl' && !form.zerosslCommonEabAccessId)
|| (form.sslProvider === 'google' && !form.googleCommonEabAccessId)
|| (form.sslProvider === 'sslcom' && !form.sslcomCommonEabAccessId)
}) })
} }
`, `,
@ -339,8 +352,8 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
async onInit() { async onInit() {
let eab: EabAccess = null; let eab: EabAccess = null;
if (this.sslProvider === "google") { if (this.sslProvider !== "letsencrypt") {
if (this.googleAccessId) { if (this.sslProvider === "google" && this.googleAccessId) {
this.logger.info("当前正在使用 google服务账号授权获取EAB"); this.logger.info("当前正在使用 google服务账号授权获取EAB");
const googleAccess = await this.getAccess(this.googleAccessId); const googleAccess = await this.getAccess(this.googleAccessId);
const googleClient = new GoogleClient({ const googleClient = new GoogleClient({
@ -348,24 +361,19 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
logger: this.logger, logger: this.logger,
}); });
eab = await googleClient.getEab(); eab = await googleClient.getEab();
} else if (this.eabAccessId) {
this.logger.info("当前正在使用 google EAB授权");
eab = await this.getAccess(this.eabAccessId);
} else if (this.googleCommonEabAccessId) {
this.logger.info("当前正在使用 google 公共EAB授权");
eab = await this.getAccess(this.googleCommonEabAccessId, true);
} else { } else {
throw new Error("google需要配置EAB授权或服务账号授权"); const getEab = async (type: string) => {
} if (this.eabAccessId) {
} else if (this.sslProvider === "zerossl") { this.logger.info(`当前正在使用 ${type} EAB授权`);
if (this.eabAccessId) { eab = await this.getAccess(this.eabAccessId);
this.logger.info("当前正在使用 zerossl EAB授权"); } else if (this[`${type}CommonEabAccessId`]) {
eab = await this.getAccess(this.eabAccessId); this.logger.info(`当前正在使用 ${type} 公共EAB授权`);
} else if (this.zerosslCommonEabAccessId) { eab = await this.getAccess(this[`${type}CommonEabAccessId`], true);
this.logger.info("当前正在使用 zerossl 公共EAB授权"); } else {
eab = await this.getAccess(this.zerosslCommonEabAccessId, true); throw new Error(`${type}需要配置EAB授权`);
} else { }
throw new Error("zerossl需要配置EAB授权"); };
await getEab(this.sslProvider);
} }
} }
this.eab = eab; this.eab = eab;
@ -397,12 +405,12 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
const csrInfo = _.merge( const csrInfo = _.merge(
{ {
country: "CN", // country: "CN",
state: "GuangDong", // state: "GuangDong",
locality: "ShengZhen", // locality: "ShengZhen",
organization: "CertD Org.", // organization: "CertD Org.",
organizationUnit: "IT Department", // organizationUnit: "IT Department",
emailAddress: email, // emailAddress: email,
}, },
this.csrInfo ? JSON.parse(this.csrInfo) : {} this.csrInfo ? JSON.parse(this.csrInfo) : {}
); );

View File

@ -116,6 +116,12 @@ export class AliyunDeployCertToFC extends AbstractTaskPlugin {
}) })
protocol!: string; protocol!: string;
@TaskInput({
title: '证书名称',
helper: '上传后将以此名称作为前缀备注',
})
certName!: string;
async onInstance() {} async onInstance() {}
async exec(cmd: string) { async exec(cmd: string) {
@ -179,7 +185,7 @@ export class AliyunDeployCertToFC extends AbstractTaskPlugin {
bodyType: 'json', bodyType: 'json',
}); });
// body params // body params
const certName = this.buildCertName(CertReader.getMainDomain(this.cert.crt)) const certName = this.buildCertName(CertReader.getMainDomain(this.cert.crt),this.certName??"")
const body: { [key: string]: any } = { const body: { [key: string]: any } = {
certConfig: { certConfig: {