diff --git a/packages/core/acme-client/src/index.js b/packages/core/acme-client/src/index.js index 2e74af0cd..f777f88a2 100644 --- a/packages/core/acme-client/src/index.js +++ b/packages/core/acme-client/src/index.js @@ -57,6 +57,32 @@ export function getDirectoryUrl(opts) { return list.production } + +export function getAllSslProviderDomains() { + const list = Object.values(directory).map((item) => { + let url = item.production.replace('https://', '') + url = url.substring(0, url.indexOf('/')) + return url + }) + return list +} + +let sslProviderReverseProxies = {} + +function initSslProviderReverseProxies() { + for (const sslProvider of getAllSslProviderDomains()) { + sslProviderReverseProxies[sslProvider] = "" + } +} +initSslProviderReverseProxies() + +export function getSslProviderReverseProxies() { + return sslProviderReverseProxies +} +export function setSslProviderReverseProxies(reverseProxies) { + Object.assign(sslProviderReverseProxies, reverseProxies) +} + /** * Crypto */ diff --git a/packages/core/acme-client/types/index.d.ts b/packages/core/acme-client/types/index.d.ts index f0a55597f..a1d9dd899 100644 --- a/packages/core/acme-client/types/index.d.ts +++ b/packages/core/acme-client/types/index.d.ts @@ -118,6 +118,9 @@ export const directory: { }; export function getDirectoryUrl(opts:{sslProvider:string, pkType: string}): string; +export function getAllSslProviderDomains(): string[]; +export function getSslProviderReverseProxies(): Record; +export function setSslProviderReverseProxies(reverseProxies: Record): void; /** * Crypto diff --git a/packages/libs/lib-server/src/system/settings/service/models.ts b/packages/libs/lib-server/src/system/settings/service/models.ts index 1b9a8128d..892fc2546 100644 --- a/packages/libs/lib-server/src/system/settings/service/models.ts +++ b/packages/libs/lib-server/src/system/settings/service/models.ts @@ -76,6 +76,9 @@ export class SysPrivateSettings extends BaseSettings { httpsProxy? = ''; httpProxy? = ''; + + reverseProxies?: Record = {}; + dnsResultOrder? = ''; commonCnameEnabled?: boolean = true; diff --git a/packages/libs/lib-server/src/system/settings/service/sys-settings-service.ts b/packages/libs/lib-server/src/system/settings/service/sys-settings-service.ts index d74428887..5cb56673d 100644 --- a/packages/libs/lib-server/src/system/settings/service/sys-settings-service.ts +++ b/packages/libs/lib-server/src/system/settings/service/sys-settings-service.ts @@ -4,10 +4,10 @@ import { Repository } from 'typeorm'; import { SysSettingsEntity } from '../entity/sys-settings.js'; import { BaseSettings, SysInstallInfo, SysPrivateSettings, SysPublicSettings, SysSecret, SysSecretBackup } from './models.js'; -import { BaseService } from '../../../basic/index.js'; -import { cache, logger, setGlobalProxy } from '@certd/basic'; +import { getAllSslProviderDomains, setSslProviderReverseProxies } from '@certd/acme-client'; +import { cache, logger, mergeUtils, setGlobalProxy } from '@certd/basic'; import * as dns from 'node:dns'; -import {mergeUtils} from "@certd/basic"; +import { BaseService } from '../../../basic/index.js'; import { executorQueue } from '../../basic/service/executor-queue.js'; const {merge} = mergeUtils; /** @@ -120,7 +120,14 @@ export class SysSettingsService extends BaseService { } async getPrivateSettings(): Promise { - return await this.getSetting(SysPrivateSettings); + const res = await this.getSetting(SysPrivateSettings); + const sslProviderDomains = getAllSslProviderDomains(); + for (const domain of sslProviderDomains) { + if (!res.reverseProxies[domain]) { + res.reverseProxies[domain] = ""; + } + } + return res } async savePrivateSettings(bean: SysPrivateSettings) { @@ -145,6 +152,8 @@ export class SysSettingsService extends BaseService { if (bean.pipelineMaxRunningCount){ executorQueue.setMaxRunningCount(bean.pipelineMaxRunningCount); } + + setSslProviderReverseProxies(bean.reverseProxies); } async updateByKey(key: string, setting: any) { diff --git a/packages/ui/certd-client/src/locales/langs/en-US/certd.ts b/packages/ui/certd-client/src/locales/langs/en-US/certd.ts index 778ce2893..161ea6801 100644 --- a/packages/ui/certd-client/src/locales/langs/en-US/certd.ts +++ b/packages/ui/certd-client/src/locales/langs/en-US/certd.ts @@ -785,6 +785,7 @@ export default { captchaSetting: "Captcha Setting", pipelineSetting: "Pipeline Settings", oauthSetting: "OAuth2 Settings", + networkSetting: "Network Settings", showRunStrategy: "Show RunStrategy", showRunStrategyHelper: "Allow modify the run strategy of the task", @@ -836,6 +837,11 @@ export default { notice: "System Notice", noticeHelper: "System notice, will be displayed on the login page", noticePlaceholder: "System notice", + + reverseProxy: "Reverse Proxy List", + reverseProxyHelper: "Reverse proxy for ACME address, used when applying for certificate", + reverseProxyPlaceholder: "http://le.px.handfree.work", + reverseProxyEmpty: "No reverse proxy list configured", }, }, modal: { diff --git a/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts b/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts index 09d501223..af5ee3a79 100644 --- a/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts +++ b/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts @@ -792,6 +792,7 @@ export default { captchaSetting: "验证码设置", pipelineSetting: "流水线设置", oauthSetting: "第三方登录", + networkSetting: "网络设置", showRunStrategy: "显示运行策略选择", showRunStrategyHelper: "任务设置中是否允许选择运行策略", @@ -851,6 +852,11 @@ export default { notice: "系统公告", noticeHelper: "系统公告,将在首页显示", noticePlaceholder: "系统公告", + + reverseProxy: "反向代理列表", + reverseProxyHelper: "证书颁发机构ACME地址的反向代理,在申请证书时自动使用", + reverseProxyPlaceholder: "http://le.px.handfree.work", + reverseProxyEmpty: "未配置反向代理", }, }, modal: { diff --git a/packages/ui/certd-client/src/store/settings/api.basic.ts b/packages/ui/certd-client/src/store/settings/api.basic.ts index 48a0012fb..4ea251426 100644 --- a/packages/ui/certd-client/src/store/settings/api.basic.ts +++ b/packages/ui/certd-client/src/store/settings/api.basic.ts @@ -93,6 +93,7 @@ export type SuiteSetting = { export type SysPrivateSetting = { httpProxy?: string; httpsProxy?: string; + reverseProxies?: any; dnsResultOrder?: string; commonCnameEnabled?: boolean; // 同一个用户同时最大运行流水线数量 diff --git a/packages/ui/certd-client/src/style/common.less b/packages/ui/certd-client/src/style/common.less index 5d83d6d5f..5af60ac55 100644 --- a/packages/ui/certd-client/src/style/common.less +++ b/packages/ui/certd-client/src/style/common.less @@ -372,6 +372,13 @@ h6 { border-spacing: 0; overflow: auto; + &.cd-table-none-border { + border: 0 !important; + td, th { + border: 0 !important; + } + } + .fs-loading { position: absolute; left: 0; diff --git a/packages/ui/certd-client/src/views/certd/pipeline/pipeline/index.vue b/packages/ui/certd-client/src/views/certd/pipeline/pipeline/index.vue index 501a6b5c3..a2eadc6f3 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/pipeline/index.vue +++ b/packages/ui/certd-client/src/views/certd/pipeline/pipeline/index.vue @@ -1065,7 +1065,7 @@ export default defineComponent({ } .layout-right { - width: 364px; + width: 368px; height: 100%; max-width: 90vw; } @@ -1292,7 +1292,7 @@ export default defineComponent({ .layout-right { position: relative; &.collapsed { - margin-right: max(-364px, -90vw); + margin-right: max(-368px, -90vw); } .collapse-toggle { diff --git a/packages/ui/certd-client/src/views/sys/settings/index.vue b/packages/ui/certd-client/src/views/sys/settings/index.vue index 962d75c8d..cda0a3882 100644 --- a/packages/ui/certd-client/src/views/sys/settings/index.vue +++ b/packages/ui/certd-client/src/views/sys/settings/index.vue @@ -26,6 +26,9 @@ + + + @@ -39,6 +42,7 @@ import SettingSafe from "/@/views/sys/settings/tabs/safe.vue"; import SettingCaptcha from "/@/views/sys/settings/tabs/captcha.vue"; import SettingPipeline from "/@/views/sys/settings/tabs/pipeline.vue"; import SettingOauth from "/@/views/sys/settings/tabs/oauth.vue"; +import SettingNetwork from "/@/views/sys/settings/tabs/network.vue"; import { useRoute, useRouter } from "vue-router"; import { ref } from "vue"; import { useSettingStore } from "/@/store/settings"; diff --git a/packages/ui/certd-client/src/views/sys/settings/tabs/base.vue b/packages/ui/certd-client/src/views/sys/settings/tabs/base.vue index 4b2b92189..5e63ceedf 100644 --- a/packages/ui/certd-client/src/views/sys/settings/tabs/base.vue +++ b/packages/ui/certd-client/src/views/sys/settings/tabs/base.vue @@ -15,33 +15,6 @@ - - -
{{ t("certd.httpProxyHelper") }}
-
- - -
- - {{ t("certd.testButton") }} -
-
{{ t("certd.httpsProxyHelper") }}
-
- - - - {{ t("certd.default") }} - {{ t("certd.ipv4Priority") }} - {{ t("certd.ipv6Priority") }} - -
{{ t("certd.dualStackNetworkHelper") }}, {{ t("certd.helpDocLink") }}
-
- - - -
{{ t("certd.sys.setting.showRunStrategyHelper") }}
-
-
@@ -60,16 +33,14 @@ diff --git a/packages/ui/certd-client/src/views/sys/settings/tabs/pipeline.vue b/packages/ui/certd-client/src/views/sys/settings/tabs/pipeline.vue index 22ff625cb..35d7d7046 100644 --- a/packages/ui/certd-client/src/views/sys/settings/tabs/pipeline.vue +++ b/packages/ui/certd-client/src/views/sys/settings/tabs/pipeline.vue @@ -8,6 +8,10 @@
{{ t("certd.limitUserPipelineCountHelper") }}
+ + +
{{ t("certd.sys.setting.showRunStrategyHelper") }}
+
diff --git a/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts b/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts index f040d9e71..52352e6a2 100644 --- a/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts +++ b/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts @@ -1,13 +1,12 @@ // @ts-ignore import * as acme from "@certd/acme-client"; import { ClientExternalAccountBindingOptions, UrlMapping } from "@certd/acme-client"; -import * as _ from "lodash-es"; import { Challenge } from "@certd/acme-client/types/rfc8555.js"; -import { IContext } from "@certd/pipeline"; import { ILogger, utils } from "@certd/basic"; +import { IContext } from "@certd/pipeline"; +import { IDnsProvider, IDomainParser } from "@certd/plugin-lib"; import punycode from "punycode.js"; import { IOssClient } from "../../../plugin-lib/index.js"; -import { IDnsProvider, IDomainParser } from "@certd/plugin-lib"; export type CnameVerifyPlan = { type?: string; domain: string; @@ -112,11 +111,26 @@ export class AcmeService { } async getAcmeClient(email: string): Promise { - const mappings = {}; - if (this.sslProvider === "letsencrypt") { - mappings["acme-v02.api.letsencrypt.org"] = this.options.reverseProxy || "le.px.certd.handfree.work"; - } else if (this.sslProvider === "google") { - mappings["dv.acme-v02.api.pki.goog"] = this.options.reverseProxy || "gg.px.certd.handfree.work"; + + const directoryUrl = acme.getDirectoryUrl({ sslProvider: this.sslProvider, pkType: this.options.privateKeyType }); + let targetUrl = directoryUrl.replace("https://", ""); + targetUrl = targetUrl.substring(0, targetUrl.indexOf("/")); + + const mappings = { + "acme-v02.api.letsencrypt.org": "le.px.certd.handfree.work", + "dv.acme-v02.api.pki.goog": "gg.px.certd.handfree.work", + }; + const reverseProxies = acme.getSslProviderReverseProxies(); + if (reverseProxies) { + for (const key in reverseProxies) { + const value = reverseProxies[key]; + if (value) { + mappings[key] = value; + } + } + } + if (this.options.reverseProxy && targetUrl) { + mappings[targetUrl] = this.options.reverseProxy; } const urlMapping: UrlMapping = { enabled: false, @@ -128,7 +142,7 @@ export class AcmeService { await this.saveAccountConfig(email, conf); this.logger.info(`创建新的Accountkey:${email}`); } - const directoryUrl = acme.getDirectoryUrl({ sslProvider: this.sslProvider, pkType: this.options.privateKeyType }); + if (this.options.useMappingProxy) { urlMapping.enabled = true; } else { @@ -147,7 +161,7 @@ export class AcmeService { externalAccountBinding: this.eab, backoffAttempts: this.options.maxCheckRetryCount || 20, backoffMin: 5000, - backoffMax: 30*1000, + backoffMax: 30 * 1000, urlMapping, signal: this.options.signal, logger: this.logger, @@ -434,11 +448,7 @@ export class AcmeService { if (domains.length === 0) { throw new Error("domain can not be empty"); } - // const commonName = domains[0]; - // let altNames: undefined | string[] = undefined; - // if (domains.length > 1) { - // altNames = _.slice(domains, 1); - // } + return { // commonName, altNames: domains, diff --git a/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/apply.ts b/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/apply.ts index c4e38e1f7..7e13c171b 100644 --- a/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/apply.ts +++ b/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/apply.ts @@ -458,6 +458,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { this.eab = eab; const subDomainsGetter = await this.ctx.serviceGetter.get("subDomainsGetter"); const domainParser = new DomainParser(subDomainsGetter, this.logger); + this.acme = new AcmeService({ userId: this.ctx.user.id, userContext: this.userContext, @@ -673,6 +674,12 @@ export class CertApplyPlugin extends CertApplyBasePlugin { }, }; } + + async onGetReverseProxyList() { + const sysSettingsService:any = await this.ctx.serviceGetter.get("sysSettingsService"); + const sysSettings = await sysSettingsService.getPrivateSettings(); + return sysSettings.reverseProxyList || [] + } } new CertApplyPlugin();