mirror of https://github.com/certd/certd
feat: 支持zero ssl
parent
6ec950818c
commit
eade2c2b68
|
@ -36,6 +36,9 @@ module.exports = async (client, userOpts) => {
|
|||
if (opts.email) {
|
||||
accountPayload.contact = [`mailto:${opts.email}`];
|
||||
}
|
||||
if (opts.externalAccountBinding) {
|
||||
accountPayload.externalAccountBinding = opts.externalAccountBinding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register account
|
||||
|
|
|
@ -18,6 +18,7 @@ exports.directory = {
|
|||
production: 'https://acme-v02.api.letsencrypt.org/directory',
|
||||
},
|
||||
zerossl: {
|
||||
staging: 'https://acme.zerossl.com/v2/DV90',
|
||||
production: 'https://acme.zerossl.com/v2/DV90',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -92,6 +92,7 @@ export const directory: {
|
|||
production: string
|
||||
},
|
||||
zerossl: {
|
||||
staging: string,
|
||||
production: string
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import { IsAccess, AccessInput } from "@certd/pipeline";
|
||||
|
||||
@IsAccess({
|
||||
name: "eab",
|
||||
title: "EABAccess",
|
||||
desc: "ZeroSSL证书申请需要EAB授权",
|
||||
})
|
||||
export class EabAccess {
|
||||
@AccessInput({
|
||||
title: "KID",
|
||||
component: {
|
||||
placeholder: "kid",
|
||||
},
|
||||
helper: "EAB KID",
|
||||
required: true,
|
||||
})
|
||||
kid = "";
|
||||
@AccessInput({
|
||||
title: "HMACKey",
|
||||
component: {
|
||||
placeholder: "HMAC Key",
|
||||
},
|
||||
helper: "EAB HMAC Key",
|
||||
required: true,
|
||||
})
|
||||
hmacKey = "";
|
||||
}
|
||||
|
||||
new EabAccess();
|
|
@ -0,0 +1 @@
|
|||
export * from "./eab-access";
|
|
@ -1,2 +1,3 @@
|
|||
export * from "./plugin";
|
||||
export * from "./dns-provider";
|
||||
export * from "./access";
|
||||
|
|
|
@ -6,18 +6,24 @@ import { Logger } from "log4js";
|
|||
import { IContext } from "@certd/pipeline";
|
||||
import { IDnsProvider } from "../../dns-provider";
|
||||
import psl from "psl";
|
||||
import { ClientExternalAccountBindingOptions } from "@certd/acme-client";
|
||||
|
||||
export type CertInfo = {
|
||||
crt: string;
|
||||
key: string;
|
||||
csr: string;
|
||||
};
|
||||
export type SSLProvider = "letsencrypt" | "buypass" | "zerossl";
|
||||
export class AcmeService {
|
||||
userContext: IContext;
|
||||
logger: Logger;
|
||||
constructor(options: { userContext: IContext; logger: Logger }) {
|
||||
sslProvider: SSLProvider;
|
||||
eab?: ClientExternalAccountBindingOptions;
|
||||
constructor(options: { userContext: IContext; logger: Logger; sslProvider: SSLProvider; eab?: ClientExternalAccountBindingOptions }) {
|
||||
this.userContext = options.userContext;
|
||||
this.logger = options.logger;
|
||||
this.sslProvider = options.sslProvider || "letsencrypt";
|
||||
this.eab = options.eab;
|
||||
acme.setLogger((text: string) => {
|
||||
this.logger.info(text);
|
||||
});
|
||||
|
@ -28,7 +34,7 @@ export class AcmeService {
|
|||
}
|
||||
|
||||
buildAccountKey(email: string) {
|
||||
return "acme.config." + email;
|
||||
return `acme.config.${this.sslProvider}.${email}`;
|
||||
}
|
||||
|
||||
async saveAccountConfig(email: string, conf: any) {
|
||||
|
@ -41,11 +47,18 @@ export class AcmeService {
|
|||
conf.key = await this.createNewKey();
|
||||
await this.saveAccountConfig(email, conf);
|
||||
}
|
||||
let directoryUrl = "";
|
||||
if (isTest) {
|
||||
directoryUrl = acme.directory[this.sslProvider].staging;
|
||||
} else {
|
||||
directoryUrl = acme.directory[this.sslProvider].production;
|
||||
}
|
||||
const client = new acme.Client({
|
||||
directoryUrl: isTest ? acme.directory.letsencrypt.staging : acme.directory.letsencrypt.production,
|
||||
directoryUrl: directoryUrl,
|
||||
accountKey: conf.key,
|
||||
accountUrl: conf.accountUrl,
|
||||
backoffAttempts: 70,
|
||||
externalAccountBinding: this.eab,
|
||||
backoffAttempts: 30,
|
||||
backoffMin: 5000,
|
||||
backoffMax: 10000,
|
||||
});
|
||||
|
@ -54,6 +67,7 @@ export class AcmeService {
|
|||
const accountPayload = {
|
||||
termsOfServiceAgreed: true,
|
||||
contact: [`mailto:${email}`],
|
||||
externalAccountBinding: this.eab,
|
||||
};
|
||||
await client.createAccount(accountPayload);
|
||||
conf.accountUrl = client.getAccountUrl();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { AbstractTaskPlugin, Decorator, HttpClient, IAccessService, IContext, IsTaskPlugin, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import dayjs from "dayjs";
|
||||
import { AcmeService, CertInfo } from "./acme";
|
||||
import { AcmeService, CertInfo, SSLProvider } from "./acme";
|
||||
import _ from "lodash";
|
||||
import { Logger } from "log4js";
|
||||
import { DnsProviderContext, DnsProviderDefine, dnsProviderRegistry } from "../../dns-provider";
|
||||
|
@ -56,6 +56,32 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
|
|||
})
|
||||
email!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "证书提供商",
|
||||
value: "letsencrypt",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ value: "letsencrypt", label: "Let's Encrypt" },
|
||||
// { value: "buypass", label: "Buypass" },
|
||||
{ value: "zerossl", label: "ZeroSSL" },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
sslProvider!: SSLProvider;
|
||||
|
||||
@TaskInput({
|
||||
title: "EAB授权",
|
||||
component: {
|
||||
name: "pi-access-selector",
|
||||
type: "eab",
|
||||
},
|
||||
helper: "如果使用ZeroSSL证书,需要提供EAB授权, 请前往 https://app.zerossl.com/developer 生成 'EAB Credentials for ACME Clients' ",
|
||||
})
|
||||
eabAccessId!: number;
|
||||
|
||||
@TaskInput({
|
||||
title: "DNS提供商",
|
||||
component: {
|
||||
|
@ -135,7 +161,11 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
|
|||
this.http = this.ctx.http;
|
||||
this.lastStatus = this.ctx.lastStatus as Step;
|
||||
|
||||
this.acme = new AcmeService({ userContext: this.userContext, logger: this.logger });
|
||||
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 });
|
||||
}
|
||||
|
||||
async execute(): Promise<void> {
|
||||
|
|
Loading…
Reference in New Issue