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) {
|
if (opts.email) {
|
||||||
accountPayload.contact = [`mailto:${opts.email}`];
|
accountPayload.contact = [`mailto:${opts.email}`];
|
||||||
}
|
}
|
||||||
|
if (opts.externalAccountBinding) {
|
||||||
|
accountPayload.externalAccountBinding = opts.externalAccountBinding;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register account
|
* Register account
|
||||||
|
|
|
@ -18,6 +18,7 @@ exports.directory = {
|
||||||
production: 'https://acme-v02.api.letsencrypt.org/directory',
|
production: 'https://acme-v02.api.letsencrypt.org/directory',
|
||||||
},
|
},
|
||||||
zerossl: {
|
zerossl: {
|
||||||
|
staging: 'https://acme.zerossl.com/v2/DV90',
|
||||||
production: 'https://acme.zerossl.com/v2/DV90',
|
production: 'https://acme.zerossl.com/v2/DV90',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -92,6 +92,7 @@ export const directory: {
|
||||||
production: string
|
production: string
|
||||||
},
|
},
|
||||||
zerossl: {
|
zerossl: {
|
||||||
|
staging: string,
|
||||||
production: 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 "./plugin";
|
||||||
export * from "./dns-provider";
|
export * from "./dns-provider";
|
||||||
|
export * from "./access";
|
||||||
|
|
|
@ -6,18 +6,24 @@ import { Logger } from "log4js";
|
||||||
import { IContext } from "@certd/pipeline";
|
import { IContext } from "@certd/pipeline";
|
||||||
import { IDnsProvider } from "../../dns-provider";
|
import { IDnsProvider } from "../../dns-provider";
|
||||||
import psl from "psl";
|
import psl from "psl";
|
||||||
|
import { ClientExternalAccountBindingOptions } from "@certd/acme-client";
|
||||||
|
|
||||||
export type CertInfo = {
|
export type CertInfo = {
|
||||||
crt: string;
|
crt: string;
|
||||||
key: string;
|
key: string;
|
||||||
csr: string;
|
csr: string;
|
||||||
};
|
};
|
||||||
|
export type SSLProvider = "letsencrypt" | "buypass" | "zerossl";
|
||||||
export class AcmeService {
|
export class AcmeService {
|
||||||
userContext: IContext;
|
userContext: IContext;
|
||||||
logger: Logger;
|
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.userContext = options.userContext;
|
||||||
this.logger = options.logger;
|
this.logger = options.logger;
|
||||||
|
this.sslProvider = options.sslProvider || "letsencrypt";
|
||||||
|
this.eab = options.eab;
|
||||||
acme.setLogger((text: string) => {
|
acme.setLogger((text: string) => {
|
||||||
this.logger.info(text);
|
this.logger.info(text);
|
||||||
});
|
});
|
||||||
|
@ -28,7 +34,7 @@ export class AcmeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
buildAccountKey(email: string) {
|
buildAccountKey(email: string) {
|
||||||
return "acme.config." + email;
|
return `acme.config.${this.sslProvider}.${email}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveAccountConfig(email: string, conf: any) {
|
async saveAccountConfig(email: string, conf: any) {
|
||||||
|
@ -41,11 +47,18 @@ export class AcmeService {
|
||||||
conf.key = await this.createNewKey();
|
conf.key = await this.createNewKey();
|
||||||
await this.saveAccountConfig(email, conf);
|
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({
|
const client = new acme.Client({
|
||||||
directoryUrl: isTest ? acme.directory.letsencrypt.staging : acme.directory.letsencrypt.production,
|
directoryUrl: directoryUrl,
|
||||||
accountKey: conf.key,
|
accountKey: conf.key,
|
||||||
accountUrl: conf.accountUrl,
|
accountUrl: conf.accountUrl,
|
||||||
backoffAttempts: 70,
|
externalAccountBinding: this.eab,
|
||||||
|
backoffAttempts: 30,
|
||||||
backoffMin: 5000,
|
backoffMin: 5000,
|
||||||
backoffMax: 10000,
|
backoffMax: 10000,
|
||||||
});
|
});
|
||||||
|
@ -54,6 +67,7 @@ export class AcmeService {
|
||||||
const accountPayload = {
|
const accountPayload = {
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
contact: [`mailto:${email}`],
|
contact: [`mailto:${email}`],
|
||||||
|
externalAccountBinding: this.eab,
|
||||||
};
|
};
|
||||||
await client.createAccount(accountPayload);
|
await client.createAccount(accountPayload);
|
||||||
conf.accountUrl = client.getAccountUrl();
|
conf.accountUrl = client.getAccountUrl();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { AbstractTaskPlugin, Decorator, HttpClient, IAccessService, IContext, IsTaskPlugin, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
import { AbstractTaskPlugin, Decorator, HttpClient, IAccessService, IContext, IsTaskPlugin, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { AcmeService, CertInfo } from "./acme";
|
import { AcmeService, CertInfo, SSLProvider } from "./acme";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { Logger } from "log4js";
|
import { Logger } from "log4js";
|
||||||
import { DnsProviderContext, DnsProviderDefine, dnsProviderRegistry } from "../../dns-provider";
|
import { DnsProviderContext, DnsProviderDefine, dnsProviderRegistry } from "../../dns-provider";
|
||||||
|
@ -56,6 +56,32 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
|
||||||
})
|
})
|
||||||
email!: string;
|
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({
|
@TaskInput({
|
||||||
title: "DNS提供商",
|
title: "DNS提供商",
|
||||||
component: {
|
component: {
|
||||||
|
@ -135,7 +161,11 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
|
||||||
this.http = this.ctx.http;
|
this.http = this.ctx.http;
|
||||||
this.lastStatus = this.ctx.lastStatus as Step;
|
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> {
|
async execute(): Promise<void> {
|
||||||
|
|
Loading…
Reference in New Issue