From b59052cc43b7b070fabd8b8e914e4c2a5e0ad61c Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 1 Sep 2025 13:29:47 +0800 Subject: [PATCH 01/88] =?UTF-8?q?fix:=20=E5=89=8D=E7=BD=AE=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E8=BE=93=E5=87=BA=E4=B8=8D=E5=AD=98=E5=9C=A8=E6=97=B6?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E8=AD=A6=E5=91=8A=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/pipeline/src/core/executor.ts | 2 +- .../ui/certd-server/src/controller/basic/unhidden-controller.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/pipeline/src/core/executor.ts b/packages/core/pipeline/src/core/executor.ts index 81e4f78da..cb6f4d335 100644 --- a/packages/core/pipeline/src/core/executor.ts +++ b/packages/core/pipeline/src/core/executor.ts @@ -314,7 +314,7 @@ export class Executor { const outputKey = arr[2]; input[key] = this.currentStatusMap.get(id)?.status?.output[outputKey] ?? this.lastStatusMap.get(id)?.status?.output[outputKey]; if (input[key] == null) { - this.logger.warn(`${item.title}的配置未找到对应的输出值,请确认对应的前置任务是否存在或者是否执行正确`); + currentLogger.warn(`${item.title}的配置未找到对应的输出值,请确认对应的前置任务是否存在或者是否执行正确`); } } } diff --git a/packages/ui/certd-server/src/controller/basic/unhidden-controller.ts b/packages/ui/certd-server/src/controller/basic/unhidden-controller.ts index 1e450e1d7..f46e6989d 100644 --- a/packages/ui/certd-server/src/controller/basic/unhidden-controller.ts +++ b/packages/ui/certd-server/src/controller/basic/unhidden-controller.ts @@ -23,7 +23,7 @@ const unhiddenHtml = ` @Provide() @Controller('/api/unhidden') -export class HnhiddenController { +export class UnhiddenController { @Inject() ctx: IMidwayKoaContext; @Inject() From 1ceeacc5266eded27ba00f43ef23c69d259389cc Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 1 Sep 2025 13:33:12 +0800 Subject: [PATCH 02/88] chore: --- .../src/plugins/plugin-tencent/plugin/deploy-to-eo/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-eo/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-eo/index.ts index a35f981bc..189dcc56a 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-eo/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-eo/index.ts @@ -103,6 +103,10 @@ export class DeployCertToTencentEO extends AbstractTaskPlugin { logger: this.logger, }); + if (this.cert == null){ + throw new Error('请选择域名证书'); + } + let tencentCertId = this.cert as string; if (typeof this.cert !== 'string') { const certReader = new CertReader(this.cert); From a4cbb11693b6bb3c2d471b991384afc342c70124 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 1 Sep 2025 14:18:42 +0800 Subject: [PATCH 03/88] chore: --- .../pipeline/component/step-form/index.vue | 2 ++ .../views/certd/pipeline/pipeline/index.vue | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/packages/ui/certd-client/src/views/certd/pipeline/pipeline/component/step-form/index.vue b/packages/ui/certd-client/src/views/certd/pipeline/pipeline/component/step-form/index.vue index 97a1c8583..5c1bb9d99 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/pipeline/component/step-form/index.vue +++ b/packages/ui/certd-client/src/views/certd/pipeline/pipeline/component/step-form/index.vue @@ -313,6 +313,8 @@ function useStepForm() { }; const stepDelete = () => { + //检查输出依赖 + Modal.confirm({ title: "确认", content: `确定要删除此步骤吗?`, 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 0a0719a9f..b26a305eb 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 @@ -279,7 +279,7 @@ - + + diff --git a/packages/ui/certd-client/src/components/plugins/index.ts b/packages/ui/certd-client/src/components/plugins/index.ts index 61fadc997..be4697212 100644 --- a/packages/ui/certd-client/src/components/plugins/index.ts +++ b/packages/ui/certd-client/src/components/plugins/index.ts @@ -2,6 +2,7 @@ import SynologyIdDeviceGetter from "./synology/device-id-getter.vue"; import RemoteAutoComplete from "./common/remote-auto-complete.vue"; import RemoteSelect from "./common/remote-select.vue"; import RemoteInput from "./common/remote-input.vue"; +import RemoteTreeSelect from "./common/remote-tree-select.vue"; import CertDomainsGetter from "./common/cert-domains-getter.vue"; import OutputSelector from "/@/components/plugins/common/output-selector/index.vue"; import DnsProviderSelector from "/@/components/plugins/cert/dns-provider-selector/index.vue"; @@ -24,6 +25,7 @@ export default { app.component("SynologyDeviceIdGetter", SynologyIdDeviceGetter); app.component("RemoteAutoComplete", RemoteAutoComplete); app.component("RemoteSelect", RemoteSelect); + app.component("RemoteTreeSelect", RemoteTreeSelect); app.component("RemoteInput", RemoteInput); app.component("CertDomainsGetter", CertDomainsGetter); app.component("InputPassword", InputPassword); diff --git a/packages/ui/certd-server/package.json b/packages/ui/certd-server/package.json index af21a922e..7616e4d2b 100644 --- a/packages/ui/certd-server/package.json +++ b/packages/ui/certd-server/package.json @@ -118,7 +118,7 @@ "socks-proxy-agent": "^8.0.4", "strip-ansi": "^7.1.0", "svg-captcha": "^1.4.0", - "tencentcloud-sdk-nodejs": "^4.0.983", + "tencentcloud-sdk-nodejs": "^4.1.112", "typeorm": "^0.3.20", "uuid": "^10.0.0" }, diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/index.ts index 60db3827b..b8f9220da 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/index.ts @@ -9,3 +9,4 @@ export * from './delete-expiring-cert/index.js'; export * from './deploy-to-tke-ingress/index.js'; export * from './deploy-to-live/index.js'; export * from './start-instances/index.js'; +export * from './refresh-cert/index.js'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e2901b81b..1735c82cc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,7 +49,7 @@ importers: packages/core/acme-client: dependencies: '@certd/basic': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../basic '@peculiar/x509': specifier: ^1.11.0 @@ -210,10 +210,10 @@ importers: packages/core/pipeline: dependencies: '@certd/basic': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../basic '@certd/plus-core': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../pro/plus-core dayjs: specifier: ^1.11.7 @@ -418,7 +418,7 @@ importers: packages/libs/lib-k8s: dependencies: '@certd/basic': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/basic '@kubernetes/client-node': specifier: 0.21.0 @@ -458,16 +458,16 @@ importers: packages/libs/lib-server: dependencies: '@certd/acme-client': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/acme-client '@certd/basic': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/basic '@certd/pipeline': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/pipeline '@certd/plus-core': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../pro/plus-core '@midwayjs/cache': specifier: ~3.14.0 @@ -610,16 +610,16 @@ importers: packages/plugins/plugin-cert: dependencies: '@certd/acme-client': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/acme-client '@certd/basic': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/basic '@certd/pipeline': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/pipeline '@certd/plugin-lib': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../plugin-lib '@google-cloud/publicca': specifier: ^1.3.0 @@ -701,10 +701,10 @@ importers: specifier: ^3.787.0 version: 3.810.0(aws-crt@1.26.2) '@certd/basic': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/basic '@certd/pipeline': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/pipeline '@kubernetes/client-node': specifier: 0.21.0 @@ -792,19 +792,19 @@ importers: packages/pro/commercial-core: dependencies: '@certd/basic': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/basic '@certd/lib-server': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../libs/lib-server '@certd/pipeline': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/pipeline '@certd/plugin-plus': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../plugin-plus '@certd/plus-core': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../plus-core '@midwayjs/core': specifier: ~3.20.3 @@ -889,22 +889,22 @@ importers: specifier: ^1.0.2 version: 1.0.3 '@certd/basic': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/basic '@certd/lib-k8s': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../libs/lib-k8s '@certd/pipeline': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/pipeline '@certd/plugin-cert': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../plugins/plugin-cert '@certd/plugin-lib': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../plugins/plugin-lib '@certd/plus-core': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../plus-core ali-oss: specifier: ^6.21.0 @@ -1007,7 +1007,7 @@ importers: packages/pro/plus-core: dependencies: '@certd/basic': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/basic dayjs: specifier: ^1.11.7 @@ -1297,10 +1297,10 @@ importers: version: 0.1.3(zod@3.24.4) devDependencies: '@certd/lib-iframe': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../libs/lib-iframe '@certd/pipeline': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/pipeline '@rollup/plugin-commonjs': specifier: ^25.0.7 @@ -1483,46 +1483,46 @@ importers: specifier: ^3.705.0 version: 3.810.0(aws-crt@1.26.2) '@certd/acme-client': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/acme-client '@certd/basic': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/basic '@certd/commercial-core': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../pro/commercial-core '@certd/cv4pve-api-javascript': specifier: ^8.4.2 version: 8.4.2 '@certd/jdcloud': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../libs/lib-jdcloud '@certd/lib-huawei': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../libs/lib-huawei '@certd/lib-k8s': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../libs/lib-k8s '@certd/lib-server': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../libs/lib-server '@certd/midway-flyway-js': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../libs/midway-flyway-js '@certd/pipeline': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../core/pipeline '@certd/plugin-cert': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../plugins/plugin-cert '@certd/plugin-lib': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../plugins/plugin-lib '@certd/plugin-plus': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../pro/plugin-plus '@certd/plus-core': - specifier: ^1.36.17 + specifier: ^1.36.18 version: link:../../pro/plus-core '@huaweicloud/huaweicloud-sdk-cdn': specifier: ^3.1.120 @@ -1708,8 +1708,8 @@ importers: specifier: ^1.4.0 version: 1.4.0 tencentcloud-sdk-nodejs: - specifier: ^4.0.983 - version: 4.1.37(encoding@0.1.13) + specifier: ^4.1.112 + version: 4.1.112(encoding@0.1.13) typeorm: specifier: ^0.3.20 version: 0.3.24(better-sqlite3@11.10.0)(mysql2@3.14.1)(pg@8.16.0)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@18.19.100)(typescript@5.8.3)) @@ -12242,6 +12242,10 @@ packages: temp-path@1.0.0: resolution: {integrity: sha512-TvmyH7kC6ZVTYkqCODjJIbgvu0FKiwQpZ4D1aknE7xpcDf/qEOB8KZEK5ef2pfbVoiBhNWs3yx4y+ESMtNYmlg==} + tencentcloud-sdk-nodejs@4.1.112: + resolution: {integrity: sha512-30Ju53bTd3OjMRwfieDvEYvjHhHVg2Eqc0EM7H8gKEWq0y3xMEdrxgYRrjhIkRo5Doc5YEOl6uUJUCfeT7dmFA==} + engines: {node: '>=10'} + tencentcloud-sdk-nodejs@4.1.37: resolution: {integrity: sha512-rQV/jaUHGsB71JarqFdDJTl5tC2kIavgSUqlh8JoOUNpfJoAD4qHm1GLdDTUTEPKhv3qF9Is3qo6lj4cG9kKuw==} engines: {node: '>=10'} @@ -27035,6 +27039,20 @@ snapshots: temp-path@1.0.0: {} + tencentcloud-sdk-nodejs@4.1.112(encoding@0.1.13): + dependencies: + form-data: 3.0.3 + get-stream: 6.0.1 + https-proxy-agent: 5.0.1 + is-stream: 2.0.1 + json-bigint: 1.0.0 + node-fetch: 2.7.0(encoding@0.1.13) + tslib: 1.13.0 + uuid: 9.0.1 + transitivePeerDependencies: + - encoding + - supports-color + tencentcloud-sdk-nodejs@4.1.37(encoding@0.1.13): dependencies: form-data: 3.0.3 From a24ef48ad1a9ff6c5000edcb4fd81b354a5ea4ac Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:01:45 +0800 Subject: [PATCH 21/88] chore: --- .../plugin-lib/src/tencent/lib/ssl-client.ts | 21 +- .../plugin/plugin-refresh-cert.ts | 113 ------ .../plugin/refresh-cert/index.ts | 340 ++++++++++++++++++ 3 files changed, 359 insertions(+), 115 deletions(-) delete mode 100644 packages/ui/certd-server/src/plugins/plugin-tencent/plugin/plugin-refresh-cert.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-tencent/plugin/refresh-cert/index.ts diff --git a/packages/plugins/plugin-lib/src/tencent/lib/ssl-client.ts b/packages/plugins/plugin-lib/src/tencent/lib/ssl-client.ts index 4846ee1ae..2075d4705 100644 --- a/packages/plugins/plugin-lib/src/tencent/lib/ssl-client.ts +++ b/packages/plugins/plugin-lib/src/tencent/lib/ssl-client.ts @@ -76,9 +76,26 @@ export class TencentSslClient { return res; } - async DescribeCertificates(params: any) { + async DescribeHostUploadUpdateRecordDetail(params: any) { const client = await this.getSslClient(); - const res = await client.DescribeCertificates(params); + const res = await client.request("DescribeHostUploadUpdateRecordDetail", params); + this.checkRet(res); + return res; + } + + async UploadUpdateCertificateInstance(params: any) { + const client = await this.getSslClient(); + const res = await client.request("UploadUpdateCertificateInstance", params); + this.checkRet(res); + return res; + } + + async DescribeCertificates(params: { Limit?: number; Offset?: number; SearchKey?: string }) { + const client = await this.getSslClient(); + const res = await client.DescribeCertificates({ + ExpirationSort: "ASC", + ...params, + }); this.checkRet(res); return res; } diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/plugin-refresh-cert.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/plugin-refresh-cert.ts deleted file mode 100644 index eaac810c2..000000000 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/plugin-refresh-cert.ts +++ /dev/null @@ -1,113 +0,0 @@ -// import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; -// import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; -// import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; -// import { TencentAccess, TencentSslClient } from "@certd/plugin-lib"; -// @IsTaskPlugin({ -// //命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名 -// name: "TencentRefreshCert", -// title: "腾讯云-更新证书", -// desc: "根据证书id一键更新腾讯云证书并自动部署", -// icon: "svg:icon-tencentcloud", -// //插件分组 -// group: pluginGroups.tencent.key, -// needPlus: false, -// default: { -// //默认值配置照抄即可 -// strategy: { -// runStrategy: RunStrategy.SkipWhenSucceed -// } -// } -// }) -// //类名规范,跟上面插件名称(name)一致 -// export class TencentRefreshCert extends AbstractTaskPlugin { -// //证书选择,此项必须要有 -// @TaskInput({ -// title: "域名证书", -// helper: "请选择前置任务输出的域名证书", -// component: { -// name: "output-selector", -// from: [...CertApplyPluginNames] -// } -// // required: true, // 必填 -// }) -// cert!: CertInfo; -// -// @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) -// certDomains!: string[]; -// -// //授权选择框 -// @TaskInput({ -// title: "腾讯云授权", -// component: { -// name: "access-selector", -// type: "tencent" //固定授权类型 -// }, -// required: true //必填 -// }) -// accessId!: string; -// // -// -// @TaskInput( -// createRemoteSelectInputDefine({ -// title: "证书Id", -// helper: "要更新的证书id,如果这里没有,请先给手动绑定一次证书", -// action: TencentRefreshCert.prototype.onGetCertList.name, -// pager: false, -// search: false -// }) -// ) -// certList!: string[]; -// -// //插件实例化时执行的方法 -// async onInstance() { -// } -// -// //插件执行方法 -// async execute(): Promise { -// const access = await this.getAccess(this.accessId); -// -// // await access.createCert({cert:this.cert}) -// -// for (const certId of this.certList) { -// this.logger.info(`----------- 开始更新证书:${certId}`); -// -// await access.updateCert({ -// id: certId, -// cert: this.cert -// }); -// this.logger.info(`----------- 更新证书${certId}成功`); -// } -// -// this.logger.info("部署完成"); -// } -// -// async onGetCertList(data: PageSearch = {}) { -// const access = await this.getAccess(this.accessId); -// -// const res = await access.getCertList() -// const list = res.list -// if (!list || list.length === 0) { -// throw new Error("没有找到证书,你可以直接手动输入id,如果id不存在将自动创建"); -// } -// -// -// /** -// * certificate-id -// * name -// * dns-names -// */ -// const options = list.map((item: any) => { -// return { -// label: `${item.value.snis[0]}<${item.value.id}>`, -// value: item.value.id, -// domain: item.value.snis -// }; -// }); -// return { -// list: this.ctx.utils.options.buildGroupOptions(options, this.certDomains), -// }; -// } -// } -// -// //实例化一下,注册插件 -// new TencentRefreshCert(); diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/refresh-cert/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/refresh-cert/index.ts new file mode 100644 index 000000000..445fd4488 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/refresh-cert/index.ts @@ -0,0 +1,340 @@ +import { + AbstractTaskPlugin, + IsTaskPlugin, + Pager, + PageSearch, + pluginGroups, + RunStrategy, + TaskInput +} from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; +import { TencentAccess, TencentSslClient } from "@certd/plugin-lib"; +import { omit } from "lodash-es"; +@IsTaskPlugin({ + //命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名 + name: "TencentRefreshCert", + title: "腾讯云-更新证书(Id不变)", + desc: "根据证书id一键更新腾讯云证书并自动部署(Id不变),注意该接口为腾讯云白名单功能,非白名单用户无法使用该功能", + icon: "svg:icon-tencentcloud", + //插件分组 + group: pluginGroups.tencent.key, + needPlus: false, + default: { + //默认值配置照抄即可 + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed + } + } +}) +//类名规范,跟上面插件名称(name)一致 +export class TencentRefreshCert extends AbstractTaskPlugin { + //证书选择,此项必须要有 + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames] + } + // required: true, // 必填 + }) + cert!: CertInfo; + + @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + certDomains!: string[]; + + //授权选择框 + @TaskInput({ + title: "腾讯云授权", + component: { + name: "access-selector", + type: "tencent" //固定授权类型 + }, + required: true //必填 + }) + accessId!: string; + // + + @TaskInput( + createRemoteSelectInputDefine({ + title: "证书Id", + helper: "要更新的证书id,如果这里没有,请先给手动绑定一次证书", + action: TencentRefreshCert.prototype.onGetCertList.name, + pager: false, + search: false + }) + ) + certList!: string[]; + + // @TaskInput({ + // title: '资源类型', + // component: { + // name: 'a-select', + // vModel: 'value', + // allowClear: true, + // mode: "tags", + // options: [ + // { value: 'clb',label: '负载均衡'}, + // { value: 'cdn',label: 'CDN'}, + // { value: 'ddos',label: 'DDoS'}, + // { value: 'live',label: '直播'}, + // { value: 'vod',label: '点播'}, + // { value: 'waf',label: 'Web应用防火墙'}, + // { value: 'apigateway',label: 'API网关'}, + // { value: 'teo',label: 'TEO'}, + // { value: 'tke',label: '容器服务'}, + // { value: 'cos',label: '对象存储'}, + // { value: 'lighthouse',label: '轻应用服务器'}, + // { value: 'tse',label: '云原生微服务'}, + // { value: 'tcb',label: '云开发'}, + // ] + // }, + // helper: '', + // required: true, + // }) + // resourceTypes!: string[]; + + @TaskInput({ + title: '资源区域', + helper:"如果云资源类型区分区域,请选择区域,如果区域在选项中不存在,请手动输入", + component: { + name: 'remote-tree-select', + vModel: 'value', + action: TencentRefreshCert.prototype.onGetRegionsTree.name, + pager: false, + search: false, + watches: ['certList'], + }, + required: false, + }) + resourceTypesRegions!: string[]; + //插件实例化时执行的方法 + async onInstance() { + } + + //插件执行方法 + async execute(): Promise { + const access = await this.getAccess(this.accessId); + const sslClient = new TencentSslClient({ + access:access, + logger: this.logger, + }); + // await access.createCert({cert:this.cert}) + + let resourceTypes = [] + const resourceTypesRegions = [] + for (const item of this.resourceTypesRegions) { + const [type,region] = item.split("_") + if (!resourceTypes.includes( type)){ + resourceTypes.push(type) + } + if (!region){ + continue; + } + const resourceType = resourceTypesRegions.find(item => item.ResourceType == type) + if (!resourceType){ + resourceTypesRegions.push({ + ResourceType: type, + Regions: [region] + }) + }else{ + resourceType.Regions.push(region) + } + } + // resourceTypes = ["clb"] //固定clb + const maxRetry = 10 + for (const certId of this.certList) { + this.logger.info(`----------- 开始更新证书:${certId}`); + + let deployRes = null + + let retryCount = 0 + while(true){ + if (retryCount>maxRetry){ + this.logger.error(`任务创建失败`); + break; + } + retryCount++ + deployRes = await sslClient.UploadUpdateCertificateInstance({ + OldCertificateId: certId, + "ResourceTypes": resourceTypes, + "CertificatePublicKey": this.cert.crt, + "CertificatePrivateKey": this.cert.key, + "ResourceTypesRegions":resourceTypesRegions + }); + if (deployRes && deployRes.DeployRecordId>0){ + this.logger.info(`任务创建成功,开始检查结果:${JSON.stringify(deployRes)}`); + break; + }else{ + this.logger.info(`任务创建中,稍后查询:${JSON.stringify(deployRes)}`); + } + await this.ctx.utils.sleep(3000); + } + this.logger.info(`开始查询部署结果`); + + retryCount=0 + while(true){ + if (retryCount>maxRetry){ + this.logger.error(`任务结果检查失败`); + break; + } + retryCount++ + //查询部署状态 + const deployStatus = await sslClient.DescribeHostUploadUpdateRecordDetail({ + "DeployRecordId":deployRes.DeployRecordId + }) + const details = deployStatus.DeployRecordDetail + let allSuccess = true + for (const item of details) { + this.logger.info(`查询结果:${JSON.stringify(omit(item,"RecordDetailList"))}`); + if (item.Status === 2) { + throw new Error(`任务失败:${JSON.stringify(item.RecordDetailList)}`) + }else if (item.Status !== 1) { + //如果不是成功状态 + allSuccess = false + } + } + if (allSuccess) { + break; + } + await this.ctx.utils.sleep(10000); + } + this.logger.info(`----------- 更新证书${certId}成功`); + } + + } + + async onGetRegionsTree(data: PageSearch = {}){ + + const commonRegions = [ + /** + * 华南地区(广州) waf.ap-guangzhou.tencentcloudapi.com + * 华东地区(上海) waf.ap-shanghai.tencentcloudapi.com + * 华东地区(南京) waf.ap-nanjing.tencentcloudapi.com + * 华北地区(北京) waf.ap-beijing.tencentcloudapi.com + * 西南地区(成都) waf.ap-chengdu.tencentcloudapi.com + * 西南地区(重庆) waf.ap-chongqing.tencentcloudapi.com + * 港澳台地区(中国香港) waf.ap-hongkong.tencentcloudapi.com + * 亚太东南(新加坡) waf.ap-singapore.tencentcloudapi.com + * 亚太东南(雅加达) waf.ap-jakarta.tencentcloudapi.com + * 亚太东南(曼谷) waf.ap-bangkok.tencentcloudapi.com + * 亚太东北(首尔) waf.ap-seoul.tencentcloudapi.com + * 亚太东北(东京) waf.ap-tokyo.tencentcloudapi.com + * 美国东部(弗吉尼亚) waf.na-ashburn.tencentcloudapi.com + * 美国西部(硅谷) waf.na-siliconvalley.tencentcloudapi.com + * 南美地区(圣保罗) waf.sa-saopaulo.tencentcloudapi.com + * 欧洲地区(法兰克福) waf.eu-frankfurt.tencentcloudapi.com + */ + {value:"ap-guangzhou", label:"广州"}, + {value:"ap-shanghai", label:"上海"}, + {value:"ap-nanjing", label:"南京"}, + {value:"ap-beijing", label:"北京"}, + {value:"ap-chengdu", label:"成都"}, + {value:"ap-chongqing", label:"重庆"}, + {value:"ap-hongkong", label:"香港"}, + {value:"ap-singapore", label:"新加坡"}, + {value:"ap-jakarta", label:"雅加达"}, + {value:"ap-bangkok", label:"曼谷"}, + {value:"ap-tokyo", label:"东京"}, + {value:"ap-seoul", label:"首尔"}, + {value:"na-ashburn", label:"弗吉尼亚"}, + {value:"na-siliconvalley", label:"硅谷"}, + {value:"sa-saopaulo", label:"圣保罗"}, + {value:"eu-frankfurt", label:"法兰克福"}, + ] + + function buildTypeRegions(type: string) { + const options :any[]= [] + for (const region of commonRegions) { + options.push({ + label: type + "_" + region.label, + value: type + "_" + region.value, + }); + } + return options + } + + return [ + { value: 'cdn',label: 'CDN'}, + { value: 'ddos',label: 'DDoS'}, + { value: 'live',label: '直播'}, + { value: 'vod',label: '点播'}, + { value: 'teo',label: 'TEO'}, + { value: 'lighthouse',label: '轻应用服务器'}, + { + label: "负载均衡(clb)", + value: "clb", + children: buildTypeRegions("clb"), + }, + { + label: "Web应用防火墙(waf)", + value: "waf", + children: buildTypeRegions("waf"), + }, + { + label: "API网关(apigateway)", + value: "apigateway", + children: buildTypeRegions("apigateway"), + }, + { + label: "对象存储(COS)", + value: "cos", + children: buildTypeRegions("cos"), + }, + { + label: "容器服务(tke)", + value: "tke", + children: buildTypeRegions("tke"), + }, + { + label: "云原生微服务(tse)", + value: "tse", + children: buildTypeRegions("tse"), + }, + { + label: "云开发(tcb)", + value: "tcb", + children: buildTypeRegions("tcb"), + }, + ] + } + + async onGetCertList(data: PageSearch = {}) { + + const access = await this.getAccess(this.accessId) + const sslClient = new TencentSslClient({ + access:access, + logger: this.logger, + }); + + const pager = new Pager(data); + const offset = pager.getOffset(); + const limit = pager.pageSize + const res = await sslClient.DescribeCertificates({Limit:limit,Offset:offset,SearchKey:data.searchKey}) + const list = res.Certificates + if (!list || list.length === 0) { + throw new Error("没有找到证书,你可以直接手动输入id"); + } + + + /** + * certificate-id + * name + * dns-names + */ + const options = list.map((item: any) => { + return { + label: `${item.Alias}<${item.Domain}_${item.CertificateId}>`, + value: item.CertificateId, + domain: item.SubjectAltName, + }; + }); + return { + list: this.ctx.utils.options.buildGroupOptions(options, this.certDomains), + }; + } +} + +//实例化一下,注册插件 +new TencentRefreshCert(); From 0e96bfdfa377824d204e72923d1176408ae6b300 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:12:16 +0800 Subject: [PATCH 22/88] =?UTF-8?q?perf:=20=E5=88=9B=E5=BB=BA=E8=AF=81?= =?UTF-8?q?=E4=B9=A6=E6=97=B6=E6=94=AF=E6=8C=81=E9=80=89=E6=8B=A9=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=E6=97=B6=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/locales/langs/en-US/certd.ts | 1 + .../src/locales/langs/zh-CN/certd.ts | 1 + .../views/certd/pipeline/certd-form/use.tsx | 23 +++++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) 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 63390d5f7..19e35501a 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 @@ -219,6 +219,7 @@ export default { triggerCronHelper: "Click the button above to choose a daily execution time.\nIt is recommended to trigger once per day. The task will be skipped if the certificate has not expired and will not be executed repeatedly.", notificationTitle: "Failure Notification", + notificationWhen: "Notification Timing", notificationHelper: "Get real-time alerts when the task fails", groupIdTitle: "Pipeline Group", }, 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 4b667d64a..a2966391c 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 @@ -224,6 +224,7 @@ export default { triggerCronTitle: "定时触发", triggerCronHelper: "点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次,证书未到期之前任务会跳过,不会重复执行", notificationTitle: "失败通知", + notificationWhen: "通知时机", notificationHelper: "任务执行失败实时提醒", groupIdTitle: "流水线分组", }, diff --git a/packages/ui/certd-client/src/views/certd/pipeline/certd-form/use.tsx b/packages/ui/certd-client/src/views/certd/pipeline/certd-form/use.tsx index dd6ff4d57..5b10b8ca5 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/certd-form/use.tsx +++ b/packages/ui/certd-client/src/views/certd/pipeline/certd-form/use.tsx @@ -22,7 +22,7 @@ export function fillPipelineByDefaultForm(pipeline: any, form: any) { if (form.notification != null) { notifications.push({ type: "custom", - when: ["error", "turnToSuccess", "success"], + when: form.notificationWhen || ["error", "turnToSuccess"], notificationId: form.notification, title: form.notificationTarget?.name || "自定义通知", }); @@ -223,6 +223,25 @@ export function useCertPipelineCreator() { helper: t("certd.pipelineForm.notificationHelper"), }, }, + notificationWhen: { + title: t("certd.pipelineForm.notificationWhen"), + type: "text", + form: { + value: ["error", "turnToSuccess"], + component: { + name: "a-select", + vModel: "value", + mode: "multiple", + options: [ + { value: "start", label: t("certd.start_time") }, + { value: "success", label: t("certd.success_time") }, + { value: "turnToSuccess", label: t("certd.fail_to_success_time") }, + { value: "error", label: t("certd.fail_time") }, + ], + }, + order: 102, + }, + }, groupId: { title: t("certd.pipelineForm.groupIdTitle"), type: "dict-select", @@ -268,7 +287,7 @@ export function useCertPipelineCreator() { async function doSubmit({ form }: any) { // const certDetail = readCertDetail(form.cert.crt); // 添加certd pipeline - const pluginInput = omit(form, ["triggerCron", "notification", "notificationTarget", "certApplyPlugin", "groupId"]); + const pluginInput = omit(form, ["triggerCron", "notification", "notificationTarget", "notificationWhen", "certApplyPlugin", "groupId"]); let pipeline: any = { title: form.domains[0] + "证书自动化", runnableType: "pipeline", From cff233692323ed8f2569e1a70134d19d94c38a9e Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:17:10 +0800 Subject: [PATCH 23/88] build: prepare to build --- packages/core/basic/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/basic/build.md b/packages/core/basic/build.md index 4316bd657..ee14c1f16 100644 --- a/packages/core/basic/build.md +++ b/packages/core/basic/build.md @@ -1 +1 @@ -00:39 +00:17 From 4d875a18decb2e52a060ef0fb21d5bfbf914287d Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:26:29 +0800 Subject: [PATCH 24/88] chore: --- packages/core/basic/src/utils/util.log.ts | 51 ++++++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/packages/core/basic/src/utils/util.log.ts b/packages/core/basic/src/utils/util.log.ts index ce93a481d..3821900fe 100644 --- a/packages/core/basic/src/utils/util.log.ts +++ b/packages/core/basic/src/utils/util.log.ts @@ -1,4 +1,4 @@ -import log4js, { CallStack, Level, Logger } from "log4js"; +import log4js, { CallStack, Level } from "log4js"; let logFilePath = "./logs/app.log"; export function resetLogConfigure() { @@ -28,7 +28,54 @@ export function buildLogger(write: (text: string) => void) { return new PipelineLogger("pipeline", write); } -export type ILogger = Logger; +export type ILogger = { + log(level: Level | string, ...args: any[]): void; + + isLevelEnabled(level?: string): boolean; + + isTraceEnabled(): boolean; + isDebugEnabled(): boolean; + isInfoEnabled(): boolean; + isWarnEnabled(): boolean; + isErrorEnabled(): boolean; + isFatalEnabled(): boolean; + + _log(level: Level, data: any): void; + + addContext(key: string, value: any): void; + + removeContext(key: string): void; + + clearContext(): void; + + /** + * Replace the basic parse function with a new custom one + * - Note that linesToSkip will be based on the origin of the Error object in addition to the callStackLinesToSkip (at least 1) + * @param parseFunction the new parseFunction. Use `undefined` to reset to the base implementation + */ + setParseCallStackFunction(parseFunction: (error: Error, linesToSkip: number) => CallStack | undefined): void; + + /** + * Adjust the value of linesToSkip when the parseFunction is called. + * + * Cannot be less than 0. + */ + callStackLinesToSkip: number; + + trace(message: any, ...args: any[]): void; + + debug(message: any, ...args: any[]): void; + + info(message: any, ...args: any[]): void; + + warn(message: any, ...args: any[]): void; + + error(message: any, ...args: any[]): void; + + fatal(message: any, ...args: any[]): void; + + mark(message: any, ...args: any[]): void; +}; const locale = Intl.DateTimeFormat().resolvedOptions().locale; const formatter = new Intl.DateTimeFormat(locale, { From 02ab343e22ec71d1e6f32fb82c1c02fac9de23f8 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:26:48 +0800 Subject: [PATCH 25/88] build: prepare to build --- packages/core/basic/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/basic/build.md b/packages/core/basic/build.md index ee14c1f16..b8bc32e06 100644 --- a/packages/core/basic/build.md +++ b/packages/core/basic/build.md @@ -1 +1 @@ -00:17 +00:26 From 8bb7e8bfb286a406fa59fab5e3d9893716d8d746 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:28:43 +0800 Subject: [PATCH 26/88] chore: --- packages/core/basic/src/utils/util.log.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/basic/src/utils/util.log.ts b/packages/core/basic/src/utils/util.log.ts index 3821900fe..6a290ff41 100644 --- a/packages/core/basic/src/utils/util.log.ts +++ b/packages/core/basic/src/utils/util.log.ts @@ -1,4 +1,4 @@ -import log4js, { CallStack, Level } from "log4js"; +import log4js, { CallStack, Level, Logger } from "log4js"; let logFilePath = "./logs/app.log"; export function resetLogConfigure() { @@ -29,6 +29,8 @@ export function buildLogger(write: (text: string) => void) { } export type ILogger = { + readonly category: string; + level: Level | string; log(level: Level | string, ...args: any[]): void; isLevelEnabled(level?: string): boolean; From c7b6a6df794b5f423c0ec72f421290aa74a38b89 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:28:50 +0800 Subject: [PATCH 27/88] chore: --- packages/core/basic/src/utils/util.log.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/basic/src/utils/util.log.ts b/packages/core/basic/src/utils/util.log.ts index 6a290ff41..fbcc87e2e 100644 --- a/packages/core/basic/src/utils/util.log.ts +++ b/packages/core/basic/src/utils/util.log.ts @@ -1,4 +1,4 @@ -import log4js, { CallStack, Level, Logger } from "log4js"; +import log4js, { CallStack, Level } from "log4js"; let logFilePath = "./logs/app.log"; export function resetLogConfigure() { From 96677ff8bf67e93acb136bffb722d10827d96f84 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:28:54 +0800 Subject: [PATCH 28/88] build: prepare to build --- packages/core/basic/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/basic/build.md b/packages/core/basic/build.md index b8bc32e06..facabcbc0 100644 --- a/packages/core/basic/build.md +++ b/packages/core/basic/build.md @@ -1 +1 @@ -00:26 +00:28 From bb80bc0c0775c2f7a3a08368b3024e6bde6cea84 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:29:55 +0800 Subject: [PATCH 29/88] chore: --- packages/core/basic/src/utils/util.request.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/basic/src/utils/util.request.ts b/packages/core/basic/src/utils/util.request.ts index 39f41a2ad..b3cbb2a89 100644 --- a/packages/core/basic/src/utils/util.request.ts +++ b/packages/core/basic/src/utils/util.request.ts @@ -1,6 +1,5 @@ import axios, { AxiosHeaders, AxiosRequestConfig } from "axios"; import { ILogger, logger } from "./util.log.js"; -import { Logger } from "log4js"; import { HttpProxyAgent } from "http-proxy-agent"; import { HttpsProxyAgent } from "https-proxy-agent"; import nodeHttp from "http"; @@ -84,7 +83,7 @@ export function getGlobalAgents() { /** * @description 创建请求实例 */ -export function createAxiosService({ logger }: { logger: Logger }) { +export function createAxiosService({ logger }: { logger: ILogger }) { // 创建一个 axios 实例 const service = axios.create(); From f339bc9f7fe7f4b94257fe266cf10a014dbfc0d9 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:30:00 +0800 Subject: [PATCH 30/88] build: prepare to build --- packages/core/basic/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/basic/build.md b/packages/core/basic/build.md index facabcbc0..52e26d31c 100644 --- a/packages/core/basic/build.md +++ b/packages/core/basic/build.md @@ -1 +1 @@ -00:28 +00:30 From 6d8981479517b5de9634e242c1ebf22e70527ec4 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:33:10 +0800 Subject: [PATCH 31/88] v1.36.19 --- CHANGELOG.md | 23 +++++++++++++++++ lerna.json | 2 +- packages/core/acme-client/CHANGELOG.md | 6 +++++ packages/core/acme-client/package.json | 4 +-- packages/core/basic/CHANGELOG.md | 10 ++++++++ packages/core/basic/package.json | 2 +- packages/core/pipeline/CHANGELOG.md | 11 ++++++++ packages/core/pipeline/package.json | 6 ++--- packages/libs/lib-huawei/CHANGELOG.md | 4 +++ packages/libs/lib-huawei/package.json | 2 +- packages/libs/lib-iframe/CHANGELOG.md | 4 +++ packages/libs/lib-iframe/package.json | 2 +- packages/libs/lib-jdcloud/CHANGELOG.md | 4 +++ packages/libs/lib-jdcloud/package.json | 2 +- packages/libs/lib-k8s/CHANGELOG.md | 10 ++++++++ packages/libs/lib-k8s/package.json | 4 +-- packages/libs/lib-server/CHANGELOG.md | 4 +++ packages/libs/lib-server/package.json | 10 ++++---- packages/libs/midway-flyway-js/CHANGELOG.md | 4 +++ packages/libs/midway-flyway-js/package.json | 2 +- packages/plugins/plugin-cert/CHANGELOG.md | 7 ++++++ packages/plugins/plugin-cert/package.json | 10 ++++---- packages/plugins/plugin-lib/CHANGELOG.md | 6 +++++ packages/plugins/plugin-lib/package.json | 6 ++--- packages/ui/certd-client/CHANGELOG.md | 16 ++++++++++++ packages/ui/certd-client/package.json | 6 ++--- packages/ui/certd-server/CHANGELOG.md | 14 +++++++++++ packages/ui/certd-server/package.json | 28 ++++++++++----------- 28 files changed, 166 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 317406481..10ff8c38c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,29 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +### Bug Fixes + +* 前置任务输出不存在时输出警告提示 ([b59052c](https://github.com/certd/certd/commit/b59052cc43b7b070fabd8b8e914e4c2a5e0ad61c)) +* 修复批量流水线执行时日志显示错乱的问题 ([4372adc](https://github.com/certd/certd/commit/4372adc703b9a4c785664054ab2a533626d815a8)) +* 修复远程数据选择无法过滤的bug ([6cbb073](https://github.com/certd/certd/commit/6cbb0739f8428d51b0712f718fe4d236cc087cf9)) +* 修复mysql下购买套餐加量包无效的bug ([c26ad4c](https://github.com/certd/certd/commit/c26ad4c8075f0606d45b8da13915737968d6191a)) + +### Performance Improvements + +* 创建证书时支持选择通知时机 ([0e96bfd](https://github.com/certd/certd/commit/0e96bfdfa377824d204e72923d1176408ae6b300)) +* 创建k8s secret 时设置type为tls ([79ebabf](https://github.com/certd/certd/commit/79ebabfcfb9e5a534049c84f5f1a642b357fc856)) +* 去掉宝塔url后面的斜杠 ([8a0c2b9](https://github.com/certd/certd/commit/8a0c2b9b13628da750c25757e0cb8ed3038775ba)) +* 商业版隐藏文档相关链接 ([4443a1c](https://github.com/certd/certd/commit/4443a1c0308fa6b95a05efd73d15d24b65d641c9)) +* 商业版隐藏文档相关链接 ([db89561](https://github.com/certd/certd/commit/db8956148083bc4f988226ccf719940d08158a27)) +* 增加健康检查探针 /health/liveliness 和 /health/readiness ([44019e1](https://github.com/certd/certd/commit/44019e104289fedd32a867db00e9c6cb71b389cc)) +* 支持根据id更新证书(证书Id不变接口),不过该接口为白名单功能,普通腾讯云账户无法使用 ([fe9c4f3](https://github.com/certd/certd/commit/fe9c4f3391ff07c01dd9a252225f69a129c39050)) +* 支持godaddy ([b7980aa](https://github.com/certd/certd/commit/b7980aad5ab50f58662eaddf5d84aa82876a98eb)) +* 支持ssl.com证书颁发机构 ([27b6dfa](https://github.com/certd/certd/commit/27b6dfa4d2ab3bddd284c3a34511a72e1a513a4c)) +* 子域名托管说明 ([39a0223](https://github.com/certd/certd/commit/39a02235cf4416bb5bd1acd3831241efeaa2f602)) +* ssh 增加超时断开连接,默认10分钟超时 ([c24a040](https://github.com/certd/certd/commit/c24a040c19cacafc79228d7a7649af93837d94a1)) + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) ### Bug Fixes diff --git a/lerna.json b/lerna.json index 26a7f3583..20b55aad1 100644 --- a/lerna.json +++ b/lerna.json @@ -9,5 +9,5 @@ } }, "npmClient": "pnpm", - "version": "1.36.18" + "version": "1.36.19" } diff --git a/packages/core/acme-client/CHANGELOG.md b/packages/core/acme-client/CHANGELOG.md index 329ae74ae..d9cff0293 100644 --- a/packages/core/acme-client/CHANGELOG.md +++ b/packages/core/acme-client/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/publishlab/node-acme-client/compare/v1.36.18...v1.36.19) (2025-09-05) + +### Performance Improvements + +* 支持ssl.com证书颁发机构 ([27b6dfa](https://github.com/publishlab/node-acme-client/commit/27b6dfa4d2ab3bddd284c3a34511a72e1a513a4c)) + ## [1.36.18](https://github.com/publishlab/node-acme-client/compare/v1.36.17...v1.36.18) (2025-08-28) **Note:** Version bump only for package @certd/acme-client diff --git a/packages/core/acme-client/package.json b/packages/core/acme-client/package.json index d77cfec87..fe59cc4cd 100644 --- a/packages/core/acme-client/package.json +++ b/packages/core/acme-client/package.json @@ -3,7 +3,7 @@ "description": "Simple and unopinionated ACME client", "private": false, "author": "nmorsman", - "version": "1.36.18", + "version": "1.36.19", "type": "module", "module": "scr/index.js", "main": "src/index.js", @@ -18,7 +18,7 @@ "types" ], "dependencies": { - "@certd/basic": "^1.36.18", + "@certd/basic": "^1.36.19", "@peculiar/x509": "^1.11.0", "asn1js": "^3.0.5", "axios": "^1.7.2", diff --git a/packages/core/basic/CHANGELOG.md b/packages/core/basic/CHANGELOG.md index d8c3f8a14..b3503bc8d 100644 --- a/packages/core/basic/CHANGELOG.md +++ b/packages/core/basic/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +### Bug Fixes + +* 修复批量流水线执行时日志显示错乱的问题 ([4372adc](https://github.com/certd/certd/commit/4372adc703b9a4c785664054ab2a533626d815a8)) + +### Performance Improvements + +* 去掉宝塔url后面的斜杠 ([8a0c2b9](https://github.com/certd/certd/commit/8a0c2b9b13628da750c25757e0cb8ed3038775ba)) + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) **Note:** Version bump only for package @certd/basic diff --git a/packages/core/basic/package.json b/packages/core/basic/package.json index def44d2fe..341795920 100644 --- a/packages/core/basic/package.json +++ b/packages/core/basic/package.json @@ -1,7 +1,7 @@ { "name": "@certd/basic", "private": false, - "version": "1.36.18", + "version": "1.36.19", "type": "module", "main": "./dist/index.js", "module": "./dist/index.js", diff --git a/packages/core/pipeline/CHANGELOG.md b/packages/core/pipeline/CHANGELOG.md index d954ea085..c8c7396e3 100644 --- a/packages/core/pipeline/CHANGELOG.md +++ b/packages/core/pipeline/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +### Bug Fixes + +* 前置任务输出不存在时输出警告提示 ([b59052c](https://github.com/certd/certd/commit/b59052cc43b7b070fabd8b8e914e4c2a5e0ad61c)) + +### Performance Improvements + +* 支持godaddy ([b7980aa](https://github.com/certd/certd/commit/b7980aad5ab50f58662eaddf5d84aa82876a98eb)) +* 支持ssl.com证书颁发机构 ([27b6dfa](https://github.com/certd/certd/commit/27b6dfa4d2ab3bddd284c3a34511a72e1a513a4c)) + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) **Note:** Version bump only for package @certd/pipeline diff --git a/packages/core/pipeline/package.json b/packages/core/pipeline/package.json index 0dcf7704e..572a7aba2 100644 --- a/packages/core/pipeline/package.json +++ b/packages/core/pipeline/package.json @@ -1,7 +1,7 @@ { "name": "@certd/pipeline", "private": false, - "version": "1.36.18", + "version": "1.36.19", "type": "module", "main": "./dist/index.js", "module": "./dist/index.js", @@ -17,8 +17,8 @@ "pub": "npm publish" }, "dependencies": { - "@certd/basic": "^1.36.18", - "@certd/plus-core": "^1.36.18", + "@certd/basic": "^1.36.19", + "@certd/plus-core": "^1.36.19", "dayjs": "^1.11.7", "lodash-es": "^4.17.21", "reflect-metadata": "^0.1.13" diff --git a/packages/libs/lib-huawei/CHANGELOG.md b/packages/libs/lib-huawei/CHANGELOG.md index 5e582f6bd..fb1dba6aa 100644 --- a/packages/libs/lib-huawei/CHANGELOG.md +++ b/packages/libs/lib-huawei/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +**Note:** Version bump only for package @certd/lib-huawei + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) **Note:** Version bump only for package @certd/lib-huawei diff --git a/packages/libs/lib-huawei/package.json b/packages/libs/lib-huawei/package.json index bb3a33df8..3c8918849 100644 --- a/packages/libs/lib-huawei/package.json +++ b/packages/libs/lib-huawei/package.json @@ -1,7 +1,7 @@ { "name": "@certd/lib-huawei", "private": false, - "version": "1.36.18", + "version": "1.36.19", "main": "./dist/bundle.js", "module": "./dist/bundle.js", "types": "./dist/d/index.d.ts", diff --git a/packages/libs/lib-iframe/CHANGELOG.md b/packages/libs/lib-iframe/CHANGELOG.md index f2a0a6938..e3608ca1e 100644 --- a/packages/libs/lib-iframe/CHANGELOG.md +++ b/packages/libs/lib-iframe/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +**Note:** Version bump only for package @certd/lib-iframe + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) **Note:** Version bump only for package @certd/lib-iframe diff --git a/packages/libs/lib-iframe/package.json b/packages/libs/lib-iframe/package.json index 8466cce21..b95f12c3a 100644 --- a/packages/libs/lib-iframe/package.json +++ b/packages/libs/lib-iframe/package.json @@ -1,7 +1,7 @@ { "name": "@certd/lib-iframe", "private": false, - "version": "1.36.18", + "version": "1.36.19", "type": "module", "main": "./dist/index.js", "module": "./dist/index.js", diff --git a/packages/libs/lib-jdcloud/CHANGELOG.md b/packages/libs/lib-jdcloud/CHANGELOG.md index ffaf02e09..852315b23 100644 --- a/packages/libs/lib-jdcloud/CHANGELOG.md +++ b/packages/libs/lib-jdcloud/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +**Note:** Version bump only for package @certd/jdcloud + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) **Note:** Version bump only for package @certd/jdcloud diff --git a/packages/libs/lib-jdcloud/package.json b/packages/libs/lib-jdcloud/package.json index df4e817ef..0e7bebc33 100644 --- a/packages/libs/lib-jdcloud/package.json +++ b/packages/libs/lib-jdcloud/package.json @@ -1,6 +1,6 @@ { "name": "@certd/jdcloud", - "version": "1.36.18", + "version": "1.36.19", "description": "jdcloud openApi sdk", "main": "./dist/bundle.js", "module": "./dist/bundle.js", diff --git a/packages/libs/lib-k8s/CHANGELOG.md b/packages/libs/lib-k8s/CHANGELOG.md index f7570468a..0c147305c 100644 --- a/packages/libs/lib-k8s/CHANGELOG.md +++ b/packages/libs/lib-k8s/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +### Bug Fixes + +* 修复远程数据选择无法过滤的bug ([6cbb073](https://github.com/certd/certd/commit/6cbb0739f8428d51b0712f718fe4d236cc087cf9)) + +### Performance Improvements + +* 创建k8s secret 时设置type为tls ([79ebabf](https://github.com/certd/certd/commit/79ebabfcfb9e5a534049c84f5f1a642b357fc856)) + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) ### Performance Improvements diff --git a/packages/libs/lib-k8s/package.json b/packages/libs/lib-k8s/package.json index 2ae6f74a0..f559c2e52 100644 --- a/packages/libs/lib-k8s/package.json +++ b/packages/libs/lib-k8s/package.json @@ -1,7 +1,7 @@ { "name": "@certd/lib-k8s", "private": false, - "version": "1.36.18", + "version": "1.36.19", "type": "module", "main": "./dist/index.js", "module": "./dist/index.js", @@ -17,7 +17,7 @@ "pub": "npm publish" }, "dependencies": { - "@certd/basic": "^1.36.18", + "@certd/basic": "^1.36.19", "@kubernetes/client-node": "0.21.0" }, "devDependencies": { diff --git a/packages/libs/lib-server/CHANGELOG.md b/packages/libs/lib-server/CHANGELOG.md index 213e6268e..9b9a0c16f 100644 --- a/packages/libs/lib-server/CHANGELOG.md +++ b/packages/libs/lib-server/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +**Note:** Version bump only for package @certd/lib-server + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) **Note:** Version bump only for package @certd/lib-server diff --git a/packages/libs/lib-server/package.json b/packages/libs/lib-server/package.json index 329dfa97d..1ab87cfec 100644 --- a/packages/libs/lib-server/package.json +++ b/packages/libs/lib-server/package.json @@ -1,6 +1,6 @@ { "name": "@certd/lib-server", - "version": "1.36.18", + "version": "1.36.19", "description": "midway with flyway, sql upgrade way ", "private": false, "type": "module", @@ -27,10 +27,10 @@ ], "license": "AGPL", "dependencies": { - "@certd/acme-client": "^1.36.18", - "@certd/basic": "^1.36.18", - "@certd/pipeline": "^1.36.18", - "@certd/plus-core": "^1.36.18", + "@certd/acme-client": "^1.36.19", + "@certd/basic": "^1.36.19", + "@certd/pipeline": "^1.36.19", + "@certd/plus-core": "^1.36.19", "@midwayjs/cache": "~3.14.0", "@midwayjs/core": "~3.20.3", "@midwayjs/i18n": "~3.20.3", diff --git a/packages/libs/midway-flyway-js/CHANGELOG.md b/packages/libs/midway-flyway-js/CHANGELOG.md index 771525204..a1b5e56ea 100644 --- a/packages/libs/midway-flyway-js/CHANGELOG.md +++ b/packages/libs/midway-flyway-js/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +**Note:** Version bump only for package @certd/midway-flyway-js + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) **Note:** Version bump only for package @certd/midway-flyway-js diff --git a/packages/libs/midway-flyway-js/package.json b/packages/libs/midway-flyway-js/package.json index ab01b2a23..a45c0eb5a 100644 --- a/packages/libs/midway-flyway-js/package.json +++ b/packages/libs/midway-flyway-js/package.json @@ -1,6 +1,6 @@ { "name": "@certd/midway-flyway-js", - "version": "1.36.18", + "version": "1.36.19", "description": "midway with flyway, sql upgrade way ", "private": false, "type": "module", diff --git a/packages/plugins/plugin-cert/CHANGELOG.md b/packages/plugins/plugin-cert/CHANGELOG.md index 3e8521a58..43fbde4e5 100644 --- a/packages/plugins/plugin-cert/CHANGELOG.md +++ b/packages/plugins/plugin-cert/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +### Performance Improvements + +* 支持ssl.com证书颁发机构 ([27b6dfa](https://github.com/certd/certd/commit/27b6dfa4d2ab3bddd284c3a34511a72e1a513a4c)) +* 子域名托管说明 ([39a0223](https://github.com/certd/certd/commit/39a02235cf4416bb5bd1acd3831241efeaa2f602)) + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) ### Performance Improvements diff --git a/packages/plugins/plugin-cert/package.json b/packages/plugins/plugin-cert/package.json index c6d56d933..a96723024 100644 --- a/packages/plugins/plugin-cert/package.json +++ b/packages/plugins/plugin-cert/package.json @@ -1,7 +1,7 @@ { "name": "@certd/plugin-cert", "private": false, - "version": "1.36.18", + "version": "1.36.19", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -16,10 +16,10 @@ "pub": "npm publish" }, "dependencies": { - "@certd/acme-client": "^1.36.18", - "@certd/basic": "^1.36.18", - "@certd/pipeline": "^1.36.18", - "@certd/plugin-lib": "^1.36.18", + "@certd/acme-client": "^1.36.19", + "@certd/basic": "^1.36.19", + "@certd/pipeline": "^1.36.19", + "@certd/plugin-lib": "^1.36.19", "@google-cloud/publicca": "^1.3.0", "dayjs": "^1.11.7", "jszip": "^3.10.1", diff --git a/packages/plugins/plugin-lib/CHANGELOG.md b/packages/plugins/plugin-lib/CHANGELOG.md index d2c403c37..c9c150593 100644 --- a/packages/plugins/plugin-lib/CHANGELOG.md +++ b/packages/plugins/plugin-lib/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +### Performance Improvements + +* ssh 增加超时断开连接,默认10分钟超时 ([c24a040](https://github.com/certd/certd/commit/c24a040c19cacafc79228d7a7649af93837d94a1)) + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) ### Performance Improvements diff --git a/packages/plugins/plugin-lib/package.json b/packages/plugins/plugin-lib/package.json index 7d96007cf..e569111fa 100644 --- a/packages/plugins/plugin-lib/package.json +++ b/packages/plugins/plugin-lib/package.json @@ -1,7 +1,7 @@ { "name": "@certd/plugin-lib", "private": false, - "version": "1.36.18", + "version": "1.36.19", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -21,8 +21,8 @@ "@alicloud/pop-core": "^1.7.10", "@alicloud/tea-util": "^1.4.10", "@aws-sdk/client-s3": "^3.787.0", - "@certd/basic": "^1.36.18", - "@certd/pipeline": "^1.36.18", + "@certd/basic": "^1.36.19", + "@certd/pipeline": "^1.36.19", "@kubernetes/client-node": "0.21.0", "ali-oss": "^6.22.0", "basic-ftp": "^5.0.5", diff --git a/packages/ui/certd-client/CHANGELOG.md b/packages/ui/certd-client/CHANGELOG.md index c91dfd093..b83431421 100644 --- a/packages/ui/certd-client/CHANGELOG.md +++ b/packages/ui/certd-client/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +### Bug Fixes + +* 修复批量流水线执行时日志显示错乱的问题 ([4372adc](https://github.com/certd/certd/commit/4372adc703b9a4c785664054ab2a533626d815a8)) +* 修复远程数据选择无法过滤的bug ([6cbb073](https://github.com/certd/certd/commit/6cbb0739f8428d51b0712f718fe4d236cc087cf9)) +* 修复mysql下购买套餐加量包无效的bug ([c26ad4c](https://github.com/certd/certd/commit/c26ad4c8075f0606d45b8da13915737968d6191a)) + +### Performance Improvements + +* 创建证书时支持选择通知时机 ([0e96bfd](https://github.com/certd/certd/commit/0e96bfdfa377824d204e72923d1176408ae6b300)) +* 商业版隐藏文档相关链接 ([4443a1c](https://github.com/certd/certd/commit/4443a1c0308fa6b95a05efd73d15d24b65d641c9)) +* 商业版隐藏文档相关链接 ([db89561](https://github.com/certd/certd/commit/db8956148083bc4f988226ccf719940d08158a27)) +* 支持根据id更新证书(证书Id不变接口),不过该接口为白名单功能,普通腾讯云账户无法使用 ([fe9c4f3](https://github.com/certd/certd/commit/fe9c4f3391ff07c01dd9a252225f69a129c39050)) +* 子域名托管说明 ([39a0223](https://github.com/certd/certd/commit/39a02235cf4416bb5bd1acd3831241efeaa2f602)) + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) ### Bug Fixes diff --git a/packages/ui/certd-client/package.json b/packages/ui/certd-client/package.json index 156fb9e60..a64fe5975 100644 --- a/packages/ui/certd-client/package.json +++ b/packages/ui/certd-client/package.json @@ -1,6 +1,6 @@ { "name": "@certd/ui-client", - "version": "1.36.18", + "version": "1.36.19", "private": true, "scripts": { "dev": "vite --open", @@ -103,8 +103,8 @@ "zod-defaults": "^0.1.3" }, "devDependencies": { - "@certd/lib-iframe": "^1.36.18", - "@certd/pipeline": "^1.36.18", + "@certd/lib-iframe": "^1.36.19", + "@certd/pipeline": "^1.36.19", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-node-resolve": "^15.2.3", "@types/chai": "^4.3.12", diff --git a/packages/ui/certd-server/CHANGELOG.md b/packages/ui/certd-server/CHANGELOG.md index 61b7ed361..6ab273d6f 100644 --- a/packages/ui/certd-server/CHANGELOG.md +++ b/packages/ui/certd-server/CHANGELOG.md @@ -3,6 +3,20 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +### Bug Fixes + +* 前置任务输出不存在时输出警告提示 ([b59052c](https://github.com/certd/certd/commit/b59052cc43b7b070fabd8b8e914e4c2a5e0ad61c)) +* 修复mysql下购买套餐加量包无效的bug ([c26ad4c](https://github.com/certd/certd/commit/c26ad4c8075f0606d45b8da13915737968d6191a)) + +### Performance Improvements + +* 增加健康检查探针 /health/liveliness 和 /health/readiness ([44019e1](https://github.com/certd/certd/commit/44019e104289fedd32a867db00e9c6cb71b389cc)) +* 支持根据id更新证书(证书Id不变接口),不过该接口为白名单功能,普通腾讯云账户无法使用 ([fe9c4f3](https://github.com/certd/certd/commit/fe9c4f3391ff07c01dd9a252225f69a129c39050)) +* 支持godaddy ([b7980aa](https://github.com/certd/certd/commit/b7980aad5ab50f58662eaddf5d84aa82876a98eb)) +* 支持ssl.com证书颁发机构 ([27b6dfa](https://github.com/certd/certd/commit/27b6dfa4d2ab3bddd284c3a34511a72e1a513a4c)) + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) ### Bug Fixes diff --git a/packages/ui/certd-server/package.json b/packages/ui/certd-server/package.json index 7616e4d2b..1b675ef0b 100644 --- a/packages/ui/certd-server/package.json +++ b/packages/ui/certd-server/package.json @@ -1,6 +1,6 @@ { "name": "@certd/ui-server", - "version": "1.36.18", + "version": "1.36.19", "description": "fast-server base midway", "private": true, "type": "module", @@ -43,20 +43,20 @@ "@aws-sdk/client-cloudfront": "^3.699.0", "@aws-sdk/client-iam": "^3.699.0", "@aws-sdk/client-s3": "^3.705.0", - "@certd/acme-client": "^1.36.18", - "@certd/basic": "^1.36.18", - "@certd/commercial-core": "^1.36.18", + "@certd/acme-client": "^1.36.19", + "@certd/basic": "^1.36.19", + "@certd/commercial-core": "^1.36.19", "@certd/cv4pve-api-javascript": "^8.4.2", - "@certd/jdcloud": "^1.36.18", - "@certd/lib-huawei": "^1.36.18", - "@certd/lib-k8s": "^1.36.18", - "@certd/lib-server": "^1.36.18", - "@certd/midway-flyway-js": "^1.36.18", - "@certd/pipeline": "^1.36.18", - "@certd/plugin-cert": "^1.36.18", - "@certd/plugin-lib": "^1.36.18", - "@certd/plugin-plus": "^1.36.18", - "@certd/plus-core": "^1.36.18", + "@certd/jdcloud": "^1.36.19", + "@certd/lib-huawei": "^1.36.19", + "@certd/lib-k8s": "^1.36.19", + "@certd/lib-server": "^1.36.19", + "@certd/midway-flyway-js": "^1.36.19", + "@certd/pipeline": "^1.36.19", + "@certd/plugin-cert": "^1.36.19", + "@certd/plugin-lib": "^1.36.19", + "@certd/plugin-plus": "^1.36.19", + "@certd/plus-core": "^1.36.19", "@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120", "@huaweicloud/huaweicloud-sdk-core": "^3.1.120", "@koa/cors": "^5.0.0", From 1dec3f000e0c09b94c89b39aeab5a0d3e60ab13d Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:34:58 +0800 Subject: [PATCH 32/88] build: trigger build image --- build.trigger | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.trigger b/build.trigger index bacbe4702..222b6abb3 100644 --- a/build.trigger +++ b/build.trigger @@ -1 +1 @@ -00:43 +00:34 From bb4d5f1e935f4f7dc375a2e02c6343fa53e7c3fa Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 00:35:14 +0800 Subject: [PATCH 33/88] build: publish --- docs/guide/changelogs/CHANGELOG.md | 23 +++++++++++++++++++++ packages/core/acme-client/package.json | 2 +- packages/core/basic/package.json | 2 +- packages/core/pipeline/package.json | 2 +- packages/libs/lib-huawei/package.json | 2 +- packages/libs/lib-iframe/package.json | 2 +- packages/libs/lib-jdcloud/package.json | 2 +- packages/libs/lib-k8s/package.json | 2 +- packages/libs/lib-server/package.json | 2 +- packages/libs/midway-flyway-js/package.json | 2 +- packages/plugins/plugin-cert/package.json | 2 +- packages/plugins/plugin-lib/package.json | 2 +- 12 files changed, 34 insertions(+), 11 deletions(-) diff --git a/docs/guide/changelogs/CHANGELOG.md b/docs/guide/changelogs/CHANGELOG.md index 317406481..10ff8c38c 100644 --- a/docs/guide/changelogs/CHANGELOG.md +++ b/docs/guide/changelogs/CHANGELOG.md @@ -3,6 +3,29 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.36.19](https://github.com/certd/certd/compare/v1.36.18...v1.36.19) (2025-09-05) + +### Bug Fixes + +* 前置任务输出不存在时输出警告提示 ([b59052c](https://github.com/certd/certd/commit/b59052cc43b7b070fabd8b8e914e4c2a5e0ad61c)) +* 修复批量流水线执行时日志显示错乱的问题 ([4372adc](https://github.com/certd/certd/commit/4372adc703b9a4c785664054ab2a533626d815a8)) +* 修复远程数据选择无法过滤的bug ([6cbb073](https://github.com/certd/certd/commit/6cbb0739f8428d51b0712f718fe4d236cc087cf9)) +* 修复mysql下购买套餐加量包无效的bug ([c26ad4c](https://github.com/certd/certd/commit/c26ad4c8075f0606d45b8da13915737968d6191a)) + +### Performance Improvements + +* 创建证书时支持选择通知时机 ([0e96bfd](https://github.com/certd/certd/commit/0e96bfdfa377824d204e72923d1176408ae6b300)) +* 创建k8s secret 时设置type为tls ([79ebabf](https://github.com/certd/certd/commit/79ebabfcfb9e5a534049c84f5f1a642b357fc856)) +* 去掉宝塔url后面的斜杠 ([8a0c2b9](https://github.com/certd/certd/commit/8a0c2b9b13628da750c25757e0cb8ed3038775ba)) +* 商业版隐藏文档相关链接 ([4443a1c](https://github.com/certd/certd/commit/4443a1c0308fa6b95a05efd73d15d24b65d641c9)) +* 商业版隐藏文档相关链接 ([db89561](https://github.com/certd/certd/commit/db8956148083bc4f988226ccf719940d08158a27)) +* 增加健康检查探针 /health/liveliness 和 /health/readiness ([44019e1](https://github.com/certd/certd/commit/44019e104289fedd32a867db00e9c6cb71b389cc)) +* 支持根据id更新证书(证书Id不变接口),不过该接口为白名单功能,普通腾讯云账户无法使用 ([fe9c4f3](https://github.com/certd/certd/commit/fe9c4f3391ff07c01dd9a252225f69a129c39050)) +* 支持godaddy ([b7980aa](https://github.com/certd/certd/commit/b7980aad5ab50f58662eaddf5d84aa82876a98eb)) +* 支持ssl.com证书颁发机构 ([27b6dfa](https://github.com/certd/certd/commit/27b6dfa4d2ab3bddd284c3a34511a72e1a513a4c)) +* 子域名托管说明 ([39a0223](https://github.com/certd/certd/commit/39a02235cf4416bb5bd1acd3831241efeaa2f602)) +* ssh 增加超时断开连接,默认10分钟超时 ([c24a040](https://github.com/certd/certd/commit/c24a040c19cacafc79228d7a7649af93837d94a1)) + ## [1.36.18](https://github.com/certd/certd/compare/v1.36.17...v1.36.18) (2025-08-28) ### Bug Fixes diff --git a/packages/core/acme-client/package.json b/packages/core/acme-client/package.json index fe59cc4cd..3ff1e30cd 100644 --- a/packages/core/acme-client/package.json +++ b/packages/core/acme-client/package.json @@ -69,5 +69,5 @@ "bugs": { "url": "https://github.com/publishlab/node-acme-client/issues" }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } diff --git a/packages/core/basic/package.json b/packages/core/basic/package.json index 341795920..68eefa3d9 100644 --- a/packages/core/basic/package.json +++ b/packages/core/basic/package.json @@ -45,5 +45,5 @@ "tslib": "^2.8.1", "typescript": "^5.4.2" }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } diff --git a/packages/core/pipeline/package.json b/packages/core/pipeline/package.json index 572a7aba2..7025c7cd1 100644 --- a/packages/core/pipeline/package.json +++ b/packages/core/pipeline/package.json @@ -44,5 +44,5 @@ "tslib": "^2.8.1", "typescript": "^5.4.2" }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } diff --git a/packages/libs/lib-huawei/package.json b/packages/libs/lib-huawei/package.json index 3c8918849..37cd34dcd 100644 --- a/packages/libs/lib-huawei/package.json +++ b/packages/libs/lib-huawei/package.json @@ -24,5 +24,5 @@ "prettier": "^2.8.8", "tslib": "^2.8.1" }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } diff --git a/packages/libs/lib-iframe/package.json b/packages/libs/lib-iframe/package.json index b95f12c3a..468ba05b2 100644 --- a/packages/libs/lib-iframe/package.json +++ b/packages/libs/lib-iframe/package.json @@ -31,5 +31,5 @@ "tslib": "^2.8.1", "typescript": "^5.4.2" }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } diff --git a/packages/libs/lib-jdcloud/package.json b/packages/libs/lib-jdcloud/package.json index 0e7bebc33..00bed88fb 100644 --- a/packages/libs/lib-jdcloud/package.json +++ b/packages/libs/lib-jdcloud/package.json @@ -61,5 +61,5 @@ "fetch" ] }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } diff --git a/packages/libs/lib-k8s/package.json b/packages/libs/lib-k8s/package.json index f559c2e52..2965a546c 100644 --- a/packages/libs/lib-k8s/package.json +++ b/packages/libs/lib-k8s/package.json @@ -32,5 +32,5 @@ "tslib": "^2.8.1", "typescript": "^5.4.2" }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } diff --git a/packages/libs/lib-server/package.json b/packages/libs/lib-server/package.json index 1ab87cfec..2181257bd 100644 --- a/packages/libs/lib-server/package.json +++ b/packages/libs/lib-server/package.json @@ -61,5 +61,5 @@ "typeorm": "^0.3.11", "typescript": "^5.4.2" }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } diff --git a/packages/libs/midway-flyway-js/package.json b/packages/libs/midway-flyway-js/package.json index a45c0eb5a..34b30dec1 100644 --- a/packages/libs/midway-flyway-js/package.json +++ b/packages/libs/midway-flyway-js/package.json @@ -46,5 +46,5 @@ "typeorm": "^0.3.11", "typescript": "^5.4.2" }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } diff --git a/packages/plugins/plugin-cert/package.json b/packages/plugins/plugin-cert/package.json index a96723024..6904eb4a3 100644 --- a/packages/plugins/plugin-cert/package.json +++ b/packages/plugins/plugin-cert/package.json @@ -43,5 +43,5 @@ "tslib": "^2.8.1", "typescript": "^5.4.2" }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } diff --git a/packages/plugins/plugin-lib/package.json b/packages/plugins/plugin-lib/package.json index e569111fa..ab7dd9717 100644 --- a/packages/plugins/plugin-lib/package.json +++ b/packages/plugins/plugin-lib/package.json @@ -53,5 +53,5 @@ "tslib": "^2.8.1", "typescript": "^5.4.2" }, - "gitHead": "ea18a5ad151b296fda54fb5bcbe64c7d80cdff2f" + "gitHead": "6d8981479517b5de9634e242c1ebf22e70527ec4" } From 902359f24ed12eee4f9b65178f1d6a60378351d2 Mon Sep 17 00:00:00 2001 From: Zero Clover <13190004+ZeroClover@users.noreply.github.com> Date: Sat, 6 Sep 2025 00:41:03 +0800 Subject: [PATCH 34/88] perf: add preferred chain option (#519) @ZeroClover --- .../src/plugin/cert-plugin/acme.ts | 4 +++- .../src/plugin/cert-plugin/index.ts | 24 +++++++++++++++++++ .../pipeline/service/pipeline-service.ts | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) 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 0362c6c96..8b5f04c77 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts @@ -329,8 +329,9 @@ export class AcmeService { isTest?: boolean; privateKeyType?: string; profile?: string; + preferredChain?: string; }): Promise { - const { email, isTest, csrInfo, dnsProvider, domainsVerifyPlan, profile } = options; + const { email, isTest, csrInfo, dnsProvider, domainsVerifyPlan, profile, preferredChain } = options; const client: acme.Client = await this.getAcmeClient(email, isTest); let domains = options.domains; @@ -404,6 +405,7 @@ export class AcmeService { }, signal: this.options.signal, profile, + preferredChain, }); const crtString = crt.toString(); 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 1b9e452dc..1d6086480 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -292,6 +292,29 @@ export class CertApplyPlugin extends CertApplyBasePlugin { }) certProfile!: string; + @TaskInput({ + title: "首选链", + value: "ISRG Root X1", + component: { + name: "a-select", + vModel: "value", + options: [ + { value: "ISRG Root X1", label: "ISRG Root X1" }, + { value: "ISRG Root X2", label: "ISRG Root X2" }, + ], + }, + helper: "仅 Let's Encrypt 可选,默认为 ISRG Root X1", + required: false, + mergeScript: ` + return { + show: ctx.compute(({form})=>{ + return form.sslProvider === 'letsencrypt' + }) + } + `, + }) + preferredChain!: string; + @TaskInput({ title: "使用代理", value: false, @@ -438,6 +461,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { isTest: false, privateKeyType: this.privateKeyType, profile: this.certProfile, + preferredChain: this.preferredChain, }); const certInfo = this.formatCerts(cert); diff --git a/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts b/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts index a4937cd04..3d5b9420c 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts @@ -934,6 +934,7 @@ export class PipelineService extends BaseService { "sslProvider": "letsencrypt", "privateKeyType": "rsa_2048", "certProfile": "classic", + "preferredChain": "ISRG Root X1", "useProxy": false, "skipLocalVerify": false, "maxCheckRetryCount": 20, From f6ea9c1300e024d764c843746f25d2e47081cf80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?COYG=E2=9A=A1=EF=B8=8F?= <67215517+1411430556@users.noreply.github.com> Date: Sat, 6 Sep 2025 00:43:08 +0800 Subject: [PATCH 35/88] =?UTF-8?q?docs:=20=E6=9B=B4=E6=94=B9=E4=B8=AD?= =?UTF-8?q?=E8=8B=B1=E6=96=87=E6=A1=A3=E8=B7=B3=E8=BD=AC=E9=93=BE=E6=8E=A5?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=BD=A2=E5=BC=8F=20(#518)=20@1411430556?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update README.md * Update README_en.md --- README.md | 2 +- README_en.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fc5be4673..4ebbc0d07 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Certd -[English](./README_en.md) | [中文](./README.md) +中文 | [English](./README_en.md) Certd® 是一个免费的全自动证书管理系统,让你的网站证书永不过期。 后缀d取自linux守护进程的命名风格,意为证书守护进程 diff --git a/README_en.md b/README_en.md index 57f8ea3aa..66f67a04c 100644 --- a/README_en.md +++ b/README_en.md @@ -1,6 +1,6 @@ # Certd -[English](./README_en.md) | [中文](./README.md) +[中文](./README.md) | English Certd® is a free, fully automated certificate management system that ensures your website certificates never expire. The suffix 'd' is inspired by the naming convention of Linux daemons, representing a certificate daemon. From 40475e02ec65c489e28045cfe51eac5a7ebedbba Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Sep 2025 20:07:50 +0800 Subject: [PATCH 36/88] chore: --- packages/ui/certd-server/src/plugins/plugin-upyun/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 05c9c4e53..262d247d1 100644 --- a/packages/ui/certd-server/src/plugins/plugin-upyun/client.ts +++ b/packages/ui/certd-server/src/plugins/plugin-upyun/client.ts @@ -65,7 +65,7 @@ export class UpyunClient { Cookie: req.cookie } }); - if (res.msg.errors.length > 0) { + if (res.msg?.errors?.length > 0) { throw new Error(JSON.stringify(res.msg)); } if(res.data?.error_code){ From d75dd058d65c85f80c49e1fa7a910e6c6f08e824 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 8 Sep 2025 14:29:15 +0800 Subject: [PATCH 37/88] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=95=86?= =?UTF-8?q?=E4=B8=9A=E7=89=88=E9=80=80=E5=87=BA=E7=99=BB=E5=BD=95=E5=90=8E?= =?UTF-8?q?=EF=BC=8C=E4=B8=A2=E5=A4=B1=E7=AB=99=E7=82=B9=E4=B8=AA=E6=80=A7?= =?UTF-8?q?=E5=8C=96=E8=AE=BE=E7=BD=AE=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/certd-client/src/store/settings/index.ts | 2 ++ packages/ui/certd-client/src/vben/stores/setup.ts | 3 +++ 2 files changed, 5 insertions(+) diff --git a/packages/ui/certd-client/src/store/settings/index.ts b/packages/ui/certd-client/src/store/settings/index.ts index 2f6bf9a6f..fcfd98c76 100644 --- a/packages/ui/certd-client/src/store/settings/index.ts +++ b/packages/ui/certd-client/src/store/settings/index.ts @@ -12,6 +12,7 @@ import { utils } from "/@/utils"; import { cloneDeep, merge } from "lodash-es"; import { useI18n } from "/src/locales"; export interface SettingState { + skipReset?: boolean; // 注销登录时,不清空此store的状态 sysPublic?: SysPublicSetting; installInfo?: { siteId: string; @@ -64,6 +65,7 @@ const defaultSiteInfo: SiteInfo = { export const useSettingStore = defineStore({ id: "app.setting", state: (): SettingState => ({ + skipReset: true, plusInfo: { isPlus: false, vipType: "free", diff --git a/packages/ui/certd-client/src/vben/stores/setup.ts b/packages/ui/certd-client/src/vben/stores/setup.ts index ad2560a6c..09ee70fca 100644 --- a/packages/ui/certd-client/src/vben/stores/setup.ts +++ b/packages/ui/certd-client/src/vben/stores/setup.ts @@ -38,6 +38,9 @@ export function resetAllStores() { } const allStores = (pinia as any)._s; for (const [_key, store] of allStores) { + if (store.skipReset) { + continue; + } store.$reset(); } } From 3c65f37d84177ba107d4a6462648af12d2fc4b7a Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 8 Sep 2025 14:43:36 +0800 Subject: [PATCH 38/88] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=8A=A0?= =?UTF-8?q?=E9=87=8F=E5=8C=85=E5=B1=95=E7=A4=BA=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/certd/suite/mine/api.ts | 1 + .../framework/home/dashboard/suite-card.vue | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/ui/certd-client/src/views/certd/suite/mine/api.ts b/packages/ui/certd-client/src/views/certd/suite/mine/api.ts index f647164d9..9d5ebac10 100644 --- a/packages/ui/certd-client/src/views/certd/suite/mine/api.ts +++ b/packages/ui/certd-client/src/views/certd/suite/mine/api.ts @@ -9,6 +9,7 @@ export type SuiteValue = { export type SuiteDetail = { enabled?: boolean; suites?: any[]; + addons?: any[]; expiresTime?: number; pipelineCount?: SuiteValue; domainCount?: SuiteValue; diff --git a/packages/ui/certd-client/src/views/framework/home/dashboard/suite-card.vue b/packages/ui/certd-client/src/views/framework/home/dashboard/suite-card.vue index b04c96ae7..d62ef16f4 100644 --- a/packages/ui/certd-client/src/views/framework/home/dashboard/suite-card.vue +++ b/packages/ui/certd-client/src/views/framework/home/dashboard/suite-card.vue @@ -3,7 +3,16 @@
- + {{ item.title }} () + 加量包+{{ detail.addonList.length }}
暂无套餐 去购买
@@ -59,6 +69,10 @@ const detail = ref({}); async function loadSuiteDetail() { detail.value = await mySuiteApi.SuiteDetailGet(); + const suites = detail.value.suites.filter(item => item.productType === "suite"); + const addons = detail.value.suites.filter(item => item.productType === "addon"); + detail.value.suiteList = suites; + detail.value.addonList = addons; } loadSuiteDetail(); From 521083a309dcf043aa8cbe0b9c647d163e6e9106 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 8 Sep 2025 14:45:31 +0800 Subject: [PATCH 39/88] chore: --- packages/ui/certd-client/src/views/certd/suite/mine/api.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ui/certd-client/src/views/certd/suite/mine/api.ts b/packages/ui/certd-client/src/views/certd/suite/mine/api.ts index 9d5ebac10..1e1faa42b 100644 --- a/packages/ui/certd-client/src/views/certd/suite/mine/api.ts +++ b/packages/ui/certd-client/src/views/certd/suite/mine/api.ts @@ -9,7 +9,8 @@ export type SuiteValue = { export type SuiteDetail = { enabled?: boolean; suites?: any[]; - addons?: any[]; + suiteList?: any[]; + addonList?: any[]; expiresTime?: number; pipelineCount?: SuiteValue; domainCount?: SuiteValue; From 3b3c93dd53a4eec50507b47285eef7c147f185b6 Mon Sep 17 00:00:00 2001 From: greper Date: Mon, 8 Sep 2025 22:06:57 +0800 Subject: [PATCH 40/88] Create FUNDING.yml --- .github/FUNDING.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..a8ca082e5 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,5 @@ +# These are supported funding model platforms + +github: greper +buy_me_a_coffee: # Replace with a single Buy Me a Coffee username +custom: ['https://afdian.com/a/greper'] From 6b765a1f7714e20be5beafdcc1dab3c5f1ddeba1 Mon Sep 17 00:00:00 2001 From: greper Date: Mon, 8 Sep 2025 22:14:57 +0800 Subject: [PATCH 41/88] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index a8ca082e5..d19e47465 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,5 +1,5 @@ # These are supported funding model platforms github: greper -buy_me_a_coffee: # Replace with a single Buy Me a Coffee username +buy_me_a_coffee: greper custom: ['https://afdian.com/a/greper'] From 7d6a6e53f7d689a9faedec8f9ebbdd9444700be9 Mon Sep 17 00:00:00 2001 From: greper Date: Mon, 8 Sep 2025 22:23:43 +0800 Subject: [PATCH 42/88] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ebbc0d07..a29f3a4da 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,8 @@ https://afdian.com/a/greper | 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署、宝塔、1Panel等大部分插件 | 群晖 | | 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、钉钉、飞书、anpush、server酱等 | - +************************ +[![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-red)](https://github.com/sponsors/greper) ************************ ## 九、贡献代码 From f1876e20f8adfdff3cbb9560c8ddc496663c6d55 Mon Sep 17 00:00:00 2001 From: greper Date: Mon, 8 Sep 2025 22:25:52 +0800 Subject: [PATCH 43/88] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a29f3a4da..cb6a2d9a2 100644 --- a/README.md +++ b/README.md @@ -152,8 +152,8 @@ https://certd.handfree.work/ ## 八、捐赠 ************************ -支持开源,为爱发电,我已入驻爱发电 -https://afdian.com/a/greper +支持开源,为爱发电,我已入驻[爱发电](https://afdian.com/a/greper) / [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-red)](https://github.com/sponsors/greper) + 发电权益: 1. 可加入发电专属群,可以获得作者一对一技术支持 @@ -172,7 +172,7 @@ https://afdian.com/a/greper | 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、钉钉、飞书、anpush、server酱等 | ************************ -[![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-red)](https://github.com/sponsors/greper) + ************************ ## 九、贡献代码 From 0b2a7fdc1544577eccf58b7ea1799dcbfded2c19 Mon Sep 17 00:00:00 2001 From: greper Date: Mon, 8 Sep 2025 22:27:01 +0800 Subject: [PATCH 44/88] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cb6a2d9a2..fd0b5228a 100644 --- a/README.md +++ b/README.md @@ -152,8 +152,10 @@ https://certd.handfree.work/ ## 八、捐赠 ************************ -支持开源,为爱发电,我已入驻[爱发电](https://afdian.com/a/greper) / [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-red)](https://github.com/sponsors/greper) - +Github Sponsor [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-red)](https://github.com/sponsors/greper) +************************ +支持开源,为爱发电,我已入驻爱发电 +https://afdian.com/a/greper 发电权益: 1. 可加入发电专属群,可以获得作者一对一技术支持 From a0a093e260abcafc62887ae93c29b4b92791ce35 Mon Sep 17 00:00:00 2001 From: greper Date: Mon, 8 Sep 2025 22:27:28 +0800 Subject: [PATCH 45/88] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index fd0b5228a..f0960aafe 100644 --- a/README.md +++ b/README.md @@ -152,8 +152,6 @@ https://certd.handfree.work/ ## 八、捐赠 ************************ -Github Sponsor [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-red)](https://github.com/sponsors/greper) -************************ 支持开源,为爱发电,我已入驻爱发电 https://afdian.com/a/greper From 768bdc2cc2af5255d2768bd12a005aad91424737 Mon Sep 17 00:00:00 2001 From: greper Date: Mon, 8 Sep 2025 22:27:59 +0800 Subject: [PATCH 46/88] Update README_en.md --- README_en.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README_en.md b/README_en.md index 66f67a04c..d665a9825 100644 --- a/README_en.md +++ b/README_en.md @@ -134,6 +134,8 @@ You can also add the author as a friend. | QR Code | | ## 8. Donation +************************ + [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-red)](https://github.com/sponsors/greper) ************************ Support open-source projects and contribute with love. I've joined Afdian. https://afdian.com/a/greper From b7271d7a464773a1bf87d7d1f24d933ba0f86915 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 8 Sep 2025 23:01:45 +0800 Subject: [PATCH 47/88] =?UTF-8?q?perf:=20start.sh=E5=A2=9E=E5=8A=A0sudo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- start.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/start.sh b/start.sh index 78bb46ce0..0845ffde0 100755 --- a/start.sh +++ b/start.sh @@ -25,30 +25,30 @@ done echo "安装pnpm, 前提是已经安装了nodejs" -npm install -g pnpm --registry https://registry.npmmirror.com +sudo npm install -g pnpm --registry https://registry.npmmirror.com echo "安装依赖" -pnpm install --registry https://registry.npmmirror.com +sudo pnpm install --registry https://registry.npmmirror.com echo "开始构建" echo "构建certd-client" export NODE_OPTIONS=--max-old-space-size=32768 cd packages/ui/certd-client -pnpm run build +sudo pnpm run build cp -r dist/* ../certd-server/public echo "构建certd-server" cd ../certd-server -pnpm run build +sudo pnpm run build echo "构建完成" echo "启动服务" # 前台运行 if [ $confirmNohup != "y" ]; then echo "当前运行模式为前台运行,ctrl+c或者关闭ssh将会停止运行" - pnpm run start + sudo pnpm run start else echo "当前运行模式为后台运行,可以通过tail -f ./certd.log 命令查看日志" - nohup pnpm run start > certd.log & + nohup sudo pnpm run start > certd.log & fi From b5cba19d26d0e52153d4bf359b308e9c9dbf33e2 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 8 Sep 2025 23:04:02 +0800 Subject: [PATCH 48/88] chore: --- start.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start.sh b/start.sh index 0845ffde0..1f3bb7ca9 100755 --- a/start.sh +++ b/start.sh @@ -33,12 +33,12 @@ echo "开始构建" echo "构建certd-client" export NODE_OPTIONS=--max-old-space-size=32768 cd packages/ui/certd-client -sudo pnpm run build +sudo -E pnpm run build cp -r dist/* ../certd-server/public echo "构建certd-server" cd ../certd-server -sudo pnpm run build +sudo -E pnpm run build echo "构建完成" echo "启动服务" From d04f3831611011a90ec0594724b9694490d5edd0 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Tue, 9 Sep 2025 16:30:21 +0800 Subject: [PATCH 49/88] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dsecret=20patch?= =?UTF-8?q?=20=E7=B1=BB=E5=9E=8B=E5=A4=9A=E4=BA=86type=EF=BC=9A=E7=9A=84bu?= =?UTF-8?q?g?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/libs/lib-k8s/src/lib/k8s.client.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/libs/lib-k8s/src/lib/k8s.client.ts b/packages/libs/lib-k8s/src/lib/k8s.client.ts index 5a980bf75..d5f8f6bd0 100644 --- a/packages/libs/lib-k8s/src/lib/k8s.client.ts +++ b/packages/libs/lib-k8s/src/lib/k8s.client.ts @@ -85,7 +85,6 @@ export class K8sClient { /** * 创建Secret * @param opts {namespace:default, body:yamlStr} - * @returns {Promise<*>} */ async createSecret(opts: { namespace: string; body: V1Secret }) { const namespace = opts.namespace || "default"; @@ -121,7 +120,7 @@ export class K8sClient { //没有找到,则创建 const body = merge( { - type: "type: kubernetes.io/tls", + type: "kubernetes.io/tls", }, opts.body ); From ae41c6038b27c9476e64a2402a8daf247c38a5b6 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Tue, 9 Sep 2025 18:14:14 +0800 Subject: [PATCH 50/88] =?UTF-8?q?perf:=20ssh=E9=85=8D=E7=BD=AE=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E8=84=9A=E6=9C=AC=E7=B1=BB=E5=9E=8B=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=EF=BC=8Cbash=E8=BF=98=E6=98=AFsh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugins/plugin-lib/src/ssh/ssh-access.ts | 16 ++++++++++++++++ packages/plugins/plugin-lib/src/ssh/ssh.ts | 12 ++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/plugins/plugin-lib/src/ssh/ssh-access.ts b/packages/plugins/plugin-lib/src/ssh/ssh-access.ts index 882071e44..4d20696d8 100644 --- a/packages/plugins/plugin-lib/src/ssh/ssh-access.ts +++ b/packages/plugins/plugin-lib/src/ssh/ssh-access.ts @@ -64,6 +64,22 @@ export class SshAccess extends BaseAccess { }) passphrase!: string; + @AccessInput({ + title: "脚本类型", + helper: "bash 、sh 、fish", + component: { + name: "a-select", + vModel: "value", + options: [ + { value: "default", label: "默认" }, + { value: "sh", label: "sh" }, + { value: "bash", label: "bash" }, + { value: "fish", label: "fish(不支持set -e)" }, + ], + }, + }) + scriptType: string; + @AccessInput({ title: "伪终端", helper: "如果登录报错:all authentication methods failed,可以尝试开启伪终端模式进行keyboard-interactive方式登录\n开启后对日志输出有一定的影响", diff --git a/packages/plugins/plugin-lib/src/ssh/ssh.ts b/packages/plugins/plugin-lib/src/ssh/ssh.ts index 32d83f303..197ebfc1d 100644 --- a/packages/plugins/plugin-lib/src/ssh/ssh.ts +++ b/packages/plugins/plugin-lib/src/ssh/ssh.ts @@ -543,8 +543,16 @@ export class SshClient { } } - if (isLinux && options.stopOnError !== false) { - script = "set -e\n" + script; + if (isLinux) { + if (options.connectConf.scriptType == "bash") { + script = "#!/usr/bin/env bash \n" + script; + } else if (options.connectConf.scriptType == "sh") { + script = "#!/bin/sh\n" + script; + } + + if (options.connectConf.scriptType != "fish" && options.stopOnError !== false) { + script = "set -e\n" + script; + } } return await conn.exec(script as string, { throwOnStdErr }); From 1f759dce5be705941417262e3d8591442b2cba1b Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Wed, 10 Sep 2025 12:21:04 +0800 Subject: [PATCH 51/88] docs: --- docs/guide/install/source/index.md | 31 ++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/guide/install/source/index.md b/docs/guide/install/source/index.md index 8f404264b..3c25c889d 100644 --- a/docs/guide/install/source/index.md +++ b/docs/guide/install/source/index.md @@ -12,7 +12,7 @@ git clone https://github.com/certd/certd --depth=1 # git checkout v1.x.x # 当v2主干分支代码无法正常启动时,可以尝试此命令,1.x.x换成最新版本号 cd certd # 启动服务 -./start.sh +./start.sh ``` >如果是windows,请先安装`git for windows` ,然后右键,选择`open git bash here`打开终端,再执行`./start.sh`命令 @@ -21,9 +21,9 @@ cd certd ### 访问测试 -http://your_server_ip:7001 -https://your_server_ip:7002 -默认账号密码:admin/123456 +http://your_server_ip:7001 +https://your_server_ip:7002 +默认账号密码:admin/123456 记得修改密码 @@ -37,7 +37,7 @@ cp -rf ./packages/ui/certd-server/data ../certd-data-backup git pull # 如果提示pull失败,可以尝试强制更新 -# git checkout v2 -f && git pull +# git checkout v2 -f && git pull # 先停止旧的服务,7001是certd的默认端口 kill -9 $(lsof -t -i:7001) @@ -45,16 +45,31 @@ kill -9 $(lsof -t -i:7001) ./start.sh ``` -::: warning -升级certd版本前,切记切记先备份一下数据 +::: warning +升级certd版本前,切记切记先备份一下数据 ::: ## 三、数据备份 -> 数据默认保存在 `./packages/ui/certd-server/data` 目录下 +> 数据默认保存在 `./packages/ui/certd-server/data` 目录下 > 建议配置一条[数据库备份流水线](../../use/backup/) 自动备份 ## 四、备份恢复 将备份的`db.sqlite`及同目录下的其他文件覆盖到原来的位置,重启certd即可 + +## 六、常见问题 + +### 1. npm install better-sqlite3 时,提示node-gyp需要vscode环境编译 + +1. 首先确保node版本为22以上 +2. 将下面两行加到 ~/.npmrc 里面 +3. 重新install +> better_sqlite3_binary_host=https://registry.npmmirror.com/-/binary/better-sqlite3 +> better_sqlite3_binary_host_mirror=https://registry.npmmirror.com/-/binary/better-sqlite3 + + + + + From d2ecfe5491b2639eb30b5cae293af6062d58bb9f Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Wed, 10 Sep 2025 14:12:36 +0800 Subject: [PATCH 52/88] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=AF=81?= =?UTF-8?q?=E4=B9=A6=E7=9B=91=E6=8E=A7=E6=9F=90=E4=BA=9B=E6=83=85=E5=86=B5?= =?UTF-8?q?=E4=B8=8B=E6=8A=A5=20options.lookup=E4=B8=8D=E8=83=BD=E4=B8=BAn?= =?UTF-8?q?ull=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../certd-server/src/modules/monitor/service/site-tester.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/ui/certd-server/src/modules/monitor/service/site-tester.ts b/packages/ui/certd-server/src/modules/monitor/service/site-tester.ts index e2b997310..f7e57b1b8 100644 --- a/packages/ui/certd-server/src/modules/monitor/service/site-tester.ts +++ b/packages/ui/certd-server/src/modules/monitor/service/site-tester.ts @@ -80,7 +80,11 @@ export class SiteTester { } } - options.agent = new https.Agent({ keepAlive: false, lookup: customLookup }); + const agentOptions:any = { keepAlive: false }; + if (customLookup) { + agentOptions.lookup = customLookup + } + options.agent = new https.Agent(agentOptions); // 创建 HTTPS 请求 const requestPromise = safePromise((resolve, reject) => { From 3635fb391059fbcff1244d0fbb5fac57e7970da2 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 11 Sep 2025 00:19:38 +0800 Subject: [PATCH 53/88] chore: --- .../core/pipeline/src/registry/registry.ts | 13 +- .../src/system/settings/service/models.ts | 10 +- .../libs/lib-server/src/user/addon/api/api.ts | 96 +++++++ .../src/user/addon/api/decorator.ts | 65 +++++ .../lib-server/src/user/addon/api/index.ts | 3 + .../lib-server/src/user/addon/api/registry.ts | 3 + .../lib-server/src/user/addon/entity/addon.ts | 44 +++ .../libs/lib-server/src/user/addon/index.ts | 5 + .../src/user/addon/service/addon-getter.ts | 18 ++ .../src/user/addon/service/addon-service.ts | 217 ++++++++++++++ .../user/addon/service/addon-sys-getter.ts | 17 ++ packages/libs/lib-server/src/user/index.ts | 1 + packages/ui/certd-client/index.html | 1 + .../src/store/settings/api.basic.ts | 4 + .../certd-client/src/views/certd/addon/api.ts | 117 ++++++++ .../src/views/certd/addon/common.tsx | 270 ++++++++++++++++++ .../src/views/certd/addon/crud.tsx | 54 ++++ .../src/views/certd/addon/index.vue | 41 +++ .../src/views/framework/login/captcha.vue | 46 +++ .../src/views/framework/login/index.vue | 5 + .../controller/user/addon/addon-controller.ts | 200 +++++++++++++ .../controller/user/login/login-controller.ts | 1 + .../modules/login/service/login-service.ts | 30 +- packages/ui/certd-server/src/plugins/index.ts | 1 + .../plugins/plugin-captcha/geetest/index.ts | 109 +++++++ .../src/plugins/plugin-captcha/index.ts | 1 + 26 files changed, 1368 insertions(+), 4 deletions(-) create mode 100644 packages/libs/lib-server/src/user/addon/api/api.ts create mode 100644 packages/libs/lib-server/src/user/addon/api/decorator.ts create mode 100644 packages/libs/lib-server/src/user/addon/api/index.ts create mode 100644 packages/libs/lib-server/src/user/addon/api/registry.ts create mode 100644 packages/libs/lib-server/src/user/addon/entity/addon.ts create mode 100644 packages/libs/lib-server/src/user/addon/index.ts create mode 100644 packages/libs/lib-server/src/user/addon/service/addon-getter.ts create mode 100644 packages/libs/lib-server/src/user/addon/service/addon-service.ts create mode 100644 packages/libs/lib-server/src/user/addon/service/addon-sys-getter.ts create mode 100644 packages/ui/certd-client/src/views/certd/addon/api.ts create mode 100644 packages/ui/certd-client/src/views/certd/addon/common.tsx create mode 100644 packages/ui/certd-client/src/views/certd/addon/crud.tsx create mode 100644 packages/ui/certd-client/src/views/certd/addon/index.vue create mode 100644 packages/ui/certd-client/src/views/framework/login/captcha.vue create mode 100644 packages/ui/certd-server/src/controller/user/addon/addon-controller.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-captcha/index.ts diff --git a/packages/core/pipeline/src/registry/registry.ts b/packages/core/pipeline/src/registry/registry.ts index b466bcc9f..3322d7080 100644 --- a/packages/core/pipeline/src/registry/registry.ts +++ b/packages/core/pipeline/src/registry/registry.ts @@ -69,9 +69,15 @@ export class Registry { return this.storage; } - getDefineList() { + getDefineList(prefix?: string) { let list = []; + if (prefix) { + prefix = prefix + ":"; + } for (const key in this.storage) { + if (prefix && !key.startsWith(prefix)) { + continue; + } const define = this.getDefine(key); if (define) { if (define?.deprecated) { @@ -90,7 +96,10 @@ export class Registry { return list; } - getDefine(key: string) { + getDefine(key: string, prefix?: string) { + if (prefix) { + key = prefix + ":" + key; + } const item = this.storage[key]; if (!item) { return; 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 c31f14fbe..08431bbdf 100644 --- a/packages/libs/lib-server/src/system/settings/service/models.ts +++ b/packages/libs/lib-server/src/system/settings/service/models.ts @@ -30,6 +30,12 @@ export class SysPublicSettings extends BaseSettings { mpsNo?: string; robots?: boolean = true; aiChatEnabled = true; + + + //验证码是否开启 + captchaEnabled = false; + //验证码类型 + captchaType?: string; } export class SysPrivateSettings extends BaseSettings { @@ -44,6 +50,9 @@ export class SysPrivateSettings extends BaseSettings { dnsResultOrder? = ''; commonCnameEnabled?: boolean = true; + //验证码配置id + captchaAddonId?: number; + sms?: { type?: string; config?: any; @@ -207,4 +216,3 @@ export class SysSafeSetting extends BaseSettings { }; } - diff --git a/packages/libs/lib-server/src/user/addon/api/api.ts b/packages/libs/lib-server/src/user/addon/api/api.ts new file mode 100644 index 000000000..560bccf2a --- /dev/null +++ b/packages/libs/lib-server/src/user/addon/api/api.ts @@ -0,0 +1,96 @@ +import { HttpClient, ILogger, utils } from "@certd/basic"; +import {upperFirst} from "lodash-es"; +import { FormItemProps, PluginRequestHandleReq, Registrable } from "@certd/pipeline"; + + +export type AddonRequestHandleReqInput = { + id?: number; + title?: string; + addon: T; +}; + +export type AddonRequestHandleReq = { + addonType: string; +} &PluginRequestHandleReq>; + +export type AddonInputDefine = FormItemProps & { + title: string; + required?: boolean; +}; +export type AddonDefine = Registrable & { + addonType: string; + needPlus?: boolean; + input?: { + [key: string]: AddonInputDefine; + }; +}; + +export type AddonInstanceConfig = { + id: number; + addonType: string; + type: string; + name: string; + userId: number; + setting: { + [key: string]: any; + }; +}; + + + +export interface IAddon { + ctx: AddonContext; + [key: string]: any; +} + +export type AddonContext = { + http: HttpClient; + logger: ILogger; + utils: typeof utils; +}; + +export abstract class BaseAddon implements IAddon { + define!: AddonDefine; + ctx!: AddonContext; + http!: HttpClient; + logger!: ILogger; + + + + // eslint-disable-next-line @typescript-eslint/no-empty-function + async onInstance() {} + setCtx(ctx: AddonContext) { + this.ctx = ctx; + this.http = ctx.http; + this.logger = ctx.logger; + } + setDefine = (define:AddonDefine) => { + this.define = define; + }; + + async onRequest(req:AddonRequestHandleReq) { + if (!req.action) { + throw new Error("action is required"); + } + + let methodName = req.action; + if (!req.action.startsWith("on")) { + methodName = `on${upperFirst(req.action)}`; + } + + // @ts-ignore + const method = this[methodName]; + if (method) { + // @ts-ignore + return await this[methodName](req.data); + } + throw new Error(`action ${req.action} not found`); + } + +} + + +export interface IAddonGetter { + getById(id: any): Promise; + getCommonById(id: any): Promise; +} diff --git a/packages/libs/lib-server/src/user/addon/api/decorator.ts b/packages/libs/lib-server/src/user/addon/api/decorator.ts new file mode 100644 index 000000000..6a96b49ac --- /dev/null +++ b/packages/libs/lib-server/src/user/addon/api/decorator.ts @@ -0,0 +1,65 @@ +// src/decorator/memoryCache.decorator.ts +import * as _ from "lodash-es"; +import { merge } from "lodash-es"; +import { addonRegistry } from "./registry.js"; +import { AddonContext, AddonDefine, AddonInputDefine } from "./api.js"; +import { Decorator } from "@certd/pipeline"; + +// 提供一个唯一 key +export const ADDON_CLASS_KEY = "pipeline:addon"; +export const ADDON_INPUT_KEY = "pipeline:addon:input"; + +export function IsAddon(define: AddonDefine): ClassDecorator { + return (target: any) => { + target = Decorator.target(target); + + const inputs: any = {}; + const properties = Decorator.getClassProperties(target); + for (const property in properties) { + const input = Reflect.getMetadata(ADDON_INPUT_KEY, target, property); + if (input) { + inputs[property] = input; + } + } + _.merge(define, { input: inputs }); + Reflect.defineMetadata(ADDON_CLASS_KEY, define, target); + target.define = define; + const key = `${define.addonType}:${define.name}`; + addonRegistry.register(key, { + define, + target: async () => { + return target; + }, + }); + }; +} + +export function AddonInput(input?: AddonInputDefine): PropertyDecorator { + return (target, propertyKey) => { + target = Decorator.target(target, propertyKey); + // const _type = Reflect.getMetadata("design:type", target, propertyKey); + Reflect.defineMetadata(ADDON_INPUT_KEY, input, target, propertyKey); + }; +} + +export async function newAddon(addonType:string,type: string, input: any, ctx: AddonContext) { + const key = `${addonType}:${type}` + const register = addonRegistry.get(key); + if (register == null) { + throw new Error(`${addonType} ${type} not found`); + } + // @ts-ignore + const pluginCls = await register.target(); + // @ts-ignore + const plugin = new pluginCls(); + merge(plugin, input); + if (!ctx) { + throw new Error("ctx is required"); + } + plugin.setDefine(register.define); + plugin.setCtx(ctx); + await plugin.onInstance(); + return plugin; +} + + diff --git a/packages/libs/lib-server/src/user/addon/api/index.ts b/packages/libs/lib-server/src/user/addon/api/index.ts new file mode 100644 index 000000000..9b9e3a489 --- /dev/null +++ b/packages/libs/lib-server/src/user/addon/api/index.ts @@ -0,0 +1,3 @@ +export * from "./api.js"; +export * from "./registry.js"; +export * from "./decorator.js"; diff --git a/packages/libs/lib-server/src/user/addon/api/registry.ts b/packages/libs/lib-server/src/user/addon/api/registry.ts new file mode 100644 index 000000000..643de99cf --- /dev/null +++ b/packages/libs/lib-server/src/user/addon/api/registry.ts @@ -0,0 +1,3 @@ +import { createRegistry } from "@certd/pipeline"; + +export const addonRegistry = createRegistry("addon"); diff --git a/packages/libs/lib-server/src/user/addon/entity/addon.ts b/packages/libs/lib-server/src/user/addon/entity/addon.ts new file mode 100644 index 000000000..f62de283f --- /dev/null +++ b/packages/libs/lib-server/src/user/addon/entity/addon.ts @@ -0,0 +1,44 @@ +import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; + +/** + */ +@Entity('cd_addon') +export class AddonEntity { + @PrimaryGeneratedColumn() + id: number; + @Column({ name: 'user_id', comment: '用户id' }) + userId: number; + @Column({ comment: '名称', length: 100 }) + name: string; + + + @Column({ comment: 'addon类型', length: 100 }) + addonType: string; + + + @Column({ comment: '类型', length: 100 }) + type: string; + + @Column({ name: 'setting', comment: '设置', length: 10240, nullable: true }) + setting: string; + + @Column({ name: 'is_system', comment: '是否系统级别', nullable: false, default: false }) + isSystem: boolean; + + @Column({ name: 'is_default', comment: '是否默认', nullable: false, default: false }) + isDefault: boolean; + + + @Column({ + name: 'create_time', + comment: '创建时间', + default: () => 'CURRENT_TIMESTAMP', + }) + createTime: Date; + @Column({ + name: 'update_time', + comment: '修改时间', + default: () => 'CURRENT_TIMESTAMP', + }) + updateTime: Date; +} diff --git a/packages/libs/lib-server/src/user/addon/index.ts b/packages/libs/lib-server/src/user/addon/index.ts new file mode 100644 index 000000000..727232b4f --- /dev/null +++ b/packages/libs/lib-server/src/user/addon/index.ts @@ -0,0 +1,5 @@ +export * from './api/index.js' +export * from './entity/addon.js' +export * from './service/addon-service.js' +export * from './service/addon-getter.js' +export * from './service/addon-sys-getter.js' diff --git a/packages/libs/lib-server/src/user/addon/service/addon-getter.ts b/packages/libs/lib-server/src/user/addon/service/addon-getter.ts new file mode 100644 index 000000000..8e91ad7e0 --- /dev/null +++ b/packages/libs/lib-server/src/user/addon/service/addon-getter.ts @@ -0,0 +1,18 @@ +import { IAddonGetter } from "../api/index.js"; + +export class AddonGetter implements IAddonGetter { + userId: number; + getter: (id: any, userId?: number) => Promise; + constructor(userId: number, getter: (id: any, userId: number) => Promise) { + this.userId = userId; + this.getter = getter; + } + + async getById(id: any) { + return await this.getter(id, this.userId); + } + + async getCommonById(id: any) { + return await this.getter(id, 0); + } +} diff --git a/packages/libs/lib-server/src/user/addon/service/addon-service.ts b/packages/libs/lib-server/src/user/addon/service/addon-service.ts new file mode 100644 index 000000000..f4834c277 --- /dev/null +++ b/packages/libs/lib-server/src/user/addon/service/addon-service.ts @@ -0,0 +1,217 @@ +import { Provide, Scope, ScopeEnum } from "@midwayjs/core"; +import { InjectEntityModel } from "@midwayjs/typeorm"; +import { In, Repository } from "typeorm"; +import { AddonDefine, BaseService, PageReq, PermissionException, ValidateException } from "../../../index.js"; +import { addonRegistry, newAddon } from "../api/index.js"; +import { AddonEntity } from "../entity/addon.js"; +import { http, logger, utils } from "@certd/basic"; + +/** + * Addon + */ +@Provide() +@Scope(ScopeEnum.Request, {allowDowngrade: true}) +export class AddonService extends BaseService { + @InjectEntityModel(AddonEntity) + repository: Repository; + + //@ts-ignore + getRepository() { + return this.repository; + } + + async page(pageReq: PageReq) { + const res = await super.page(pageReq); + res.records = res.records.map(item => { + return item; + }); + return res; + } + + async add(param) { + let oldEntity = null; + if (param._copyFrom){ + oldEntity = await this.info(param._copyFrom); + if (oldEntity == null) { + throw new ValidateException('该Addon配置不存在,请确认是否已被删除'); + } + if (oldEntity.userId !== param.userId) { + throw new ValidateException('您无权查看该Addon配置'); + } + } + delete param._copyFrom + return await super.add(param); + } + + + /** + * 修改 + * @param param 数据 + */ + async update(param) { + const oldEntity = await this.info(param.id); + if (oldEntity == null) { + throw new ValidateException('该Addon配置不存在,请确认是否已被删除'); + } + return await super.update(param); + } + + async getSimpleInfo(id: number) { + const entity = await this.info(id); + if (entity == null) { + throw new ValidateException('该Addon配置不存在,请确认是否已被删除'); + } + return { + id: entity.id, + name: entity.name, + userId: entity.userId, + }; + } + + async getAddonById(id: any, checkUserId: boolean, userId?: number): Promise { + const entity = await this.info(id); + if (entity == null) { + throw new Error(`该Addon配置不存在,请确认是否已被删除:id=${id}`); + } + if (checkUserId) { + if (userId == null) { + throw new ValidateException('userId不能为空'); + } + if (userId !== entity.userId) { + throw new PermissionException('您对该Addon无访问权限'); + } + } + + // const access = accessRegistry.get(entity.type); + const setting = JSON.parse(entity.setting ??"{}") + const input = { + id: entity.id, + ...setting, + }; + const ctx = { + http: http, + logger: logger, + utils: utils, + }; + return await newAddon(entity.addonType, entity.type, input,ctx); + } + + async getById(id: any, userId: number): Promise { + return await this.getAddonById(id, true, userId); + } + + + getDefineList(addonType: string) { + return addonRegistry.getDefineList(); + } + + getDefineByType(type: string,prefix?: string) { + return addonRegistry.getDefine(type,prefix) as AddonDefine; + } + + + async getSimpleByIds(ids: number[], userId: any) { + if (ids.length === 0) { + return []; + } + if (!userId) { + return []; + } + return await this.repository.find({ + where: { + id: In(ids), + userId, + }, + select: { + id: true, + name: true, + addonType: true, + type: true, + userId:true, + isSystem: true, + }, + }); + + } + + + + async getDefault(userId: number,addonType: string): Promise { + const res = await this.repository.findOne({ + where: { + userId, + addonType + }, + order: { + isDefault: 'DESC', + }, + }); + if (!res) { + return null; + } + return this.buildAddonInstanceConfig(res); + } + + private buildAddonInstanceConfig(res: AddonEntity) { + const setting = JSON.parse(res.setting); + return { + id: res.id, + addonType: res.addonType, + type: res.type, + name: res.name, + userId: res.userId, + setting, + }; + } + + async setDefault(id: number, userId: number,addonType:string) { + if (!id) { + throw new ValidateException('id不能为空'); + } + if (!userId) { + throw new ValidateException('userId不能为空'); + } + await this.repository.update( + { + userId, + addonType + }, + { + isDefault: false, + } + ); + await this.repository.update( + { + id, + userId, + addonType + }, + { + isDefault: true, + } + ); + } + + async getOrCreateDefault(opts:{addonType:string,type:string, inputs: any, userId: any}) { + const {addonType,type,inputs,userId} = opts; + + const addonDefine = this.getDefineByType( type,addonType) + + const defaultConfig = await this.getDefault(userId); + if (defaultConfig) { + return defaultConfig; + } + const setting = { + ...inputs, + }; + const res = await this.repository.save({ + userId, + addonType, + type: type, + name: addonDefine.title, + setting: JSON.stringify(setting), + isDefault: true, + }); + return this.buildAddonInstanceConfig(res); + } +} diff --git a/packages/libs/lib-server/src/user/addon/service/addon-sys-getter.ts b/packages/libs/lib-server/src/user/addon/service/addon-sys-getter.ts new file mode 100644 index 000000000..773e1a7aa --- /dev/null +++ b/packages/libs/lib-server/src/user/addon/service/addon-sys-getter.ts @@ -0,0 +1,17 @@ +import { IAccessService } from '@certd/pipeline'; +import { AddonService } from './addon-service.js'; + +export class AddonSysGetter implements IAccessService { + addonService: AddonService; + constructor(addonService: AddonService) { + this.addonService = addonService; + } + + async getById(id: any) { + return await this.addonService.getById(id, 0); + } + + async getCommonById(id: any) { + return await this.addonService.getById(id, 0); + } +} diff --git a/packages/libs/lib-server/src/user/index.ts b/packages/libs/lib-server/src/user/index.ts index 17e3af2c4..f0fce929a 100644 --- a/packages/libs/lib-server/src/user/index.ts +++ b/packages/libs/lib-server/src/user/index.ts @@ -1 +1,2 @@ export * from './access/index.js'; +export * from './addon/index.js'; diff --git a/packages/ui/certd-client/index.html b/packages/ui/certd-client/index.html index 1740a304a..d760b2f58 100644 --- a/packages/ui/certd-client/index.html +++ b/packages/ui/certd-client/index.html @@ -23,5 +23,6 @@
+ 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 ceaa16810..ebe7b6915 100644 --- a/packages/ui/certd-client/src/store/settings/api.basic.ts +++ b/packages/ui/certd-client/src/store/settings/api.basic.ts @@ -46,6 +46,10 @@ export type SysPublicSetting = { aiChatEnabled?: boolean; showRunStrategy?: boolean; + + captchaEnabled?: boolean; + captchaType?: number; + captchaAddonId?: number; }; export type SuiteSetting = { enabled?: boolean; diff --git a/packages/ui/certd-client/src/views/certd/addon/api.ts b/packages/ui/certd-client/src/views/certd/addon/api.ts new file mode 100644 index 000000000..818a49c19 --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/addon/api.ts @@ -0,0 +1,117 @@ +import { request } from "/src/api/service"; +import { RequestHandleReq } from "/@/components/plugins/lib"; + +export function createAddonApi() { + const apiPrefix = "/addon"; + return { + async GetList(query: any) { + return await request({ + url: apiPrefix + "/page", + method: "post", + data: query, + }); + }, + + async AddObj(obj: any) { + return await request({ + url: apiPrefix + "/add", + method: "post", + data: obj, + }); + }, + + async UpdateObj(obj: any) { + return await request({ + url: apiPrefix + "/update", + method: "post", + data: obj, + }); + }, + + async DelObj(id: number) { + return await request({ + url: apiPrefix + "/delete", + method: "post", + params: { id }, + }); + }, + + async GetObj(id: number) { + return await request({ + url: apiPrefix + "/info", + method: "post", + params: { id }, + }); + }, + + async GetOptions(id: number) { + return await request({ + url: apiPrefix + "/options", + method: "post", + }); + }, + + async SetDefault(id: number) { + return await request({ + url: apiPrefix + "/setDefault", + method: "post", + params: { id }, + }); + }, + + async GetDefaultId() { + return await request({ + url: apiPrefix + "/getDefaultId", + method: "post", + }); + }, + + async GetSimpleInfo(id: number) { + return await request({ + url: apiPrefix + "/simpleInfo", + method: "post", + params: { id }, + }); + }, + + async GetDefineTypes(addonType: string) { + return await request({ + url: apiPrefix + `/getTypeDict?addonType=${addonType}`, + method: "post", + }); + }, + + async GetProviderDefine(type: string) { + return await request({ + url: apiPrefix + "/define", + method: "post", + params: { type }, + }); + }, + + async GetProviderDefineByType(type: string) { + return await request({ + url: apiPrefix + "/defineByType", + method: "post", + params: { type }, + }); + }, + + async Handle(req: RequestHandleReq, opts: any = {}) { + const url = `/pi/handle/${req.type}`; + const { typeName, action, data, input } = req; + const res = await request({ + url, + method: "post", + data: { + typeName, + action, + data, + input, + }, + ...opts, + }); + return res; + }, + }; +} diff --git a/packages/ui/certd-client/src/views/certd/addon/common.tsx b/packages/ui/certd-client/src/views/certd/addon/common.tsx new file mode 100644 index 000000000..7d123a3b9 --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/addon/common.tsx @@ -0,0 +1,270 @@ +import { ColumnCompositionProps, compute, dict } from "@fast-crud/fast-crud"; +import { computed, provide, ref, toRef } from "vue"; +import { useReference } from "/@/use/use-refrence"; +import { forEach, get, merge, set } from "lodash-es"; +import { Modal } from "ant-design-vue"; +import { mitter } from "/@/utils/util.mitt"; +import { useI18n } from "/src/locales"; + +export function addonProvide(api: any) { + provide("addonApi", api); + provide("get:plugin:type", () => { + return "addon"; + }); +} + +export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) { + const { t } = useI18n(); + const addonTypeTypeDictRef = dict({ + data: [{ value: "captcha", label: "验证码" }], + }); + const addonTypeDictRef = dict({ + url: "/addon/getTypeDict?addonType=captcha", + }); + const defaultPluginConfig = { + component: { + name: "a-input", + vModel: "value", + }, + }; + + function buildDefineFields(define: any, form: any, mode: string) { + const formWrapperRef = crudExpose.getFormWrapperRef(); + const columnsRef = toRef(formWrapperRef.formOptions, "columns"); + + for (const key in columnsRef.value) { + if (key.indexOf(".") >= 0) { + delete columnsRef.value[key]; + } + } + console.log('crudBinding.value[mode + "Form"].columns', columnsRef.value); + forEach(define.input, (value: any, mapKey: any) => { + const key = "body." + mapKey; + const field = { + ...value, + key, + }; + const column = merge({ title: key }, defaultPluginConfig, field); + //eval + useReference(column); + + if (column.required) { + if (!column.rules) { + column.rules = []; + } + column.rules.push({ required: true, message: t("certd.requiredField") }); + } + + //设置默认值 + if (column.value != null && get(form, key) == null) { + set(form, key, column.value); + } + //字段配置赋值 + columnsRef.value[key] = column; + console.log("form", columnsRef.value, form); + }); + } + + const currentDefine = ref(); + + return { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 100, + }, + form: { + show: false, + }, + }, + addonType: { + title: "Addon类型", + type: "dict-select", + dict: addonTypeTypeDictRef, + search: { + show: false, + }, + column: { + width: 200, + component: { + color: "auto", + }, + }, + form: { + onChange(ctx: { value: any }) { + addonTypeDictRef.url = `/addon/getTypeDict?addonType=${ctx.value}`; + }, + }, + editForm: { + component: { + disabled: false, + }, + }, + }, + type: { + title: t("certd.notificationType"), + type: "dict-select", + dict: addonTypeDictRef, + search: { + show: false, + }, + column: { + width: 200, + component: { + color: "auto", + }, + }, + editForm: { + component: { + disabled: false, + }, + }, + form: { + component: { + disabled: false, + showSearch: true, + filterOption: (input: string, option: any) => { + input = input?.toLowerCase(); + return option.value.toLowerCase().indexOf(input) >= 0 || option.label.toLowerCase().indexOf(input) >= 0; + }, + renderLabel(item: any) { + return ( + + {item.label} + {item.needPlus && } + + ); + }, + }, + rules: [{ required: true, message: t("certd.selectNotificationType") }], + valueChange: { + immediate: true, + async handle({ value, mode, form, immediate }) { + if (value == null) { + return; + } + const lastTitle = currentDefine.value?.title; + const define = await api.GetProviderDefine(value); + currentDefine.value = define; + console.log("define", define); + + if (!immediate) { + form.body = {}; + if (define.needPlus) { + mitter.emit("openVipModal"); + } + } + + if (!form.name || form.name === lastTitle) { + form.name = define.title; + } + buildDefineFields(define, form, mode); + }, + }, + helper: computed(() => { + const define = currentDefine.value; + if (define == null) { + return ""; + } + return define.desc; + }), + }, + } as ColumnCompositionProps, + name: { + title: t("certd.notificationName"), + search: { + show: true, + }, + type: ["text"], + form: { + rules: [{ required: true, message: t("certd.enterName") }], + helper: t("certd.helperNotificationName"), + }, + column: { + width: 200, + }, + }, + isDefault: { + title: t("certd.isDefault"), + type: "dict-switch", + dict: dict({ + data: [ + { label: t("certd.yes"), value: true, color: "success" }, + { label: t("certd.no"), value: false, color: "default" }, + ], + }), + form: { + value: false, + rules: [{ required: true, message: t("certd.selectIsDefault") }], + order: 999, + }, + column: { + align: "center", + width: 100, + component: { + name: "a-switch", + vModel: "checked", + disabled: compute(({ value }) => { + return value === true; + }), + on: { + change({ row }) { + Modal.confirm({ + title: t("certd.prompt"), + content: t("certd.confirmSetDefaultNotification"), + onOk: async () => { + await api.SetDefault(row.id); + await crudExpose.doRefresh(); + }, + onCancel: async () => { + await crudExpose.doRefresh(); + }, + }); + }, + }, + }, + }, + } as ColumnCompositionProps, + test: { + title: t("certd.test"), + form: { + show: compute(({ form }) => { + return !!form.type; + }), + component: { + name: "api-test", + action: "TestRequest", + }, + order: 990, + col: { + span: 24, + }, + }, + column: { + show: false, + }, + }, + setting: { + column: { show: false }, + form: { + show: false, + valueBuilder({ value, form }) { + form.body = {}; + if (!value) { + return; + } + const setting = JSON.parse(value); + for (const key in setting) { + form.body[key] = setting[key]; + } + }, + valueResolve({ form }) { + const setting = form.body; + form.setting = JSON.stringify(setting); + }, + }, + } as ColumnCompositionProps, + }; +} diff --git a/packages/ui/certd-client/src/views/certd/addon/crud.tsx b/packages/ui/certd-client/src/views/certd/addon/crud.tsx new file mode 100644 index 000000000..5bc56a03d --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/addon/crud.tsx @@ -0,0 +1,54 @@ +import { ref } from "vue"; +import { getCommonColumnDefine } from "./common"; +import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; +import { createAddonApi } from "/@/views/certd/addon/api"; +const api = createAddonApi(); +export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { + const pageRequest = async (query: UserPageQuery): Promise => { + return await api.GetList(query); + }; + const editRequest = async (req: EditReq) => { + const { form, row } = req; + form.id = row.id; + const res = await api.UpdateObj(form); + return res; + }; + const delRequest = async (req: DelReq) => { + const { row } = req; + return await api.DelObj(row.id); + }; + + const addRequest = async (req: AddReq) => { + const { form } = req; + const res = await api.AddObj(form); + return res; + }; + + const typeRef = ref(); + const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api); + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest, + }, + form: { + labelCol: { + //固定label宽度 + span: null, + style: { + width: "145px", + }, + }, + }, + rowHandle: { + width: 200, + }, + columns: { + ...commonColumnsDefine, + }, + }, + }; +} diff --git a/packages/ui/certd-client/src/views/certd/addon/index.vue b/packages/ui/certd-client/src/views/certd/addon/index.vue new file mode 100644 index 000000000..059404bbd --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/addon/index.vue @@ -0,0 +1,41 @@ + + + diff --git a/packages/ui/certd-client/src/views/framework/login/captcha.vue b/packages/ui/certd-client/src/views/framework/login/captcha.vue new file mode 100644 index 000000000..2d9d2fdd5 --- /dev/null +++ b/packages/ui/certd-client/src/views/framework/login/captcha.vue @@ -0,0 +1,46 @@ + + diff --git a/packages/ui/certd-client/src/views/framework/login/index.vue b/packages/ui/certd-client/src/views/framework/login/index.vue index 604aa0d30..ff38ca561 100644 --- a/packages/ui/certd-client/src/views/framework/login/index.vue +++ b/packages/ui/certd-client/src/views/framework/login/index.vue @@ -20,6 +20,10 @@ + + + + @@ -111,6 +115,7 @@ export default defineComponent({ imgCode: "", smsCode: "", randomStr: "", + captcha: {}, }); const rules = { diff --git a/packages/ui/certd-server/src/controller/user/addon/addon-controller.ts b/packages/ui/certd-server/src/controller/user/addon/addon-controller.ts new file mode 100644 index 000000000..de370ef49 --- /dev/null +++ b/packages/ui/certd-server/src/controller/user/addon/addon-controller.ts @@ -0,0 +1,200 @@ +import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; +import { + AccessGetter, + AddonRequestHandleReq, + Constants, + CrudController, + newAddon, + ValidateException +} from "@certd/lib-server"; +import { AuthService } from '../../../modules/sys/authority/service/auth-service.js'; +import { checkPlus } from '@certd/plus-core'; +import { AddonService } from "@certd/lib-server"; +import { AddonDefine } from "@certd/lib-server"; +import { AccessRequestHandleReq, newAccess } from "@certd/pipeline"; +import { http, logger, utils } from "@certd/basic"; +/** + * Addon + */ +@Provide() +@Controller('/api/addon') +export class AddonController extends CrudController { + @Inject() + service: AddonService; + @Inject() + authService: AuthService; + + getService(): AddonService { + return this.service; + } + + @Post('/page', { summary: Constants.per.authOnly }) + async page(@Body(ALL) body) { + body.query = body.query ?? {}; + delete body.query.userId; + const buildQuery = qb => { + qb.andWhere('user_id = :userId', { userId: this.getUserId() }); + }; + const res = await this.service.page({ + query: body.query, + page: body.page, + sort: body.sort, + buildQuery, + }); + return this.ok(res); + } + + @Post('/list', { summary: Constants.per.authOnly }) + async list(@Body(ALL) body) { + body.query = body.query ?? {}; + body.query.userId = this.getUserId(); + return super.list(body); + } + + @Post('/add', { summary: Constants.per.authOnly }) + async add(@Body(ALL) bean) { + bean.userId = this.getUserId(); + const type = bean.type; + const addonType = bean.addonType; + if (! type || !addonType){ + throw new ValidateException('请选择Addon类型'); + } + const define: AddonDefine = this.service.getDefineByType(type,addonType); + if (!define) { + throw new ValidateException('Addon类型不存在'); + } + if (define.needPlus) { + checkPlus(); + } + return super.add(bean); + } + + @Post('/update', { summary: Constants.per.authOnly }) + async update(@Body(ALL) bean) { + await this.service.checkUserId(bean.id, this.getUserId()); + const old = await this.service.info(bean.id); + if (!old) { + throw new ValidateException('Addon配置不存在'); + } + if (old.type !== bean.type ) { + const addonType = old.type; + const type = bean.type; + const define: AddonDefine = this.service.getDefineByType(type,addonType); + if (!define) { + throw new ValidateException('Addon类型不存在'); + } + if (define.needPlus) { + checkPlus(); + } + } + delete bean.userId; + return super.update(bean); + } + @Post('/info', { summary: Constants.per.authOnly }) + async info(@Query('id') id: number) { + await this.service.checkUserId(id, this.getUserId()); + return super.info(id); + } + + @Post('/delete', { summary: Constants.per.authOnly }) + async delete(@Query('id') id: number) { + await this.service.checkUserId(id, this.getUserId()); + return super.delete(id); + } + + @Post('/define', { summary: Constants.per.authOnly }) + async define(@Query('type') type: string,@Query('addonType') addonType: string) { + const notification = this.service.getDefineByType(type,addonType); + return this.ok(notification); + } + + @Post('/getTypeDict', { summary: Constants.per.authOnly }) + async getTypeDict(@Query('addonType') addonType: string) { + const list: any = this.service.getDefineList(addonType); + let dict = []; + for (const item of list) { + dict.push({ + value: item.name, + label: item.title, + needPlus: item.needPlus ?? false, + icon: item.icon, + }); + } + dict = dict.sort(a => { + return a.needPlus ? 0 : -1; + }); + return this.ok(dict); + } + + @Post('/simpleInfo', { summary: Constants.per.authOnly }) + async simpleInfo(@Query('addonType') addonType: string,@Query('id') id: number) { + if (id === 0) { + //获取默认 + const res = await this.service.getDefault(this.getUserId(),addonType); + if (!res) { + throw new ValidateException('默认Addon配置不存在'); + } + const simple = await this.service.getSimpleInfo(res.id); + return this.ok(simple); + } + await this.authService.checkEntityUserId(this.ctx, this.service, id); + const res = await this.service.getSimpleInfo(id); + return this.ok(res); + } + + @Post('/getDefaultId', { summary: Constants.per.authOnly }) + async getDefaultId(@Query('addonType') addonType: string) { + const res = await this.service.getDefault(this.getUserId(),addonType); + return this.ok(res?.id); + } + + @Post('/setDefault', { summary: Constants.per.authOnly }) + async setDefault(@Query('addonType') addonType: string,@Query('id') id: number) { + await this.service.checkUserId(id, this.getUserId()); + const res = await this.service.setDefault(id, this.getUserId(),addonType); + return this.ok(res); + } + + + @Post('/options', { summary: Constants.per.authOnly }) + async options(@Query('addonType') addonType: string) { + const res = await this.service.list({ + query: { + userId: this.getUserId(), + addonType + }, + }); + for (const item of res) { + delete item.setting; + } + return this.ok(res); + } + + + @Post('/handle', { summary: Constants.per.authOnly }) + async handle(@Body(ALL) body: AddonRequestHandleReq) { + const userId = this.getUserId(); + let inputAddon = body.input.addon; + if (body.input.id > 0) { + const oldEntity = await this.service.info(body.input.id); + if (oldEntity) { + if (oldEntity.userId !== userId) { + throw new Error('addon not found'); + } + // const param: any = { + // type: body.typeName, + // setting: JSON.stringify(body.input.access), + // }; + inputAddon = JSON.parse( oldEntity.setting) + } + } + const ctx = { + http: http, + logger:logger, + utils:utils, + } + const addon = await newAddon(body.addonType,body.typeName, inputAddon,ctx); + const res = await addon.onRequest(body); + return this.ok(res); + } +} diff --git a/packages/ui/certd-server/src/controller/user/login/login-controller.ts b/packages/ui/certd-server/src/controller/user/login/login-controller.ts index 2877c257c..7d2dfc335 100644 --- a/packages/ui/certd-server/src/controller/user/login/login-controller.ts +++ b/packages/ui/certd-server/src/controller/user/login/login-controller.ts @@ -22,6 +22,7 @@ export class LoginController extends BaseController { @Body(ALL) user: any ) { + await this.loginService.doCaptchaValidate({form:user}) const token = await this.loginService.loginByPassword(user); this.writeTokenCookie(token); return this.ok(token); diff --git a/packages/ui/certd-server/src/modules/login/service/login-service.ts b/packages/ui/certd-server/src/modules/login/service/login-service.ts index ed7cc39b9..fe02f93a2 100644 --- a/packages/ui/certd-server/src/modules/login/service/login-service.ts +++ b/packages/ui/certd-server/src/modules/login/service/login-service.ts @@ -6,12 +6,13 @@ import {RoleService} from '../../sys/authority/service/role-service.js'; import {UserEntity} from '../../sys/authority/entity/user.js'; import {SysSettingsService} from '@certd/lib-server'; import {SysPrivateSettings} from '@certd/lib-server'; -import {cache, utils} from '@certd/basic'; +import { cache, logger, utils } from "@certd/basic"; import {LoginErrorException} from '@certd/lib-server/dist/basic/exception/login-error-exception.js'; import {CodeService} from '../../basic/service/code-service.js'; import {TwoFactorService} from "../../mine/service/two-factor-service.js"; import {UserSettingsService} from '../../mine/service/user-settings-service.js'; import {isPlus} from "@certd/plus-core"; +import { AddonService } from "@certd/lib-server/dist/user/addon/service/addon-service.js"; /** * 系统用户 @@ -35,6 +36,8 @@ export class LoginService { userSettingsService: UserSettingsService; @Inject() twoFactorService: TwoFactorService; + @Inject() + addonService: AddonService; checkIsBlocked(username: string) { const blockDurationKey = `login_block_duration:${username}`; @@ -97,6 +100,31 @@ export class LoginService { throw new LoginErrorException(errorMessage, leftTimes); } + async doCaptchaValidate(opts:{form:any}){ + + const pubSetting = await this.sysSettingsService.getPublicSettings() + + if (pubSetting.captchaEnabled) { + const prvSetting = await this.sysSettingsService.getPrivateSettings() + + const addon = await this.addonService.getById(prvSetting.captchaAddonId,0) + if (!addon) { + logger.warn('验证码插件还未配置,忽略验证码校验') + return true + } + if (addon.addonType !== pubSetting.captchaType) { + logger.warn('验证码插件类型错误,忽略验证码校验') + return true + } + + return await addon.onValidate(opts.form) + } + + return true + + } + + async loginBySmsCode(req: { mobile: string; phoneCode: string; smsCode: string; randomStr: string }) { diff --git a/packages/ui/certd-server/src/plugins/index.ts b/packages/ui/certd-server/src/plugins/index.ts index 92da08bca..85e4d93a3 100644 --- a/packages/ui/certd-server/src/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/index.ts @@ -35,3 +35,4 @@ export * from './plugin-ksyun/index.js' export * from './plugin-apisix/index.js' export * from './plugin-dokploy/index.js' export * from './plugin-godaddy/index.js' +export * from './plugin-captcha/index.js' diff --git a/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts b/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts new file mode 100644 index 000000000..033b4dae6 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts @@ -0,0 +1,109 @@ +import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server/dist/user/addon/api/index.js"; +import crypto from 'crypto'; +@IsAddon({ + addonType:"captcha", + name: 'geetest', + title: '极验验证码', + desc: '', +}) +export class GeeTestCaptcha extends BaseAddon { + @AddonInput({ + title: 'captchaId', + component: { + placeholder: 'captchaId', + }, + required: true, + }) + captchaId = ''; + + @AddonInput({ + title: 'captchaKey', + component: { + placeholder: 'captchaKey', + }, + required: true, + }) + captchaKey = ''; + + + async onValidate(data?:any) { + + // geetest 服务地址 +// geetest server url + const API_SERVER = "http://gcaptcha4.geetest.com"; + +// geetest 验证接口 +// geetest server interface + const API_URL = API_SERVER + "/validate" + "?captcha_id=" + this.captchaId; + + + // 前端参数 + // web parameter + var lot_number = data['lot_number']; + var captcha_output = data['captcha_output']; + var pass_token = data['pass_token']; + var gen_time = data['gen_time']; + + // 生成签名, 使用标准的hmac算法,使用用户当前完成验证的流水号lot_number作为原始消息message,使用客户验证私钥作为key + // 采用sha256散列算法将message和key进行单向散列生成最终的 “sign_token” 签名 + // use lot_number + CAPTCHA_KEY, generate the signature + var sign_token = this.hmac_sha256_encode(lot_number, this.captchaKey); + + // 向极验转发前端数据 + “sign_token” 签名 + // send web parameter and “sign_token” to geetest server + var datas = { + 'lot_number': lot_number, + 'captcha_output': captcha_output, + 'pass_token': pass_token, + 'gen_time': gen_time, + 'sign_token': sign_token + }; + + // post request + // 根据极验返回的用户验证状态, 网站主进行自己的业务逻辑 + // According to the user authentication status returned by the geetest, the website owner carries out his own business logic + try{ + const res = await this.doRequest(datas, API_URL) + if (res.result == "success") { + // 验证成功 + // verification successful + return true; + } else { + // 验证失败 + // verification failed + this.logger.error("极验验证不通过 ",res.reason) + return false; + } + }catch (e) { + this.ctx.logger.error("极验验证服务异常",e) + return true + } + + + } + + // 生成签名 +// Generate signature + hmac_sha256_encode(value, key){ + var hash = crypto.createHmac("sha256", key) + .update(value, 'utf8') + .digest('hex'); + return hash; + } + + +// 发送post请求, 响应json数据如:{"result": "success", "reason": "", "captcha_args": {}} +// Send a post request and respond to JSON data, such as: {result ":" success "," reason ":" "," captcha_args ": {}} + async doRequest(datas, url){ + var options = { + url: url, + method: "POST", + params: datas, + timeout: 5000 + }; + const result = await this.ctx.http.request(options); + return result.data; + } + + +} diff --git a/packages/ui/certd-server/src/plugins/plugin-captcha/index.ts b/packages/ui/certd-server/src/plugins/plugin-captcha/index.ts new file mode 100644 index 000000000..3be7e3713 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-captcha/index.ts @@ -0,0 +1 @@ +export * from './geetest/index.js'; From 32034d590a889eda6f8140a7153da167d21d5241 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 11 Sep 2025 11:24:51 +0800 Subject: [PATCH 54/88] docs: --- docs/.vitepress/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 8ac252506..4261d7efb 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -107,7 +107,6 @@ export default defineConfig({ text: "常见问题", items: [ {text: "QA", link: "/guide/qa/use.md"}, - {text: "常见报错处理", link: "/guide/qa/"}, {text: "群晖证书部署", link: "/guide/use/synology/"}, {text: "腾讯云密钥获取", link: "/guide/use/tencent/"}, {text: "连接windows主机", link: "/guide/use/host/windows.md"}, From 00a3908abbdf42385e1f03e4a2cb247e872f1f0a Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 11 Sep 2025 15:20:13 +0800 Subject: [PATCH 55/88] docs: --- docs/guide/qa/use.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/guide/qa/use.md b/docs/guide/qa/use.md index 36f3ce4db..b7cbce7ba 100644 --- a/docs/guide/qa/use.md +++ b/docs/guide/qa/use.md @@ -1,4 +1,4 @@ -# 使用问题 +# 常见问题 ## 1. 是否支持IP证书 @@ -7,8 +7,14 @@ ## 2. 建议设置多长时间运行一次流水线 -建议每天运行一次,检查证书过期时间 +建议每天运行一次,检查证书过期时间 当证书没过期时,自动跳过部署 当证书到期前35天(创建流水线时可以修改),将会自动重新申请证书,自动部署 +## 3. too many certificates 错误 +当出现如下报错时,说明相同的域名短时间内申请超过5次 +解决方案:可以加多一个子域名,重新执行就可以规避次错误 +``` +"detail": too many certificates (5) already issued for this exact set of idantifiers in the last 168hm0s +``` \ No newline at end of file From 370db62bf0aece241859244927beabba32d6a257 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 11 Sep 2025 23:47:05 +0800 Subject: [PATCH 56/88] =?UTF-8?q?perf:=20=E7=99=BB=E5=BD=95=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=9E=81=E9=AA=8C=E9=AA=8C=E8=AF=81=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/libs/lib-server/src/index.ts | 3 +- .../src/system/settings/service/models.ts | 4 +- .../lib-server/src/user/addon/entity/addon.ts | 2 +- .../src/user/addon/service/addon-service.ts | 9 +- .../src/locales/langs/en-US/certd.ts | 8 + .../src/locales/langs/zh-CN/certd.ts | 8 + .../certd/addon/addon-selector/index.vue | 173 ++++++++++++++++++ .../certd-client/src/views/certd/addon/api.ts | 34 ++-- .../src/views/certd/addon/common.tsx | 60 +++--- .../src/views/certd/addon/crud.tsx | 7 +- .../src/views/certd/addon/index.vue | 10 +- .../views/framework/login/captcha-input.vue | 90 +++++++++ .../src/views/framework/login/captcha.vue | 46 ----- .../src/views/framework/login/index.vue | 27 ++- .../src/views/sys/settings/tabs/base.vue | 21 ++- .../db/migration/v10029__addon.sql | 13 ++ .../controller/sys/addon/addon-controller.ts | 83 +++++++++ .../controller/user/addon/addon-controller.ts | 13 +- .../controller/user/login/login-controller.ts | 40 +++- .../modules/login/service/login-service.ts | 10 +- .../src/plugins/plugin-captcha/api.ts | 4 + .../plugins/plugin-captcha/geetest/index.ts | 16 +- 22 files changed, 552 insertions(+), 129 deletions(-) create mode 100644 packages/ui/certd-client/src/views/certd/addon/addon-selector/index.vue create mode 100644 packages/ui/certd-client/src/views/framework/login/captcha-input.vue delete mode 100644 packages/ui/certd-client/src/views/framework/login/captcha.vue create mode 100644 packages/ui/certd-server/db/migration/v10029__addon.sql create mode 100644 packages/ui/certd-server/src/controller/sys/addon/addon-controller.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-captcha/api.ts diff --git a/packages/libs/lib-server/src/index.ts b/packages/libs/lib-server/src/index.ts index a6d3f603b..f4bfaf593 100644 --- a/packages/libs/lib-server/src/index.ts +++ b/packages/libs/lib-server/src/index.ts @@ -1,8 +1,9 @@ import { SysSettingsEntity } from './system/index.js'; import { AccessEntity } from './user/access/entity/access.js'; +import { AddonEntity } from "./user/index.js"; export * from './basic/index.js'; export * from './system/index.js'; export * from './user/index.js'; export { LibServerConfiguration as Configuration } from './configuration.js'; -export const libServerEntities = [SysSettingsEntity, AccessEntity]; +export const libServerEntities = [SysSettingsEntity, AccessEntity,AddonEntity]; 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 08431bbdf..05391a606 100644 --- a/packages/libs/lib-server/src/system/settings/service/models.ts +++ b/packages/libs/lib-server/src/system/settings/service/models.ts @@ -36,6 +36,7 @@ export class SysPublicSettings extends BaseSettings { captchaEnabled = false; //验证码类型 captchaType?: string; + captchaAddonId?:string; } export class SysPrivateSettings extends BaseSettings { @@ -50,9 +51,6 @@ export class SysPrivateSettings extends BaseSettings { dnsResultOrder? = ''; commonCnameEnabled?: boolean = true; - //验证码配置id - captchaAddonId?: number; - sms?: { type?: string; config?: any; diff --git a/packages/libs/lib-server/src/user/addon/entity/addon.ts b/packages/libs/lib-server/src/user/addon/entity/addon.ts index f62de283f..4d16fb43b 100644 --- a/packages/libs/lib-server/src/user/addon/entity/addon.ts +++ b/packages/libs/lib-server/src/user/addon/entity/addon.ts @@ -12,7 +12,7 @@ export class AddonEntity { name: string; - @Column({ comment: 'addon类型', length: 100 }) + @Column({ name: 'addon_type', comment: 'addon类型', length: 100 }) addonType: string; diff --git a/packages/libs/lib-server/src/user/addon/service/addon-service.ts b/packages/libs/lib-server/src/user/addon/service/addon-service.ts index f4834c277..a4a9ba7d5 100644 --- a/packages/libs/lib-server/src/user/addon/service/addon-service.ts +++ b/packages/libs/lib-server/src/user/addon/service/addon-service.ts @@ -39,6 +39,11 @@ export class AddonService extends BaseService { throw new ValidateException('您无权查看该Addon配置'); } } + if (!param.userId){ + param.isSystem = true + }else{ + param.isSystem = false + } delete param._copyFrom return await super.add(param); } @@ -65,6 +70,8 @@ export class AddonService extends BaseService { id: entity.id, name: entity.name, userId: entity.userId, + addonType: entity.addonType, + type: entity.type, }; } @@ -197,7 +204,7 @@ export class AddonService extends BaseService { const addonDefine = this.getDefineByType( type,addonType) - const defaultConfig = await this.getDefault(userId); + const defaultConfig = await this.getDefault(userId,addonType); if (defaultConfig) { return defaultConfig; } 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 19e35501a..fd0809ede 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 @@ -711,6 +711,10 @@ export default { setting: { showRunStrategy: "Show RunStrategy", showRunStrategyHelper: "Allow modify the run strategy of the task", + + captchaEnabled: "Enable Captcha", + captchaHelper: "Whether to enable captcha verification for login", + captchaType: "Captcha Type", }, }, modal: { @@ -731,4 +735,8 @@ export default { challengeSetting: "Challenge Setting", gotoCnameTip: "Please go to CNAME Record Page", }, + addonSelector: { + select: "Select", + placeholder: "select please", + }, }; 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 a2966391c..65e403734 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 @@ -714,6 +714,10 @@ export default { setting: { showRunStrategy: "显示运行策略选择", showRunStrategyHelper: "任务设置中是否允许选择运行策略", + + captchaEnabled: "启用验证码", + captchaHelper: "登录时是否启用验证码", + captchaType: "验证码类型", }, }, modal: { @@ -734,4 +738,8 @@ export default { challengeSetting: "校验配置", gotoCnameTip: "CNAME域名配置请前往CNAME记录页面添加", }, + addonSelector: { + select: "选择", + placeholder: "请选择", + }, }; diff --git a/packages/ui/certd-client/src/views/certd/addon/addon-selector/index.vue b/packages/ui/certd-client/src/views/certd/addon/addon-selector/index.vue new file mode 100644 index 000000000..595c0a081 --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/addon/addon-selector/index.vue @@ -0,0 +1,173 @@ + + + + diff --git a/packages/ui/certd-client/src/views/certd/addon/api.ts b/packages/ui/certd-client/src/views/certd/addon/api.ts index 818a49c19..f3004e82a 100644 --- a/packages/ui/certd-client/src/views/certd/addon/api.ts +++ b/packages/ui/certd-client/src/views/certd/addon/api.ts @@ -1,14 +1,23 @@ import { request } from "/src/api/service"; import { RequestHandleReq } from "/@/components/plugins/lib"; -export function createAddonApi() { - const apiPrefix = "/addon"; +export function createAddonApi(opts: { from: any; addonType: string }) { + let apiPrefix = "/addon"; + if (opts.from === "sys") { + apiPrefix = "/sys/addon"; + } return { async GetList(query: any) { return await request({ url: apiPrefix + "/page", method: "post", - data: query, + data: { + ...query, + query: { + addonType: opts.addonType, + ...query.query, + }, + }, }); }, @@ -16,7 +25,10 @@ export function createAddonApi() { return await request({ url: apiPrefix + "/add", method: "post", - data: obj, + data: { + ...obj, + addonType: opts.addonType, + }, }); }, @@ -46,7 +58,7 @@ export function createAddonApi() { async GetOptions(id: number) { return await request({ - url: apiPrefix + "/options", + url: apiPrefix + `/options?addonType=${opts.addonType}`, method: "post", }); }, @@ -68,22 +80,22 @@ export function createAddonApi() { async GetSimpleInfo(id: number) { return await request({ - url: apiPrefix + "/simpleInfo", + url: apiPrefix + `/simpleInfo?addonType=${opts.addonType}`, method: "post", params: { id }, }); }, - async GetDefineTypes(addonType: string) { + async GetDefineTypes() { return await request({ - url: apiPrefix + `/getTypeDict?addonType=${addonType}`, + url: apiPrefix + `/getTypeDict?addonType=${opts.addonType}`, method: "post", }); }, async GetProviderDefine(type: string) { return await request({ - url: apiPrefix + "/define", + url: apiPrefix + `/define?addonType=${opts.addonType}`, method: "post", params: { type }, }); @@ -91,14 +103,14 @@ export function createAddonApi() { async GetProviderDefineByType(type: string) { return await request({ - url: apiPrefix + "/defineByType", + url: apiPrefix + `/defineByType?addonType=${opts.addonType}`, method: "post", params: { type }, }); }, async Handle(req: RequestHandleReq, opts: any = {}) { - const url = `/pi/handle/${req.type}`; + const url = `/handle/${req.type}?addonType=${opts.addonType}`; const { typeName, action, data, input } = req; const res = await request({ url, diff --git a/packages/ui/certd-client/src/views/certd/addon/common.tsx b/packages/ui/certd-client/src/views/certd/addon/common.tsx index 7d123a3b9..9a9e98058 100644 --- a/packages/ui/certd-client/src/views/certd/addon/common.tsx +++ b/packages/ui/certd-client/src/views/certd/addon/common.tsx @@ -5,6 +5,7 @@ import { forEach, get, merge, set } from "lodash-es"; import { Modal } from "ant-design-vue"; import { mitter } from "/@/utils/util.mitt"; import { useI18n } from "/src/locales"; +import * as pipelineApi from "/@/views/certd/pipeline/api"; export function addonProvide(api: any) { provide("addonApi", api); @@ -13,13 +14,13 @@ export function addonProvide(api: any) { }); } -export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) { +export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any, addonType: string) { const { t } = useI18n(); - const addonTypeTypeDictRef = dict({ - data: [{ value: "captcha", label: "验证码" }], - }); + // const addonTypeTypeDictRef = dict({ + // data: [{ value: "captcha", label: "验证码" }], + // }); const addonTypeDictRef = dict({ - url: "/addon/getTypeDict?addonType=captcha", + url: `/addon/getTypeDict?addonType=${addonType}`, }); const defaultPluginConfig = { component: { @@ -61,7 +62,6 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) { } //字段配置赋值 columnsRef.value[key] = column; - console.log("form", columnsRef.value, form); }); } @@ -79,30 +79,30 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) { show: false, }, }, - addonType: { - title: "Addon类型", - type: "dict-select", - dict: addonTypeTypeDictRef, - search: { - show: false, - }, - column: { - width: 200, - component: { - color: "auto", - }, - }, - form: { - onChange(ctx: { value: any }) { - addonTypeDictRef.url = `/addon/getTypeDict?addonType=${ctx.value}`; - }, - }, - editForm: { - component: { - disabled: false, - }, - }, - }, + // addonType: { + // title: "Addon类型", + // type: "dict-select", + // dict: addonTypeTypeDictRef, + // search: { + // show: false, + // }, + // column: { + // width: 200, + // component: { + // color: "auto", + // }, + // }, + // form: { + // onChange(ctx: { value: any }) { + // addonTypeDictRef.url = `/addon/getTypeDict?addonType=${ctx.value}`; + // }, + // }, + // editForm: { + // component: { + // disabled: false, + // }, + // }, + // }, type: { title: t("certd.notificationType"), type: "dict-select", diff --git a/packages/ui/certd-client/src/views/certd/addon/crud.tsx b/packages/ui/certd-client/src/views/certd/addon/crud.tsx index 5bc56a03d..73f00f03c 100644 --- a/packages/ui/certd-client/src/views/certd/addon/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/addon/crud.tsx @@ -1,9 +1,10 @@ import { ref } from "vue"; import { getCommonColumnDefine } from "./common"; import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; -import { createAddonApi } from "/@/views/certd/addon/api"; -const api = createAddonApi(); + export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { + const api = context.api; + const addonType = context.addonType; const pageRequest = async (query: UserPageQuery): Promise => { return await api.GetList(query); }; @@ -25,7 +26,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }; const typeRef = ref(); - const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api); + const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api, addonType); return { crudOptions: { request: { diff --git a/packages/ui/certd-client/src/views/certd/addon/index.vue b/packages/ui/certd-client/src/views/certd/addon/index.vue index 059404bbd..3b4607db8 100644 --- a/packages/ui/certd-client/src/views/certd/addon/index.vue +++ b/packages/ui/certd-client/src/views/certd/addon/index.vue @@ -14,14 +14,14 @@ import { defineComponent, onActivated, onMounted } from "vue"; import { useFs } from "@fast-crud/fast-crud"; import createCrudOptions from "./crud"; -import { createNotificationApi } from "./api"; -import { notificationProvide } from "/@/views/certd/notification/common"; +import { createAddonApi } from "./api"; +import { addonProvide } from "/@/views/certd/addon/common"; export default defineComponent({ - name: "NotificationManager", + name: "AddonManager", setup() { - const api = createNotificationApi(); - notificationProvide(api); + const api = createAddonApi(); + addonProvide(api); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { api } }); // 页面打开后获取列表数据 diff --git a/packages/ui/certd-client/src/views/framework/login/captcha-input.vue b/packages/ui/certd-client/src/views/framework/login/captcha-input.vue new file mode 100644 index 000000000..a910b8d45 --- /dev/null +++ b/packages/ui/certd-client/src/views/framework/login/captcha-input.vue @@ -0,0 +1,90 @@ + + + diff --git a/packages/ui/certd-client/src/views/framework/login/captcha.vue b/packages/ui/certd-client/src/views/framework/login/captcha.vue deleted file mode 100644 index 2d9d2fdd5..000000000 --- a/packages/ui/certd-client/src/views/framework/login/captcha.vue +++ /dev/null @@ -1,46 +0,0 @@ - - diff --git a/packages/ui/certd-client/src/views/framework/login/index.vue b/packages/ui/certd-client/src/views/framework/login/index.vue index ff38ca561..8e5fd6e40 100644 --- a/packages/ui/certd-client/src/views/framework/login/index.vue +++ b/packages/ui/certd-client/src/views/framework/login/index.vue @@ -21,8 +21,8 @@ - - + + @@ -95,10 +95,10 @@ import ImageCode from "/@/views/framework/login/image-code.vue"; import SmsCode from "/@/views/framework/login/sms-code.vue"; import { useI18n } from "/@/locales"; import { LanguageToggle } from "/@/vben/layouts"; - +import CaptchaInput from "./captcha-input.vue"; export default defineComponent({ name: "LoginPage", - components: { LanguageToggle, SmsCode, ImageCode }, + components: { LanguageToggle, SmsCode, ImageCode, CaptchaInput }, setup() { const { t } = useI18n(); const verifyCodeInputRef = ref(); @@ -165,6 +165,10 @@ export default defineComponent({ const handleFinish = async (values: any) => { loading.value = true; try { + formState.captcha = await doCaptchaValidate(); + if (!formState.captcha) { + return; + } const loginType = formState.loginType; await userStore.login(loginType, toRaw(formState)); } catch (e: any) { @@ -199,6 +203,20 @@ export default defineComponent({ return sysPublicSettings.registerEnabled && (sysPublicSettings.usernameRegisterEnabled || sysPublicSettings.emailRegisterEnabled); } + const captchaInputRef = ref(); + async function doCaptchaValidate() { + if (!sysPublicSettings.captchaEnabled) { + return {}; + } + const res = await captchaInputRef.value.getValidatedForm(); + if (!res) { + return false; + } + return { + ...res, + }; + } + return { t, loading, @@ -216,6 +234,7 @@ export default defineComponent({ handleTwoFactorSubmit, verifyCodeInputRef, settingStore, + captchaInputRef, }; }, }); 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 a3024ae4c..d574a755e 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 @@ -47,6 +47,20 @@
+ + +
+
+ + + + + + + + {{ t("certd.saveButton") }} @@ -63,7 +77,7 @@ import { useSettingStore } from "/@/store/settings"; import { notification } from "ant-design-vue"; import { util } from "/@/utils"; import { useI18n } from "/src/locales"; - +import AddonSelector from "../../../certd/addon/addon-selector/index.vue"; const { t } = useI18n(); defineOptions({ @@ -115,6 +129,11 @@ async function stopOtherUserTimer() { }); } +function onAddonChanged(target: any) { + debugger; + formState.public.captchaType = target.type; +} + const testProxyLoading = ref(false); async function testProxy() { testProxyLoading.value = true; diff --git a/packages/ui/certd-server/db/migration/v10029__addon.sql b/packages/ui/certd-server/db/migration/v10029__addon.sql new file mode 100644 index 000000000..be7c3a951 --- /dev/null +++ b/packages/ui/certd-server/db/migration/v10029__addon.sql @@ -0,0 +1,13 @@ + +CREATE TABLE "cd_addon" ( + "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, + "user_id" integer NOT NULL, + "name" varchar(100) NOT NULL, + "type" varchar(100) NOT NULL, + "addon_type" varchar(100) NOT NULL, + "is_default" boolean NOT NULL DEFAULT (false), + "is_system" boolean NOT NULL DEFAULT (false), + "setting" text, + "create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), + "update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP) +); diff --git a/packages/ui/certd-server/src/controller/sys/addon/addon-controller.ts b/packages/ui/certd-server/src/controller/sys/addon/addon-controller.ts new file mode 100644 index 000000000..bd5864237 --- /dev/null +++ b/packages/ui/certd-server/src/controller/sys/addon/addon-controller.ts @@ -0,0 +1,83 @@ +import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core"; +import { AddonRequestHandleReq, AddonService, Constants } from "@certd/lib-server"; +import { AddonController } from "../../user/addon/addon-controller.js"; + +@Provide() +@Controller('/api/sys/addon') +export class SysAddonController extends AddonController { + @Inject() + service2: AddonService; + + getService(): AddonService { + return this.service2; + } + + getUserId() { + // checkComm(); + return 0; + } + + @Post('/page', { summary: 'sys:settings:view' }) + async page(@Body(ALL) body: any) { + return await super.page(body); + } + + @Post('/list', { summary: 'sys:settings:view' }) + async list(@Body(ALL) body: any) { + return await super.list(body); + } + + @Post('/add', { summary: 'sys:settings:edit' }) + async add(@Body(ALL) bean: any) { + return await super.add(bean); + } + + @Post('/update', { summary: 'sys:settings:edit' }) + async update(@Body(ALL) bean: any) { + return await super.update(bean); + } + @Post('/info', { summary: 'sys:settings:view' }) + async info(@Query('id') id: number) { + return await super.info(id); + } + + @Post('/delete', { summary: 'sys:settings:edit' }) + async delete(@Query('id') id: number) { + return await super.delete(id); + } + @Post('/define', { summary: Constants.per.authOnly }) + async define(@Query('type') type: string,@Query('addonType') addonType: string) { + return await super.define(type,addonType); + } + + @Post('/getTypeDict', { summary: Constants.per.authOnly }) + async getTypeDict(@Query('addonType') addonType: string) { + return await super.getTypeDict(addonType); + } + + @Post('/simpleInfo', { summary: Constants.per.authOnly }) + async simpleInfo(@Query('addonType') addonType: string,@Query('id') id: number) { + return await super.simpleInfo(addonType,id); + } + + @Post('/getDefaultId', { summary: Constants.per.authOnly }) + async getDefaultId(@Query('addonType') addonType: string) { + return await super.getDefaultId(addonType); + } + + @Post('/setDefault', { summary: Constants.per.authOnly }) + async setDefault(@Query('addonType') addonType: string,@Query('id') id: number) { + return await super.setDefault(addonType,id); + } + + + @Post('/options', { summary: Constants.per.authOnly }) + async options(@Query('addonType') addonType: string) { + return await super.options(addonType); + } + + @Post('/handle', { summary: Constants.per.authOnly }) + async handle(@Body(ALL) body: AddonRequestHandleReq) { + return await super.handle(body); + } +} diff --git a/packages/ui/certd-server/src/controller/user/addon/addon-controller.ts b/packages/ui/certd-server/src/controller/user/addon/addon-controller.ts index de370ef49..299f7f5f0 100644 --- a/packages/ui/certd-server/src/controller/user/addon/addon-controller.ts +++ b/packages/ui/certd-server/src/controller/user/addon/addon-controller.ts @@ -1,18 +1,17 @@ -import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; +import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core"; import { - AccessGetter, + AddonDefine, AddonRequestHandleReq, + AddonService, Constants, CrudController, newAddon, ValidateException } from "@certd/lib-server"; -import { AuthService } from '../../../modules/sys/authority/service/auth-service.js'; -import { checkPlus } from '@certd/plus-core'; -import { AddonService } from "@certd/lib-server"; -import { AddonDefine } from "@certd/lib-server"; -import { AccessRequestHandleReq, newAccess } from "@certd/pipeline"; +import { AuthService } from "../../../modules/sys/authority/service/auth-service.js"; +import { checkPlus } from "@certd/plus-core"; import { http, logger, utils } from "@certd/basic"; + /** * Addon */ diff --git a/packages/ui/certd-server/src/controller/user/login/login-controller.ts b/packages/ui/certd-server/src/controller/user/login/login-controller.ts index 7d2dfc335..f185f25e0 100644 --- a/packages/ui/certd-server/src/controller/user/login/login-controller.ts +++ b/packages/ui/certd-server/src/controller/user/login/login-controller.ts @@ -1,8 +1,10 @@ -import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core'; -import { LoginService } from '../../../modules/login/service/login-service.js'; -import { BaseController, Constants, SysPublicSettings, SysSettingsService } from '@certd/lib-server'; -import { CodeService } from '../../../modules/basic/service/code-service.js'; -import { checkComm } from '@certd/plus-core'; +import { ALL, Body, Controller, Inject, Post, Provide } from "@midwayjs/core"; +import { LoginService } from "../../../modules/login/service/login-service.js"; +import { AddonService, BaseController, Constants, SysPublicSettings, SysSettingsService } from "@certd/lib-server"; +import { CodeService } from "../../../modules/basic/service/code-service.js"; +import { checkComm } from "@certd/plus-core"; +import { logger } from "@certd/basic"; +import { ICaptchaAddon } from "../../../plugins/plugin-captcha/api.js"; /** */ @@ -16,14 +18,16 @@ export class LoginController extends BaseController { @Inject() sysSettingsService: SysSettingsService; + @Inject() + addonService: AddonService; @Post('/login', { summary: Constants.per.guest }) public async login( @Body(ALL) - user: any + body: any ) { - await this.loginService.doCaptchaValidate({form:user}) - const token = await this.loginService.loginByPassword(user); + await this.loginService.doCaptchaValidate({form:body.captcha}) + const token = await this.loginService.loginByPassword(body); this.writeTokenCookie(token); return this.ok(token); } @@ -79,4 +83,24 @@ export class LoginController extends BaseController { }); return this.ok(); } + + @Post('/captcha/getParams', { summary: Constants.per.guest }) + async getCaptchaParams() { + + const settings = await this.sysSettingsService.getPublicSettings() + if (settings.captchaEnabled) { + const addonId = settings.captchaAddonId; + + const addon:ICaptchaAddon = await this.addonService.getAddonById(addonId,true,0) + if (!addon) { + logger.warn('验证码插件还未配置') + return this.ok({}); + } + + const params = await addon.getClientParams() + return this.ok(params); + } + + return this.ok({}); + } } diff --git a/packages/ui/certd-server/src/modules/login/service/login-service.ts b/packages/ui/certd-server/src/modules/login/service/login-service.ts index fe02f93a2..c6c292726 100644 --- a/packages/ui/certd-server/src/modules/login/service/login-service.ts +++ b/packages/ui/certd-server/src/modules/login/service/login-service.ts @@ -105,19 +105,21 @@ export class LoginService { const pubSetting = await this.sysSettingsService.getPublicSettings() if (pubSetting.captchaEnabled) { - const prvSetting = await this.sysSettingsService.getPrivateSettings() - const addon = await this.addonService.getById(prvSetting.captchaAddonId,0) + const addon = await this.addonService.getById(pubSetting.captchaAddonId,0) if (!addon) { logger.warn('验证码插件还未配置,忽略验证码校验') return true } - if (addon.addonType !== pubSetting.captchaType) { + if (addon.define.name !== pubSetting.captchaType) { logger.warn('验证码插件类型错误,忽略验证码校验') return true } - return await addon.onValidate(opts.form) + const res = await addon.onValidate(opts.form) + if (!res) { + throw new Error('验证码错误'); + } } return true diff --git a/packages/ui/certd-server/src/plugins/plugin-captcha/api.ts b/packages/ui/certd-server/src/plugins/plugin-captcha/api.ts new file mode 100644 index 000000000..1bfae9f46 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-captcha/api.ts @@ -0,0 +1,4 @@ +export interface ICaptchaAddon{ + onValidate(data?:any):Promise; + getClientParams():Promise; +} diff --git a/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts b/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts index 033b4dae6..1e1cb9993 100644 --- a/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts @@ -1,12 +1,13 @@ import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server/dist/user/addon/api/index.js"; import crypto from 'crypto'; +import { ICaptchaAddon } from "../api.js"; @IsAddon({ addonType:"captcha", name: 'geetest', title: '极验验证码', desc: '', }) -export class GeeTestCaptcha extends BaseAddon { +export class GeeTestCaptcha extends BaseAddon implements ICaptchaAddon{ @AddonInput({ title: 'captchaId', component: { @@ -43,6 +44,9 @@ export class GeeTestCaptcha extends BaseAddon { var captcha_output = data['captcha_output']; var pass_token = data['pass_token']; var gen_time = data['gen_time']; + if (!lot_number || !captcha_output || !pass_token || !gen_time) { + return false; + } // 生成签名, 使用标准的hmac算法,使用用户当前完成验证的流水号lot_number作为原始消息message,使用客户验证私钥作为key // 采用sha256散列算法将message和key进行单向散列生成最终的 “sign_token” 签名 @@ -78,8 +82,6 @@ export class GeeTestCaptcha extends BaseAddon { this.ctx.logger.error("极验验证服务异常",e) return true } - - } // 生成签名 @@ -102,7 +104,13 @@ export class GeeTestCaptcha extends BaseAddon { timeout: 5000 }; const result = await this.ctx.http.request(options); - return result.data; + return result; + } + + async getClientParams(): Promise { + return { + captchaId: this.captchaId, + } } From 50f92f55e2865c4e3409dd1bc951a218f6cbe6e5 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 13 Sep 2025 16:27:20 +0800 Subject: [PATCH 57/88] chore: --- .../ui/certd-client/src/store/plugin/index.ts | 2 +- .../plugins/plugin-captcha/geetest/index.ts | 2 +- .../src/plugins/plugin-captcha/image/index.ts | 50 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 packages/ui/certd-server/src/plugins/plugin-captcha/image/index.ts diff --git a/packages/ui/certd-client/src/store/plugin/index.ts b/packages/ui/certd-client/src/store/plugin/index.ts index 6ecb356e1..7f0880ee6 100644 --- a/packages/ui/certd-client/src/store/plugin/index.ts +++ b/packages/ui/certd-client/src/store/plugin/index.ts @@ -167,7 +167,7 @@ export const usePluginStore = defineStore({ }, async clear() { this.group = null; - this.originGroup = null + this.originGroup = null; }, async getList(): Promise { await this.init(); diff --git a/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts b/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts index 1e1cb9993..60f99d2df 100644 --- a/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-captcha/geetest/index.ts @@ -1,4 +1,4 @@ -import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server/dist/user/addon/api/index.js"; +import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server"; import crypto from 'crypto'; import { ICaptchaAddon } from "../api.js"; @IsAddon({ diff --git a/packages/ui/certd-server/src/plugins/plugin-captcha/image/index.ts b/packages/ui/certd-server/src/plugins/plugin-captcha/image/index.ts new file mode 100644 index 000000000..c7f3ddf3d --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-captcha/image/index.ts @@ -0,0 +1,50 @@ +import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server"; +import crypto from 'crypto'; +import { ICaptchaAddon } from "../api.js"; +@IsAddon({ + addonType:"captcha", + name: 'image', + title: '图片验证码', + desc: '', +}) +export class ImageCaptcha extends BaseAddon implements ICaptchaAddon{ + + + + + async onValidate(data?:any) { + + + } + + // 生成签名 +// Generate signature + hmac_sha256_encode(value, key){ + var hash = crypto.createHmac("sha256", key) + .update(value, 'utf8') + .digest('hex'); + return hash; + } + + +// 发送post请求, 响应json数据如:{"result": "success", "reason": "", "captcha_args": {}} +// Send a post request and respond to JSON data, such as: {result ":" success "," reason ":" "," captcha_args ": {}} + async doRequest(datas, url){ + var options = { + url: url, + method: "POST", + params: datas, + timeout: 5000 + }; + const result = await this.ctx.http.request(options); + return result; + } + + async getClientParams(): Promise { + return { + captchaId: this.captchaId, + } + } + + +} From 7bdde68ecea29fe2c570fd3cb082139db6c93d93 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 13 Sep 2025 23:01:14 +0800 Subject: [PATCH 58/88] =?UTF-8?q?perf:=20=E7=99=BB=E5=BD=95=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E3=80=81=E6=89=BE=E5=9B=9E=E5=AF=86=E7=A0=81=E9=83=BD?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9E=81=E9=AA=8C=E9=AA=8C=E8=AF=81=E7=A0=81?= =?UTF-8?q?=E5=92=8C=E5=9B=BE=E7=89=87=E9=AA=8C=E8=AF=81=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/system/settings/service/models.ts | 2 +- .../src/user/addon/service/addon-service.ts | 21 +++-- .../src/components/captcha/captcha-input.vue | 50 ++++++++++ .../captcha/captchas/geetest_captcha.vue} | 76 ++++++++------- .../captcha/captchas/image_captcha.vue | 59 ++++++++++++ .../plugins/common/remote-tree-select.vue | 1 - .../src/locales/langs/en-US/certd.ts | 2 +- .../src/locales/langs/zh-CN/certd.ts | 2 +- .../certd/addon/addon-selector/index.vue | 5 + .../views/framework/forgot-password/index.vue | 40 ++++---- .../src/views/framework/login/image-code.vue | 41 -------- .../src/views/framework/login/index.vue | 36 ++++--- .../src/views/framework/login/sms-code.vue | 12 +-- .../views/framework/register/email-code.vue | 12 +-- .../src/views/framework/register/index.vue | 39 ++------ .../src/views/sys/settings/tabs/base.vue | 7 +- .../src/controller/basic/code-controller.ts | 50 +++++----- .../sys/settings/sys-settings-controller.ts | 20 ++-- .../user/login/forgot-password-controller.ts | 8 +- .../controller/user/login/login-controller.ts | 31 ++----- .../user/login/register-controller.ts | 7 +- .../modules/basic/service/captcha-service.ts | 54 +++++++++++ .../src/modules/basic/service/code-service.ts | 93 +++++++------------ .../modules/login/service/login-service.ts | 62 ++++--------- .../sys/authority/service/user-service.ts | 17 +++- .../src/plugins/plugin-captcha/api.ts | 2 +- .../plugins/plugin-captcha/geetest/index.ts | 11 ++- .../src/plugins/plugin-captcha/image/index.ts | 75 ++++++++------- .../src/plugins/plugin-captcha/index.ts | 1 + 29 files changed, 446 insertions(+), 390 deletions(-) create mode 100644 packages/ui/certd-client/src/components/captcha/captcha-input.vue rename packages/ui/certd-client/src/{views/framework/login/captcha-input.vue => components/captcha/captchas/geetest_captcha.vue} (52%) create mode 100644 packages/ui/certd-client/src/components/captcha/captchas/image_captcha.vue delete mode 100644 packages/ui/certd-client/src/views/framework/login/image-code.vue create mode 100644 packages/ui/certd-server/src/modules/basic/service/captcha-service.ts 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 05391a606..af7ddf052 100644 --- a/packages/libs/lib-server/src/system/settings/service/models.ts +++ b/packages/libs/lib-server/src/system/settings/service/models.ts @@ -36,7 +36,7 @@ export class SysPublicSettings extends BaseSettings { captchaEnabled = false; //验证码类型 captchaType?: string; - captchaAddonId?:string; + captchaAddonId?:number; } export class SysPrivateSettings extends BaseSettings { diff --git a/packages/libs/lib-server/src/user/addon/service/addon-service.ts b/packages/libs/lib-server/src/user/addon/service/addon-service.ts index a4a9ba7d5..d58d2453c 100644 --- a/packages/libs/lib-server/src/user/addon/service/addon-service.ts +++ b/packages/libs/lib-server/src/user/addon/service/addon-service.ts @@ -76,9 +76,21 @@ export class AddonService extends BaseService { } async getAddonById(id: any, checkUserId: boolean, userId?: number): Promise { + const ctx = { + http: http, + logger: logger, + utils: utils, + }; + + + if (!id){ + //使用图片验证码 + return await newAddon("captcha", "image", {},ctx); + } const entity = await this.info(id); if (entity == null) { - throw new Error(`该Addon配置不存在,请确认是否已被删除:id=${id}`); + //使用图片验证码 + return await newAddon("captcha", "image", {},ctx); } if (checkUserId) { if (userId == null) { @@ -89,17 +101,12 @@ export class AddonService extends BaseService { } } - // const access = accessRegistry.get(entity.type); const setting = JSON.parse(entity.setting ??"{}") const input = { id: entity.id, ...setting, }; - const ctx = { - http: http, - logger: logger, - utils: utils, - }; + return await newAddon(entity.addonType, entity.type, input,ctx); } diff --git a/packages/ui/certd-client/src/components/captcha/captcha-input.vue b/packages/ui/certd-client/src/components/captcha/captcha-input.vue new file mode 100644 index 000000000..3a348c332 --- /dev/null +++ b/packages/ui/certd-client/src/components/captcha/captcha-input.vue @@ -0,0 +1,50 @@ + + diff --git a/packages/ui/certd-client/src/views/framework/login/captcha-input.vue b/packages/ui/certd-client/src/components/captcha/captchas/geetest_captcha.vue similarity index 52% rename from packages/ui/certd-client/src/views/framework/login/captcha-input.vue rename to packages/ui/certd-client/src/components/captcha/captchas/geetest_captcha.vue index a910b8d45..926b9da96 100644 --- a/packages/ui/certd-client/src/views/framework/login/captcha-input.vue +++ b/packages/ui/certd-client/src/components/captcha/captchas/geetest_captcha.vue @@ -1,64 +1,56 @@