From d9e6dbf889ac75a4069e40d3f81add524aa068ae Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 15 Dec 2025 22:21:43 +0800 Subject: [PATCH 01/13] =?UTF-8?q?chore:=20=E4=BC=98=E5=8C=96telegram?= =?UTF-8?q?=E6=9B=B4=E5=A4=9A=E4=BF=9D=E7=95=99=E5=AD=97=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/plugins/plugin-notification/telegram/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ui/certd-server/src/plugins/plugin-notification/telegram/index.ts b/packages/ui/certd-server/src/plugins/plugin-notification/telegram/index.ts index 109b72e52..59f596847 100644 --- a/packages/ui/certd-server/src/plugins/plugin-notification/telegram/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-notification/telegram/index.ts @@ -60,7 +60,9 @@ export class TelegramNotification extends BaseNotification { replaceText(text: string) { // .*()<> 等都需要用\\进行替换 - return text.replace(/[\\.*()<>]/g, '\\$&'); + return text.replace(/[_*[\]()~`>#\+\-=|{}.!]/g, '\\$&'); + // .replace(/([\\_*`|!.[\](){}>+#=~-])/gm, '\\$1') + // return text.replace(/[\\.*()<>]/g, '\\$&'); } async send(body: NotificationBody) { if (!this.botToken || !this.chatId) { From e4c21c4d5cac2a1bd8544368c482d2c8877d1220 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 15 Dec 2025 22:32:25 +0800 Subject: [PATCH 02/13] =?UTF-8?q?chore:=20=E6=A8=A1=E7=89=88=E5=8F=91?= =?UTF-8?q?=E9=82=AE=E4=BB=B6=20plus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/sys/settings/email/index.vue | 9 ++- .../modules/basic/service/email-service.ts | 55 ++++++++++--------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/packages/ui/certd-client/src/views/sys/settings/email/index.vue b/packages/ui/certd-client/src/views/sys/settings/email/index.vue index 8d94f2a27..2937a78db 100644 --- a/packages/ui/certd-client/src/views/sys/settings/email/index.vue +++ b/packages/ui/certd-client/src/views/sys/settings/email/index.vue @@ -78,7 +78,14 @@ - + diff --git a/packages/ui/certd-server/src/modules/basic/service/email-service.ts b/packages/ui/certd-server/src/modules/basic/service/email-service.ts index aeac0458b..b10c7b53f 100644 --- a/packages/ui/certd-server/src/modules/basic/service/email-service.ts +++ b/packages/ui/certd-server/src/modules/basic/service/email-service.ts @@ -117,8 +117,8 @@ export class EmailService implements IEmailService { async test(userId: number, receiver: string) { await this.sendByTemplate({ - type:"common", - data:{ + type: "common", + data: { title: '测试邮件,from certd', content: '测试邮件,from certd', }, @@ -150,36 +150,39 @@ export class EmailService implements IEmailService { async sendByTemplate(req: EmailSendByTemplateReq) { - const emailConf = await this.sysSettingsService.getSetting(SysEmailConf); - - const template = emailConf?.templates?.[req.type] let content = null - if (template && template.addonId) { - const addon: ITemplateProvider = await this.addonGetterService.getAddonById(template.addonId, true, 0) - if (addon) { - content = await addon.buildContent({ data: req.data }) - } - } - if (!content) { - //看看有没有通用模版 - if (emailConf?.templates?.common && emailConf?.templates?.common.addonId) { - const addon: ITemplateProvider = await this.addonGetterService.getAddonById(emailConf.templates.common.addonId, true, 0) + if (isPlus()) { + const emailConf = await this.sysSettingsService.getSetting(SysEmailConf); + const template = emailConf?.templates?.[req.type] + if (template && template.addonId) { + const addon: ITemplateProvider = await this.addonGetterService.getAddonById(template.addonId, true, 0) if (addon) { content = await addon.buildContent({ data: req.data }) } } - } - // 没有找到模版,使用默认模版 - if (!content) { - try { - const addon: ITemplateProvider = await this.addonGetterService.getBlank("emailTemplate", req.type) - content = await addon.buildDefaultContent({ data: req.data }) - } catch (e) { - // 对应的通知类型模版可能没有注册或者开发 - const addon: ITemplateProvider = await this.addonGetterService.getBlank("emailTemplate", "common") - content = await addon.buildDefaultContent({ data: req.data }) - //common类型的一定有,已经开发了 + if (!content) { + //看看有没有通用模版 + if (emailConf?.templates?.common && emailConf?.templates?.common.addonId) { + const addon: ITemplateProvider = await this.addonGetterService.getAddonById(emailConf.templates.common.addonId, true, 0) + if (addon) { + content = await addon.buildContent({ data: req.data }) + } + } } + // 没有找到模版,使用默认模版 + if (!content) { + try { + const addon: ITemplateProvider = await this.addonGetterService.getBlank("emailTemplate", req.type) + content = await addon.buildDefaultContent({ data: req.data }) + } catch (e) { + // 对应的通知类型模版可能没有注册或者开发 + } + } + } + + if (!content) { + const addon: ITemplateProvider = await this.addonGetterService.getBlank("emailTemplate", "common") + content = await addon.buildDefaultContent({ data: req.data }) } return await this.send({ ...req.email, From e4e16bc6a65bb082c18ca0590226f0987a47d477 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 15 Dec 2025 23:34:47 +0800 Subject: [PATCH 03/13] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dipv6=E4=BD=9C?= =?UTF-8?q?=E4=B8=BA=E8=AF=81=E4=B9=A6=E5=9F=9F=E5=90=8D=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=E8=AF=81=E4=B9=A6=E6=A0=A1=E9=AA=8C=E5=A4=B1=E8=B4=A5=E7=9A=84?= =?UTF-8?q?bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/acme-client/src/verify.js | 10 +++++-- packages/core/basic/.gitignore | 1 + packages/core/basic/src/utils/util.domain.ts | 2 +- packages/core/basic/test.mjs | 28 +++++++++++-------- .../src/system/settings/service/models.ts | 9 ++---- .../src/dns-provider/domain-parser.ts | 5 ++++ .../src/plugin/cert-plugin/index.ts | 2 +- .../src/plugin/validator/index.ts | 26 ++++++++++++++++- 8 files changed, 59 insertions(+), 24 deletions(-) diff --git a/packages/core/acme-client/src/verify.js b/packages/core/acme-client/src/verify.js index 6d94d7394..bcf854846 100644 --- a/packages/core/acme-client/src/verify.js +++ b/packages/core/acme-client/src/verify.js @@ -8,7 +8,7 @@ import {log as defaultLog} from './logger.js' import axios from './axios.js' import * as util from './util.js' import {isAlpnCertificateAuthorizationValid} from './crypto/index.js' - +import {utils} from '@certd/basic' const dns = dnsSdk.promises @@ -60,11 +60,15 @@ async function verifyHttpChallenge(authz, challenge, keyAuthorization, suffix = } const httpPort = axios.defaults.acmeSettings.httpChallengePort || 80; - const challengeUrl = `http://${authz.identifier.value}:${httpPort}${suffix}`; + let host = authz.identifier.value; + if(utils.domain.isIpv6(host)){ + host = `[${host}]`; + } + const challengeUrl = `http://${host}:${httpPort}${suffix}`; if (!await doQuery(challengeUrl)) { const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443; - const httpsChallengeUrl = `https://${authz.identifier.value}:${httpsPort}${suffix}`; + const httpsChallengeUrl = `https://${host}:${httpsPort}${suffix}`; const res = await doQuery(httpsChallengeUrl) if (!res) { throw new Error(`[error] 验证失败,请检查以上测试url是否可以正常访问`); diff --git a/packages/core/basic/.gitignore b/packages/core/basic/.gitignore index c90f5f96b..f897596ac 100644 --- a/packages/core/basic/.gitignore +++ b/packages/core/basic/.gitignore @@ -26,3 +26,4 @@ dist-ssr test/user.secret.* test/**/*.js src/**/*.spec.ts +test.mjs diff --git a/packages/core/basic/src/utils/util.domain.ts b/packages/core/basic/src/utils/util.domain.ts index ed08f0d22..59c1ee56f 100644 --- a/packages/core/basic/src/utils/util.domain.ts +++ b/packages/core/basic/src/utils/util.domain.ts @@ -58,7 +58,7 @@ function isIpv6(d: string) { if (!d) { return false; } - const isIPv6Regex = /^([\da-f]{1,4}:){2,7}[\da-f]{1,4}$/i; + const isIPv6Regex = /^([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})$/gm; return isIPv6Regex.test(d); } diff --git a/packages/core/basic/test.mjs b/packages/core/basic/test.mjs index 5e87fae90..c8889c56e 100644 --- a/packages/core/basic/test.mjs +++ b/packages/core/basic/test.mjs @@ -1,14 +1,18 @@ -import { random } from "lodash-es"; -import { locker } from "./dist/utils/util.lock.js"; +// import { random } from "lodash-es"; +// import { locker } from "./dist/utils/util.lock.js"; -async function testLocker() { - for (let i = 0; i < 10; i++) { - await locker.execute("test", async () => { - console.log("test", i); - await new Promise(resolve => setTimeout(resolve, Math.random() * 1000)); - throw new Error("test error"); - }); - } -} +// async function testLocker() { +// for (let i = 0; i < 10; i++) { +// await locker.execute("test", async () => { +// console.log("test", i); +// await new Promise(resolve => setTimeout(resolve, Math.random() * 1000)); +// throw new Error("test error"); +// }); +// } +// } -await testLocker(); +// await testLocker(); + +import { domainUtils } from "./dist/utils/util.domain.js"; + +console.log(domainUtils.isIpv6("::0:0:0:FFFF:129.144.52.38")); 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 17a0fd54c..5df3952f7 100644 --- a/packages/libs/lib-server/src/system/settings/service/models.ts +++ b/packages/libs/lib-server/src/system/settings/service/models.ts @@ -134,12 +134,9 @@ export class SysEmailConf extends BaseSettings { templates:{ registerCode?: EmailTemplate, - forgotPasswordCode?: EmailTemplate, - certSuccessNotify?: EmailTemplate, - certSend?: EmailTemplate, - pipelineNotify?: EmailTemplate, - test?: EmailTemplate, - siteMonitorNotify?: EmailTemplate, + forgotPassword?: EmailTemplate, + pipelineResult?: EmailTemplate, + common?: EmailTemplate, } } diff --git a/packages/plugins/plugin-cert/src/dns-provider/domain-parser.ts b/packages/plugins/plugin-cert/src/dns-provider/domain-parser.ts index 40ae592e5..b1c7838da 100644 --- a/packages/plugins/plugin-cert/src/dns-provider/domain-parser.ts +++ b/packages/plugins/plugin-cert/src/dns-provider/domain-parser.ts @@ -21,6 +21,11 @@ export class DomainParser implements IDomainParser { } async parse(fullDomain: string) { + //如果是ip + if (utils.domain.isIp(fullDomain)) { + return fullDomain; + } + this.logger.info(`查找主域名:${fullDomain}`); const cacheKey = `domain_parse:${fullDomain}`; const value = utils.cache.get(cacheKey); 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 506776403..7774cda01 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -220,7 +220,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { if(form.challengeType === 'cname' ){ return '请按照上面的提示,给要申请证书的域名添加CNAME记录,添加后,点击验证,验证成功后不要删除记录,申请和续期证书会一直用它' }else if (form.challengeType === 'http'){ - return '请按照上面的提示,给每个域名设置文件上传配置,证书申请过程中会上传校验文件到网站根目录下' + return '请按照上面的提示,给每个域名设置文件上传配置,证书申请过程中会上传校验文件到网站根目录的.well-known/acme-challenge/目录下' }else if (form.challengeType === 'http'){ return '给每个域名单独配置dns提供商' } diff --git a/packages/ui/certd-client/src/plugin/validator/index.ts b/packages/ui/certd-client/src/plugin/validator/index.ts index 105b9a10d..392b258f8 100644 --- a/packages/ui/certd-client/src/plugin/validator/index.ts +++ b/packages/ui/certd-client/src/plugin/validator/index.ts @@ -1,4 +1,26 @@ import Validator from "async-validator"; + +function isIpv6(d: string) { + if (!d) { + return false; + } + const isIPv6Regex = /^([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})$/gm; + return isIPv6Regex.test(d); +} +function isIpv4(d: string) { + if (!d) { + return false; + } + const isIPv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/; + return isIPv4Regex.test(d); +} +function isIp(d: string) { + if (!d) { + return false; + } + return isIpv4(d) || isIpv6(d); +} + // 自定义验证器函数 export function isDomain(rule: any, value: any) { if (value == null || value == "") { @@ -14,7 +36,9 @@ export function isDomain(rule: any, value: any) { const compiled = new RegExp(exp); for (const domain of domains) { //域名可以是泛域名,中文域名,数字域名,英文域名,域名中可以包含-和. ,可以_开头 - + if (isIp(domain)) { + continue; + } if (!compiled.test(domain)) { throw new Error(`域名有误:${domain},请输入正确的域名`); } From 63d8bcf8823f713365042d3c7aee3cf31d44b044 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Tue, 16 Dec 2025 00:21:31 +0800 Subject: [PATCH 04/13] =?UTF-8?q?perf:=20=E6=89=B9=E9=87=8F=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E5=AE=9A=E6=97=B6=EF=BC=8C=E6=94=AF=E6=8C=81=E6=B8=85?= =?UTF-8?q?=E9=99=A4=E5=AE=9A=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pipeline/components/change-trigger.vue | 33 +++++++++++++- .../modules/basic/service/email-service.ts | 1 + .../pipeline/service/pipeline-service.ts | 44 +++++++++++-------- .../plugin-notification/email/index.ts | 11 +++-- .../plugin-template/email/plugin-base.ts | 10 ++++- 5 files changed, 72 insertions(+), 27 deletions(-) diff --git a/packages/ui/certd-client/src/views/certd/pipeline/components/change-trigger.vue b/packages/ui/certd-client/src/views/certd/pipeline/components/change-trigger.vue index 73c322912..a524aebdc 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/components/change-trigger.vue +++ b/packages/ui/certd-client/src/views/certd/pipeline/components/change-trigger.vue @@ -3,10 +3,11 @@