From d35d9c17c50370c405d7c3495bd53dbb8b574bee Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Tue, 6 May 2025 10:57:07 +0800 Subject: [PATCH 01/29] chore: doc --- .../plugins/plugin-cert/src/plugin/cert-plugin/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 ec0a3098..a29bead8 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -68,9 +68,9 @@ export class CertApplyPlugin extends CertApplyBasePlugin { ], }, required: true, - helper: `DNS直接验证:域名是在阿里云/腾讯云/华为云/Cloudflare/NameSilo/西数/火山/dns.la/京东云注册的,选它; -CNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录; -HTTP文件验证:不支持泛域名,需要配置网站文件上传`, + helper: `1. DNS直接验证:域名是在阿里云/腾讯云/华为云/CF/NameSilo/西数/火山/dns.la/京东云注册的,选它; +2. CNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录(建议直接修改为阿里云/腾讯云的DNS服务器地址,然后使用DNS直接验证); +3. HTTP文件验证:不支持泛域名,需要配置网站文件上传`, }) challengeType!: string; From 826be45b6a20fe6025b3c0257245fdaee74c3897 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Tue, 6 May 2025 11:04:02 +0800 Subject: [PATCH 02/29] =?UTF-8?q?chore:=20=E7=AD=89=E5=BE=85=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E7=94=9F=E6=95=88=E6=97=B6=E9=95=BF=E5=8F=AF=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/acme-client/src/auto.js | 5 +++-- .../plugin-cert/src/plugin/cert-plugin/acme.ts | 1 + .../plugin-cert/src/plugin/cert-plugin/index.ts | 12 ++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/core/acme-client/src/auto.js b/packages/core/acme-client/src/auto.js index 30c454a3..ddaa7d54 100644 --- a/packages/core/acme-client/src/auto.js +++ b/packages/core/acme-client/src/auto.js @@ -234,6 +234,7 @@ export default async (client, userOpts) => { throw new CancelError("用户取消"); } + const waitDnsDiffuseTime = opts.waitDnsDiffuseTime || 30; try { // eslint-disable-next-line no-await-in-loop await runPromisePa(challengePromises); @@ -242,8 +243,8 @@ export default async (client, userOpts) => { await wait(60 * 1000); } else { await runPromisePa(localVerifyTasks, 1000); - log("本地校验完成,等待30s") - await wait(30 * 1000) + log(`本地校验完成,等待${waitDnsDiffuseTime}s`) + await wait(waitDnsDiffuseTime * 1000) } log("开始向提供商请求挑战验证"); 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 d01d8d11..beb99697 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts @@ -63,6 +63,7 @@ type AcmeServiceOptions = { maxCheckRetryCount?: number; userId: number; domainParser: IDomainParser; + waitDnsDiffuseTime?: number; }; export class AcmeService { 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 a29bead8..09a2197c 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -290,6 +290,17 @@ export class CertApplyPlugin extends CertApplyBasePlugin { }) maxCheckRetryCount = 20; + @TaskInput({ + title: "等待解析生效时长", + value: 30, + component: { + name: "a-input-number", + vModel: "value", + }, + helper: "等待解析生效时长(秒)", + }) + waitDnsDiffuseTime = 30; + acme!: AcmeService; eab!: EabAccess; @@ -341,6 +352,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { signal: this.ctx.signal, maxCheckRetryCount: this.maxCheckRetryCount, domainParser, + waitDnsDiffuseTime: this.waitDnsDiffuseTime, }); } From d75fcb7fec421a9a638eaa27fe9378c84b5e0f19 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Tue, 6 May 2025 17:01:20 +0800 Subject: [PATCH 03/29] =?UTF-8?q?perf:=20http=E6=96=B9=E5=BC=8F=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=A0=A1=E9=AA=8C443=E7=AB=AF=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/acme-client/src/verify.js | 46 ++++++++++++++----- .../plugin-lib/src/aliyun/lib/oss-client.ts | 12 +++-- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/packages/core/acme-client/src/verify.js b/packages/core/acme-client/src/verify.js index 2334331a..f148194c 100644 --- a/packages/core/acme-client/src/verify.js +++ b/packages/core/acme-client/src/verify.js @@ -24,22 +24,46 @@ const dns = dnsSdk.promises */ async function verifyHttpChallenge(authz, challenge, keyAuthorization, suffix = `/.well-known/acme-challenge/${challenge.token}`) { + + async function doQuery(challengeUrl){ + log(`正在测试请求 ${challengeUrl} `) + // const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443; + // const challengeUrl = `https://${authz.identifier.value}:${httpsPort}${suffix}`; + + /* May redirect to HTTPS with invalid/self-signed cert - https://letsencrypt.org/docs/challenge-types/#http-01-challenge */ + const httpsAgent = new https.Agent({ rejectUnauthorized: false }); + + log(`Sending HTTP query to ${authz.identifier.value}, suffix: ${suffix}, port: ${httpPort}`); + let data = "" + try{ + const resp = await axios.get(challengeUrl, { httpsAgent }); + data = (resp.data || '').replace(/\s+$/, ''); + }catch (e) { + log(`[error] HTTP request error from ${authz.identifier.value}`,e); + return false + } + + if (!data || (data !== keyAuthorization)) { + log(`[error] Authorization not found in HTTPS response from ${authz.identifier.value}`); + return false + } + return true + + } + const httpPort = axios.defaults.acmeSettings.httpChallengePort || 80; const challengeUrl = `http://${authz.identifier.value}:${httpPort}${suffix}`; - /* May redirect to HTTPS with invalid/self-signed cert - https://letsencrypt.org/docs/challenge-types/#http-01-challenge */ - const httpsAgent = new https.Agent({ rejectUnauthorized: false }); - - log(`Sending HTTP query to ${authz.identifier.value}, suffix: ${suffix}, port: ${httpPort}`); - const resp = await axios.get(challengeUrl, { httpsAgent }); - const data = (resp.data || '').replace(/\s+$/, ''); - - log(`Query successful, HTTP status code: ${resp.status}`); - - if (!data || (data !== keyAuthorization)) { - throw new Error(`Authorization not found in HTTP response from ${authz.identifier.value}`); + if (!await doQuery(challengeUrl)) { + const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443; + const httpsChallengeUrl = `https://${authz.identifier.value}:${httpsPort}${suffix}`; + const res = await doQuery(httpsChallengeUrl) + if (!res) { + throw new Error(`[error] 验证失败,请检查以上测试url是否可以正常访问`); + } } + log(`Key authorization match for ${challenge.type}/${authz.identifier.value}, ACME challenge verified`); return true; } diff --git a/packages/plugins/plugin-lib/src/aliyun/lib/oss-client.ts b/packages/plugins/plugin-lib/src/aliyun/lib/oss-client.ts index 362abc9b..9b23309d 100644 --- a/packages/plugins/plugin-lib/src/aliyun/lib/oss-client.ts +++ b/packages/plugins/plugin-lib/src/aliyun/lib/oss-client.ts @@ -52,9 +52,11 @@ export class AliossClient { } } - async uploadFile(filePath: string, content: Buffer | string) { + async uploadFile(filePath: string, content: Buffer | string, timeout = 1000 * 60 * 60) { await this.init(); - return await this.client.put(filePath, content); + return await this.client.put(filePath, content, { + timeout, + }); } async removeFile(filePath: string) { @@ -62,9 +64,11 @@ export class AliossClient { return await this.client.delete(filePath); } - async downloadFile(key: string, savePath: string) { + async downloadFile(key: string, savePath: string, timeout = 1000 * 60 * 60) { await this.init(); - return await this.client.get(key, savePath); + return await this.client.get(key, savePath, { + timeout, + }); } async listDir(dirKey: string) { From f5d1d1a0b7b47953fcdcf8bd8935f1b312952ea7 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Tue, 6 May 2025 17:52:39 +0800 Subject: [PATCH 04/29] chore: 1 --- packages/core/acme-client/src/verify.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/acme-client/src/verify.js b/packages/core/acme-client/src/verify.js index f148194c..0af93fd5 100644 --- a/packages/core/acme-client/src/verify.js +++ b/packages/core/acme-client/src/verify.js @@ -39,12 +39,12 @@ async function verifyHttpChallenge(authz, challenge, keyAuthorization, suffix = const resp = await axios.get(challengeUrl, { httpsAgent }); data = (resp.data || '').replace(/\s+$/, ''); }catch (e) { - log(`[error] HTTP request error from ${authz.identifier.value}`,e); + log(`[error] HTTP request error from ${authz.identifier.value}`,e.message); return false } if (!data || (data !== keyAuthorization)) { - log(`[error] Authorization not found in HTTPS response from ${authz.identifier.value}`); + log(`[error] Authorization not found in HTTP response from ${authz.identifier.value}`); return false } return true From 9dd49054d18ec436a5029444ca55a38adc682933 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Wed, 7 May 2025 14:15:32 +0800 Subject: [PATCH 05/29] =?UTF-8?q?perf:=20=E9=9B=86=E6=88=90=E6=99=BA?= =?UTF-8?q?=E8=83=BD=E9=97=AE=E7=AD=94=E6=9C=BA=E5=99=A8=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/certd-client/src/App.vue | 11 +- .../certd-client/src/components/ai/index.vue | 307 ++++++++++++++++++ .../ui/certd-client/src/components/index.ts | 1 + 3 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 packages/ui/certd-client/src/components/ai/index.vue diff --git a/packages/ui/certd-client/src/App.vue b/packages/ui/certd-client/src/App.vue index 9197921d..d8f9367f 100644 --- a/packages/ui/certd-client/src/App.vue +++ b/packages/ui/certd-client/src/App.vue @@ -3,6 +3,7 @@ + @@ -10,7 +11,7 @@ diff --git a/packages/ui/certd-client/src/components/ai/index.vue b/packages/ui/certd-client/src/components/ai/index.vue new file mode 100644 index 00000000..dc9020de --- /dev/null +++ b/packages/ui/certd-client/src/components/ai/index.vue @@ -0,0 +1,307 @@ + + + + + diff --git a/packages/ui/certd-client/src/components/index.ts b/packages/ui/certd-client/src/components/index.ts index 4698b26d..ed9ea3e2 100644 --- a/packages/ui/certd-client/src/components/index.ts +++ b/packages/ui/certd-client/src/components/index.ts @@ -19,6 +19,7 @@ export default { "CodeEditor", defineAsyncComponent(() => import("./code-editor/index.vue")) ); + app.component("PiContainer", PiContainer); app.component("TextEditable", TextEditable); app.component("FileInput", FileInput); From a47805e494bb386de15b3252e78e850f060b7178 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 8 May 2025 10:22:31 +0800 Subject: [PATCH 06/29] chore: --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1736aee1..e840d712 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,11 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系 关键字:证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具 +> 关于证书续期: +>* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。 +>* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。 +>* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少 + ## 一、特性 本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。 @@ -23,10 +28,7 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系 > 流水线数量现已调整为无限制,欢迎大家使用 > -> 关于证书续期: - >* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。 - >* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。 - >* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少 + ## 二、在线体验 From 892c6ad80c71ebc11d9c68f01ea69aa77ca9ccf6 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 8 May 2025 10:23:47 +0800 Subject: [PATCH 07/29] chore: --- docs/guide/index.md | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/docs/guide/index.md b/docs/guide/index.md index 5844eeef..4229dbbd 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -5,8 +5,13 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工 关键字:证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具 +## 1、关于证书续期 +>* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。 +>* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。 +>* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少 -## 一、特性 + +## 2、特性 本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。 * 全自动申请证书(支持所有注册商注册的域名) @@ -19,18 +24,4 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工 ![](../images/intro/intro.svg) -## 二、一些说明 -* 本项目申请证书过程遵循acme协议 -* 需要验证域名所有权,一般有两种方式 - * http-01: 在网站根目录下放置一份txt文件 - * dns-01: 需要给域名添加txt解析记录,通配符域名只能用这种方式(本项目仅支持dns-01) -* 证书续期: - * 实际上没有办法不改变证书文件本身情况下直接续期或者续签。 - * 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。 -* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少 -* 设置每天自动运行,当证书过期前35天,会自动重新申请证书并部署 -## 三、证书颁发机构对比 -* Let's Encrypt:申请最简单。 -* Google: 大厂光环,兼容性好,首次需要翻墙获取EAB。 -* ZeroSSL: 需要EAB,获取EAB无需翻墙。 \ No newline at end of file From f5c0b51428d1b20ad82685e5cab87c4bce149793 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 8 May 2025 10:27:49 +0800 Subject: [PATCH 08/29] chore: --- README.md | 17 +++++++++-------- docs/guide/index.md | 16 +++++++++------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index e840d712..13831faa 100644 --- a/README.md +++ b/README.md @@ -10,23 +10,24 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系 >* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。 >* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少 + +> 流水线数量现已调整为无限制,欢迎大家使用 + ## 一、特性 本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。 -* 全自动申请证书(支持所有注册商注册的域名) +* 全自动申请证书(支持所有注册商注册的域名,支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式) * 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等70+部署插件) -* 支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式 * 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式 * 邮件通知、webhook通知 -* 私有化部署,数据保存本地,授权信息加密存储,镜像由Github Actions构建,过程公开透明 -* 支持SQLite,PostgreSQL、MySQL数据库 - +* 私有化部署,数据保存本地,安装升级非常简单快捷 +* 镜像由Github Actions构建,过程公开透明 +* 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障 +* 支持SQLite,PostgreSQL、MySQL多种数据库 ![](./docs/images/intro/intro.svg) -> -> 流水线数量现已调整为无限制,欢迎大家使用 -> + diff --git a/docs/guide/index.md b/docs/guide/index.md index 4229dbbd..799e0591 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -11,15 +11,17 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工 >* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少 -## 2、特性 +## 2、项目特性 本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。 -* 全自动申请证书(支持所有注册商注册的域名) -* 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等,目前已支持60+部署插件) -* 支持通配符域名/泛域名,支持多个域名打到一个证书上 -* 邮件通知 -* 私有化部署,保障数据安全 -* 支持SQLite、Postgresql、MySQL数据库 +* 全自动申请证书(支持所有注册商注册的域名,支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式) +* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等70+部署插件) +* 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式 +* 邮件通知、webhook通知 +* 私有化部署,数据保存本地,安装升级非常简单快捷 +* 镜像由Github Actions构建,过程公开透明 +* 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障 +* 支持SQLite,PostgreSQL、MySQL多种数据库 ![](../images/intro/intro.svg) From 721dbe415a55422172f02a6dda420555d99a298c Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 8 May 2025 10:28:44 +0800 Subject: [PATCH 09/29] chore: --- README.md | 3 +++ docs/guide/index.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index 13831faa..ae7180a4 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,9 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系 * 镜像由Github Actions构建,过程公开透明 * 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障 * 支持SQLite,PostgreSQL、MySQL多种数据库 +* 开放接口支持 +* 站点证书监控 +* 多用户管理 ![](./docs/images/intro/intro.svg) diff --git a/docs/guide/index.md b/docs/guide/index.md index 799e0591..ad4ddb91 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -22,6 +22,9 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工 * 镜像由Github Actions构建,过程公开透明 * 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障 * 支持SQLite,PostgreSQL、MySQL多种数据库 +* 开放接口支持 +* 站点证书监控 +* 多用户管理 ![](../images/intro/intro.svg) From 41bc11cf96eb730569bed7866238ab8d9164308d Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 8 May 2025 10:29:25 +0800 Subject: [PATCH 10/29] chore: --- docs/guide/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/index.md b/docs/guide/index.md index ad4ddb91..fb38fa18 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -17,7 +17,7 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工 * 全自动申请证书(支持所有注册商注册的域名,支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式) * 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等70+部署插件) * 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式 -* 邮件通知、webhook通知 +* 邮件通知、webhook通知、企微、钉钉、飞书、anpush等多种通知方式 * 私有化部署,数据保存本地,安装升级非常简单快捷 * 镜像由Github Actions构建,过程公开透明 * 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障 From 81d6dad548f258e39c024d6041a66d9a4407b116 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 8 May 2025 10:29:42 +0800 Subject: [PATCH 11/29] chore: --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ae7180a4..7f57e359 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系 * 全自动申请证书(支持所有注册商注册的域名,支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式) * 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等70+部署插件) * 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式 -* 邮件通知、webhook通知 +* 邮件通知、webhook通知、企微、钉钉、飞书、anpush等多种通知方式 * 私有化部署,数据保存本地,安装升级非常简单快捷 * 镜像由Github Actions构建,过程公开透明 * 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障 @@ -28,6 +28,7 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系 * 站点证书监控 * 多用户管理 + ![](./docs/images/intro/intro.svg) From 98b51f0799b7fdf2606426ba9bb3c4f150d3dc1a Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 8 May 2025 23:27:46 +0800 Subject: [PATCH 12/29] =?UTF-8?q?chore:=20=E6=96=87=E6=A1=A3=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=8F=92=E4=BB=B6=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.vitepress/config.ts | 9 +- docs/guide/plugins.md | 5 - docs/guide/plugins/access.md | 48 +++++++ docs/guide/plugins/deploy.md | 120 ++++++++++++++++++ docs/guide/plugins/dns-provider.md | 12 ++ docs/guide/plugins/notification.md | 16 +++ packages/ui/certd-server/export-plugin-md.js | 63 +++++++++ .../ui/certd-server/export-plugin-yaml.js | 75 +++++------ packages/ui/certd-server/package.json | 1 + 9 files changed, 306 insertions(+), 43 deletions(-) delete mode 100644 docs/guide/plugins.md create mode 100644 docs/guide/plugins/access.md create mode 100644 docs/guide/plugins/deploy.md create mode 100644 docs/guide/plugins/dns-provider.md create mode 100644 docs/guide/plugins/notification.md create mode 100644 packages/ui/certd-server/export-plugin-md.js diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index e32d1353..21a9ddba 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -88,7 +88,6 @@ export default defineConfig({ text: "特性", items: [ {text: "CNAME代理校验", link: "/guide/feature/cname/index.md"}, - {text: "插件列表", link: "/guide/plugins.md"}, {text: "多数据库支持", link: "/guide/install/database.md"}, {text: "开放接口", link: "/guide/open/index.md"}, { @@ -98,7 +97,13 @@ export default defineConfig({ {text: "安全生产建议", link: "/guide/feature/safe/suggest"}, ] }, - + {text: "插件列表", items:[ + {text: "授权提供商", link: "/guide/plugins/access"}, + {text: "DNS提供商", link: "/guide/plugins/dns-provider"}, + {text: "任务插件", link: "/guide/plugins/deploy"}, + {text: "通知插件", link: "/guide/plugins/notification"}, + ] + }, ] }, { diff --git a/docs/guide/plugins.md b/docs/guide/plugins.md deleted file mode 100644 index 4e0d7d21..00000000 --- a/docs/guide/plugins.md +++ /dev/null @@ -1,5 +0,0 @@ -# 插件列表 - -![img_1.png](../images/plugins/list.png) - - diff --git a/docs/guide/plugins/access.md b/docs/guide/plugins/access.md new file mode 100644 index 00000000..cf5d7937 --- /dev/null +++ b/docs/guide/plugins/access.md @@ -0,0 +1,48 @@ +# 授权列表 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **阿里云授权** | | +| 2.| **EAB授权** | ZeroSSL证书申请需要EAB授权 | +| 3.| **google cloud** | 谷歌云授权 | +| 4.| **主机登录授权** | | +| 5.| **SFTP授权** | | +| 6.| **阿里云OSS授权** | 包含地域和Bucket | +| 7.| **FTP授权** | | +| 8.| **腾讯云** | | +| 9.| **腾讯云COS授权** | 腾讯云对象存储授权,包含地域和存储桶 | +| 10.| **七牛云授权** | | +| 11.| **七牛OSS授权** | | +| 12.| **天翼云授权** | | +| 13.| **s3/minio授权** | S3/minio oss授权 | +| 14.| **baota授权** | | +| 15.| **易盾DCDN授权** | https://user.yiduncdn.com | +| 16.| **易盾rcdn授权** | 易盾CDN,每月免费30G,[注册即领](https://rhcdn.yiduncdn.com/register?code=8mn536rrzfbf8) | +| 17.| **易发云短信** | sms.yfyidc.cn/ | +| 18.| **cdnfly授权** | | +| 19.| **群晖登录授权** | | +| 20.| **k8s授权** | | +| 21.| **1panel授权** | 账号和密码 | +| 22.| **百度云授权** | | +| 23.| **LeCDN授权** | | +| 24.| **白山云授权** | | +| 25.| **plesk授权** | | +| 26.| **易支付** | | +| 27.| **支付宝** | | +| 28.| **微信支付** | | +| 29.| **长亭雷池授权** | | +| 30.| **lucky** | | +| 31.| **括彩云cdn授权** | 括彩云CDN,每月免费30G,[注册即领](https://kuocaicdn.com/register?code=8mn536rrzfbf8) | +| 32.| **uniCloud** | unicloud授权 | +| 33.| **华为云授权** | | +| 34.| **西部数码授权** | | +| 35.| **多吉云** | | +| 36.| **我爱云授权** | 我爱云CDN | +| 37.| **CacheFly** | CacheFly | +| 38.| **Gcore** | Gcore | +| 39.| **亚马逊云aws授权** | | +| 40.| **dns.la授权** | | +| 41.| **又拍云** | | +| 42.| **火山引擎** | | +| 43.| **京东云** | | +| 44.| **51dns授权** | | diff --git a/docs/guide/plugins/deploy.md b/docs/guide/plugins/deploy.md new file mode 100644 index 00000000..befefaf1 --- /dev/null +++ b/docs/guide/plugins/deploy.md @@ -0,0 +1,120 @@ +# 任务插件 +共 `70` 款任务插件 +## 1. 证书申请 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **证书申请(JS版)** | 免费通配符域名证书申请,支持多个域名打到同一个证书上 | +| 2.| **证书申请(Lego)** | 支持海量DNS解析提供商,推荐使用,一样的免费通配符域名证书申请,支持多个域名打到同一个证书上 | +| 3.| **商用证书托管** | 手动上传自定义证书后,自动部署(每次证书有更新,都需要手动上传一次) | +## 2. 主机 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **FTP-上传证书到FTP** | 将证书上传到FTP服务器 | +| 2.| **IIS-部署到IIS站点** | | +| 3.| **主机-执行远程主机脚本命令** | 可以执行重启nginx等操作让证书生效 | +| 4.| **主机-部署证书到SSH主机** | SFTP上传证书到主机,然后SSH执行部署脚本命令 | +## 3. CDN + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **易盾-部署到易盾DCDN** | 主要是防御,http://user.yiduncdn.com/ | +| 2.| **易盾-部署到易盾RCDN** | 易盾CDN,每月免费30G,[注册即领](https://rhcdn.yiduncdn.com/register?code=8mn536rrzfbf8) | +| 3.| **cdnfly-部署证书到cdnfly** | cdnfly | +| 4.| **百度云-部署证书到CDN** | 部署到百度云CDN | +| 5.| **LeCDN-更新证书** | | +| 6.| **LeCDN-更新证书V2** | 支持新版本LeCDN | +| 7.| **白山云-更新证书** | | +| 8.| **天翼云-部署证书到CDN** | 部署证书到天翼云CDN和全站加速 | +| 9.| **括彩云-部署到括彩云CDN** | 括彩云CDN,每月免费30G,[注册即领](https://kuocaicdn.com/register?code=8mn536rrzfbf8) | +| 10.| **多吉云-部署到多吉云CDN** | | +| 11.| **我爱云-部署证书到我爱云CDN** | 部署证书到我爱云CDN | +| 12.| **CacheFly-部署证书到CacheFly** | 部署证书到 CacheFly | +| 13.| **Gcore-部署证书到Gcore** | 仅上传 并不会部署到cdn | +| 14.| **Gcore-刷新Gcore证书** | 刷新现有的证书 | +| 15.| **又拍云-部署证书到CDN/USS** | 支持又拍云CDN,又拍云云存储USS | +## 4. 面板 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **宝塔-面板证书部署** | 部署宝塔面板本身的ssl证书 | +| 2.| **宝塔-网站证书部署** | 部署宝塔管理的站点的ssl证书,目前支持网站站点、docker站点等 | +| 3.| **群晖-部署证书到群晖面板** | Synology,支持6.x以上版本 | +| 4.| **K8S-部署证书到Secret** | 部署证书到k8s的secret | +| 5.| **K8S-Ingress 证书部署** | 部署证书到k8s的Ingress | +| 6.| **1Panel-部署证书到1Panel** | 更新1Panel的证书 | +| 7.| **Plesk-部署Plesk网站证书** | | +| 8.| **雷池-更新证书** | 更新长亭雷池WAF的证书 | +| 9.| **lucky-更新Lucky证书** | | +| 10.| **uniCloud-部署到服务空间** | 部署到服务空间 | +| 11.| **威联通-部署证书到威联通** | 部署证书到qnap | +## 5. 阿里云 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **阿里云-部署到Ack** | 部署到阿里云Ack集群Ingress等通过Secret管理证书的应用 | +| 2.| **阿里云-部署至任意云资源** | 【不建议使用】需要消耗阿里云自动部署次数,支持SLB、LIVE、webHosting、VOD、CR、DCDN、DDoS、CDN、ALB、APIGateway、FC、GA、MSE、NLB、OSS、SAE、WAF等云产品 | +| 3.| **阿里云-部署证书至CDN** | 自动部署域名证书至阿里云CDN | +| 4.| **阿里云-部署证书至DCDN** | 依赖证书申请前置任务,自动部署域名证书至阿里云DCDN | +| 5.| **阿里云-部署证书至OSS** | 自动部署域名证书至阿里云OSS | +| 6.| **阿里云-上传证书到阿里云** | 如果不想在阿里云上同一份证书上传多次,可以把此任务作为前置任务,其他阿里云任务证书那一项选择此任务的输出 | +| 7.| **阿里云-部署至阿里云WAF** | 部署证书到阿里云WAF | +| 8.| **阿里云-部署至ALB(应用负载均衡)** | ALB,更新监听器的默认证书 | +| 9.| **阿里云-部署至NLB(网络负载均衡)** | NLB,网络负载均衡,更新监听器的默认证书 | +| 10.| **阿里云-部署至SLB(传统负载均衡)** | 部署证书到阿里云SLB(传统负载均衡) | +| 11.| **阿里云-部署至阿里云FC(3.0)** | 部署证书到阿里云函数计算(FC3.0),【注意】证书的加密算法必须选择【pkcs1旧版】 | +## 6. 华为云 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **华为云-部署证书至CDN** | | +## 7. 腾讯云 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **腾讯云-部署证书到任意云资源** | 支持负载均衡、CDN、DDoS、直播、点播、Web应用防火墙、API网关、TEO、容器服务、对象存储、轻应用服务器、云原生微服务、云开发 | +| 2.| **腾讯云-部署到CLB** | 暂时只支持单向认证证书,暂时只支持通用负载均衡 | +| 3.| **腾讯云-部署到CDN(废弃)** | 已废弃,请使用v2版 | +| 4.| **腾讯云-部署到CDN-v2** | 推荐使用 | +| 5.| **腾讯云-上传证书到腾讯云** | 上传成功后输出:tencentCertId | +| 6.| **腾讯云-部署证书到COS** | 部署到腾讯云COS源站域名证书【注意:很不稳定,需要重试很多次偶尔才能成功一次】 | +| 7.| **腾讯云-部署到腾讯云EO** | 腾讯云边缘安全加速平台EO,必须配置上传证书到腾讯云任务 | +| 8.| **腾讯云-删除即将过期证书** | 仅删除未使用的证书 | +| 9.| **腾讯云-部署到TKE-ingress** | serverless集群请使用K8S部署插件;Qcloud类型需要【上传到腾讯云】作为前置任务;ApiServer未开启外网访问则需要做域名的内网IP映射 | +## 8. 火山引擎 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **火山引擎-部署证书至CDN** | 支持网页,文件下载,音视频点播 | +| 2.| **火山引擎-部署证书至CLB** | 部署至火山引擎负载均衡 | +| 3.| **火山引擎-上传证书至证书中心** | 上传证书至火山引擎证书中心 | +| 4.| **火山引擎-部署证书至ALB** | 部署至火山引擎应用负载均衡 | +| 5.| **火山引擎-部署证书至Live** | 部署至火山引擎视频直播 | +## 9. 京东云 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **京东云-部署证书至CDN** | 京东云内容分发网络 | +| 2.| **京东云-更新已有证书** | 更新SSL数字证书中的证书 | +| 3.| **京东云-上传新证书** | 上传证书到SSL数字证书中心 | +## 10. 七牛云 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **七牛云-部署证书至OSS** | 自动部署域名证书至七牛云KODO,注意是自定义源站域名,不是CDN域名 | +| 2.| **七牛云-部署证书至CDN** | 自动部署域名证书至七牛云CDN | +## 11. 亚马逊云 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **AWS-部署证书到CloudFront** | 部署证书到 AWS CloudFront | +## 12. 其他 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **Demo-测试插件** | | +| 2.| **重启 Certd** | 【仅管理员可用】 重启 certd的https服务,用于更新 Certd 的 ssl 证书 | +| 3.| **自定义js脚本** | 【仅管理员】运行自定义js脚本执行 | +| 4.| **等待** | 等待一段时间 | +| 5.| **数据库备份** | 仅支持备份SQLite数据库 | diff --git a/docs/guide/plugins/dns-provider.md b/docs/guide/plugins/dns-provider.md new file mode 100644 index 00000000..ee3ba5f3 --- /dev/null +++ b/docs/guide/plugins/dns-provider.md @@ -0,0 +1,12 @@ +# DNS提供商 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **阿里云** | 阿里云DNS解析提供商 | +| 2.| **腾讯云** | 腾讯云域名DNS解析提供者 | +| 3.| **华为云** | 华为云DNS解析提供商 | +| 4.| **西部数码** | west dns provider | +| 5.| **dns.la** | dns.la | +| 6.| **火山引擎** | 火山引擎DNS解析提供商 | +| 7.| **京东云** | 京东云DNS解析提供商 | +| 8.| **51dns** | 51DNS | diff --git a/docs/guide/plugins/notification.md b/docs/guide/plugins/notification.md new file mode 100644 index 00000000..6535ef6b --- /dev/null +++ b/docs/guide/plugins/notification.md @@ -0,0 +1,16 @@ +# 通知插件 + +| 序号 | 名称 | 说明 | +|-----|-----|-----| +| 1.| **企业微信通知** | 企业微信群聊机器人通知 | +| 2.| **电子邮件** | 电子邮件通知 | +| 3.| **爱语飞飞微信通知(iyuu)** | https://iyuu.cn/ | +| 4.| **自定义webhook** | 根据模版自定义http请求 | +| 5.| **Server酱ᵀ** | https://sct.ftqq.com/ | +| 6.| **Server酱³** | https://doc.sc3.ft07.com/serverchan3 | +| 7.| **AnPush** | https://anpush.com | +| 8.| **Telegram通知** | Telegram Bot推送通知 | +| 9.| **Discord 通知** | Discord 机器人通知 | +| 10.| **Slack通知** | Slack消息推送通知 | +| 11.| **Bark 通知** | Bark 推送通知插件 | +| 12.| **飞书通知** | 飞书群聊webhook通知 | diff --git a/packages/ui/certd-server/export-plugin-md.js b/packages/ui/certd-server/export-plugin-md.js new file mode 100644 index 00000000..adb3f61c --- /dev/null +++ b/packages/ui/certd-server/export-plugin-md.js @@ -0,0 +1,63 @@ +import "./dist/plugins/index.js"; +import { accessRegistry, notificationRegistry, pluginGroups, pluginRegistry } from "@certd/pipeline"; +import { dnsProviderRegistry } from "@certd/plugin-cert"; +import fs from "fs"; + +function genPluginMd() { + const plugins = { + access: [], + deploy: [], + dnsProvider: [], + notification: [] + }; + + plugins.access = accessRegistry.getDefineList(); + plugins.deploy = pluginRegistry.getDefineList(); + plugins.dnsProvider = dnsProviderRegistry.getDefineList(); + plugins.notification = notificationRegistry.getDefineList(); + + + function genMd(list) { + let mdContent = ` +| 序号 | 名称 | 说明 | +|-----|-----|-----| +`; + let i = 0; + for (const x of list) { + i++ + mdContent += `| ${i}.| **${x.title}** | ${x.desc||''} | \n`; + } + return mdContent; + } + + let mdContent = ""; + mdContent = "# 授权列表\n"; + mdContent += genMd(plugins.access); + fs.writeFileSync("../../../docs/guide/plugins/access.md", mdContent); + + mdContent = "# DNS提供商\n"; + mdContent += genMd(plugins.dnsProvider); + fs.writeFileSync("../../../docs/guide/plugins/dns-provider.md", mdContent); + + + mdContent = "# 通知插件\n"; + mdContent += genMd(plugins.notification); + fs.writeFileSync("../../../docs/guide/plugins/notification.md", mdContent); + + + mdContent = "# 任务插件\n"; + mdContent += `共 \`${plugins.deploy.length}\` 款任务插件 \n` + let index =0 + for (const key in pluginGroups) { + index++ + const group = pluginGroups[key]; + mdContent += `## ${index}. ${group.title}\n`; + mdContent += genMd(group.plugins); + fs.writeFileSync("../../../docs/guide/plugins/deploy.md", mdContent); + } + + + process.exit() +} + +genPluginMd() diff --git a/packages/ui/certd-server/export-plugin-yaml.js b/packages/ui/certd-server/export-plugin-yaml.js index 4bda07a1..75fbe839 100644 --- a/packages/ui/certd-server/export-plugin-yaml.js +++ b/packages/ui/certd-server/export-plugin-yaml.js @@ -50,49 +50,52 @@ export default async function loadModules(dir) { function isPrototypeOf(value,cls){ return cls.prototype.isPrototypeOf(value.prototype) } +async function genMetadata(){ + const modules = await loadModules('./dist/plugins'); -const modules = await loadModules('./dist/plugins'); + fs.rmSync("./metadata", { recursive: true }); + fs.mkdirSync("./metadata", { recursive: true }); + for (const key in modules) { + console.log(key) + const module = modules[key] + const entry = Object.entries(module) + for (const [name, value] of entry) { + //如果有define属性 + if(value.define){ + //那么就是插件 + let location = key.substring(4) + location = location.substring(0, location.length - 3) + location = location.replaceAll("\\","/") + location += ".js" + location = `../../..${location}` // 从modules/plugin/plugin-service 加载 ../../plugins目录下的文件 -fs.rmSync("./metadata", { recursive: true }); -fs.mkdirSync("./metadata", { recursive: true }); -for (const key in modules) { - console.log(key) - const module = modules[key] - const entry = Object.entries(module) - for (const [name, value] of entry) { - //如果有define属性 - if(value.define){ - //那么就是插件 - let location = key.substring(4) - location = location.substring(0, location.length - 3) - location = location.replaceAll("\\","/") - location += ".js" - location = `../../..${location}` // 从modules/plugin/plugin-service 加载 ../../plugins目录下的文件 + const pluginDefine = { + ...value.define + } + pluginDefine.type = "builtIn" + if(pluginDefine.accessType){ + pluginDefine.pluginType = "dnsProvider" + }else if(isPrototypeOf(value,AbstractTaskPlugin)){ + pluginDefine.pluginType = "deploy" + }else if(isPrototypeOf(value,BaseNotification)){ + pluginDefine.pluginType = "notification" + }else if(isPrototypeOf(value,BaseAccess)){ + pluginDefine.pluginType = "access" + }else{ + console.log(`[warning] 未知的插件类型:${pluginDefine.name}`) + } - const pluginDefine = { - ...value.define + const filePath = path.join(`./metadata/${pluginDefine.pluginType}_${pluginDefine.name}.yaml`) + + pluginDefine.scriptFilePath = location + const data = yaml.dump(pluginDefine) + fs.writeFileSync(filePath,data ,'utf8') } - pluginDefine.type = "builtIn" - if(pluginDefine.accessType){ - pluginDefine.pluginType = "dnsProvider" - }else if(isPrototypeOf(value,AbstractTaskPlugin)){ - pluginDefine.pluginType = "deploy" - }else if(isPrototypeOf(value,BaseNotification)){ - pluginDefine.pluginType = "notification" - }else if(isPrototypeOf(value,BaseAccess)){ - pluginDefine.pluginType = "access" - }else{ - console.log(`[warning] 未知的插件类型:${pluginDefine.name}`) - } - const filePath = path.join(`./metadata/${pluginDefine.pluginType}_${pluginDefine.name}.yaml`) - - pluginDefine.scriptFilePath = location - const data = yaml.dump(pluginDefine) - fs.writeFileSync(filePath,data ,'utf8') } } + process.exit() } // import why from 'why-is-node-running' // setTimeout(() => why(), 100); // 延迟打印原因 +genMetadata() -process.exit() diff --git a/packages/ui/certd-server/package.json b/packages/ui/certd-server/package.json index 8ed1c701..03802791 100644 --- a/packages/ui/certd-server/package.json +++ b/packages/ui/certd-server/package.json @@ -22,6 +22,7 @@ "ci": "npm run cov", "build": "mwtsc --cleanOutDir --skipLibCheck", "export-metadata": "node export-plugin-yaml.js", + "export-md": "node export-plugin-md.js", "dev-build": "echo 1", "build-on-docker": "node ./before-build.js && npm run build", "up-mw-deps": "npx midway-version -u -w", From 8cc0f3918b8e3eaebe8f88201cf3a1a1c0a3597d Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 8 May 2025 23:47:50 +0800 Subject: [PATCH 13/29] =?UTF-8?q?chore:=20=E6=96=87=E6=A1=A3=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=8F=92=E4=BB=B6=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/guide/plugins/access.md | 10 ++++ docs/guide/plugins/deploy.md | 10 ++++ docs/guide/plugins/dns-provider.md | 10 ++++ docs/guide/plugins/notification.md | 10 ++++ packages/ui/certd-server/export-plugin-md.js | 48 +++++++++++++++++++- 5 files changed, 86 insertions(+), 2 deletions(-) diff --git a/docs/guide/plugins/access.md b/docs/guide/plugins/access.md index cf5d7937..b4e920fc 100644 --- a/docs/guide/plugins/access.md +++ b/docs/guide/plugins/access.md @@ -46,3 +46,13 @@ | 42.| **火山引擎** | | | 43.| **京东云** | | | 44.| **51dns授权** | | + + + \ No newline at end of file diff --git a/docs/guide/plugins/deploy.md b/docs/guide/plugins/deploy.md index befefaf1..823897c1 100644 --- a/docs/guide/plugins/deploy.md +++ b/docs/guide/plugins/deploy.md @@ -118,3 +118,13 @@ | 3.| **自定义js脚本** | 【仅管理员】运行自定义js脚本执行 | | 4.| **等待** | 等待一段时间 | | 5.| **数据库备份** | 仅支持备份SQLite数据库 | + + + \ No newline at end of file diff --git a/docs/guide/plugins/dns-provider.md b/docs/guide/plugins/dns-provider.md index ee3ba5f3..1c4718ea 100644 --- a/docs/guide/plugins/dns-provider.md +++ b/docs/guide/plugins/dns-provider.md @@ -10,3 +10,13 @@ | 6.| **火山引擎** | 火山引擎DNS解析提供商 | | 7.| **京东云** | 京东云DNS解析提供商 | | 8.| **51dns** | 51DNS | + + + \ No newline at end of file diff --git a/docs/guide/plugins/notification.md b/docs/guide/plugins/notification.md index 6535ef6b..c9c72637 100644 --- a/docs/guide/plugins/notification.md +++ b/docs/guide/plugins/notification.md @@ -14,3 +14,13 @@ | 10.| **Slack通知** | Slack消息推送通知 | | 11.| **Bark 通知** | Bark 推送通知插件 | | 12.| **飞书通知** | 飞书群聊webhook通知 | + + + \ No newline at end of file diff --git a/packages/ui/certd-server/export-plugin-md.js b/packages/ui/certd-server/export-plugin-md.js index adb3f61c..aabc2907 100644 --- a/packages/ui/certd-server/export-plugin-md.js +++ b/packages/ui/certd-server/export-plugin-md.js @@ -17,6 +17,34 @@ function genPluginMd() { plugins.notification = notificationRegistry.getDefineList(); +// function genMd(list) { +// let mdContent = ` +// +// +// +// +// +// +// `; +// let i = 0; +// for (const x of list) { +// i++ +// mdContent += ``; +// } +// mdContent += `
序号名称说明
${i}. ${x.title} ${x.desc||''}
`; +// return mdContent; +// } + + // function genMd(list) { + // let mdContent = ``; + // let i = 0; + // for (const x of list) { + // i++ + // mdContent += `${i}. **${x.title}** \n${x.desc||''} \n\n\n`; + // } + // return mdContent; + // } + function genMd(list) { let mdContent = ` | 序号 | 名称 | 说明 | @@ -30,18 +58,34 @@ function genPluginMd() { return mdContent; } + function addTableStyle(){ + return ` + + ` + } + let mdContent = ""; mdContent = "# 授权列表\n"; mdContent += genMd(plugins.access); + mdContent += addTableStyle() fs.writeFileSync("../../../docs/guide/plugins/access.md", mdContent); mdContent = "# DNS提供商\n"; mdContent += genMd(plugins.dnsProvider); + mdContent += addTableStyle() fs.writeFileSync("../../../docs/guide/plugins/dns-provider.md", mdContent); mdContent = "# 通知插件\n"; mdContent += genMd(plugins.notification); + mdContent += addTableStyle() fs.writeFileSync("../../../docs/guide/plugins/notification.md", mdContent); @@ -53,9 +97,9 @@ function genPluginMd() { const group = pluginGroups[key]; mdContent += `## ${index}. ${group.title}\n`; mdContent += genMd(group.plugins); - fs.writeFileSync("../../../docs/guide/plugins/deploy.md", mdContent); } - + mdContent += addTableStyle() + fs.writeFileSync("../../../docs/guide/plugins/deploy.md", mdContent); process.exit() } From 716c35d52ae26e06858c9b27f03f03b38db81b1d Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 9 May 2025 18:51:08 +0800 Subject: [PATCH 14/29] chore: doc --- docs/guide/use/pretask/images/pretask1.png | Bin 0 -> 10414 bytes docs/guide/use/pretask/images/pretask2.png | Bin 0 -> 25399 bytes docs/guide/use/pretask/index.md | 13 +++++++++++++ 3 files changed, 13 insertions(+) create mode 100644 docs/guide/use/pretask/images/pretask1.png create mode 100644 docs/guide/use/pretask/images/pretask2.png create mode 100644 docs/guide/use/pretask/index.md diff --git a/docs/guide/use/pretask/images/pretask1.png b/docs/guide/use/pretask/images/pretask1.png new file mode 100644 index 0000000000000000000000000000000000000000..e933ac0e9aa09d7f9aa9023c7a346cba01ed9076 GIT binary patch literal 10414 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 literal 0 HcmV?d00001 diff --git a/docs/guide/use/pretask/index.md b/docs/guide/use/pretask/index.md new file mode 100644 index 00000000..96b6df8e --- /dev/null +++ b/docs/guide/use/pretask/index.md @@ -0,0 +1,13 @@ +# 带输出的前置任务 + +前置任务输出可以在后续任务中使用 + +比如上传证书到阿里云,会返回阿里云的CertId,之后其他阿里云的部署任务可以选择复用这个证书 + +## 复用证书 + +![img.png](images/pretask1.png) + +在后续任务中可以选择前置任务的输出 + +![img.png](images/pretask2.png) \ No newline at end of file From 626f5d3487442d8e110b89926a7a9b9a65879976 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 10 May 2025 13:58:08 +0800 Subject: [PATCH 15/29] chore: --- docker/run/docker-compose.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/run/docker-compose.yaml b/docker/run/docker-compose.yaml index b66ffc6f..c8624f06 100644 --- a/docker/run/docker-compose.yaml +++ b/docker/run/docker-compose.yaml @@ -35,6 +35,8 @@ services: # networks: # - ip6net environment: +# ↓↓↓↓ ----------------------------------------------------- 使用上海东八时区 +# - TZ=Asia/Shanghai # 设置环境变量即可自定义certd配置 # 配置项见: packages/ui/certd-server/src/config/config.default.ts # 配置规则: certd_ + 配置项, 点号用_代替 From 06a7371d2be2bd350c59facdc96930ebbdc97b39 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 10 May 2025 15:04:57 +0800 Subject: [PATCH 16/29] chore: --- .../plugin/deploy-to-fc/index.ts | 13 ++++++------- .../plugin/deploy-to-waf/index.ts | 19 ++++++++++++------- .../plugins/plugin-deploy-to-cloudfront.ts | 19 +++++++++---------- .../plugin/deploy-to-live/index.ts | 13 ++++++------- .../plugin/deploy-to-tke-ingress/index.ts | 14 +++++++------- .../plugins/plugin-depoy-to-cdn.ts | 10 ++++------ 6 files changed, 44 insertions(+), 44 deletions(-) diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-fc/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-fc/index.ts index 12d3857e..7fdaa829 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-fc/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-fc/index.ts @@ -1,22 +1,21 @@ -import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { CertInfo } from '@certd/plugin-cert'; -import { AliyunAccess, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; -import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; -import { CertApplyPluginNames} from '@certd/plugin-cert'; +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { AliyunAccess, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; + @IsTaskPlugin({ name: 'AliyunDeployCertToFC', title: '阿里云-部署至阿里云FC(3.0)', icon: 'svg:icon-aliyun', group: pluginGroups.aliyun.key, desc: '部署证书到阿里云函数计算(FC3.0),【注意】证书的加密算法必须选择【pkcs1旧版】', - needPlus: true, + needPlus: false, default: { strategy: { runStrategy: RunStrategy.SkipWhenSucceed, }, }, }) -export class AliyunDeployCertToFC extends AbstractPlusTaskPlugin { +export class AliyunDeployCertToFC extends AbstractTaskPlugin { @TaskInput({ title: '域名证书', helper: '请选择证书申请任务输出的域名证书', diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-waf/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-waf/index.ts index d8588ce6..108c975c 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-waf/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-waf/index.ts @@ -1,22 +1,27 @@ -import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { CertInfo } from '@certd/plugin-cert'; -import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; -import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; -import { CertApplyPluginNames} from '@certd/plugin-cert'; +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { + AliyunAccess, + AliyunClient, + AliyunSslClient, + createCertDomainGetterInputDefine, + createRemoteSelectInputDefine +} from "@certd/plugin-lib"; + @IsTaskPlugin({ name: 'AliyunDeployCertToWaf', title: '阿里云-部署至阿里云WAF', icon: 'svg:icon-aliyun', group: pluginGroups.aliyun.key, desc: '部署证书到阿里云WAF', - needPlus: true, + needPlus: false, default: { strategy: { runStrategy: RunStrategy.SkipWhenSucceed, }, }, }) -export class AliyunDeployCertToWaf extends AbstractPlusTaskPlugin { +export class AliyunDeployCertToWaf extends AbstractTaskPlugin { @TaskInput({ title: '域名证书', helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID,可以减少上传到阿里云的证书数量', diff --git a/packages/ui/certd-server/src/plugins/plugin-aws/plugins/plugin-deploy-to-cloudfront.ts b/packages/ui/certd-server/src/plugins/plugin-aws/plugins/plugin-deploy-to-cloudfront.ts index d7b29747..1d66bae7 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aws/plugins/plugin-deploy-to-cloudfront.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aws/plugins/plugin-deploy-to-cloudfront.ts @@ -1,25 +1,24 @@ -import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { CertInfo } from '@certd/plugin-cert'; -import { AwsAccess, AwsRegions } from '../access.js'; -import { AwsAcmClient } from '../libs/aws-acm-client.js'; -import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; -import { optionsUtils } from '@certd/basic/dist/utils/util.options.js'; -import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; -import { CertApplyPluginNames} from '@certd/plugin-cert'; +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { AwsAccess, AwsRegions } from "../access.js"; +import { AwsAcmClient } from "../libs/aws-acm-client.js"; +import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; +import { optionsUtils } from "@certd/basic/dist/utils/util.options.js"; + @IsTaskPlugin({ name: 'AwsDeployToCloudFront', title: 'AWS-部署证书到CloudFront', desc: '部署证书到 AWS CloudFront', icon: 'svg:icon-aws', group: pluginGroups.aws.key, - needPlus: true, + needPlus: false, default: { strategy: { runStrategy: RunStrategy.SkipWhenSucceed, }, }, }) -export class AwsDeployToCloudFront extends AbstractPlusTaskPlugin { +export class AwsDeployToCloudFront extends AbstractTaskPlugin { @TaskInput({ title: '域名证书', helper: '请选择前置任务输出的域名证书', diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-live/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-live/index.ts index c086fbc2..92b0f626 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-live/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-live/index.ts @@ -1,22 +1,21 @@ -import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { CertInfo } from '@certd/plugin-cert'; -import { createRemoteSelectInputDefine, TencentAccess, TencentSslClient } from '@certd/plugin-lib'; -import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; -import { CertApplyPluginNames} from '@certd/plugin-cert'; +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { createRemoteSelectInputDefine, TencentAccess, TencentSslClient } from "@certd/plugin-lib"; + @IsTaskPlugin({ name: 'TencentDeployCertToLive', title: '腾讯云-部署到腾讯云直播', icon: 'svg:icon-tencentcloud', desc: 'https://console.cloud.tencent.com/live/', group: pluginGroups.tencent.key, - needPlus: true, + needPlus: false, default: { strategy: { runStrategy: RunStrategy.SkipWhenSucceed, }, }, }) -export class TencentDeployCertToLive extends AbstractPlusTaskPlugin { +export class TencentDeployCertToLive extends AbstractTaskPlugin { @TaskInput({ title: 'Access提供者', helper: 'access 授权', diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-tke-ingress/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-tke-ingress/index.ts index a5244e1a..8b88001a 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-tke-ingress/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-tke-ingress/index.ts @@ -1,13 +1,13 @@ -import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { utils } from '@certd/basic'; +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { utils } from "@certd/basic"; + +import dayjs from "dayjs"; +import { CertApplyPluginNames } from "@certd/plugin-cert"; -import dayjs from 'dayjs'; -import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; -import { CertApplyPluginNames} from '@certd/plugin-cert'; @IsTaskPlugin({ name: 'DeployCertToTencentTKEIngress', title: '腾讯云-部署到TKE-ingress', - needPlus: true, + needPlus: false, icon: 'svg:icon-tencentcloud', group: pluginGroups.tencent.key, desc: 'serverless集群请使用K8S部署插件;Qcloud类型需要【上传到腾讯云】作为前置任务;ApiServer未开启外网访问则需要做域名的内网IP映射', @@ -17,7 +17,7 @@ import { CertApplyPluginNames} from '@certd/plugin-cert'; }, }, }) -export class DeployCertToTencentTKEIngressPlugin extends AbstractPlusTaskPlugin { +export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin { @TaskInput({ title: '大区', value: 'ap-guangzhou', required: true }) region!: string; diff --git a/packages/ui/certd-server/src/plugins/plugin-upyun/plugins/plugin-depoy-to-cdn.ts b/packages/ui/certd-server/src/plugins/plugin-upyun/plugins/plugin-depoy-to-cdn.ts index 3a066b6f..0e743ade 100644 --- a/packages/ui/certd-server/src/plugins/plugin-upyun/plugins/plugin-depoy-to-cdn.ts +++ b/packages/ui/certd-server/src/plugins/plugin-upyun/plugins/plugin-depoy-to-cdn.ts @@ -1,9 +1,7 @@ -import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; -import { CertInfo } from "@certd/plugin-cert"; -import { AbstractPlusTaskPlugin } from "@certd/plugin-plus"; +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; import { UpyunAccess } from "../access.js"; import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; -import { CertApplyPluginNames } from "@certd/plugin-cert"; import { optionsUtils } from "@certd/basic/dist/utils/util.options.js"; import { UpyunClient } from "../client.js"; @@ -15,7 +13,7 @@ import { UpyunClient } from "../client.js"; desc:"支持又拍云CDN,又拍云云存储USS", //插件分组 group: pluginGroups.cdn.key, - needPlus: true, + needPlus: false, default: { //默认值配置照抄即可 strategy: { @@ -24,7 +22,7 @@ import { UpyunClient } from "../client.js"; } }) //类名规范,跟上面插件名称(name)一致 -export class UpyunDeployToCdn extends AbstractPlusTaskPlugin { +export class UpyunDeployToCdn extends AbstractTaskPlugin { //证书选择,此项必须要有 @TaskInput({ title: "域名证书", From ccdc933064f0ef23febfbd54a9771f405753a43d Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 10 May 2025 17:29:10 +0800 Subject: [PATCH 17/29] chore: --- packages/core/basic/src/utils/util.request.ts | 4 ++-- packages/ui/certd-client/src/api/service.ts | 2 +- .../ui/certd-server/src/plugins/plugin-51dns/client.ts | 8 ++++---- .../ui/certd-server/src/plugins/plugin-upyun/client.ts | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/core/basic/src/utils/util.request.ts b/packages/core/basic/src/utils/util.request.ts index 983b1e39..27418ac8 100644 --- a/packages/core/basic/src/utils/util.request.ts +++ b/packages/core/basic/src/utils/util.request.ts @@ -145,7 +145,7 @@ export function createAxiosService({ logger }: { logger: Logger }) { } else { logger.info("http response status:", response?.status); } - if (response?.config?.returnResponse) { + if (response?.config?.returnOriginRes) { return response; } return response.data; @@ -215,7 +215,7 @@ export type HttpRequestConfig = { logParams?: boolean; logRes?: boolean; httpProxy?: string; - returnResponse?: boolean; + returnOriginRes?: boolean; } & AxiosRequestConfig; export type HttpClient = { request(config: HttpRequestConfig): Promise>; diff --git a/packages/ui/certd-client/src/api/service.ts b/packages/ui/certd-client/src/api/service.ts index 116db11d..7a16c726 100644 --- a/packages/ui/certd-client/src/api/service.ts +++ b/packages/ui/certd-client/src/api/service.ts @@ -36,7 +36,7 @@ function createService() { return response; } //@ts-ignore - if (response.config.returnResponse) { + if (response.config.returnOriginRes) { return response; } // dataAxios 是 axios 返回数据中的 data diff --git a/packages/ui/certd-server/src/plugins/plugin-51dns/client.ts b/packages/ui/certd-server/src/plugins/plugin-51dns/client.ts index 39cd86a5..a2bb6f78 100644 --- a/packages/ui/certd-server/src/plugins/plugin-51dns/client.ts +++ b/packages/ui/certd-server/src/plugins/plugin-51dns/client.ts @@ -58,7 +58,7 @@ export class Dns51Client { method: "get", withCredentials: true, logRes: false, - returnResponse: true, + returnOriginRes: true, headers: { // 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36', 'Origin': 'https://www.51dns.com', @@ -90,7 +90,7 @@ export class Dns51Client { }, withCredentials: true, logRes: false, - returnResponse: true, + returnOriginRes: true, headers: { 'Origin': 'https://www.51dns.com', 'Referer': 'https://www.51dns.com', @@ -117,7 +117,7 @@ export class Dns51Client { method: 'get', withCredentials: true, logRes: false, - returnResponse: true, + returnOriginRes: true, headers: { // 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36', 'Origin': 'https://www.51dns.com', @@ -144,7 +144,7 @@ export class Dns51Client { method: "get", withCredentials: true, logRes: false, - returnResponse: true, + returnOriginRes: true, headers: this.getRequestHeaders() }); diff --git a/packages/ui/certd-server/src/plugins/plugin-upyun/client.ts b/packages/ui/certd-server/src/plugins/plugin-upyun/client.ts index 500af726..05c9c4e5 100644 --- a/packages/ui/certd-server/src/plugins/plugin-upyun/client.ts +++ b/packages/ui/certd-server/src/plugins/plugin-upyun/client.ts @@ -41,7 +41,7 @@ export class UpyunClient { password: access.password }, logRes: false, - returnResponse: true + returnOriginRes: true }); if (res.data?.errors?.length > 0) { throw new Error(JSON.stringify(res.data.msg)); From 0a147d2db789e8854a703296573ae0159d8d7faf Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 10 May 2025 20:52:23 +0800 Subject: [PATCH 18/29] chore: --- docs/guide/qa/index.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 docs/guide/qa/index.md diff --git a/docs/guide/qa/index.md b/docs/guide/qa/index.md new file mode 100644 index 00000000..eae66615 --- /dev/null +++ b/docs/guide/qa/index.md @@ -0,0 +1,19 @@ +# 常见报错解决 + +## 1. getaddrinfo ENOTFOUND错误 +如果出现`getaddrinfo ENOTFOUND`错误,可以尝试在`docker-compose.yaml`中设置dns +```yaml +version: '3.3' # 兼容旧版docker-compose +services: + certd: + #↓↓↓↓ ------------ # 如果出现getaddrinfo ENOTFOUND错误,可以尝试设置dns + dns: + - 223.5.5.5 # 阿里云公共dns + - 223.6.6.6 +# # ↓↓↓↓ ------- # 如果你服务器在腾讯云,可以用这个替换上面阿里云的公共dns +# - 119.29.29.29 # 腾讯云公共dns +# - 182.254.116.116 +# # ↓↓↓↓ ------- # 如果你服务器部署在国外,可以用这个替换上面阿里云的公共dns +# - 8.8.8.8 # 谷歌公共dns +# - 8.8.4.4 +``` \ No newline at end of file From d18e431e2f08e6b37704032c4ea6fbdd8e971442 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 10 May 2025 21:31:32 +0800 Subject: [PATCH 19/29] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=BD=91=E5=AE=89=E5=A4=87=E6=A1=88=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/system/settings/service/models.ts | 1 + .../src/layout/components/footer/index.vue | 7 ++++- .../certd-client/src/layout/layout-basic.vue | 6 ++--- .../src/layout/layout-framework.vue | 2 +- .../src/layout/layout-outside.vue | 4 +++ .../src/store/settings/api.basic.ts | 1 + .../src/vben/layout-ui/vben-layout.vue | 26 +++++++++---------- .../src/views/sys/settings/tabs/base.vue | 20 ++++++++------ 8 files changed, 41 insertions(+), 26 deletions(-) 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 61161f7a..5c99a0c9 100644 --- a/packages/libs/lib-server/src/system/settings/service/models.ts +++ b/packages/libs/lib-server/src/system/settings/service/models.ts @@ -25,6 +25,7 @@ export class SysPublicSettings extends BaseSettings { limitUserPipelineCount = 0; managerOtherUserPipeline = false; icpNo?: string; + mpsNo?: string; robots?: boolean = true; } diff --git a/packages/ui/certd-client/src/layout/components/footer/index.vue b/packages/ui/certd-client/src/layout/components/footer/index.vue index 1644f596..4eac1265 100644 --- a/packages/ui/certd-client/src/layout/components/footer/index.vue +++ b/packages/ui/certd-client/src/layout/components/footer/index.vue @@ -15,8 +15,13 @@ + + + {{ sysPublic.mpsNo }} +
v{{ version }}
@@ -26,7 +31,7 @@ import { computed, onMounted, ref } from "vue"; import { useSettingStore } from "/@/store/settings"; defineOptions({ - name: "PageFooter" + name: "PageFooter", }); const version = ref(import.meta.env.VITE_APP_VERSION); diff --git a/packages/ui/certd-client/src/layout/layout-basic.vue b/packages/ui/certd-client/src/layout/layout-basic.vue index 04736a56..c96027da 100644 --- a/packages/ui/certd-client/src/layout/layout-basic.vue +++ b/packages/ui/certd-client/src/layout/layout-basic.vue @@ -20,8 +20,8 @@ const menus = computed(() => [ router.push("/certd/mine/user-profile"); }, icon: "fa-solid:book", - text: "账号信息" - } + text: "账号信息", + }, ]); const avatar = computed(() => { @@ -42,7 +42,7 @@ const siteInfo = computed(() => { return settingStore.siteInfo; }); -onErrorCaptured((e) => { +onErrorCaptured(e => { console.error("ErrorCaptured:", e); // notification.error({ message: e.message }); //阻止错误向上传递 diff --git a/packages/ui/certd-client/src/layout/layout-framework.vue b/packages/ui/certd-client/src/layout/layout-framework.vue index 1cb1d4d4..f88755a8 100644 --- a/packages/ui/certd-client/src/layout/layout-framework.vue +++ b/packages/ui/certd-client/src/layout/layout-framework.vue @@ -133,7 +133,7 @@ const asideCollapsed = ref(false); function asideCollapsedToggle() { asideCollapsed.value = !asideCollapsed.value; } -onErrorCaptured((e) => { +onErrorCaptured(e => { console.error("ErrorCaptured:", e); // notification.error({ message: e.message }); //阻止错误向上传递 diff --git a/packages/ui/certd-client/src/layout/layout-outside.vue b/packages/ui/certd-client/src/layout/layout-outside.vue index f6c3213f..7b0cc931 100644 --- a/packages/ui/certd-client/src/layout/layout-outside.vue +++ b/packages/ui/certd-client/src/layout/layout-outside.vue @@ -31,6 +31,10 @@ {{ sysPublic.icpNo }} + + + {{ sysPublic.mpsNo }} + 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 b0aeca2b..708e13d1 100644 --- a/packages/ui/certd-client/src/store/settings/api.basic.ts +++ b/packages/ui/certd-client/src/store/settings/api.basic.ts @@ -39,6 +39,7 @@ export type SysPublicSetting = { limitUserPipelineCount?: number; managerOtherUserPipeline?: boolean; icpNo?: string; + mpsNo?: string; robots?: boolean; }; export type SuiteSetting = { diff --git a/packages/ui/certd-client/src/vben/layout-ui/vben-layout.vue b/packages/ui/certd-client/src/vben/layout-ui/vben-layout.vue index 544f1b00..726cc744 100644 --- a/packages/ui/certd-client/src/vben/layout-ui/vben-layout.vue +++ b/packages/ui/certd-client/src/vben/layout-ui/vben-layout.vue @@ -18,7 +18,7 @@ import { useLayout } from "./hooks/use-layout"; interface Props extends VbenLayoutProps {} defineOptions({ - name: "VbenLayout" + name: "VbenLayout", }); const props = withDefaults(defineProps(), { @@ -48,7 +48,7 @@ const props = withDefaults(defineProps(), { sideCollapseWidth: 60, tabbarEnable: true, tabbarHeight: 40, - zIndex: 200 + zIndex: 200, }); const emit = defineEmits<{ sideMouseLeave: []; toggleSidebar: [] }>(); @@ -193,7 +193,7 @@ const mainStyle = computed(() => { } return { sidebarAndExtraWidth, - width + width, }; }); @@ -221,7 +221,7 @@ const tabbarStyle = computed((): CSSProperties => { return { marginLeft: `${marginLeft}px`, - width + width, }; }); @@ -231,7 +231,7 @@ const contentStyle = computed((): CSSProperties => { const { footerEnable, footerFixed, footerHeight } = props; return { marginTop: fixed && !isFullContent.value && !headerIsHidden.value && (!isHeaderAutoMode.value || scrollY.value < headerWrapperHeight.value) ? `${headerWrapperHeight.value}px` : 0, - paddingBottom: `${footerEnable && footerFixed ? footerHeight : 0}px` + paddingBottom: `${footerEnable && footerFixed ? footerHeight : 0}px`, }; }); @@ -249,7 +249,7 @@ const headerWrapperStyle = computed((): CSSProperties => { position: fixed ? "fixed" : "static", top: headerIsHidden.value || isFullContent.value ? `-${headerWrapperHeight.value}px` : 0, width: mainStyle.value.width, - "z-index": headerZIndex.value + "z-index": headerZIndex.value, }; }); @@ -289,13 +289,13 @@ const showHeaderLogo = computed(() => { watch( () => props.isMobile, - (val) => { + val => { if (val) { sidebarCollapse.value = true; } }, { - immediate: true + immediate: true, } ); @@ -305,7 +305,7 @@ watch( setLayoutHeaderHeight(isFullContent.value ? 0 : height); }, { - immediate: true + immediate: true, } ); @@ -315,7 +315,7 @@ watch( setLayoutFooterHeight(height); }, { - immediate: true + immediate: true, } ); @@ -336,7 +336,7 @@ watch( mouseMove(); }, { - immediate: true + immediate: true, } ); } @@ -433,9 +433,9 @@ const idMainContent = ELEMENT_ID_MAIN_CONTENT;
+ + + @@ -53,19 +56,20 @@ import { notification } from "ant-design-vue"; import { util } from "/@/utils"; defineOptions({ - name: "SettingBase" + name: "SettingBase", }); const formState = reactive>({ public: { - icpNo: "" + icpNo: "", + mpsNo: "", }, - private: {} + private: {}, }); const urlRules = ref({ type: "url", - message: "请输入正确的URL" + message: "请输入正确的URL", }); async function loadSysSettings() { @@ -82,7 +86,7 @@ const onFinish = async (form: any) => { await api.SysSettingsSave(form); await settingsStore.loadSysSettings(); notification.success({ - message: "保存成功" + message: "保存成功", }); } finally { saveLoading.value = false; @@ -96,7 +100,7 @@ const onFinishFailed = (errorInfo: any) => { async function stopOtherUserTimer() { await api.stopOtherUserTimer(); notification.success({ - message: "停止成功" + message: "停止成功", }); } @@ -120,13 +124,13 @@ async function testProxy() { if (!success) { notification.error({ message: "测试失败", - description: content + description: content, }); return; } notification.success({ message: "测试完成", - description: content + description: content, }); } finally { testProxyLoading.value = false; From 47df2ffc3ebe40c02226b45bf18e653b15214a7b Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 10 May 2025 22:05:21 +0800 Subject: [PATCH 20/29] chore: doc --- .../plugins/plugin-cert/src/plugin/cert-plugin/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 09a2197c..39a1e552 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -68,9 +68,9 @@ export class CertApplyPlugin extends CertApplyBasePlugin { ], }, required: true, - helper: `1. DNS直接验证:域名是在阿里云/腾讯云/华为云/CF/NameSilo/西数/火山/dns.la/京东云注册的,选它; -2. CNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录(建议直接修改为阿里云/腾讯云的DNS服务器地址,然后使用DNS直接验证); -3. HTTP文件验证:不支持泛域名,需要配置网站文件上传`, + helper: `1. DNS直接验证:域名dns解析是在阿里云/腾讯云/华为云/CF/NameSilo/西数/火山/dns.la/京东云/51dns的,选它 +2. CNAME代理验证:支持任何注册商的域名,第一次需要手动添加CNAME记录(建议将DNS服务器修改为阿里云/腾讯云的,然后使用DNS直接验证) +3. HTTP文件验证:不支持泛域名,需要配置网站文件上传`, }) challengeType!: string; From b454e02d01776ebe966293ae5e66910397abf7ce Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sun, 11 May 2025 10:04:54 +0800 Subject: [PATCH 21/29] chore: doc --- docs/.vitepress/config.ts | 48 ++++++------------ docs/deploy/index.md | 4 -- docs/guide/feature/safe/hidden/index.md | 4 +- docs/guide/feature/safe/index.md | 34 +++++++++---- docs/guide/feature/safe/suggest.md | 10 ---- .../{deploy => guide/use}/ESXi/images/ssh.png | Bin docs/{deploy => guide/use}/ESXi/index.md | 0 docs/{ => guide/use}/comm/images/index.png | Bin docs/{ => guide/use}/comm/index.md | 0 docs/{ => guide/use}/comm/payments/alipay.md | 0 docs/{ => guide/use}/comm/payments/wxpay.md | 0 docs/{ => guide/use}/comm/payments/yizhifu.md | 0 12 files changed, 42 insertions(+), 58 deletions(-) delete mode 100644 docs/deploy/index.md rename docs/{deploy => guide/use}/ESXi/images/ssh.png (100%) rename docs/{deploy => guide/use}/ESXi/index.md (100%) rename docs/{ => guide/use}/comm/images/index.png (100%) rename docs/{ => guide/use}/comm/index.md (100%) rename docs/{ => guide/use}/comm/payments/alipay.md (100%) rename docs/{ => guide/use}/comm/payments/wxpay.md (100%) rename docs/{ => guide/use}/comm/payments/yizhifu.md (100%) diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 21a9ddba..02847ebc 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -91,17 +91,14 @@ export default defineConfig({ {text: "多数据库支持", link: "/guide/install/database.md"}, {text: "开放接口", link: "/guide/open/index.md"}, { - text: "站点安全", items: [ - {text: "安全特性", link: "/guide/feature/safe"}, - {text: "站点隐藏", link: "/guide/feature/safe/hidden"}, - {text: "安全生产建议", link: "/guide/feature/safe/suggest"}, - ] + text: "站点安全", link: "/guide/feature/safe" }, - {text: "插件列表", items:[ - {text: "授权提供商", link: "/guide/plugins/access"}, - {text: "DNS提供商", link: "/guide/plugins/dns-provider"}, - {text: "任务插件", link: "/guide/plugins/deploy"}, - {text: "通知插件", link: "/guide/plugins/notification"}, + { + text: "插件列表", items: [ + {text: "授权提供商", link: "/guide/plugins/access"}, + {text: "DNS提供商", link: "/guide/plugins/dns-provider"}, + {text: "任务插件", link: "/guide/plugins/deploy"}, + {text: "通知插件", link: "/guide/plugins/notification"}, ] }, ] @@ -109,6 +106,7 @@ export default defineConfig({ { text: "常见问题", items: [ + {text: "常见报错处理", link: "/guide/qa/"}, {text: "群晖证书部署", link: "/guide/use/synology/"}, {text: "腾讯云密钥获取", link: "/guide/use/tencent/"}, {text: "连接windows主机", link: "/guide/use/host/windows.md"}, @@ -120,8 +118,14 @@ export default defineConfig({ {text: "js脚本插件使用", link: "/guide/use/custom-script/index.md"}, {text: "邮箱配置", link: "/guide/use/email/index.md"}, {text: "IPv6支持", link: "/guide/use/setting/ipv6.md"}, - {text: "其他插件使用", link: "/deploy/"}, - {text: "商业版说明", link: "/comm/"}, + {text: "ESXi", link: "/guide/use/ESXi/index.md"}, + ] + }, + { + text: "商业版配置", link: "/guide/use/comm/", items: [ + {text: "支付宝配置", link: "/guide/use/comm/payments/alipay.md"}, + {text: "微信支付配置", link: "/guide/use/comm/payments/wxpay.md"}, + {text: "彩虹易支付配置", link: "/guide/use/comm/payments/yizhifu.md"}, ] }, { @@ -138,26 +142,6 @@ export default defineConfig({ ] } ], - "/deploy/": [ - { - text: "部署证书插件", - items: [ - {text: "插件说明", link: "/deploy/index.md"}, - {text: "部署到ESXi", link: "/deploy/ESXi/index.md"}, - ] - } - ], - "/comm/": [ - { - text: "商业版", - items: [ - {text: "支付宝配置", link: "/comm/payments/alipay.md"}, - {text: "微信支付配置", link: "/comm/payments/wxpay.md"}, - {text: "彩虹易支付配置", link: "/comm/payments/yizhifu.md"}, - ] - } - ] - , }, socialLinks: [ diff --git a/docs/deploy/index.md b/docs/deploy/index.md deleted file mode 100644 index 2fe18e65..00000000 --- a/docs/deploy/index.md +++ /dev/null @@ -1,4 +0,0 @@ -# 部署插件说明 - -## 待完善 - diff --git a/docs/guide/feature/safe/hidden/index.md b/docs/guide/feature/safe/hidden/index.md index d56e80c9..ffd6e429 100644 --- a/docs/guide/feature/safe/hidden/index.md +++ b/docs/guide/feature/safe/hidden/index.md @@ -22,4 +22,6 @@ ![](./images/hidden2.png) ## 3、忘记解除地址和解除密码怎么办 -登录服务器,在数据库平级的目录下创建`.unhidden`文件即可`临时解除`站点隐藏 +登录服务器,在数据库平级的目录下创建`.unhidden`命名的空白文件,即可临时解除站点隐藏 +临时解除后会自动删除`.unhidden`文件,请尽快设置好新的`解除地址`和`解除密码`,并记住 + diff --git a/docs/guide/feature/safe/index.md b/docs/guide/feature/safe/index.md index b578c95d..6aec4647 100644 --- a/docs/guide/feature/safe/index.md +++ b/docs/guide/feature/safe/index.md @@ -1,36 +1,48 @@ -# 站点安全特性 +# 安全特性 -Certd 存储了证书以及授权等敏感数据,所以需要严格保障安全。 -我们非常重视您的数据安全,提供了以下安全特性 +Certd 存储了证书以及授权等敏感数据,所以需要严格保障安全。 +我们提供了以下安全特性,以及安全生产建议(请遵照建议进行生产部署以保障数据安全) -## 1、 授权数据加密存储【默认开启】 +## 一、站点安全特性 + +### 1、 授权数据加密存储【默认开启】 * 所有的授权敏感字段会加密后存储 * 每个用户独立维护授权数据,连管理员都无权查看 ![星号部分为加密数据](./images/access.png) 星号部分为加密数据 -## 2、 密码防爆破【默认开启】 +### 2、 密码防爆破【默认开启】 * 登录失败次数过多,账号将被锁定,最高24小时(重启服务可解除锁定) * 用户登录密码加密hash后存储,无法计算出密码明文 ![](./images/login.png) -## 3、站点隐藏【建议开启】 +### 3、站点隐藏【建议开启】 * 一般来说Certd设置好之后,后续很少需要访问修改。 * 所以我们平时可以把站点访问关闭,需要的时候再打开,减少站点被攻击的风险 * 请前往 `系统管理->系统设置->安全设置->开启站点隐藏` -* [站点隐藏设置说明](./hidden/) ![](./images/hidden.png) -## 4、登录双重验证 +点击查看 [站点隐藏功能详细使用说明](./hidden/) + + +### 4、登录双重验证 支持2FA双重认证 ![](./images/2fa.png) -## 5、数据库自动备份【建议开启】 +### 5、数据库自动备份【建议开启】 * [自动备份设置说明](../../use/backup/) -## 更多安全生产建议 -[安全生产建议](./suggest.md) \ No newline at end of file +## 二、安全生产建议 + +尽管`Cert`本身实现了很多安全特性,但`外部环境的安全`仍需要您来确保。 +请`务必`遵循如下建议做好安全防护 + +* 请`务必`使用`HTTPS协议`访问本应用,避免被中间人攻击 +* 请`务必`使用`web应用防火墙`防护本应用,防止XSS、SQL注入等攻击 +* 请`务必`做好`服务器本身`的安全防护,防止数据库泄露 +* 请`务必`做好[`数据备份`](../../use/backup/),避免数据丢失 +* 建议开启[`站点隐藏`](./hidden/)功能 diff --git a/docs/guide/feature/safe/suggest.md b/docs/guide/feature/safe/suggest.md index 87f37fc4..e69de29b 100644 --- a/docs/guide/feature/safe/suggest.md +++ b/docs/guide/feature/safe/suggest.md @@ -1,10 +0,0 @@ -# 安全生产建议 - -尽管`Cert`本身实现了很多安全特性,但`外部环境的安全`仍需要您来确保。 -请`务必`遵循如下建议做好安全防护 - -* 请`务必`使用`HTTPS协议`访问本应用,避免被中间人攻击 -* 请`务必`使用`web应用防火墙`防护本应用,防止XSS、SQL注入等攻击 -* 请`务必`做好`服务器本身`的安全防护,防止数据库泄露 -* 请`务必`做好[`数据备份`](../../use/backup/),避免数据丢失 -* 建议开启[`站点隐藏`](./hidden/)功能 diff --git a/docs/deploy/ESXi/images/ssh.png b/docs/guide/use/ESXi/images/ssh.png similarity index 100% rename from docs/deploy/ESXi/images/ssh.png rename to docs/guide/use/ESXi/images/ssh.png diff --git a/docs/deploy/ESXi/index.md b/docs/guide/use/ESXi/index.md similarity index 100% rename from docs/deploy/ESXi/index.md rename to docs/guide/use/ESXi/index.md diff --git a/docs/comm/images/index.png b/docs/guide/use/comm/images/index.png similarity index 100% rename from docs/comm/images/index.png rename to docs/guide/use/comm/images/index.png diff --git a/docs/comm/index.md b/docs/guide/use/comm/index.md similarity index 100% rename from docs/comm/index.md rename to docs/guide/use/comm/index.md diff --git a/docs/comm/payments/alipay.md b/docs/guide/use/comm/payments/alipay.md similarity index 100% rename from docs/comm/payments/alipay.md rename to docs/guide/use/comm/payments/alipay.md diff --git a/docs/comm/payments/wxpay.md b/docs/guide/use/comm/payments/wxpay.md similarity index 100% rename from docs/comm/payments/wxpay.md rename to docs/guide/use/comm/payments/wxpay.md diff --git a/docs/comm/payments/yizhifu.md b/docs/guide/use/comm/payments/yizhifu.md similarity index 100% rename from docs/comm/payments/yizhifu.md rename to docs/guide/use/comm/payments/yizhifu.md From c7f2ead696f4121659c03b46c5f3914814559275 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sun, 11 May 2025 10:22:10 +0800 Subject: [PATCH 22/29] chore: doc --- packages/core/basic/src/utils/util.request.ts | 1 + .../plugins/plugin-cert/src/dns-provider/base.ts | 2 ++ .../ui/certd-client/src/layout/layout-basic.vue | 3 +++ .../widgets/user-dropdown/user-dropdown.vue | 14 +++++++------- .../dns-provider/aliyun-dns-provider.ts | 1 + 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/core/basic/src/utils/util.request.ts b/packages/core/basic/src/utils/util.request.ts index 27418ac8..f1da0a5f 100644 --- a/packages/core/basic/src/utils/util.request.ts +++ b/packages/core/basic/src/utils/util.request.ts @@ -145,6 +145,7 @@ export function createAxiosService({ logger }: { logger: Logger }) { } else { logger.info("http response status:", response?.status); } + if (response?.config?.returnOriginRes) { return response; } diff --git a/packages/plugins/plugin-cert/src/dns-provider/base.ts b/packages/plugins/plugin-cert/src/dns-provider/base.ts index ae9a61ce..25dfa5a8 100644 --- a/packages/plugins/plugin-cert/src/dns-provider/base.ts +++ b/packages/plugins/plugin-cert/src/dns-provider/base.ts @@ -8,6 +8,8 @@ export abstract class AbstractDnsProvider implements IDnsProvider { logger!: ILogger; usePunyCode(): boolean { + //是否使用punycode来添加解析记录 + //默认都使用原始中文域名来添加 return false; } diff --git a/packages/ui/certd-client/src/layout/layout-basic.vue b/packages/ui/certd-client/src/layout/layout-basic.vue index c96027da..da33b3e6 100644 --- a/packages/ui/certd-client/src/layout/layout-basic.vue +++ b/packages/ui/certd-client/src/layout/layout-basic.vue @@ -69,6 +69,9 @@ onMounted(async () => {
+
+ +