diff --git a/packages/core/acme-client/src/client.js b/packages/core/acme-client/src/client.js index 42abd1ca..055696b3 100644 --- a/packages/core/acme-client/src/client.js +++ b/packages/core/acme-client/src/client.js @@ -100,7 +100,7 @@ class AcmeClient { max: this.opts.backoffMax, }; - this.http = new HttpClient(this.opts.directoryUrl, this.opts.accountKey, this.opts.externalAccountBinding); + this.http = new HttpClient(this.opts.directoryUrl, this.opts.accountKey, this.opts.externalAccountBinding, this.opts.urlMapping); this.api = new AcmeApi(this.http, this.opts.accountUrl); } diff --git a/packages/core/acme-client/src/http.js b/packages/core/acme-client/src/http.js index 29742d4f..caf73dd7 100644 --- a/packages/core/acme-client/src/http.js +++ b/packages/core/acme-client/src/http.js @@ -12,10 +12,11 @@ const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy; let httpsAgent = null; if (httpsProxy) { httpsAgent = new HttpsProxyAgent(httpsProxy); + log(`use https_proxy:${httpsProxy}`); } const axios = axios1.create({ proxy: false, - httpsAgent + httpsAgent, }); /** @@ -30,7 +31,7 @@ const axios = axios1.create({ */ class HttpClient { - constructor(directoryUrl, accountKey, externalAccountBinding = {}) { + constructor(directoryUrl, accountKey, externalAccountBinding = {}, urlMapping = {}) { this.directoryUrl = directoryUrl; this.accountKey = accountKey; this.externalAccountBinding = externalAccountBinding; @@ -41,6 +42,7 @@ class HttpClient { this.directoryCache = null; this.directoryMaxAge = 86400; this.directoryTimestamp = 0; + this.urlMapping = urlMapping; } /** @@ -53,6 +55,16 @@ class HttpClient { */ async request(url, method, opts = {}) { + if (this.urlMapping && this.urlMapping.enabled === true && this.urlMapping.mappings) { + // eslint-disable-next-line no-restricted-syntax + for (const key in this.urlMapping.mappings) { + if (url.includes(key)) { + const newUrl = url.replace(key, this.urlMapping.mappings[key]); + log(`use reverse proxy: ${newUrl}`); + url = newUrl; + } + } + } opts.url = url; opts.method = method; opts.validateStatus = null; diff --git a/packages/core/acme-client/tsconfig.json b/packages/core/acme-client/tsconfig.json index c501a7b8..4b084b3c 100644 --- a/packages/core/acme-client/tsconfig.json +++ b/packages/core/acme-client/tsconfig.json @@ -1,4 +1,5 @@ { + "compileOnSave": false, "compilerOptions": { "module": "commonjs", "lib": ["es6"], diff --git a/packages/core/acme-client/types/index.d.ts b/packages/core/acme-client/types/index.d.ts index 21de9640..0969d885 100644 --- a/packages/core/acme-client/types/index.d.ts +++ b/packages/core/acme-client/types/index.d.ts @@ -27,6 +27,11 @@ export interface Authorization extends rfc8555.Authorization { url: string; } +export type UrlMapping={ + enabled: boolean + mappings: Record +} + /** * Client */ @@ -39,6 +44,7 @@ export interface ClientOptions { backoffAttempts?: number; backoffMin?: number; backoffMax?: number; + urlMapping?: UrlMapping; } export interface ClientExternalAccountBindingOptions { diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts index 7187652f..70a9f9f8 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts @@ -6,7 +6,7 @@ import { Logger } from "log4js"; import { IContext } from "@certd/pipeline"; import { IDnsProvider } from "../../dns-provider/index.js"; import psl from "psl"; -import { ClientExternalAccountBindingOptions } from "@certd/acme-client"; +import { ClientExternalAccountBindingOptions, UrlMapping } from "@certd/acme-client"; export type CertInfo = { crt: string; @@ -14,19 +14,24 @@ export type CertInfo = { csr: string; }; export type SSLProvider = "letsencrypt" | "buypass" | "zerossl"; +type AcmeServiceOptions = { + userContext: IContext; + logger: Logger; + sslProvider: SSLProvider; + eab?: ClientExternalAccountBindingOptions; + skipLocalVerify?: boolean; + useMappingProxy?: boolean; +}; + export class AcmeService { + options: AcmeServiceOptions; userContext: IContext; logger: Logger; sslProvider: SSLProvider; skipLocalVerify = true; eab?: ClientExternalAccountBindingOptions; - constructor(options: { - userContext: IContext; - logger: Logger; - sslProvider: SSLProvider; - eab?: ClientExternalAccountBindingOptions; - skipLocalVerify?: boolean; - }) { + constructor(options: AcmeServiceOptions) { + this.options = options; this.userContext = options.userContext; this.logger = options.logger; this.sslProvider = options.sslProvider || "letsencrypt"; @@ -61,6 +66,13 @@ export class AcmeService { } else { directoryUrl = acme.directory[this.sslProvider].production; } + const urlMapping: UrlMapping = { enabled: false, mappings: {} }; + if (this.options.useMappingProxy) { + urlMapping.enabled = true; + urlMapping.mappings = { + "acme-v02.api.letsencrypt.org": "letsencrypt-proxy.handsfree.work", + }; + } const client = new acme.Client({ directoryUrl: directoryUrl, accountKey: conf.key, @@ -69,6 +81,7 @@ export class AcmeService { backoffAttempts: 30, backoffMin: 5000, backoffMax: 10000, + urlMapping, }); if (conf.accountUrl == null) { diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts index 5c4b4b69..35c40c02 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -80,6 +80,17 @@ export class CertApplyPlugin extends CertApplyBasePlugin { }) dnsProviderAccess!: string; + @TaskInput({ + title: "使用代理", + default: false, + component: { + name: "a-switch", + vModel: "checked", + }, + helper: "如果acme-v02.api.letsencrypt.org被墙无法连接访问,请尝试开启此选项", + }) + useProxy = false; + @TaskInput({ title: "跳过本地校验DNS", default: false, @@ -104,6 +115,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { sslProvider: this.sslProvider, eab, skipLocalVerify: this.skipLocalVerify, + useMappingProxy: this.useProxy, }); }