From c451823c2b7e4b8bd6faa29567bf8ee397171131 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Wed, 9 Jul 2025 16:00:55 +0800 Subject: [PATCH 01/34] chore: chore: auto domain entity --- .../src/modules/cert/entity/domain.ts | 50 +++++++++++++++++++ .../modules/cert/service/domain-service.ts | 25 ++++++++++ 2 files changed, 75 insertions(+) create mode 100644 packages/ui/certd-server/src/modules/cert/entity/domain.ts create mode 100644 packages/ui/certd-server/src/modules/cert/service/domain-service.ts diff --git a/packages/ui/certd-server/src/modules/cert/entity/domain.ts b/packages/ui/certd-server/src/modules/cert/entity/domain.ts new file mode 100644 index 00000000..5bfb8b5b --- /dev/null +++ b/packages/ui/certd-server/src/modules/cert/entity/domain.ts @@ -0,0 +1,50 @@ +import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; +/** + * 域名管理 + */ +@Entity('cd_domain') +export class DomainEntity { + @PrimaryGeneratedColumn() + id: number; + + @Column({ comment: '用户ID', name: 'user_id' }) + userId: number; + + @Column({ comment: '主域名', length: 100 }) + domain: string; + + @Column({ comment: '校验类型', name: 'challenge_type', length: 100 }) + challengeType : string; + + @Column({ comment: 'DNS提供商', name: 'dns_provider_type', length: 100 }) + dnsProviderType: string; + + @Column({ comment: 'DNS提供商授权', name: 'dns_provider_access', length: 200 }) + dnsProviderAccess: number; + + @Column({ comment: '是否禁用', name: 'disabled' }) + disabled: boolean; + + + @Column({ comment: 'http上传类型', name: 'http_uploader_type', length: 200 }) + httpUploaderType: string; + + @Column({ comment: 'http上传授权', name: 'http_uploader_access', length: 200 }) + httpUploaderAccess: number; + + @Column({ comment: 'http上传根目录', name: 'http_upload_root_dir', length: 200 }) + httpUploadRootDir: string; + + @Column({ + comment: '创建时间', + name: 'create_time', + default: () => 'CURRENT_TIMESTAMP', + }) + createTime: Date; + @Column({ + comment: '修改时间', + name: 'update_time', + default: () => 'CURRENT_TIMESTAMP', + }) + updateTime: Date; +} diff --git a/packages/ui/certd-server/src/modules/cert/service/domain-service.ts b/packages/ui/certd-server/src/modules/cert/service/domain-service.ts new file mode 100644 index 00000000..f6f6bbce --- /dev/null +++ b/packages/ui/certd-server/src/modules/cert/service/domain-service.ts @@ -0,0 +1,25 @@ +import {Inject, Provide, Scope, ScopeEnum} from '@midwayjs/core'; +import {InjectEntityModel} from '@midwayjs/typeorm'; +import {Repository} from 'typeorm'; +import {AccessService, BaseService} from '@certd/lib-server'; +import {DomainEntity} from '../entity/domain.js'; + + +/** + * + */ +@Provide() +@Scope(ScopeEnum.Request, {allowDowngrade: true}) +export class DomainService extends BaseService { + @InjectEntityModel(DomainEntity) + repository: Repository; + + @Inject() + accessService: AccessService; + + //@ts-ignore + getRepository() { + return this.repository; + } + +} From f3002e4fb6d6fa1e694efb08c9b6f9cbb34292d9 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 10 Jul 2025 16:32:12 +0800 Subject: [PATCH 02/34] chore: domain manager --- .../http-verify-plan.vue | 13 +- .../src/components/plugins/lib/dicts.ts | 25 +++ .../src/locales/langs/en-US/certd.ts | 10 ++ .../src/locales/langs/zh-CN/certd.ts | 10 ++ .../src/router/source/modules/certd.ts | 11 ++ .../src/views/certd/cert/domain/api.ts | 60 +++++++ .../src/views/certd/cert/domain/crud.tsx | 166 ++++++++++++++++++ .../src/views/certd/cert/domain/index.vue | 60 +++++++ .../views/certd/pipeline/certd-form/dicts.ts | 14 -- .../db/migration/v10027__auto.sql | 19 ++ .../controller/user/cert/domain-controller.ts | 81 +++++++++ .../src/modules/cert/entity/domain.ts | 12 +- 12 files changed, 450 insertions(+), 31 deletions(-) create mode 100644 packages/ui/certd-client/src/components/plugins/lib/dicts.ts create mode 100644 packages/ui/certd-client/src/views/certd/cert/domain/api.ts create mode 100644 packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx create mode 100644 packages/ui/certd-client/src/views/certd/cert/domain/index.vue delete mode 100644 packages/ui/certd-client/src/views/certd/pipeline/certd-form/dicts.ts create mode 100644 packages/ui/certd-server/db/migration/v10027__auto.sql create mode 100644 packages/ui/certd-server/src/controller/user/cert/domain-controller.ts diff --git a/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/http-verify-plan.vue b/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/http-verify-plan.vue index f0c0bebd..16c66497 100644 --- a/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/http-verify-plan.vue +++ b/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/http-verify-plan.vue @@ -33,6 +33,7 @@ import { Ref, ref, watch, nextTick } from "vue"; import { HttpRecord } from "/@/components/plugins/cert/domains-verify-plan-editor/type"; import { dict } from "@fast-crud/fast-crud"; +import { Dicts } from "/@/components/plugins/lib/dicts"; defineOptions({ name: "HttpVerifyPlan", @@ -68,17 +69,7 @@ async function onRecordChange() { emit("change", records.value); } -const uploaderTypeDict = dict({ - data: [ - { label: "SFTP", value: "sftp" }, - { label: "FTP", value: "ftp" }, - { label: "阿里云OSS", value: "alioss" }, - { label: "腾讯云COS", value: "tencentcos" }, - { label: "七牛OSS", value: "qiniuoss" }, - { label: "S3/Minio", value: "s3" }, - { label: "SSH(已废弃,请选择SFTP方式)", value: "ssh", disabled: true }, - ], -}); +const uploaderTypeDict = Dicts.uploaderTypeDict; diff --git a/packages/ui/certd-client/src/views/certd/pipeline/certd-form/dicts.ts b/packages/ui/certd-client/src/views/certd/pipeline/certd-form/dicts.ts deleted file mode 100644 index d135544b..00000000 --- a/packages/ui/certd-client/src/views/certd/pipeline/certd-form/dicts.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { dict } from "@fast-crud/fast-crud"; - -export const Dicts = { - sslProviderDict: dict({ - data: [ - { value: "letsencrypt", label: "Let‘s Encrypt" }, - { value: "zerossl", label: "ZeroSSL" }, - ], - }), - challengeTypeDict: dict({ data: [{ value: "dns", label: "DNS校验" }] }), - dnsProviderTypeDict: dict({ - url: "pi/dnsProvider/dnsProviderTypeDict", - }), -}; diff --git a/packages/ui/certd-server/db/migration/v10027__auto.sql b/packages/ui/certd-server/db/migration/v10027__auto.sql new file mode 100644 index 00000000..512cfaa2 --- /dev/null +++ b/packages/ui/certd-server/db/migration/v10027__auto.sql @@ -0,0 +1,19 @@ +CREATE TABLE "cd_domain" +( + "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, + "user_id" integer, + "domain" varchar(1024), + challenge_type varchar(50), + dns_provider_type varchar(50), + dns_provider_access bigint, + http_uploader_type varchar(50), + http_uploader_access bigint, + http_upload_root_dir varchar(512), + "disabled" boolean NOT NULL DEFAULT (false), + "create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), + "update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP) +); + +CREATE INDEX "index_domain_user_id" ON "cd_domain" ("user_id"); +CREATE INDEX "index_domain_domain" ON "cd_domain" ("domain"); + diff --git a/packages/ui/certd-server/src/controller/user/cert/domain-controller.ts b/packages/ui/certd-server/src/controller/user/cert/domain-controller.ts new file mode 100644 index 00000000..ffcb0bd2 --- /dev/null +++ b/packages/ui/certd-server/src/controller/user/cert/domain-controller.ts @@ -0,0 +1,81 @@ +import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; +import { Constants, CrudController } from '@certd/lib-server'; +import {DomainService} from "../../../modules/cert/service/domain-service.js"; + +/** + * 授权 + */ +@Provide() +@Controller('/api/cert/domain') +export class DomainController extends CrudController { + @Inject() + service: DomainService; + + getService(): DomainService { + return this.service; + } + + @Post('/page', { summary: Constants.per.authOnly }) + async page(@Body(ALL) body: any) { + body.query = body.query ?? {}; + body.query.userId = this.getUserId(); + const domain = body.query.domain; + delete body.query.domain; + + const bq = qb => { + if (domain) { + qb.andWhere('domain like :domain', { domain: `%${domain}%` }); + } + }; + + const pageRet = await this.getService().page({ + query: body.query, + page: body.page, + sort: body.sort, + buildQuery: bq, + }); + return this.ok(pageRet); + } + + @Post('/list', { summary: Constants.per.authOnly }) + async list(@Body(ALL) body: any) { + body.query = body.query ?? {}; + body.query.userId = this.getUserId(); + const list = await this.getService().list(body); + return this.ok(list); + } + + @Post('/add', { summary: Constants.per.authOnly }) + async add(@Body(ALL) bean: any) { + bean.userId = this.getUserId(); + return super.add(bean); + } + + @Post('/update', { summary: Constants.per.authOnly }) + async update(@Body(ALL) bean: any) { + await this.service.checkUserId(bean.id, this.getUserId()); + 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('/deleteByIds', { summary: Constants.per.authOnly }) + async deleteByIds(@Body(ALL) body: any) { + await this.service.delete(body.ids, { + userId: this.getUserId(), + }); + return this.ok(); + } + +} diff --git a/packages/ui/certd-server/src/modules/cert/entity/domain.ts b/packages/ui/certd-server/src/modules/cert/entity/domain.ts index 5bfb8b5b..51c36fe1 100644 --- a/packages/ui/certd-server/src/modules/cert/entity/domain.ts +++ b/packages/ui/certd-server/src/modules/cert/entity/domain.ts @@ -13,26 +13,26 @@ export class DomainEntity { @Column({ comment: '主域名', length: 100 }) domain: string; - @Column({ comment: '校验类型', name: 'challenge_type', length: 100 }) + @Column({ comment: '校验类型', name: 'challenge_type', length: 50 }) challengeType : string; - @Column({ comment: 'DNS提供商', name: 'dns_provider_type', length: 100 }) + @Column({ comment: 'DNS提供商', name: 'dns_provider_type', length: 50 }) dnsProviderType: string; - @Column({ comment: 'DNS提供商授权', name: 'dns_provider_access', length: 200 }) + @Column({ comment: 'DNS提供商授权', name: 'dns_provider_access' }) dnsProviderAccess: number; @Column({ comment: '是否禁用', name: 'disabled' }) disabled: boolean; - @Column({ comment: 'http上传类型', name: 'http_uploader_type', length: 200 }) + @Column({ comment: 'http上传类型', name: 'http_uploader_type', length: 50 }) httpUploaderType: string; - @Column({ comment: 'http上传授权', name: 'http_uploader_access', length: 200 }) + @Column({ comment: 'http上传授权', name: 'http_uploader_access' }) httpUploaderAccess: number; - @Column({ comment: 'http上传根目录', name: 'http_upload_root_dir', length: 200 }) + @Column({ comment: 'http上传根目录', name: 'http_upload_root_dir', length: 512 }) httpUploadRootDir: string; @Column({ From 39dc5c8160501c60e67a5685cd65a5bf2c3d2429 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 10 Jul 2025 17:00:47 +0800 Subject: [PATCH 03/34] chore: domain manager --- .../src/components/plugins/lib/dicts.ts | 8 ++- .../src/locales/langs/en-US/certd.ts | 1 + .../src/locales/langs/zh-CN/certd.ts | 1 + .../src/router/source/modules/certd.ts | 2 +- .../src/views/certd/cert/domain/crud.tsx | 58 +++++++++++++++++-- .../modules/cert/service/domain-service.ts | 47 ++++++++++++++- 6 files changed, 110 insertions(+), 7 deletions(-) diff --git a/packages/ui/certd-client/src/components/plugins/lib/dicts.ts b/packages/ui/certd-client/src/components/plugins/lib/dicts.ts index 64fb77e5..aecdcb66 100644 --- a/packages/ui/certd-client/src/components/plugins/lib/dicts.ts +++ b/packages/ui/certd-client/src/components/plugins/lib/dicts.ts @@ -7,7 +7,13 @@ export const Dicts = { { value: "zerossl", label: "ZeroSSL" }, ], }), - challengeTypeDict: dict({ data: [{ value: "dns", label: "DNS校验" }] }), + challengeTypeDict: dict({ + data: [ + { value: "dns", label: "DNS校验" }, + { value: "cname", label: "CNAME代理校验" }, + { value: "http", label: "HTTP校验" }, + ], + }), dnsProviderTypeDict: dict({ url: "pi/dnsProvider/dnsProviderTypeDict", }), 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 22c797eb..7f9d1f5f 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 @@ -717,5 +717,6 @@ export default { httpUploaderType: "HTTP Uploader Type", httpUploaderAccess: "HTTP Uploader Access", httpUploadRootDir: "HTTP Upload Root Dir", + disabled: "Disabled", }, }; 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 c4a0e3ab..edbdd17c 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 @@ -720,5 +720,6 @@ export default { httpUploaderType: "上传方式", httpUploaderAccess: "上传授权信息", httpUploadRootDir: "网站根路径", + disabled: "禁用/启用", }, }; diff --git a/packages/ui/certd-client/src/router/source/modules/certd.ts b/packages/ui/certd-client/src/router/source/modules/certd.ts index 620fc65f..bba7fae8 100644 --- a/packages/ui/certd-client/src/router/source/modules/certd.ts +++ b/packages/ui/certd-client/src/router/source/modules/certd.ts @@ -122,7 +122,7 @@ export const certdResources = [ path: "/certd/cert/domain", component: "/certd/cert/domain/index.vue", meta: { - icon: "material-symbols:approval-delegation-outline", + icon: "ion:globe-outline", auth: true, keepAlive: true, }, diff --git a/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx b/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx index e82725dc..fd58711f 100644 --- a/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx @@ -82,17 +82,21 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat search: { show: true, }, + form: { + required: true, + }, editForm: { component: { - disabled: true, + disabled: false, }, }, }, challengeType: { title: t("certd.domain.challengeType"), type: "dict-select", + dict: Dicts.challengeTypeDict, form: { - show: false, + required: true, }, }, /** @@ -110,6 +114,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat component: { name: "DnsProviderSelector", }, + show: compute(({ form }) => { + return form.challengeType === "dns"; + }), + required: true, }, }, dnsProviderAccess: { @@ -118,16 +126,27 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat form: { component: { name: "AccessSelector", + vModel: "modelValue", type: compute(({ form }) => { return form.dnsProviderType; }), }, + show: compute(({ form }) => { + return form.challengeType === "dns"; + }), + required: true, }, }, httpUploaderType: { title: t("certd.domain.httpUploaderType"), type: "dict-text", dict: Dicts.uploaderTypeDict, + form: { + show: compute(({ form }) => { + return form.challengeType === "http"; + }), + required: true, + }, }, httpUploaderAccess: { title: t("certd.domain.httpUploaderAccess"), @@ -136,10 +155,41 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat component: { name: "AccessSelector", }, + show: compute(({ form }) => { + return form.challengeType === "http"; + }), + required: true, + }, + }, + httpUploadRootDir: { + title: t("certd.domain.httpUploadRootDir"), + type: "text", + form: { + show: compute(({ form }) => { + return form.challengeType === "http"; + }), + required: true, + }, + }, + disabled: { + title: t("certd.domain.disabled"), + type: "dict-switch", + dict: dict({ + data: [ + { label: "启用", value: false }, + { label: "禁用", value: true }, + ], + }), + form: { + value: false, + required: true, + }, + column: { + width: 80, }, }, createTime: { - title: t("certd.create_time"), + title: t("certd.createTime"), type: "datetime", form: { show: false, @@ -151,7 +201,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }, }, updateTime: { - title: t("certd.update_time"), + title: t("certd.updateTime"), type: "datetime", form: { show: false, diff --git a/packages/ui/certd-server/src/modules/cert/service/domain-service.ts b/packages/ui/certd-server/src/modules/cert/service/domain-service.ts index f6f6bbce..ed99159a 100644 --- a/packages/ui/certd-server/src/modules/cert/service/domain-service.ts +++ b/packages/ui/certd-server/src/modules/cert/service/domain-service.ts @@ -1,6 +1,6 @@ import {Inject, Provide, Scope, ScopeEnum} from '@midwayjs/core'; import {InjectEntityModel} from '@midwayjs/typeorm'; -import {Repository} from 'typeorm'; +import {Not, Repository} from 'typeorm'; import {AccessService, BaseService} from '@certd/lib-server'; import {DomainEntity} from '../entity/domain.js'; @@ -22,4 +22,49 @@ export class DomainService extends BaseService { return this.repository; } + async add(param) { + if (param.userId == null ){ + throw new Error('userId 不能为空'); + } + if (!param.domain) { + throw new Error('domain 不能为空'); + } + const old = await this.repository.findOne({ + where: { + domain: param.domain, + userId: param.userId + } + }); + if (old) { + throw new Error(`域名(${param.domain})不能重复`); + } + return await super.add(param); + } + + async update(param) { + if (!param.id) { + throw new Error('id 不能为空'); + } + const old = await this.info(param.id) + if (!old) { + throw new Error('domain记录不存在'); + } + + const same = await this.repository.findOne({ + where: { + domain: param.domain, + userId: old.userId, + id: Not(param.id) + } + }); + + if (same) { + throw new Error(`域名(${param.domain})不能重复`); + } + delete param.userId + return await super.update(param); + + + } + } From 4b3f4a868a8b0800c5c59de9d0f47bddc079e7b3 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 11 Jul 2025 09:45:33 +0800 Subject: [PATCH 04/34] =?UTF-8?q?fix:=20=E6=9F=90=E4=BA=9B=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E6=89=BE=E4=B8=8D=E5=88=B0=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/certd-server/src/plugins/index.ts | 4 ++++ .../ui/certd-server/src/plugins/plugin-aliyun/plugin/index.ts | 1 + .../ui/certd-server/src/plugins/plugin-aws/plugins/index.ts | 1 + .../ui/certd-server/src/plugins/plugin-host/plugin/index.ts | 1 + packages/ui/certd-server/src/plugins/plugin-huawei/index.ts | 2 +- .../certd-server/src/plugins/plugin-huawei/plugins/index.ts | 2 ++ .../ui/certd-server/src/plugins/plugin-notification/index.ts | 2 ++ .../ui/certd-server/src/plugins/plugin-other/access/index.ts | 0 .../ui/certd-server/src/plugins/plugin-qiniu/plugin/index.ts | 1 + packages/ui/certd-server/src/plugins/plugin-rainyun/index.ts | 1 + .../certd-server/src/plugins/plugin-rainyun/plugins/index.ts | 1 + .../certd-server/src/plugins/plugin-tencent/plugin/index.ts | 2 ++ .../ui/certd-server/src/plugins/plugin-volcengine/index.ts | 3 +++ .../src/plugins/plugin-volcengine/plugins/index.ts | 2 ++ 14 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 packages/ui/certd-server/src/plugins/plugin-huawei/plugins/index.ts delete mode 100644 packages/ui/certd-server/src/plugins/plugin-other/access/index.ts diff --git a/packages/ui/certd-server/src/plugins/index.ts b/packages/ui/certd-server/src/plugins/index.ts index 902f87fb..20d6311b 100644 --- a/packages/ui/certd-server/src/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/index.ts @@ -25,4 +25,8 @@ export * from './plugin-flex/index.js' export * from './plugin-farcdn/index.js' export * from './plugin-fnos/index.js' export * from './plugin-rainyun/index.js' +export * from './plugin-cloudflare/index.js' +export * from './plugin-github/index.js' +export * from './plugin-namesilo/index.js' +export * from './plugin-proxmox/index.js' export * from './plugin-wangsu/index.js' diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/index.ts index 0334b990..d011be82 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/index.ts @@ -7,4 +7,5 @@ export * from './deploy-to-alb/index.js'; export * from './deploy-to-nlb/index.js'; export * from './deploy-to-slb/index.js'; export * from './deploy-to-fc/index.js'; +export * from './deploy-to-esa/index.js'; export * from './deploy-to-vod/index.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-aws/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-aws/plugins/index.ts index b2dfca5d..b715dc42 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aws/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aws/plugins/index.ts @@ -1 +1,2 @@ export * from './plugin-deploy-to-cloudfront.js'; +export * from './plugin-upload-to-acm.js' diff --git a/packages/ui/certd-server/src/plugins/plugin-host/plugin/index.ts b/packages/ui/certd-server/src/plugins/plugin-host/plugin/index.ts index 16349501..6bb828b9 100644 --- a/packages/ui/certd-server/src/plugins/plugin-host/plugin/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-host/plugin/index.ts @@ -1,2 +1,3 @@ export * from './host-shell-execute/index.js'; export * from './upload-to-host/index.js'; +export * from './copy-to-local/index.js' diff --git a/packages/ui/certd-server/src/plugins/plugin-huawei/index.ts b/packages/ui/certd-server/src/plugins/plugin-huawei/index.ts index c9aa8714..f6e792f0 100644 --- a/packages/ui/certd-server/src/plugins/plugin-huawei/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-huawei/index.ts @@ -1,3 +1,3 @@ export * from './access/index.js'; export * from './dns-provider/index.js'; -export * from './plugins/deploy-to-cdn/index.js'; +export * from './plugins/index.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/index.ts new file mode 100644 index 00000000..3043939b --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/index.ts @@ -0,0 +1,2 @@ +export * from './deploy-to-cdn/index.js' +export * from './upload-to-ccm/index.js' diff --git a/packages/ui/certd-server/src/plugins/plugin-notification/index.ts b/packages/ui/certd-server/src/plugins/plugin-notification/index.ts index db431331..aab72469 100644 --- a/packages/ui/certd-server/src/plugins/plugin-notification/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-notification/index.ts @@ -10,3 +10,5 @@ export * from './discord/index.js'; export * from './slack/index.js'; export * from './bark/index.js'; export * from './feishu/index.js'; +export * from './dingtalk/index.js'; +export * from './vocechat/index.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-other/access/index.ts b/packages/ui/certd-server/src/plugins/plugin-other/access/index.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/index.ts b/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/index.ts index 71437bc9..b1ada785 100644 --- a/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/index.ts @@ -1 +1,2 @@ export * from './deploy-to-cdn/index.js'; +export * from './upload-cert/index.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-rainyun/index.ts b/packages/ui/certd-server/src/plugins/plugin-rainyun/index.ts index 02dc3945..fc34cee7 100644 --- a/packages/ui/certd-server/src/plugins/plugin-rainyun/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-rainyun/index.ts @@ -1,2 +1,3 @@ export * from "./plugins/index.js"; export * from "./access.js"; +export * from "./dns-provider.js"; diff --git a/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/index.ts index e69de29b..5c00fea6 100644 --- a/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/index.ts @@ -0,0 +1 @@ +import * from './plugin-refresh-cert.js' 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 88ed5ee2..60db3827 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 @@ -7,3 +7,5 @@ export * from './deploy-to-cos/index.js'; export * from './deploy-to-eo/index.js'; 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'; diff --git a/packages/ui/certd-server/src/plugins/plugin-volcengine/index.ts b/packages/ui/certd-server/src/plugins/plugin-volcengine/index.ts index a0225ab8..04bb4047 100644 --- a/packages/ui/certd-server/src/plugins/plugin-volcengine/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-volcengine/index.ts @@ -1,3 +1,6 @@ export * from './plugins/index.js'; export * from './access.js'; export * from './volcengine-dns-provider.js'; +export * from './ve-client.js'; +export * from './dns-client.js'; +export * from './cdn-client.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/index.ts index 1f6adb71..21483913 100644 --- a/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/index.ts @@ -3,3 +3,5 @@ export * from './plugin-deploy-to-clb.js' export * from './plugin-upload-to-cert-center.js' export * from './plugin-deploy-to-alb.js' export * from './plugin-deploy-to-live.js' +export * from './plugin-deploy-to-dcdn.js' +export * from './plugin-deploy-to-vod.js' From 06991ddb176d2a891cc9ef7a5090cd28dcb10a41 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 11 Jul 2025 10:44:49 +0800 Subject: [PATCH 05/34] chore: --- .../src/plugins/plugin-notification/feishu/index.ts | 2 +- .../src/plugins/plugin-rainyun/plugins/index.ts | 2 +- .../src/plugins/plugin-volcengine/cdn-client.ts | 2 +- .../src/plugins/plugin-volcengine/dns-client.ts | 9 ++------- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/ui/certd-server/src/plugins/plugin-notification/feishu/index.ts b/packages/ui/certd-server/src/plugins/plugin-notification/feishu/index.ts index bc79c468..0fed0b1c 100644 --- a/packages/ui/certd-server/src/plugins/plugin-notification/feishu/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-notification/feishu/index.ts @@ -7,7 +7,7 @@ import { BaseNotification, IsNotification, NotificationBody, NotificationInput } needPlus: true, }) // https://open.dingtalk.com/document/orgapp/the-creation-and-installation-of-the-application-robot-in-the?spm=ding_open_doc.document.0.0.242d1563cDgZz3 -export class DingTalkNotification extends BaseNotification { +export class FeishuNotification extends BaseNotification { @NotificationInput({ title: 'webhook地址', component: { diff --git a/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/index.ts index 5c00fea6..3ce4f30c 100644 --- a/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/index.ts @@ -1 +1 @@ -import * from './plugin-refresh-cert.js' +export * from './plugin-refresh-cert.js' diff --git a/packages/ui/certd-server/src/plugins/plugin-volcengine/cdn-client.ts b/packages/ui/certd-server/src/plugins/plugin-volcengine/cdn-client.ts index 90fcbe78..93c80c38 100644 --- a/packages/ui/certd-server/src/plugins/plugin-volcengine/cdn-client.ts +++ b/packages/ui/certd-server/src/plugins/plugin-volcengine/cdn-client.ts @@ -1,4 +1,4 @@ -import { VolcengineOpts } from "./dns-client.js"; +import { VolcengineOpts } from "./ve-client.js"; import { CertInfo } from "@certd/plugin-cert"; export class VolcengineCdnClient { diff --git a/packages/ui/certd-server/src/plugins/plugin-volcengine/dns-client.ts b/packages/ui/certd-server/src/plugins/plugin-volcengine/dns-client.ts index d4dbb215..2228e599 100644 --- a/packages/ui/certd-server/src/plugins/plugin-volcengine/dns-client.ts +++ b/packages/ui/certd-server/src/plugins/plugin-volcengine/dns-client.ts @@ -1,12 +1,7 @@ -import { VolcengineAccess } from "./access.js"; -import { http, HttpClient, ILogger } from "@certd/basic"; +import {http} from "@certd/basic"; import querystring from "querystring"; +import {VolcengineOpts} from "./ve-client.js"; -export type VolcengineOpts = { - access: VolcengineAccess - logger: ILogger - http: HttpClient -} export type VolcengineReq = { method?: string; From b46466ac9688ec297f27a2afa938264a66a4d92f Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 11 Jul 2025 10:46:08 +0800 Subject: [PATCH 06/34] 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 cc04063b..ec71cc3d 100644 --- a/packages/core/basic/build.md +++ b/packages/core/basic/build.md @@ -1 +1 @@ -23:36 +10:46 From c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 11 Jul 2025 10:49:26 +0800 Subject: [PATCH 07/34] v1.36.5 --- CHANGELOG.md | 6 +++++ lerna.json | 2 +- packages/core/acme-client/CHANGELOG.md | 4 +++ packages/core/acme-client/package.json | 4 +-- packages/core/basic/CHANGELOG.md | 4 +++ packages/core/basic/package.json | 2 +- packages/core/pipeline/CHANGELOG.md | 4 +++ 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 | 4 +++ 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 | 4 +++ packages/plugins/plugin-cert/package.json | 10 ++++---- packages/plugins/plugin-lib/CHANGELOG.md | 4 +++ packages/plugins/plugin-lib/package.json | 6 ++--- packages/ui/certd-client/CHANGELOG.md | 4 +++ packages/ui/certd-client/package.json | 6 ++--- packages/ui/certd-server/CHANGELOG.md | 6 +++++ packages/ui/certd-server/package.json | 28 ++++++++++----------- 28 files changed, 103 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfa077bd..a6cde127 100644 --- a/CHANGELOG.md +++ b/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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +### Bug Fixes + +* 某些插件找不到的bug ([4b3f4a8](https://github.com/certd/certd/commit/4b3f4a868a8b0800c5c59de9d0f47bddc079e7b3)) + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) ### Bug Fixes diff --git a/lerna.json b/lerna.json index 55c78335..64ac2e14 100644 --- a/lerna.json +++ b/lerna.json @@ -9,5 +9,5 @@ } }, "npmClient": "pnpm", - "version": "1.36.4" + "version": "1.36.5" } diff --git a/packages/core/acme-client/CHANGELOG.md b/packages/core/acme-client/CHANGELOG.md index 06a57f6f..45f54c2f 100644 --- a/packages/core/acme-client/CHANGELOG.md +++ b/packages/core/acme-client/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.5](https://github.com/publishlab/node-acme-client/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/acme-client + ## [1.36.4](https://github.com/publishlab/node-acme-client/compare/v1.36.3...v1.36.4) (2025-07-10) **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 9451a314..c47ec849 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.4", + "version": "1.36.5", "type": "module", "module": "scr/index.js", "main": "src/index.js", @@ -18,7 +18,7 @@ "types" ], "dependencies": { - "@certd/basic": "^1.36.4", + "@certd/basic": "^1.36.5", "@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 77f6240e..12314e27 100644 --- a/packages/core/basic/CHANGELOG.md +++ b/packages/core/basic/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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/basic + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) **Note:** Version bump only for package @certd/basic diff --git a/packages/core/basic/package.json b/packages/core/basic/package.json index e405fd2a..725a7ba2 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.4", + "version": "1.36.5", "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 1536a6bf..4771e8a6 100644 --- a/packages/core/pipeline/CHANGELOG.md +++ b/packages/core/pipeline/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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/pipeline + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) **Note:** Version bump only for package @certd/pipeline diff --git a/packages/core/pipeline/package.json b/packages/core/pipeline/package.json index 113ba72a..c46998f7 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.4", + "version": "1.36.5", "type": "module", "main": "./dist/index.js", "module": "./dist/index.js", @@ -17,8 +17,8 @@ "pub": "npm publish" }, "dependencies": { - "@certd/basic": "^1.36.4", - "@certd/plus-core": "^1.36.4", + "@certd/basic": "^1.36.5", + "@certd/plus-core": "^1.36.5", "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 18cf3812..6a375336 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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/lib-huawei + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) **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 e452577d..366441ac 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.4", + "version": "1.36.5", "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 6cade79a..7fbe9c75 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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/lib-iframe + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) **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 461b2918..973f7ea8 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.4", + "version": "1.36.5", "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 8303b817..a8fede16 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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/jdcloud + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) **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 723eef60..982365bd 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.4", + "version": "1.36.5", "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 04a3201a..d1bfa449 100644 --- a/packages/libs/lib-k8s/CHANGELOG.md +++ b/packages/libs/lib-k8s/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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/lib-k8s + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) **Note:** Version bump only for package @certd/lib-k8s diff --git a/packages/libs/lib-k8s/package.json b/packages/libs/lib-k8s/package.json index 10227c26..4b7baa74 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.4", + "version": "1.36.5", "type": "module", "main": "./dist/index.js", "module": "./dist/index.js", @@ -17,7 +17,7 @@ "pub": "npm publish" }, "dependencies": { - "@certd/basic": "^1.36.4", + "@certd/basic": "^1.36.5", "@kubernetes/client-node": "0.21.0" }, "devDependencies": { diff --git a/packages/libs/lib-server/CHANGELOG.md b/packages/libs/lib-server/CHANGELOG.md index 624b9659..f8e2f7c3 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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/lib-server + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) **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 cb7d5bad..863e6b42 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.4", + "version": "1.36.5", "description": "midway with flyway, sql upgrade way ", "private": false, "type": "module", @@ -27,10 +27,10 @@ ], "license": "AGPL", "dependencies": { - "@certd/acme-client": "^1.36.4", - "@certd/basic": "^1.36.4", - "@certd/pipeline": "^1.36.4", - "@certd/plus-core": "^1.36.4", + "@certd/acme-client": "^1.36.5", + "@certd/basic": "^1.36.5", + "@certd/pipeline": "^1.36.5", + "@certd/plus-core": "^1.36.5", "@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 210cc93e..dfb102ef 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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/midway-flyway-js + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) **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 504d05e5..4b8df47d 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.4", + "version": "1.36.5", "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 7a28b75b..771675ea 100644 --- a/packages/plugins/plugin-cert/CHANGELOG.md +++ b/packages/plugins/plugin-cert/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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/plugin-cert + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) ### Performance Improvements diff --git a/packages/plugins/plugin-cert/package.json b/packages/plugins/plugin-cert/package.json index cfe251ac..c9def53d 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.4", + "version": "1.36.5", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -16,10 +16,10 @@ "pub": "npm publish" }, "dependencies": { - "@certd/acme-client": "^1.36.4", - "@certd/basic": "^1.36.4", - "@certd/pipeline": "^1.36.4", - "@certd/plugin-lib": "^1.36.4", + "@certd/acme-client": "^1.36.5", + "@certd/basic": "^1.36.5", + "@certd/pipeline": "^1.36.5", + "@certd/plugin-lib": "^1.36.5", "@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 5b3a7568..26f0f9c0 100644 --- a/packages/plugins/plugin-lib/CHANGELOG.md +++ b/packages/plugins/plugin-lib/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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/plugin-lib + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) ### Bug Fixes diff --git a/packages/plugins/plugin-lib/package.json b/packages/plugins/plugin-lib/package.json index ac8027ac..73062bdd 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.4", + "version": "1.36.5", "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.4", - "@certd/pipeline": "^1.36.4", + "@certd/basic": "^1.36.5", + "@certd/pipeline": "^1.36.5", "@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 366f1e2d..5ab819fa 100644 --- a/packages/ui/certd-client/CHANGELOG.md +++ b/packages/ui/certd-client/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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +**Note:** Version bump only for package @certd/ui-client + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) ### Bug Fixes diff --git a/packages/ui/certd-client/package.json b/packages/ui/certd-client/package.json index 9bc4569d..67502ccb 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.4", + "version": "1.36.5", "private": true, "scripts": { "dev": "vite --open", @@ -103,8 +103,8 @@ "zod-defaults": "^0.1.3" }, "devDependencies": { - "@certd/lib-iframe": "^1.36.4", - "@certd/pipeline": "^1.36.4", + "@certd/lib-iframe": "^1.36.5", + "@certd/pipeline": "^1.36.5", "@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 1f80de69..e375227b 100644 --- a/packages/ui/certd-server/CHANGELOG.md +++ b/packages/ui/certd-server/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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +### Bug Fixes + +* 某些插件找不到的bug ([4b3f4a8](https://github.com/certd/certd/commit/4b3f4a868a8b0800c5c59de9d0f47bddc079e7b3)) + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) ### Performance Improvements diff --git a/packages/ui/certd-server/package.json b/packages/ui/certd-server/package.json index e7552e61..73d4ae50 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.4", + "version": "1.36.5", "description": "fast-server base midway", "private": true, "type": "module", @@ -42,20 +42,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.4", - "@certd/basic": "^1.36.4", - "@certd/commercial-core": "^1.36.4", + "@certd/acme-client": "^1.36.5", + "@certd/basic": "^1.36.5", + "@certd/commercial-core": "^1.36.5", "@certd/cv4pve-api-javascript": "^8.4.1", - "@certd/jdcloud": "^1.36.4", - "@certd/lib-huawei": "^1.36.4", - "@certd/lib-k8s": "^1.36.4", - "@certd/lib-server": "^1.36.4", - "@certd/midway-flyway-js": "^1.36.4", - "@certd/pipeline": "^1.36.4", - "@certd/plugin-cert": "^1.36.4", - "@certd/plugin-lib": "^1.36.4", - "@certd/plugin-plus": "^1.36.4", - "@certd/plus-core": "^1.36.4", + "@certd/jdcloud": "^1.36.5", + "@certd/lib-huawei": "^1.36.5", + "@certd/lib-k8s": "^1.36.5", + "@certd/lib-server": "^1.36.5", + "@certd/midway-flyway-js": "^1.36.5", + "@certd/pipeline": "^1.36.5", + "@certd/plugin-cert": "^1.36.5", + "@certd/plugin-lib": "^1.36.5", + "@certd/plugin-plus": "^1.36.5", + "@certd/plus-core": "^1.36.5", "@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120", "@huaweicloud/huaweicloud-sdk-core": "^3.1.120", "@koa/cors": "^5.0.0", From 9a3754fbf874efc45d220ed4080f7ff52c3a0a01 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 11 Jul 2025 10:51:05 +0800 Subject: [PATCH 08/34] build: trigger build image --- build.trigger | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.trigger b/build.trigger index 9da31454..e217ac05 100644 --- a/build.trigger +++ b/build.trigger @@ -1 +1 @@ -23:42 +10:51 From 24d3096752836b263b997fba05af0b7d5abea65d Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 11 Jul 2025 10:51:21 +0800 Subject: [PATCH 09/34] build: publish --- docs/guide/changelogs/CHANGELOG.md | 6 ++++++ 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, 17 insertions(+), 11 deletions(-) diff --git a/docs/guide/changelogs/CHANGELOG.md b/docs/guide/changelogs/CHANGELOG.md index bfa077bd..a6cde127 100644 --- a/docs/guide/changelogs/CHANGELOG.md +++ b/docs/guide/changelogs/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.5](https://github.com/certd/certd/compare/v1.36.4...v1.36.5) (2025-07-11) + +### Bug Fixes + +* 某些插件找不到的bug ([4b3f4a8](https://github.com/certd/certd/commit/4b3f4a868a8b0800c5c59de9d0f47bddc079e7b3)) + ## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10) ### Bug Fixes diff --git a/packages/core/acme-client/package.json b/packages/core/acme-client/package.json index c47ec849..833bd1cb 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": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } diff --git a/packages/core/basic/package.json b/packages/core/basic/package.json index 725a7ba2..9b96d2af 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": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } diff --git a/packages/core/pipeline/package.json b/packages/core/pipeline/package.json index c46998f7..c545d254 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": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } diff --git a/packages/libs/lib-huawei/package.json b/packages/libs/lib-huawei/package.json index 366441ac..9893897d 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": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } diff --git a/packages/libs/lib-iframe/package.json b/packages/libs/lib-iframe/package.json index 973f7ea8..26184f3d 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": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } diff --git a/packages/libs/lib-jdcloud/package.json b/packages/libs/lib-jdcloud/package.json index 982365bd..4a779605 100644 --- a/packages/libs/lib-jdcloud/package.json +++ b/packages/libs/lib-jdcloud/package.json @@ -61,5 +61,5 @@ "fetch" ] }, - "gitHead": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } diff --git a/packages/libs/lib-k8s/package.json b/packages/libs/lib-k8s/package.json index 4b7baa74..77b2dd86 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": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } diff --git a/packages/libs/lib-server/package.json b/packages/libs/lib-server/package.json index 863e6b42..d0e4e8f1 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": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } diff --git a/packages/libs/midway-flyway-js/package.json b/packages/libs/midway-flyway-js/package.json index 4b8df47d..6790ed2f 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": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } diff --git a/packages/plugins/plugin-cert/package.json b/packages/plugins/plugin-cert/package.json index c9def53d..e59fdcaa 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": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } diff --git a/packages/plugins/plugin-lib/package.json b/packages/plugins/plugin-lib/package.json index 73062bdd..1d1ffac0 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": "0ff700849ff6427f79cce241f92257eca35af65d" + "gitHead": "c2a95a13fe6edf05ea0f72f5f7c76f9eea3ab0bd" } From 8273031d7e5c5e4dec9c934fc2097fd78759e925 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 11 Jul 2025 17:37:33 +0800 Subject: [PATCH 10/34] =?UTF-8?q?docs:=20=E8=87=AA=E5=8A=A8=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E5=B8=AE=E5=8A=A9=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../guide/install/images/github-release-2.png | Bin 0 -> 28254 bytes docs/guide/install/images/github-release.png | Bin 0 -> 21202 bytes docs/guide/install/upgrade.md | 50 ++++++++++++++++++ packages/plugins/plugin-lib/src/ssh/ssh.ts | 7 ++- .../plugins/plugin-check-release.ts | 50 +++++++++++------- 5 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 docs/guide/install/images/github-release-2.png create mode 100644 docs/guide/install/images/github-release.png diff --git a/docs/guide/install/images/github-release-2.png b/docs/guide/install/images/github-release-2.png new file mode 100644 index 0000000000000000000000000000000000000000..4e9bb77957819000026ff5381718b89a35c95e3b GIT binary patch literal 28254 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 literal 0 HcmV?d00001 diff --git a/docs/guide/install/upgrade.md b/docs/guide/install/upgrade.md index 11c6dc42..0f562ec5 100644 --- a/docs/guide/install/upgrade.md +++ b/docs/guide/install/upgrade.md @@ -13,4 +13,54 @@ ::: ## 升级日志 +可以查看最新版本号,以及所有版本的更新日志 [CHANGELOG](../changelogs/CHANGELOG.md) + + +## 自动升级配置 + +### 1. 方法一:使用watchtower监控 + +修改docker-compose.yaml文件增加如下配置, 使用watchtower监控自动升级 +```yaml +services: + certd: + ... + labels: + com.centurylinklabs.watchtower.enable: "true" + +# ↓↓↓↓ --------------------------------------------------------- 自动升级,上面certd的版本号要保持为latest + certd-updater: # 添加 Watchtower 服务 + image: containrrr/watchtower:latest + container_name: certd-updater + restart: unless-stopped + volumes: + - /var/run/docker.sock:/var/run/docker.sock + # 配置 自动更新 + environment: + - WATCHTOWER_CLEANUP=true # 自动清理旧版本容器 + - WATCHTOWER_INCLUDE_STOPPED=false # 不更新已停止的容器 + - WATCHTOWER_LABEL_ENABLE=true # 根据容器标签进行更新 + - WATCHTOWER_POLL_INTERVAL=600 # 每 10 分钟检查一次更新 + +``` + + +### 2. 方法二:使用Certd版本监控功能 + +选择Github-检查Release版本插件 +![](./images/github-release.png) +按如下图填写配置 +![](./images/github-release-2.png) + + +检测到新版本后执行宿主机升级命令: + +```shell +# 拉取最新镜像 +docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest +# 升级容器命令, 替换成你自己的certd更新命令 +export RESTART_CERT='sleep 10; cd ~/deploy/certd/ ; docker compose down; docker compose up -d' +# 构造一个脚本10s后在后台执行,避免容器销毁时执行太快,导致流水线任务无法结束 +nohup sh -c '$RESTART_CERT' >/dev/null 2>&1 & echo '10秒后重启' && exit +``` \ No newline at end of file diff --git a/packages/plugins/plugin-lib/src/ssh/ssh.ts b/packages/plugins/plugin-lib/src/ssh/ssh.ts index ccd12caf..b7d203a6 100644 --- a/packages/plugins/plugin-lib/src/ssh/ssh.ts +++ b/packages/plugins/plugin-lib/src/ssh/ssh.ts @@ -491,7 +491,7 @@ export class SshClient { * Set-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\cmd.exe" * @param options */ - async exec(options: { connectConf: SshAccess; script: string | Array; env?: any; throwOnStdErr?: boolean }): Promise { + async exec(options: { connectConf: SshAccess; script: string | Array; env?: any; throwOnStdErr?: boolean; stopOnError?: boolean }): Promise { let { script } = options; const { connectConf, throwOnStdErr } = options; @@ -506,6 +506,10 @@ export class SshClient { isWinCmd = await this.isCmd(conn); } + if (isLinux && options.stopOnError !== false) { + script = "set -e\n" + script; + } + if (options.env) { for (const key in options.env) { if (isLinux) { @@ -538,6 +542,7 @@ export class SshClient { script = envScripts.join(newLine) + newLine + script; } } + return await conn.exec(script as string, { throwOnStdErr }); }, }); diff --git a/packages/ui/certd-server/src/plugins/plugin-github/plugins/plugin-check-release.ts b/packages/ui/certd-server/src/plugins/plugin-github/plugins/plugin-check-release.ts index 2a596e84..2b34cbb1 100644 --- a/packages/ui/certd-server/src/plugins/plugin-github/plugins/plugin-check-release.ts +++ b/packages/ui/certd-server/src/plugins/plugin-github/plugins/plugin-check-release.ts @@ -47,7 +47,7 @@ export class GithubCheckRelease extends AbstractTaskPlugin { mode:"tags" } }, - required:true, + required:false, }) notificationIds!: number[]; @@ -74,9 +74,21 @@ export class GithubCheckRelease extends AbstractTaskPlugin { name: 'a-textarea', vModel: 'value', rows: 6, - placeholder: `#拉取最新版镜像\ndocker pull greper/certd:latest \n#重建容器 \nnohup sh -c 'sleep 10; cd ~/deploy/certd/ ; docker compose down; docker compose up -d' >/dev/null & `, + placeholder: ` +# 拉取最新镜像 +docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest +# 升级容器命令, 替换成你自己的实际部署位置及更新命令 +export RESTART_CERT='sleep 10; cd ~/deploy/certd/ ; docker compose down; docker compose up -d' +# 构造一个脚本10s后在后台执行,避免容器销毁时执行太快,导致流水线任务无法结束 +nohup sh -c '$RESTART_CERT' >/dev/null 2>&1 & echo '10秒后重启' && exit`, }, - helper: '有新版本后执行命令,比如:拉取最新版镜像,然后重建容器\n注意:自己升级自己需要使用nobup配合sleep', + helper: `有新版本后执行命令,比如:拉取最新版镜像,然后重建容器 +注意:自己升级自己需要使用nohup配合sleep +自动升级命令示例: +docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest +export RESTART_CERT='sleep 10; cd ~/deploy/certd/ ; docker compose down; docker compose up -d' +nohup sh -c '$RESTART_CERT' >/dev/null 2>&1 & echo '10秒后重启' && exit +`, required: false, }) script!: string; @@ -108,24 +120,24 @@ export class GithubCheckRelease extends AbstractTaskPlugin { //仅每行开头的* 替换成 -, *号前面可以有空格 const body = res.body.replace(/^(\s*)\* /gm, "$1- ") - if (this.notificationIds == null){ - this.notificationIds = [0] - } - //发送通知 - for (const notificationId of this.notificationIds) { - await this.ctx.notificationService.send({ - id: notificationId, - useDefault: false, - useEmail:false, - logger: this.logger, - body: { - title: `${this.repoName} 新版本 ${this.lastVersion} 发布`, - content: `${body}\n\n > [Certd](https://certd.docmirror.cn),不止证书自动化,插件解锁无限可能!\n\n`, - url: `https://github.com/${this.repoName}/releases/tag/${this.lastVersion}`, - } - }) + if (this.notificationIds && this.notificationIds.length > 0){ + //发送通知 + for (const notificationId of this.notificationIds) { + await this.ctx.notificationService.send({ + id: notificationId, + useDefault: false, + useEmail:false, + logger: this.logger, + body: { + title: `${this.repoName} 新版本 ${this.lastVersion} 发布`, + content: `${body}\n\n > [Certd](https://certd.docmirror.cn),不止证书自动化,插件解锁无限可能!\n\n`, + url: `https://github.com/${this.repoName}/releases/tag/${this.lastVersion}`, + } + }) + } } + if (this.script != null && this.script.trim() != "") { const connectConf = await this.getAccess(this.sshAccessId); const sshClient = new SshClient(this.logger); From 4b335db31ca24b00ddab3fd01a3f596f10015cee Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 11 Jul 2025 18:17:11 +0800 Subject: [PATCH 11/34] chore: --- packages/ui/certd-client/src/locales/langs/en-US/certd.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0d917c33..d17346cc 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 @@ -471,7 +471,7 @@ export default { statusError: "Error", actionImportBatch: "Batch Import", actionSyncIp: "Sync IP", - TitleSyncIp: "Sync IP", + modalTitleSyncIp: "Sync IP", modalContentSyncIp: "Are you sure to sync IP?", notificationSyncComplete: "Sync Complete", actionCheckAll: "Check All", From 785bee2b3955493b60892677a6ba5a89044df531 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 12 Jul 2025 23:00:04 +0800 Subject: [PATCH 12/34] chore: auto --- .../src/user/access/service/access-service.ts | 25 ++++- .../plugin-cert/src/dns-provider/api.ts | 29 ++++++ .../src/plugin/cert-plugin/index.ts | 76 ++++++++++++++- .../src/components/plugins/lib/dicts.ts | 6 +- .../src/views/certd/access/api.ts | 8 ++ .../src/views/certd/cert/domain/crud.tsx | 96 +++++++++++++++++-- .../user/pipeline/access-controller.ts | 6 ++ 7 files changed, 230 insertions(+), 16 deletions(-) diff --git a/packages/libs/lib-server/src/user/access/service/access-service.ts b/packages/libs/lib-server/src/user/access/service/access-service.ts index bc19f964..f99f6330 100644 --- a/packages/libs/lib-server/src/user/access/service/access-service.ts +++ b/packages/libs/lib-server/src/user/access/service/access-service.ts @@ -1,6 +1,6 @@ import {Inject, Provide, Scope, ScopeEnum} from '@midwayjs/core'; import {InjectEntityModel} from '@midwayjs/typeorm'; -import {Repository} from 'typeorm'; +import { In, Repository } from "typeorm"; import {AccessGetter, BaseService, PageReq, PermissionException, ValidateException} from '../../../index.js'; import {AccessEntity} from '../entity/access.js'; import {AccessDefine, accessRegistry, newAccess} from '@certd/pipeline'; @@ -175,4 +175,27 @@ export class AccessService extends BaseService { getDefineByType(type: string) { return accessRegistry.getDefine(type); } + + + 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, + type: true, + userId:true + }, + }); + + } } diff --git a/packages/plugins/plugin-cert/src/dns-provider/api.ts b/packages/plugins/plugin-cert/src/dns-provider/api.ts index 523159fe..a8817c21 100644 --- a/packages/plugins/plugin-cert/src/dns-provider/api.ts +++ b/packages/plugins/plugin-cert/src/dns-provider/api.ts @@ -59,3 +59,32 @@ export interface ISubDomainsGetter { export interface IDomainParser { parse(fullDomain: string): Promise; } + +export type DnsVerifier = { + // dns直接校验 + dnsProviderType: string; + dnsProviderAccessId: number; +}; + +export type CnameVerifier = { + cnameRecord: string; +}; + +export type HttpVerifier = { + // http校验 + httpUploaderType: string; + httpUploaderAccess: string; + httpUploadRootDir: string; +}; +export type DomainVerifier = { + domain: string; + mainDomain: string; + challengeType: string; + dns?: DnsVerifier; + cname?: CnameVerifier; + http?: HttpVerifier; +}; + +export interface IDomainVerifierGetter { + getVerifiers(domains: string[]): Promise; +} 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 6b6d864a..b08c74b7 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -4,7 +4,7 @@ import { utils } from "@certd/basic"; import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, HttpVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js"; import { AcmeService } from "./acme.js"; import * as _ from "lodash-es"; -import { createDnsProvider, DnsProviderContext, IDnsProvider, ISubDomainsGetter } from "../../dns-provider/index.js"; +import { createDnsProvider, DnsProviderContext, DomainVerifier, IDnsProvider, IDomainVerifierGetter, ISubDomainsGetter } from "../../dns-provider/index.js"; import { CertReader } from "./cert-reader.js"; import { CertApplyBasePlugin } from "./base.js"; import { GoogleClient } from "../../libs/google.js"; @@ -66,6 +66,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { { value: "cname", label: "CNAME代理验证" }, { value: "http", label: "HTTP文件验证" }, { value: "dnses", label: "多DNS提供商" }, + { value: "auto", label: "自动选择" }, ], }, required: true, @@ -73,6 +74,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { 2. CNAME代理验证:支持任何注册商的域名,第一次需要手动添加CNAME记录(建议将DNS服务器修改为阿里云/腾讯云的,然后使用DNS直接验证) 3. HTTP文件验证:不支持泛域名,需要配置网站文件上传 4. 多DNS提供商:每个域名可以选择独立的DNS提供商 +5. 自动选择:需要在[域名管理](#/certd/cert/domain)中事先配置好校验方式 `, }) challengeType!: string; @@ -408,7 +410,11 @@ export class CertApplyPlugin extends CertApplyBasePlugin { let dnsProvider: IDnsProvider = null; let domainsVerifyPlan: DomainsVerifyPlan = null; if (this.challengeType === "cname" || this.challengeType === "http" || this.challengeType === "dnses") { - domainsVerifyPlan = await this.createDomainsVerifyPlan(); + domainsVerifyPlan = await this.createDomainsVerifyPlan(this.domainsVerifyPlan); + } + if (this.challengeType === "auto") { + const planInput = await this.buildVerifyPlanInputByAuto(); + domainsVerifyPlan = await this.createDomainsVerifyPlan(planInput); } else { const dnsProviderType = this.dnsProviderType; const access = await this.getAccess(this.dnsProviderAccess); @@ -451,10 +457,10 @@ export class CertApplyPlugin extends CertApplyBasePlugin { }); } - async createDomainsVerifyPlan(): Promise { + async createDomainsVerifyPlan(verifyPlanSetting: DomainsVerifyPlanInput): Promise { const plan: DomainsVerifyPlan = {}; - for (const domain in this.domainsVerifyPlan) { - const domainVerifyPlan = this.domainsVerifyPlan[domain]; + for (const domain in verifyPlanSetting) { + const domainVerifyPlan = verifyPlanSetting[domain]; let dnsProvider = null; const cnameVerifyPlan: Record = {}; const httpVerifyPlan: Record = {}; @@ -511,6 +517,66 @@ export class CertApplyPlugin extends CertApplyBasePlugin { } return plan; } + + private async buildVerifyPlanInputByAuto() { + //从数据库里面自动选择校验方式 + // domain list + const domainList = new Set(); + //整理域名 + for (let domain in this.domains) { + domain = domain.replaceAll("*.", ""); + domainList.add(domain); + } + const domainVerifierGetter: IDomainVerifierGetter = await this.ctx.serviceGetter.get("DomainVerifierGetter"); + + const verifiers = await domainVerifierGetter.getVerifiers([...domainList]); + + const verifyPlanInput: DomainsVerifyPlanInput = {}; + + for (const verifier of verifiers) { + const domain = verifier.domain; + const mainDomain = verifier.mainDomain; + let plan = verifyPlanInput[mainDomain]; + if (!plan) { + plan = { + domain: mainDomain, + type: "cname", + }; + verifyPlanInput[mainDomain] = plan; + } + if (verifier.challengeType === "cname") { + verifyPlanInput[domain] = { + type: "cname", + domain: domain, + cnameVerifyPlan: { + [domain]: { + id: 0, + status: "validate", + }, + }, + }; + } else if (verifier.challengeType === "http") { + //http + const http = verifier.http; + verifyPlanInput[domain] = { + type: "http", + domain: domain, + httpVerifyPlan: { + [domain]: { + domain: domain, + httpUploaderType: http.httpUploaderType, + httpUploaderAccess: http.httpUploaderAccess, + httpUploadRootDir: http.httpUploadRootDir, + }, + }, + }; + } else { + //dns + } + } + + return verifyPlanInput; + } } new CertApplyPlugin(); diff --git a/packages/ui/certd-client/src/components/plugins/lib/dicts.ts b/packages/ui/certd-client/src/components/plugins/lib/dicts.ts index aecdcb66..c01a974b 100644 --- a/packages/ui/certd-client/src/components/plugins/lib/dicts.ts +++ b/packages/ui/certd-client/src/components/plugins/lib/dicts.ts @@ -9,9 +9,9 @@ export const Dicts = { }), challengeTypeDict: dict({ data: [ - { value: "dns", label: "DNS校验" }, - { value: "cname", label: "CNAME代理校验" }, - { value: "http", label: "HTTP校验" }, + { value: "dns", label: "DNS校验", color: "green" }, + { value: "cname", label: "CNAME代理校验", color: "blue" }, + { value: "http", label: "HTTP校验", color: "yellow" }, ], }), dnsProviderTypeDict: dict({ diff --git a/packages/ui/certd-client/src/views/certd/access/api.ts b/packages/ui/certd-client/src/views/certd/access/api.ts index 180984fe..9d81c0c1 100644 --- a/packages/ui/certd-client/src/views/certd/access/api.ts +++ b/packages/ui/certd-client/src/views/certd/access/api.ts @@ -55,6 +55,14 @@ export function createAccessApi(from = "user") { }); }, + async GetDictByIds(ids: number[]) { + return await request({ + url: apiPrefix + "/getDictByIds", + method: "post", + data: { ids }, + }); + }, + async GetSecretPlain(id: number, key: string) { return await request({ url: apiPrefix + "/getSecretPlain", diff --git a/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx b/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx index fd58711f..57a2688e 100644 --- a/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx @@ -5,8 +5,9 @@ import { useRouter } from "vue-router"; import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; import { useUserStore } from "/@/store/user"; import { useSettingStore } from "/@/store/settings"; -import { message } from "ant-design-vue"; import { Dicts } from "/@/components/plugins/lib/dicts"; +import { createAccessApi } from "/@/views/certd/access/api"; + export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { const router = useRouter(); const { t } = useI18n(); @@ -32,6 +33,21 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat const selectedRowKeys: Ref = ref([]); context.selectedRowKeys = selectedRowKeys; + const accessApi = createAccessApi(); + const accessDict = dict({ + value: "id", + label: "name", + url: "accessDict", + async getNodesByValues(ids: number[]) { + return await accessApi.GetDictByIds(ids); + }, + }); + + const httpUploaderTypeDict = Dicts.uploaderTypeDict; + + const dnsProviderTypeDict = dict({ + url: "pi/dnsProvider/dnsProviderTypeDict", + }); return { crudOptions: { settings: { @@ -90,6 +106,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat disabled: false, }, }, + column: { + sorter: true, + }, }, challengeType: { title: t("certd.domain.challengeType"), @@ -98,6 +117,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat form: { required: true, }, + column: { + sorter: true, + }, }, /** * challengeType varchar(50), @@ -109,7 +131,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat */ dnsProviderType: { title: t("certd.domain.dnsProviderType"), - type: "text", + type: "dict-select", + dict: dnsProviderTypeDict, form: { component: { name: "DnsProviderSelector", @@ -119,10 +142,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }), required: true, }, + column: { + show: false, + component: { + color: "auto", + }, + }, }, dnsProviderAccess: { title: t("certd.domain.dnsProviderAccess"), - type: "text", + type: "dict-select", + dict: accessDict, form: { component: { name: "AccessSelector", @@ -136,10 +166,16 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }), required: true, }, + column: { + show: false, + component: { + color: "auto", + }, + }, }, httpUploaderType: { title: t("certd.domain.httpUploaderType"), - type: "dict-text", + type: "dict-select", dict: Dicts.uploaderTypeDict, form: { show: compute(({ form }) => { @@ -147,6 +183,12 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }), required: true, }, + column: { + show: false, + component: { + color: "auto", + }, + }, }, httpUploaderAccess: { title: t("certd.domain.httpUploaderAccess"), @@ -160,6 +202,12 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }), required: true, }, + column: { + show: false, + component: { + color: "auto", + }, + }, }, httpUploadRootDir: { title: t("certd.domain.httpUploadRootDir"), @@ -170,14 +218,47 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }), required: true, }, + column: { + show: false, + component: { + color: "auto", + }, + }, + }, + challengeSetting: { + title: "校验配置", + type: "text", + form: { show: false }, + column: { + width: 400, + conditionalRender: false, + cellRender({ row }) { + if (row.challengeType === "dns") { + return ( +
+ + +
+ ); + } else if (row.challengeType === "http") { + return ( +
+ + + {row.httpUploadRootDir} +
+ ); + } + }, + }, }, disabled: { title: t("certd.domain.disabled"), type: "dict-switch", dict: dict({ data: [ - { label: "启用", value: false }, - { label: "禁用", value: true }, + { label: "启用", value: false, color: "green" }, + { label: "禁用", value: true, color: "red" }, ], }), form: { @@ -185,7 +266,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat required: true, }, column: { - width: 80, + width: 100, + sorter: true, }, }, createTime: { diff --git a/packages/ui/certd-server/src/controller/user/pipeline/access-controller.ts b/packages/ui/certd-server/src/controller/user/pipeline/access-controller.ts index cfde0533..5be35bab 100644 --- a/packages/ui/certd-server/src/controller/user/pipeline/access-controller.ts +++ b/packages/ui/certd-server/src/controller/user/pipeline/access-controller.ts @@ -101,4 +101,10 @@ export class AccessController extends CrudController { const res = await this.service.getSimpleInfo(id); return this.ok(res); } + + @Post('/getDictByIds', { summary: Constants.per.authOnly }) + async getDictByIds(@Body('ids') ids: number[]) { + const res = await this.service.getSimpleByIds(ids, this.getUserId()); + return this.ok(res); + } } From 902d246d1a7473ad90f604028c4eb09c8c67d99c Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sun, 13 Jul 2025 17:10:15 +0800 Subject: [PATCH 13/34] =?UTF-8?q?perf:=20=E9=83=A8=E7=BD=B2plesk=E8=AF=81?= =?UTF-8?q?=E4=B9=A6=EF=BC=8C=E6=94=AF=E6=8C=81=E5=88=A0=E9=99=A4=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=E8=AF=81=E4=B9=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 185 +++++++++++++++---------------------------------- 2 files changed, 56 insertions(+), 130 deletions(-) diff --git a/package.json b/package.json index 47358de2..e104b7ae 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ }, "license": "AGPL-3.0", "dependencies": { + "@certd/ui-server": "link:packages/ui/certd-server", "axios": "^1.7.7", "copyfiles": "^2.4.1", "lodash-es": "^4.17.21", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84e984dc..85458174 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,10 +4,16 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + '@certd/ui-server': link:packages/ui/certd-server + importers: .: dependencies: + '@certd/ui-server': + specifier: link:packages/ui/certd-server + version: link:packages/ui/certd-server axios: specifier: ^1.7.7 version: 1.9.0(debug@4.4.1) @@ -46,7 +52,7 @@ importers: packages/core/acme-client: dependencies: '@certd/basic': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../basic '@peculiar/x509': specifier: ^1.11.0 @@ -207,11 +213,11 @@ importers: packages/core/pipeline: dependencies: '@certd/basic': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../basic '@certd/plus-core': - specifier: ^1.36.1 - version: 1.36.1 + specifier: ^1.36.5 + version: link:../../pro/plus-core dayjs: specifier: ^1.11.7 version: 1.11.13 @@ -415,7 +421,7 @@ importers: packages/libs/lib-k8s: dependencies: '@certd/basic': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/basic '@kubernetes/client-node': specifier: 0.21.0 @@ -455,17 +461,17 @@ importers: packages/libs/lib-server: dependencies: '@certd/acme-client': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/acme-client '@certd/basic': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/basic '@certd/pipeline': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/pipeline '@certd/plus-core': - specifier: ^1.36.1 - version: 1.36.1 + specifier: ^1.36.5 + version: link:../../pro/plus-core '@midwayjs/cache': specifier: ~3.14.0 version: 3.14.0 @@ -607,16 +613,16 @@ importers: packages/plugins/plugin-cert: dependencies: '@certd/acme-client': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/acme-client '@certd/basic': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/basic '@certd/pipeline': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/pipeline '@certd/plugin-lib': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../plugin-lib '@google-cloud/publicca': specifier: ^1.3.0 @@ -698,10 +704,10 @@ importers: specifier: ^3.787.0 version: 3.810.0(aws-crt@1.26.2) '@certd/basic': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/basic '@certd/pipeline': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/pipeline '@kubernetes/client-node': specifier: 0.21.0 @@ -789,19 +795,19 @@ importers: packages/pro/commercial-core: dependencies: '@certd/basic': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../../core/basic '@certd/lib-server': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../../libs/lib-server '@certd/pipeline': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../../core/pipeline '@certd/plugin-plus': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../plugin-plus '@certd/plus-core': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../plus-core '@midwayjs/core': specifier: ~3.20.3 @@ -886,22 +892,22 @@ importers: specifier: ^1.0.2 version: 1.0.3 '@certd/basic': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../../core/basic '@certd/lib-k8s': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../../libs/lib-k8s '@certd/pipeline': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../../core/pipeline '@certd/plugin-cert': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../../plugins/plugin-cert '@certd/plugin-lib': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../../plugins/plugin-lib '@certd/plus-core': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../plus-core ali-oss: specifier: ^6.21.0 @@ -1004,7 +1010,7 @@ importers: packages/pro/plus-core: dependencies: '@certd/basic': - specifier: ^1.36.1 + specifier: ^1.36.5 version: link:../../core/basic dayjs: specifier: ^1.11.7 @@ -1294,10 +1300,10 @@ importers: version: 0.1.3(zod@3.24.4) devDependencies: '@certd/lib-iframe': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../libs/lib-iframe '@certd/pipeline': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/pipeline '@rollup/plugin-commonjs': specifier: ^25.0.7 @@ -1480,47 +1486,47 @@ importers: specifier: ^3.705.0 version: 3.810.0(aws-crt@1.26.2) '@certd/acme-client': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/acme-client '@certd/basic': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/basic '@certd/commercial-core': - specifier: ^1.36.1 - version: 1.36.1(better-sqlite3@11.10.0)(encoding@0.1.13)(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)) + specifier: ^1.36.5 + version: link:../../pro/commercial-core '@certd/cv4pve-api-javascript': specifier: ^8.4.1 version: 8.4.1 '@certd/jdcloud': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../libs/lib-jdcloud '@certd/lib-huawei': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../libs/lib-huawei '@certd/lib-k8s': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../libs/lib-k8s '@certd/lib-server': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../libs/lib-server '@certd/midway-flyway-js': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../libs/midway-flyway-js '@certd/pipeline': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../core/pipeline '@certd/plugin-cert': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../plugins/plugin-cert '@certd/plugin-lib': - specifier: ^1.36.2 + specifier: ^1.36.5 version: link:../../plugins/plugin-lib '@certd/plugin-plus': - specifier: ^1.36.1 - version: 1.36.1(encoding@0.1.13) + specifier: ^1.36.5 + version: link:../../pro/plugin-plus '@certd/plus-core': - specifier: ^1.36.1 - version: 1.36.1 + specifier: ^1.36.5 + version: link:../../pro/plus-core '@huaweicloud/huaweicloud-sdk-cdn': specifier: ^3.1.120 version: 3.1.149 @@ -2760,18 +2766,9 @@ packages: '@better-scroll/zoom@2.5.1': resolution: {integrity: sha512-aGvFY5ooeZWS4RcxQLD+pGLpQHQxpPy0sMZV3yadcd2QK53PK9gS4Dp+BYfRv8lZ4/P2LoNEhr6Wq1DN6+uPlA==} - '@certd/commercial-core@1.36.1': - resolution: {integrity: sha512-CpZ7K7s0JoXJ8MD3FyeryKnA62fvX3DKVQ7XkSSomaqgH/a8DgP4QrJGrt2ytIYtu2SzJvJsBfy14UhVM6174Q==} - '@certd/cv4pve-api-javascript@8.4.1': resolution: {integrity: sha512-jxlRieJmCA0Z9LnwX6Ra6ZekRGJEu8o8RGYoKU0Jjkhc9jm6ChEbVyfE7Iw49/hlpA+2yaHdAXb46au/afCISg==} - '@certd/plugin-plus@1.36.1': - resolution: {integrity: sha512-Bd3tFwn/jDrpSWqUH9488YxFHnEIGI15NFoqQaLv58L+Ycm7mRbyTUC/S3xpiUkfhDI6wqvKL8SOtdpgo0IEzA==} - - '@certd/plus-core@1.36.1': - resolution: {integrity: sha512-TiRpqWCC7RGJxmVaDkSkMAFYe2zehRqZFKmNcfG8DZJTgKpQhd98HvXlyXCJD5qUtPmyvFoffTD1Q8bGqN84Vw==} - '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -15447,84 +15444,12 @@ snapshots: dependencies: '@better-scroll/core': 2.5.1 - '@certd/commercial-core@1.36.1(better-sqlite3@11.10.0)(encoding@0.1.13)(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))': - dependencies: - '@certd/basic': link:packages/core/basic - '@certd/lib-server': link:packages/libs/lib-server - '@certd/pipeline': link:packages/core/pipeline - '@certd/plugin-plus': 1.36.1(encoding@0.1.13) - '@certd/plus-core': 1.36.1 - '@midwayjs/core': 3.20.4 - '@midwayjs/koa': 3.20.5 - '@midwayjs/logger': 3.4.2 - '@midwayjs/typeorm': 3.20.4 - alipay-sdk: 4.14.0 - dayjs: 1.11.13 - typeorm: 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)) - wechatpay-node-v3: 2.2.1 - transitivePeerDependencies: - - '@google-cloud/spanner' - - '@sap/hana-client' - - babel-plugin-macros - - better-sqlite3 - - encoding - - hdb-pool - - ioredis - - mongodb - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - - proxy-agent - - redis - - reflect-metadata - - sql.js - - sqlite3 - - supports-color - - ts-node - - typeorm-aurora-data-api-driver - '@certd/cv4pve-api-javascript@8.4.1': dependencies: debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@certd/plugin-plus@1.36.1(encoding@0.1.13)': - dependencies: - '@alicloud/pop-core': 1.8.0 - '@baiducloud/sdk': 1.0.3 - '@certd/basic': link:packages/core/basic - '@certd/lib-k8s': link:packages/libs/lib-k8s - '@certd/pipeline': link:packages/core/pipeline - '@certd/plugin-cert': link:packages/plugins/plugin-cert - '@certd/plugin-lib': link:packages/plugins/plugin-lib - '@certd/plus-core': 1.36.1 - ali-oss: 6.23.0 - baidu-aip-sdk: 4.16.16 - basic-ftp: 5.0.5 - cos-nodejs-sdk-v5: 2.14.7 - crypto-js: 4.2.0 - dayjs: 1.11.13 - form-data: 4.0.2 - https-proxy-agent: 7.0.6 - js-yaml: 4.1.0 - jsencrypt: 3.3.2 - jsrsasign: 11.1.0 - qiniu: 7.14.0 - tencentcloud-sdk-nodejs: 4.1.37(encoding@0.1.13) - transitivePeerDependencies: - - encoding - - proxy-agent - - supports-color - - '@certd/plus-core@1.36.1': - dependencies: - '@certd/basic': link:packages/core/basic - dayjs: 1.11.13 - '@colors/colors@1.5.0': optional: true @@ -21599,13 +21524,13 @@ snapshots: resolve: 1.22.10 semver: 6.3.1 - eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8): + eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8): dependencies: eslint: 7.32.0 prettier: 2.8.8 prettier-linter-helpers: 1.0.0 optionalDependencies: - eslint-config-prettier: 8.10.0(eslint@8.57.0) + eslint-config-prettier: 8.10.0(eslint@7.32.0) eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8): dependencies: @@ -24313,7 +24238,7 @@ snapshots: eslint: 7.32.0 eslint-config-prettier: 8.10.0(eslint@7.32.0) eslint-plugin-node: 11.1.0(eslint@7.32.0) - eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8) + eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8) execa: 5.1.1 inquirer: 7.3.3 json5: 2.2.3 From 3f9943270cfb12946e38e6272bc5e8d95ad6ab9e Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sun, 13 Jul 2025 18:25:09 +0800 Subject: [PATCH 14/34] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E9=80=89=E6=8B=A9=E6=A0=A1=E9=AA=8C=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E7=94=B3=E8=AF=B7=E8=AF=81=E4=B9=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin-cert/src/dns-provider/api.ts | 10 +- .../src/plugin/cert-plugin/acme.ts | 30 +-- .../src/plugin/cert-plugin/index.ts | 208 +++++++++--------- .../user/pipeline/sub-domain-controller.ts | 3 +- .../modules/cert/service/domain-service.ts | 101 ++++++++- .../{ => getter}/cname-proxy-service.ts | 0 .../service/getter/domain-verifier-getter.ts | 17 ++ .../{ => getter}/notification-getter.ts | 2 +- .../service/getter/sub-domain-getter.ts | 17 ++ .../service/getter/task-service-getter.ts | 81 +++++++ .../pipeline/service/pipeline-service.ts | 2 +- .../pipeline/service/sub-domain-service.ts | 19 -- .../pipeline/service/task-service-getter.ts | 63 ------ 13 files changed, 341 insertions(+), 212 deletions(-) rename packages/ui/certd-server/src/modules/pipeline/service/{ => getter}/cname-proxy-service.ts (100%) create mode 100644 packages/ui/certd-server/src/modules/pipeline/service/getter/domain-verifier-getter.ts rename packages/ui/certd-server/src/modules/pipeline/service/{ => getter}/notification-getter.ts (91%) create mode 100644 packages/ui/certd-server/src/modules/pipeline/service/getter/sub-domain-getter.ts create mode 100644 packages/ui/certd-server/src/modules/pipeline/service/getter/task-service-getter.ts delete mode 100644 packages/ui/certd-server/src/modules/pipeline/service/task-service-getter.ts diff --git a/packages/plugins/plugin-cert/src/dns-provider/api.ts b/packages/plugins/plugin-cert/src/dns-provider/api.ts index a8817c21..b3d87be3 100644 --- a/packages/plugins/plugin-cert/src/dns-provider/api.ts +++ b/packages/plugins/plugin-cert/src/dns-provider/api.ts @@ -73,18 +73,22 @@ export type CnameVerifier = { export type HttpVerifier = { // http校验 httpUploaderType: string; - httpUploaderAccess: string; + httpUploaderAccess: number; httpUploadRootDir: string; }; export type DomainVerifier = { domain: string; mainDomain: string; - challengeType: string; + type: string; dns?: DnsVerifier; cname?: CnameVerifier; http?: HttpVerifier; }; +export type DomainVerifiers = { + [key: string]: DomainVerifier; +}; + export interface IDomainVerifierGetter { - getVerifiers(domains: string[]): Promise; + getVerifiers(domains: string[]): Promise; } 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 c12a8d08..9e4c095c 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts @@ -23,10 +23,11 @@ export type HttpVerifyPlan = { export type DomainVerifyPlan = { domain: string; + mainDomain: string; type: "cname" | "dns" | "http"; dnsProvider?: IDnsProvider; - cnameVerifyPlan?: Record; - httpVerifyPlan?: Record; + cnameVerifyPlan?: CnameVerifyPlan; + httpVerifyPlan?: HttpVerifyPlan; }; export type DomainsVerifyPlan = { [key: string]: DomainVerifyPlan; @@ -233,23 +234,20 @@ export class AcmeService { let dnsProvider = providers.dnsProvider; let fullRecord = `_acme-challenge.${fullDomain}`; - const origDomain = punycode.toUnicode(domain); + // const origDomain = punycode.toUnicode(domain); const origFullDomain = punycode.toUnicode(fullDomain); if (providers.domainsVerifyPlan) { //按照计划执行 - const domainVerifyPlan = providers.domainsVerifyPlan[origDomain]; + const domainVerifyPlan = providers.domainsVerifyPlan[origFullDomain]; if (domainVerifyPlan) { if (domainVerifyPlan.type === "dns") { dnsProvider = domainVerifyPlan.dnsProvider; } else if (domainVerifyPlan.type === "cname") { - const cnameVerifyPlan = domainVerifyPlan.cnameVerifyPlan; - if (cnameVerifyPlan) { - const cname = cnameVerifyPlan[origFullDomain]; - if (cname) { - dnsProvider = cname.dnsProvider; - domain = await this.options.domainParser.parse(cname.domain); - fullRecord = cname.fullRecord; - } + const cname: CnameVerifyPlan = domainVerifyPlan.cnameVerifyPlan; + if (cname) { + dnsProvider = cname.dnsProvider; + domain = await this.options.domainParser.parse(cname.domain); + fullRecord = cname.fullRecord; } else { this.logger.error(`未找到域名${fullDomain}的CNAME校验计划,请修改证书申请配置`); } @@ -257,13 +255,12 @@ export class AcmeService { throw new Error(`未找到域名${fullDomain}CNAME校验计划的DnsProvider,请修改证书申请配置`); } } else if (domainVerifyPlan.type === "http") { - const httpVerifyPlan = domainVerifyPlan.httpVerifyPlan; - if (httpVerifyPlan) { + const plan: HttpVerifyPlan = domainVerifyPlan.httpVerifyPlan; + if (plan) { const httpChallenge = getChallenge("http-01"); if (httpChallenge == null) { throw new Error("该域名不支持http-01方式校验"); } - const plan = httpVerifyPlan[fullDomain]; return await doHttpVerify(httpChallenge, plan.httpUploader); } else { throw new Error("未找到域名【" + fullDomain + "】的http校验配置"); @@ -275,6 +272,9 @@ export class AcmeService { this.logger.info("未找到域名校验计划,使用默认的dnsProvider"); } } + if (!dnsProvider) { + this.logger.error("dnsProvider不存在,无法申请证书"); + } const dnsChallenge = getChallenge("dns-01"); return await doDnsVerify(dnsChallenge, fullRecord, dnsProvider); 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 b08c74b7..3c654340 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -1,16 +1,16 @@ import { CancelError, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; import { utils } from "@certd/basic"; -import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, HttpVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js"; -import { AcmeService } from "./acme.js"; +import { AcmeService, CertInfo, DomainsVerifyPlan, DomainVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js"; import * as _ from "lodash-es"; -import { createDnsProvider, DnsProviderContext, DomainVerifier, IDnsProvider, IDomainVerifierGetter, ISubDomainsGetter } from "../../dns-provider/index.js"; +import { createDnsProvider, DnsProviderContext, DnsVerifier, DomainVerifiers, HttpVerifier, IDnsProvider, IDomainVerifierGetter, ISubDomainsGetter } from "../../dns-provider/index.js"; import { CertReader } from "./cert-reader.js"; import { CertApplyBasePlugin } from "./base.js"; import { GoogleClient } from "../../libs/google.js"; import { EabAccess } from "../../access"; import { DomainParser } from "../../dns-provider/domain-parser.js"; import { ossClientFactory } from "@certd/plugin-lib"; + export * from "./base.js"; export type { CertInfo }; export * from "./cert-reader.js"; @@ -335,6 +335,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { acme!: AcmeService; eab!: EabAccess; + async onInit() { let eab: EabAccess = null; @@ -410,11 +411,9 @@ export class CertApplyPlugin extends CertApplyBasePlugin { let dnsProvider: IDnsProvider = null; let domainsVerifyPlan: DomainsVerifyPlan = null; if (this.challengeType === "cname" || this.challengeType === "http" || this.challengeType === "dnses") { - domainsVerifyPlan = await this.createDomainsVerifyPlan(this.domainsVerifyPlan); - } - if (this.challengeType === "auto") { - const planInput = await this.buildVerifyPlanInputByAuto(); - domainsVerifyPlan = await this.createDomainsVerifyPlan(planInput); + domainsVerifyPlan = await this.createDomainsVerifyPlan(domains, this.domainsVerifyPlan); + } else if (this.challengeType === "auto") { + domainsVerifyPlan = await this.createDomainsVerifyPlanByAuto(domains); } else { const dnsProviderType = this.dnsProviderType; const access = await this.getAccess(this.dnsProviderAccess); @@ -450,75 +449,39 @@ export class CertApplyPlugin extends CertApplyBasePlugin { async createDnsProvider(dnsProviderType: string, dnsProviderAccess: any): Promise { const domainParser = this.acme.options.domainParser; - const context: DnsProviderContext = { access: dnsProviderAccess, logger: this.logger, http: this.ctx.http, utils, domainParser }; + const context: DnsProviderContext = { + access: dnsProviderAccess, + logger: this.logger, + http: this.ctx.http, + utils, + domainParser, + }; return await createDnsProvider({ dnsProviderType, context, }); } - async createDomainsVerifyPlan(verifyPlanSetting: DomainsVerifyPlanInput): Promise { + async createDomainsVerifyPlan(domains: string[], verifyPlanSetting: DomainsVerifyPlanInput): Promise { const plan: DomainsVerifyPlan = {}; - for (const domain in verifyPlanSetting) { - const domainVerifyPlan = verifyPlanSetting[domain]; - let dnsProvider = null; - const cnameVerifyPlan: Record = {}; - const httpVerifyPlan: Record = {}; - if (domainVerifyPlan.type === "dns") { - const access = await this.getAccess(domainVerifyPlan.dnsProviderAccessId); - dnsProvider = await this.createDnsProvider(domainVerifyPlan.dnsProviderType, access); - } else if (domainVerifyPlan.type === "cname") { - for (const key in domainVerifyPlan.cnameVerifyPlan) { - const cnameRecord = await this.ctx.cnameProxyService.getByDomain(key); - let dnsProvider = cnameRecord.commonDnsProvider; - if (cnameRecord.cnameProvider.id > 0) { - dnsProvider = await this.createDnsProvider(cnameRecord.cnameProvider.dnsProviderType, cnameRecord.cnameProvider.access); - } - cnameVerifyPlan[key] = { - type: "cname", - domain: cnameRecord.cnameProvider.domain, - fullRecord: cnameRecord.recordValue, - dnsProvider, - }; - } - } else if (domainVerifyPlan.type === "http") { - const httpUploaderContext = { - accessService: this.ctx.accessService, - logger: this.logger, - utils, - }; - for (const key in domainVerifyPlan.httpVerifyPlan) { - const httpRecord = domainVerifyPlan.httpVerifyPlan[key]; - const access = await this.getAccess(httpRecord.httpUploaderAccess); - let rootDir = httpRecord.httpUploadRootDir; - if (!rootDir.endsWith("/") && !rootDir.endsWith("\\")) { - rootDir = rootDir + "/"; - } - this.logger.info("上传方式", httpRecord.httpUploaderType); - const httpUploader = await ossClientFactory.createOssClientByType(httpRecord.httpUploaderType, { - access, - rootDir: rootDir, - ctx: httpUploaderContext, - }); - httpVerifyPlan[key] = { - type: "http", - domain: key, - httpUploader, - }; - } + + const domainParser = this.acme.options.domainParser; + for (const fullDomain of domains) { + const domain = fullDomain.replaceAll("*.", ""); + const mainDomain = await domainParser.parse(domain); + const planSetting = verifyPlanSetting[mainDomain]; + if (planSetting.type === "dns") { + await this.createDnsDomainVerifyPlan(planSetting[mainDomain], domain, mainDomain); + } else if (planSetting.type === "cname") { + await this.createCnameDomainVerifyPlan(domain, mainDomain); + } else if (planSetting.type === "http") { + await this.createHttpDomainVerifyPlan(planSetting.httpVerifyPlan[domain], domain, mainDomain); } - plan[domain] = { - domain, - type: domainVerifyPlan.type, - dnsProvider, - cnameVerifyPlan, - httpVerifyPlan, - }; } return plan; } - private async buildVerifyPlanInputByAuto() { + private async createDomainsVerifyPlanByAuto(domains: string[]) { //从数据库里面自动选择校验方式 // domain list const domainList = new Set(); @@ -527,55 +490,84 @@ export class CertApplyPlugin extends CertApplyBasePlugin { domain = domain.replaceAll("*.", ""); domainList.add(domain); } - const domainVerifierGetter: IDomainVerifierGetter = await this.ctx.serviceGetter.get("DomainVerifierGetter"); + const domainVerifierGetter: IDomainVerifierGetter = await this.ctx.serviceGetter.get("domainVerifierGetter"); - const verifiers = await domainVerifierGetter.getVerifiers([...domainList]); + const verifiers: DomainVerifiers = await domainVerifierGetter.getVerifiers([...domainList]); - const verifyPlanInput: DomainsVerifyPlanInput = {}; + const plan: DomainsVerifyPlan = {}; - for (const verifier of verifiers) { - const domain = verifier.domain; - const mainDomain = verifier.mainDomain; - let plan = verifyPlanInput[mainDomain]; - if (!plan) { - plan = { - domain: mainDomain, - type: "cname", - }; - verifyPlanInput[mainDomain] = plan; - } - if (verifier.challengeType === "cname") { - verifyPlanInput[domain] = { - type: "cname", - domain: domain, - cnameVerifyPlan: { - [domain]: { - id: 0, - status: "validate", - }, - }, - }; - } else if (verifier.challengeType === "http") { - //http - const http = verifier.http; - verifyPlanInput[domain] = { - type: "http", - domain: domain, - httpVerifyPlan: { - [domain]: { - domain: domain, - httpUploaderType: http.httpUploaderType, - httpUploaderAccess: http.httpUploaderAccess, - httpUploadRootDir: http.httpUploadRootDir, - }, - }, - }; - } else { - //dns + for (const domain in verifiers) { + const verifier = verifiers[domain]; + if (verifier.type === "dns") { + plan[domain] = await this.createDnsDomainVerifyPlan(verifier.dns, domain, verifier.mainDomain); + } else if (verifier.type === "cname") { + plan[domain] = await this.createCnameDomainVerifyPlan(domain, verifier.mainDomain); + } else if (verifier.type === "http") { + plan[domain] = await this.createHttpDomainVerifyPlan(verifier.http, domain, verifier.mainDomain); } } + return plan; + } - return verifyPlanInput; + private async createDnsDomainVerifyPlan(planSetting: DnsVerifier, domain: string, mainDomain: string): Promise { + const access = await this.getAccess(planSetting.dnsProviderAccessId); + return { + type: "dns", + mainDomain, + domain, + dnsProvider: await this.createDnsProvider(planSetting.dnsProviderType, access), + }; + } + + private async createHttpDomainVerifyPlan(httpSetting: HttpVerifier, domain: string, mainDomain: string): Promise { + const httpUploaderContext = { + accessService: this.ctx.accessService, + logger: this.logger, + utils, + }; + + const access = await this.getAccess(httpSetting.httpUploaderAccess); + let rootDir = httpSetting.httpUploadRootDir; + if (!rootDir.endsWith("/") && !rootDir.endsWith("\\")) { + rootDir = rootDir + "/"; + } + this.logger.info("上传方式", httpSetting.httpUploaderType); + const httpUploader = await ossClientFactory.createOssClientByType(httpSetting.httpUploaderType, { + access, + rootDir: rootDir, + ctx: httpUploaderContext, + }); + return { + type: "http", + domain, + mainDomain, + httpVerifyPlan: { + type: "http", + domain, + httpUploader, + }, + }; + } + + private async createCnameDomainVerifyPlan(domain: string, mainDomain: string): Promise { + const cnameRecord = await this.ctx.cnameProxyService.getByDomain(domain); + if (cnameRecord == null) { + throw new Error(`请先配置${domain}的CNAME记录,并通过校验`); + } + let dnsProvider = cnameRecord.commonDnsProvider; + if (cnameRecord.cnameProvider.id > 0) { + dnsProvider = await this.createDnsProvider(cnameRecord.cnameProvider.dnsProviderType, cnameRecord.cnameProvider.access); + } + return { + type: "cname", + domain, + mainDomain, + cnameVerifyPlan: { + domain, + fullRecord: cnameRecord.recordValue, + dnsProvider, + }, + }; } } diff --git a/packages/ui/certd-server/src/controller/user/pipeline/sub-domain-controller.ts b/packages/ui/certd-server/src/controller/user/pipeline/sub-domain-controller.ts index c94b0ecd..76dae741 100644 --- a/packages/ui/certd-server/src/controller/user/pipeline/sub-domain-controller.ts +++ b/packages/ui/certd-server/src/controller/user/pipeline/sub-domain-controller.ts @@ -1,7 +1,8 @@ import {ALL, Body, Controller, Inject, Post, Provide, Query} from '@midwayjs/core'; import {Constants, CrudController} from '@certd/lib-server'; -import {SubDomainService, SubDomainsGetter} from "../../../modules/pipeline/service/sub-domain-service.js"; +import {SubDomainService} from "../../../modules/pipeline/service/sub-domain-service.js"; import {DomainParser} from '@certd/plugin-cert/dist/dns-provider/domain-parser.js'; +import { SubDomainsGetter } from '../../../modules/pipeline/service/getter/sub-domain-getter.js'; /** * 子域名托管 diff --git a/packages/ui/certd-server/src/modules/cert/service/domain-service.ts b/packages/ui/certd-server/src/modules/cert/service/domain-service.ts index ed99159a..58c1146e 100644 --- a/packages/ui/certd-server/src/modules/cert/service/domain-service.ts +++ b/packages/ui/certd-server/src/modules/cert/service/domain-service.ts @@ -1,8 +1,12 @@ import {Inject, Provide, Scope, ScopeEnum} from '@midwayjs/core'; import {InjectEntityModel} from '@midwayjs/typeorm'; -import {Not, Repository} from 'typeorm'; +import {In, Not, Repository} from 'typeorm'; import {AccessService, BaseService} from '@certd/lib-server'; import {DomainEntity} from '../entity/domain.js'; +import {SubDomainService} from "../../pipeline/service/sub-domain-service.js"; +import {DomainParser} from "@certd/plugin-cert/dist/dns-provider/domain-parser.js"; +import {DomainVerifiers} from "@certd/plugin-cert"; +import { SubDomainsGetter } from '../../pipeline/service/getter/sub-domain-getter.js'; /** @@ -16,6 +20,8 @@ export class DomainService extends BaseService { @Inject() accessService: AccessService; + @Inject() + subDomainService: SubDomainService; //@ts-ignore getRepository() { @@ -67,4 +73,97 @@ export class DomainService extends BaseService { } + /** + * + * @param userId + * @param domains //去除* 且去重之后的域名列表 + */ + async getDomainVerifiers(userId: number, domains: string[]):Promise { + + const mainDomainMap:Record = {} + const subDomainGetter = new SubDomainsGetter(userId, this.subDomainService) + const domainParser = new DomainParser(subDomainGetter) + + const mainDomains = [] + for (const domain of domains) { + const mainDomain = await domainParser.parse(domain); + mainDomainMap[domain] = mainDomain; + mainDomains.push(mainDomain) + } + + //匹配DNS记录 + let allDomains = [...domains,...mainDomains] + //去重 + allDomains = [...new Set(allDomains)] + + const domainRecords = await this.find({ + where: { + domain: In(allDomains), + userId + } + }) + + const dnsMap = domainRecords.filter(item=>item.challengeType === 'dns').reduce((pre, item) => { + pre[item.domain] = item + return pre + }, {}) + const cnameMap = domainRecords.filter(item=>item.challengeType === 'cname').reduce((pre, item) => { + pre[item.domain] = item + return pre + }, {}) + const httpMap = domainRecords.filter(item=>item.challengeType === 'http').reduce((pre, item) => { + pre[item.domain] = item + return pre + }, {}) + + + const domainVerifiers:DomainVerifiers = {} + + for (const domain of domains) { + const mainDomain = mainDomainMap[domain] + + const dnsRecord = dnsMap[mainDomain] + if (dnsRecord) { + domainVerifiers[domain] = { + domain, + mainDomain, + type: 'dns', + dns: { + dnsProviderType: dnsRecord.dnsProviderType, + dnsProviderAccessId: dnsRecord.dnsProviderAccessId + } + } + continue + } + const cnameRecord = cnameMap[mainDomain] + if (cnameRecord) { + domainVerifiers[domain] = { + domain, + mainDomain, + type: 'cname', + cname: { + cnameRecord: cnameRecord.cnameRecord + } + } + continue + } + const httpRecord = httpMap[mainDomain] + if (httpRecord) { + domainVerifiers[domain] = { + domain, + mainDomain, + type: 'http', + http: { + httpUploaderType: httpRecord.httpUploaderType, + httpUploaderAccess: httpRecord.httpUploaderAccess, + httpUploadRootDir: httpRecord.httpUploadRootDir + } + } + continue + } + domainVerifiers[domain] = null + } + + return domainVerifiers; + } } diff --git a/packages/ui/certd-server/src/modules/pipeline/service/cname-proxy-service.ts b/packages/ui/certd-server/src/modules/pipeline/service/getter/cname-proxy-service.ts similarity index 100% rename from packages/ui/certd-server/src/modules/pipeline/service/cname-proxy-service.ts rename to packages/ui/certd-server/src/modules/pipeline/service/getter/cname-proxy-service.ts diff --git a/packages/ui/certd-server/src/modules/pipeline/service/getter/domain-verifier-getter.ts b/packages/ui/certd-server/src/modules/pipeline/service/getter/domain-verifier-getter.ts new file mode 100644 index 00000000..36744759 --- /dev/null +++ b/packages/ui/certd-server/src/modules/pipeline/service/getter/domain-verifier-getter.ts @@ -0,0 +1,17 @@ +import {DomainVerifiers, IDomainVerifierGetter} from "@certd/plugin-cert"; +import {DomainService} from "../../../cert/service/domain-service.js"; + +export class DomainVerifierGetter implements IDomainVerifierGetter { + private userId: number; + private domainService: DomainService; + + constructor(userId: number, domainService: DomainService) { + this.userId = userId; + this.domainService = domainService; + } + + async getVerifiers(domains: string[]): Promise{ + return await this.domainService.getDomainVerifiers(this.userId,domains); + } + +} diff --git a/packages/ui/certd-server/src/modules/pipeline/service/notification-getter.ts b/packages/ui/certd-server/src/modules/pipeline/service/getter/notification-getter.ts similarity index 91% rename from packages/ui/certd-server/src/modules/pipeline/service/notification-getter.ts rename to packages/ui/certd-server/src/modules/pipeline/service/getter/notification-getter.ts index 609d536c..691608ad 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/notification-getter.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/getter/notification-getter.ts @@ -1,5 +1,5 @@ import { INotificationService, NotificationSendReq } from '@certd/pipeline'; -import { NotificationService } from './notification-service.js'; +import {NotificationService} from "../notification-service.js"; export class NotificationGetter implements INotificationService { userId: number; diff --git a/packages/ui/certd-server/src/modules/pipeline/service/getter/sub-domain-getter.ts b/packages/ui/certd-server/src/modules/pipeline/service/getter/sub-domain-getter.ts new file mode 100644 index 00000000..4878aed0 --- /dev/null +++ b/packages/ui/certd-server/src/modules/pipeline/service/getter/sub-domain-getter.ts @@ -0,0 +1,17 @@ +import {ISubDomainsGetter} from "@certd/plugin-cert"; +import {SubDomainService} from "../service/sub-domain-service.js"; + +export class SubDomainsGetter implements ISubDomainsGetter { + userId: number; + subDomainService: SubDomainService; + + constructor(userId: number, subDomainService: SubDomainService) { + this.userId = userId; + this.subDomainService = subDomainService; + } + + async getSubDomains() { + return await this.subDomainService.getListByUserId(this.userId) + } + +} diff --git a/packages/ui/certd-server/src/modules/pipeline/service/getter/task-service-getter.ts b/packages/ui/certd-server/src/modules/pipeline/service/getter/task-service-getter.ts new file mode 100644 index 00000000..006018da --- /dev/null +++ b/packages/ui/certd-server/src/modules/pipeline/service/getter/task-service-getter.ts @@ -0,0 +1,81 @@ +import {IServiceGetter} from "@certd/pipeline"; +import {Inject, Provide, Scope, ScopeEnum} from "@midwayjs/core"; +import {SubDomainService} from "../sub-domain-service.js"; +import {AccessGetter, AccessService} from "@certd/lib-server"; +import {CnameProxyService} from "./cname-proxy-service.js"; +import {NotificationGetter} from "./notification-getter.js"; +import {NotificationService} from "../notification-service.js"; +import {CnameRecordService} from "../../../cname/service/cname-record-service.js"; +import {SubDomainsGetter} from './sub-domain-getter.js' +import {DomainVerifierGetter} from "./domain-verifier-getter.js"; +import {Context} from "@midwayjs/koa"; +import {DomainService} from "../../../cert/service/domain-service.js"; + +export class TaskServiceGetter implements IServiceGetter{ + private userId: number; + private ctx : Context; + constructor(userId:number,ctx:Context) { + this.userId = userId; + this.ctx = ctx + } + async get(serviceName: string): Promise { + + if(serviceName === 'subDomainsGetter'){ + return await this.getSubDomainsGetter() as T + } if (serviceName === 'accessService') { + return await this.getAccessService() as T + } else if (serviceName === 'cnameProxyService') { + return await this.getCnameProxyService() as T + } else if (serviceName === 'notificationService') { + return await this.getNotificationService() as T + } else if (serviceName === 'domainVerifierGetter') { + return await this.getDomainVerifierGetter() as T + }else{ + throw new Error(`service ${serviceName} not found`) + } + } + + async getSubDomainsGetter(): Promise { + const subDomainsService = await this.ctx.requestContext.getAsync("subDomainService") + return new SubDomainsGetter(this.userId, subDomainsService) + } + + async getAccessService(): Promise { + const accessService:AccessService = await this.ctx.requestContext.getAsync("accessService") + return new AccessGetter(this.userId, accessService.getById.bind(accessService)); + } + + async getCnameProxyService(): Promise { + const cnameRecordService:CnameRecordService = await this.ctx.requestContext.getAsync("cnameRecordService") + return new CnameProxyService(this.userId, cnameRecordService.getWithAccessByDomain.bind(cnameRecordService)); + } + + async getNotificationService(): Promise { + const notificationService:NotificationService = await this.ctx.requestContext.getAsync("notificationService") + return new NotificationGetter(this.userId, notificationService); + } + + async getDomainVerifierGetter(): Promise { + const domainService:DomainService = await this.ctx.requestContext.getAsync("domainService") + return new DomainVerifierGetter(this.userId, domainService); + } +} +export type TaskServiceCreateReq = { + userId: number; +} + +@Provide() +@Scope(ScopeEnum.Request, { allowDowngrade: true }) +export class TaskServiceBuilder { + @Inject() + ctx: Context; + + create(req:TaskServiceCreateReq){ + const userId = req.userId; + return new TaskServiceGetter(userId,this.ctx) + } +} + + + + 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 363d33e6..f9cc2b51 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 @@ -44,7 +44,7 @@ import {UrlService} from "./url-service.js"; import {NotificationService} from "./notification-service.js"; import {UserSuiteEntity, UserSuiteService} from "@certd/commercial-core"; import {CertInfoService} from "../../monitor/service/cert-info-service.js"; -import {TaskServiceBuilder} from "./task-service-getter.js"; +import {TaskServiceBuilder} from "./getter/task-service-getter.js"; import {nanoid} from "nanoid"; import {set} from "lodash-es"; diff --git a/packages/ui/certd-server/src/modules/pipeline/service/sub-domain-service.ts b/packages/ui/certd-server/src/modules/pipeline/service/sub-domain-service.ts index 9df006be..559ca8d1 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/sub-domain-service.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/sub-domain-service.ts @@ -4,7 +4,6 @@ import {InjectEntityModel} from '@midwayjs/typeorm'; import {Repository} from 'typeorm'; import {SubDomainEntity} from '../entity/sub-domain.js'; import {EmailService} from '../../basic/service/email-service.js'; -import {ISubDomainsGetter} from "@certd/plugin-cert"; @Provide() @Scope(ScopeEnum.Request, { allowDowngrade: true }) @@ -38,21 +37,3 @@ export class SubDomainService extends BaseService { } } - - - - -export class SubDomainsGetter implements ISubDomainsGetter { - userId: number; - subDomainService: SubDomainService; - - constructor(userId: number, subDomainService: SubDomainService) { - this.userId = userId; - this.subDomainService = subDomainService; - } - - async getSubDomains() { - return await this.subDomainService.getListByUserId(this.userId) - } - -} diff --git a/packages/ui/certd-server/src/modules/pipeline/service/task-service-getter.ts b/packages/ui/certd-server/src/modules/pipeline/service/task-service-getter.ts deleted file mode 100644 index a54ea260..00000000 --- a/packages/ui/certd-server/src/modules/pipeline/service/task-service-getter.ts +++ /dev/null @@ -1,63 +0,0 @@ -import {IServiceGetter} from "@certd/pipeline"; -import {Inject, Provide, Scope, ScopeEnum} from "@midwayjs/core"; -import {SubDomainService, SubDomainsGetter} from "./sub-domain-service.js"; -import {AccessGetter, AccessService} from "@certd/lib-server"; -import {CnameProxyService} from "./cname-proxy-service.js"; -import {NotificationGetter} from "./notification-getter.js"; -import {NotificationService} from "./notification-service.js"; -import {CnameRecordService} from "../../cname/service/cname-record-service.js"; - -export class TaskServiceGetter implements IServiceGetter{ - serviceContainer:Record; - constructor(serviceContainer:Record) { - this.serviceContainer = serviceContainer; - } - async get(serviceName: string): Promise { - const ret = this.serviceContainer[serviceName] as T; - if(!ret){ - throw new Error(`service ${serviceName} not found`) - } - return ret - } -} -export type TaskServiceCreateReq = { - userId: number; -} - -export type TaskServiceContainer = { - subDomainsGetter:SubDomainsGetter; - accessService: AccessGetter; - cnameProxyService: CnameProxyService; - notificationService: NotificationGetter; -} - -@Provide() -@Scope(ScopeEnum.Request, { allowDowngrade: true }) -export class TaskServiceBuilder { - - @Inject() - subDomainService: SubDomainService; - @Inject() - accessService: AccessService; - @Inject() - cnameRecordService: CnameRecordService; - @Inject() - notificationService: NotificationService; - - - create(req:TaskServiceCreateReq){ - - const userId = req.userId; - const accessGetter = new AccessGetter(userId, this.accessService.getById.bind(this.accessService)); - const cnameProxyService = new CnameProxyService(userId, this.cnameRecordService.getWithAccessByDomain.bind(this.cnameRecordService)); - const notificationGetter = new NotificationGetter(userId, this.notificationService); - - const serviceContainer:TaskServiceContainer = { - subDomainsGetter:new SubDomainsGetter(req.userId, this.subDomainService), - accessService: accessGetter, - cnameProxyService:cnameProxyService, - notificationService:notificationGetter - } - return new TaskServiceGetter(serviceContainer) - } -} From af5e1b805f07c4ffd21b5db044a19843f2a2c7bf Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sun, 13 Jul 2025 18:30:04 +0800 Subject: [PATCH 15/34] chore: --- .../src/controller/user/pipeline/handle-controller.ts | 2 +- .../src/modules/cname/service/cname-record-service.ts | 3 ++- .../src/modules/pipeline/service/getter/sub-domain-getter.ts | 2 +- .../modules/pipeline/service/getter/task-service-getter.ts | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/ui/certd-server/src/controller/user/pipeline/handle-controller.ts b/packages/ui/certd-server/src/controller/user/pipeline/handle-controller.ts index 06d3f45a..536df2d4 100644 --- a/packages/ui/certd-server/src/controller/user/pipeline/handle-controller.ts +++ b/packages/ui/certd-server/src/controller/user/pipeline/handle-controller.ts @@ -14,7 +14,7 @@ import { import {EmailService} from '../../../modules/basic/service/email-service.js'; import {http, HttpRequestConfig, logger, mergeUtils, utils} from '@certd/basic'; import {NotificationService} from '../../../modules/pipeline/service/notification-service.js'; -import {TaskServiceBuilder} from "../../../modules/pipeline/service/task-service-getter.js"; +import {TaskServiceBuilder} from "../../../modules/pipeline/service/getter/task-service-getter.js"; @Provide() @Controller('/api/pi/handle') diff --git a/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts b/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts index a94a5bbb..10c5764f 100644 --- a/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts +++ b/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts @@ -10,9 +10,10 @@ import {getAuthoritativeDnsResolver, walkTxtRecord} from '@certd/acme-client'; import {CnameProviderService} from './cname-provider-service.js'; import {CnameProviderEntity} from '../entity/cname-provider.js'; import {CommonDnsProvider} from './common-provider.js'; -import {SubDomainService, SubDomainsGetter} from "../../pipeline/service/sub-domain-service.js"; import {DomainParser} from "@certd/plugin-cert/dist/dns-provider/domain-parser.js"; import punycode from 'punycode.js' +import {SubDomainService} from "../../pipeline/service/sub-domain-service.js"; +import {SubDomainsGetter} from "../../pipeline/service/getter/sub-domain-getter.js"; type CnameCheckCacheValue = { validating: boolean; pass: boolean; diff --git a/packages/ui/certd-server/src/modules/pipeline/service/getter/sub-domain-getter.ts b/packages/ui/certd-server/src/modules/pipeline/service/getter/sub-domain-getter.ts index 4878aed0..bb0615cb 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/getter/sub-domain-getter.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/getter/sub-domain-getter.ts @@ -1,5 +1,5 @@ import {ISubDomainsGetter} from "@certd/plugin-cert"; -import {SubDomainService} from "../service/sub-domain-service.js"; +import {SubDomainService} from "../sub-domain-service.js"; export class SubDomainsGetter implements ISubDomainsGetter { userId: number; diff --git a/packages/ui/certd-server/src/modules/pipeline/service/getter/task-service-getter.ts b/packages/ui/certd-server/src/modules/pipeline/service/getter/task-service-getter.ts index 006018da..8943e45d 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/getter/task-service-getter.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/getter/task-service-getter.ts @@ -1,6 +1,5 @@ import {IServiceGetter} from "@certd/pipeline"; import {Inject, Provide, Scope, ScopeEnum} from "@midwayjs/core"; -import {SubDomainService} from "../sub-domain-service.js"; import {AccessGetter, AccessService} from "@certd/lib-server"; import {CnameProxyService} from "./cname-proxy-service.js"; import {NotificationGetter} from "./notification-getter.js"; @@ -10,6 +9,7 @@ import {SubDomainsGetter} from './sub-domain-getter.js' import {DomainVerifierGetter} from "./domain-verifier-getter.js"; import {Context} from "@midwayjs/koa"; import {DomainService} from "../../../cert/service/domain-service.js"; +import {SubDomainService} from "../sub-domain-service.js"; export class TaskServiceGetter implements IServiceGetter{ private userId: number; @@ -36,7 +36,7 @@ export class TaskServiceGetter implements IServiceGetter{ } async getSubDomainsGetter(): Promise { - const subDomainsService = await this.ctx.requestContext.getAsync("subDomainService") + const subDomainsService:SubDomainService = await this.ctx.requestContext.getAsync("subDomainService") return new SubDomainsGetter(this.userId, subDomainsService) } From 896cd950e930f529c0b9a82251c6204e2dfa9816 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sun, 13 Jul 2025 23:08:00 +0800 Subject: [PATCH 16/34] chore: auto --- .../plugin-cert/src/dns-provider/api.ts | 8 ++-- .../src/plugin/cert-plugin/acme.ts | 4 +- .../src/plugin/cert-plugin/index.ts | 18 ++++---- .../src/locales/langs/en-US/certd.ts | 3 ++ .../src/locales/langs/en-US/common.ts | 2 + .../src/locales/langs/zh-CN/certd.ts | 3 ++ .../src/locales/langs/zh-CN/common.ts | 2 + .../src/views/certd/cert/domain/crud.tsx | 44 ++++++++++++++++--- .../src/views/certd/cert/domain/index.vue | 4 +- .../modules/cert/service/domain-service.ts | 37 ++++++++++++---- 10 files changed, 96 insertions(+), 29 deletions(-) diff --git a/packages/plugins/plugin-cert/src/dns-provider/api.ts b/packages/plugins/plugin-cert/src/dns-provider/api.ts index b3d87be3..0fd36b77 100644 --- a/packages/plugins/plugin-cert/src/dns-provider/api.ts +++ b/packages/plugins/plugin-cert/src/dns-provider/api.ts @@ -62,12 +62,14 @@ export interface IDomainParser { export type DnsVerifier = { // dns直接校验 - dnsProviderType: string; - dnsProviderAccessId: number; + dnsProviderType?: string; + dnsProviderAccessId?: number; }; export type CnameVerifier = { - cnameRecord: string; + hostRecord: string; + domain: string; + recordValue: string; }; export type HttpVerifier = { 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 9e4c095c..2d1e4362 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts @@ -269,11 +269,11 @@ export class AcmeService { throw new Error("不支持的校验类型", domainVerifyPlan.type); } } else { - this.logger.info("未找到域名校验计划,使用默认的dnsProvider"); + this.logger.warn(`未找到域名${fullDomain}的校验计划,使用默认的dnsProvider`); } } if (!dnsProvider) { - this.logger.error("dnsProvider不存在,无法申请证书"); + throw new Error(`域名${fullDomain}没有匹配到任何校验方式,证书申请失败`); } const dnsChallenge = getChallenge("dns-01"); 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 3c654340..f41afe97 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -66,15 +66,15 @@ export class CertApplyPlugin extends CertApplyBasePlugin { { value: "cname", label: "CNAME代理验证" }, { value: "http", label: "HTTP文件验证" }, { value: "dnses", label: "多DNS提供商" }, - { value: "auto", label: "自动选择" }, + { value: "auto", label: "自动匹配" }, ], }, required: true, helper: `1. DNS直接验证:域名dns解析是在阿里云/腾讯云/华为云/CF/NameSilo/西数/火山/dns.la/京东云/51dns的,选它 -2. CNAME代理验证:支持任何注册商的域名,第一次需要手动添加CNAME记录(建议将DNS服务器修改为阿里云/腾讯云的,然后使用DNS直接验证) +2. CNAME代理验证:支持任何注册商的域名,第一次需要手动添加[CNAME记录](#/certd/cname/record)(建议将DNS服务器修改为阿里云/腾讯云的,然后使用DNS直接验证) 3. HTTP文件验证:不支持泛域名,需要配置网站文件上传 4. 多DNS提供商:每个域名可以选择独立的DNS提供商 -5. 自动选择:需要在[域名管理](#/certd/cert/domain)中事先配置好校验方式 +5. 自动匹配:需要在[域名管理](#/certd/cert/domain)中事先配置好校验方式 `, }) challengeType!: string; @@ -469,13 +469,13 @@ export class CertApplyPlugin extends CertApplyBasePlugin { for (const fullDomain of domains) { const domain = fullDomain.replaceAll("*.", ""); const mainDomain = await domainParser.parse(domain); - const planSetting = verifyPlanSetting[mainDomain]; + const planSetting: DomainVerifyPlanInput = verifyPlanSetting[mainDomain]; if (planSetting.type === "dns") { - await this.createDnsDomainVerifyPlan(planSetting[mainDomain], domain, mainDomain); + plan[domain] = await this.createDnsDomainVerifyPlan(planSetting, domain, mainDomain); } else if (planSetting.type === "cname") { - await this.createCnameDomainVerifyPlan(domain, mainDomain); + plan[domain] = await this.createCnameDomainVerifyPlan(domain, mainDomain); } else if (planSetting.type === "http") { - await this.createHttpDomainVerifyPlan(planSetting.httpVerifyPlan[domain], domain, mainDomain); + plan[domain] = await this.createHttpDomainVerifyPlan(planSetting.httpVerifyPlan[domain], domain, mainDomain); } } return plan; @@ -486,7 +486,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { // domain list const domainList = new Set(); //整理域名 - for (let domain in this.domains) { + for (let domain of domains) { domain = domain.replaceAll("*.", ""); domainList.add(domain); } @@ -563,7 +563,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { domain, mainDomain, cnameVerifyPlan: { - domain, + domain: cnameRecord.cnameProvider.domain, fullRecord: cnameRecord.recordValue, dnsProvider, }, 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 d17346cc..351bb5e6 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 @@ -714,6 +714,7 @@ export default { }, domain: { domainManager: "Domain Manager", + domainDescription: "used to auto apply for certificate", //管理域名的校验方式,用于申请证书时自动选择验证方式 domain: "Domain", challengeType: "Challenge Type", dnsProviderType: "DNS Provider Type", @@ -722,5 +723,7 @@ export default { httpUploaderAccess: "HTTP Uploader Access", httpUploadRootDir: "HTTP Upload Root Dir", disabled: "Disabled", + challengeSetting: "Challenge Setting", + gotoCnameTip: "Please go to CNAME Record Page", }, }; diff --git a/packages/ui/certd-client/src/locales/langs/en-US/common.ts b/packages/ui/certd-client/src/locales/langs/en-US/common.ts index 34777d30..d0542e97 100644 --- a/packages/ui/certd-client/src/locales/langs/en-US/common.ts +++ b/packages/ui/certd-client/src/locales/langs/en-US/common.ts @@ -14,6 +14,8 @@ export default { search: "Search", enabled: "Enabled", disabled: "Disabled", + enable: "Enable", + disable: "Disable", edit: "Edit", delete: "Delete", create: "Create", 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 b5d8f37d..c32ac8d7 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 @@ -717,6 +717,7 @@ export default { }, domain: { domainManager: "域名管理", + domainDescription: "管理域名的校验方式,用于申请证书时自动选择验证方式", domain: "域名", challengeType: "校验类型", dnsProviderType: "DNS提供商类型", @@ -725,5 +726,7 @@ export default { httpUploaderAccess: "上传授权信息", httpUploadRootDir: "网站根路径", disabled: "禁用/启用", + challengeSetting: "校验配置", + gotoCnameTip: "CNAME域名配置请前往CNAME记录页面添加", }, }; diff --git a/packages/ui/certd-client/src/locales/langs/zh-CN/common.ts b/packages/ui/certd-client/src/locales/langs/zh-CN/common.ts index 9cec01a9..1e990fb4 100644 --- a/packages/ui/certd-client/src/locales/langs/zh-CN/common.ts +++ b/packages/ui/certd-client/src/locales/langs/zh-CN/common.ts @@ -14,6 +14,8 @@ export default { search: "搜索", enabled: "已启用", disabled: "已禁用", + enable: "启用", + disable: "禁用", edit: "修改", delete: "删除", create: "新增", diff --git a/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx b/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx index 57a2688e..f6e10c24 100644 --- a/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/cert/domain/crud.tsx @@ -7,6 +7,7 @@ import { useUserStore } from "/@/store/user"; import { useSettingStore } from "/@/store/settings"; import { Dicts } from "/@/components/plugins/lib/dicts"; import { createAccessApi } from "/@/views/certd/access/api"; +import { Modal } from "ant-design-vue"; export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { const router = useRouter(); @@ -73,13 +74,20 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat delRequest, }, tabs: { - name: "status", + name: "challengeType", show: true, }, rowHandle: { minWidth: 200, fixed: "right", }, + form: { + beforeSubmit({ form }) { + if (form.challengeType === "cname") { + throw new Error("CNAME方式请前往CNAME记录页面进行管理"); + } + }, + }, columns: { id: { title: "ID", @@ -114,11 +122,28 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat title: t("certd.domain.challengeType"), type: "dict-select", dict: Dicts.challengeTypeDict, + search: { + show: true, + }, form: { required: true, + valueChange({ value }) { + if (value === "cname") { + Modal.confirm({ + title: t("certd.domain.gotoCnameTip"), + async onOk() { + router.push({ + path: "/certd/cname/record", + }); + crudExpose.getFormWrapperRef().close(); + }, + }); + } + }, }, column: { sorter: true, + show: false, }, }, /** @@ -196,6 +221,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat form: { component: { name: "AccessSelector", + vModel: "modelValue", + type: compute(({ form }) => { + return form.httpUploaderType; + }), }, show: compute(({ form }) => { return form.challengeType === "http"; @@ -226,16 +255,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }, }, challengeSetting: { - title: "校验配置", + title: t("certd.domain.challengeSetting"), type: "text", form: { show: false }, column: { - width: 400, + width: 600, conditionalRender: false, cellRender({ row }) { if (row.challengeType === "dns") { return (
+
@@ -243,9 +273,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat } else if (row.challengeType === "http") { return (
+ - {row.httpUploadRootDir} + 路径:{row.httpUploadRootDir}
); } @@ -255,10 +286,11 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat disabled: { title: t("certd.domain.disabled"), type: "dict-switch", + search: { show: true }, dict: dict({ data: [ - { label: "启用", value: false, color: "green" }, - { label: "禁用", value: true, color: "red" }, + { label: t("common.enabled"), value: false, color: "green" }, + { label: t("common.disabled"), value: true, color: "red" }, ], }), form: { diff --git a/packages/ui/certd-client/src/views/certd/cert/domain/index.vue b/packages/ui/certd-client/src/views/certd/cert/domain/index.vue index 8bf9ea63..b7c1f5b0 100644 --- a/packages/ui/certd-client/src/views/certd/cert/domain/index.vue +++ b/packages/ui/certd-client/src/views/certd/cert/domain/index.vue @@ -3,7 +3,9 @@ diff --git a/packages/ui/certd-server/src/modules/cert/service/domain-service.ts b/packages/ui/certd-server/src/modules/cert/service/domain-service.ts index 58c1146e..1a3426bc 100644 --- a/packages/ui/certd-server/src/modules/cert/service/domain-service.ts +++ b/packages/ui/certd-server/src/modules/cert/service/domain-service.ts @@ -7,6 +7,8 @@ import {SubDomainService} from "../../pipeline/service/sub-domain-service.js"; import {DomainParser} from "@certd/plugin-cert/dist/dns-provider/domain-parser.js"; import {DomainVerifiers} from "@certd/plugin-cert"; import { SubDomainsGetter } from '../../pipeline/service/getter/sub-domain-getter.js'; +import { CnameRecordService } from '../../cname/service/cname-record-service.js'; +import { CnameRecordEntity } from "../../cname/entity/cname-record.js"; /** @@ -23,6 +25,9 @@ export class DomainService extends BaseService { @Inject() subDomainService: SubDomainService; + @Inject() + cnameRecordService: CnameRecordService; + //@ts-ignore getRepository() { return this.repository; @@ -96,10 +101,12 @@ export class DomainService extends BaseService { //去重 allDomains = [...new Set(allDomains)] + //从 domain 表中获取配置 const domainRecords = await this.find({ where: { domain: In(allDomains), - userId + userId, + disabled:false, } }) @@ -107,16 +114,28 @@ export class DomainService extends BaseService { pre[item.domain] = item return pre }, {}) - const cnameMap = domainRecords.filter(item=>item.challengeType === 'cname').reduce((pre, item) => { - pre[item.domain] = item - return pre - }, {}) + const httpMap = domainRecords.filter(item=>item.challengeType === 'http').reduce((pre, item) => { pre[item.domain] = item return pre }, {}) + //从cname record表中获取配置 + const cnameRecords = await this.cnameRecordService.find({ + where: { + domain: In(allDomains), + userId, + status: "valid", + } + }) + + const cnameMap = cnameRecords.reduce((pre, item) => { + pre[item.domain] = item + return pre + }, {}) + + //构建域名验证计划 const domainVerifiers:DomainVerifiers = {} for (const domain of domains) { @@ -130,19 +149,21 @@ export class DomainService extends BaseService { type: 'dns', dns: { dnsProviderType: dnsRecord.dnsProviderType, - dnsProviderAccessId: dnsRecord.dnsProviderAccessId + dnsProviderAccessId: dnsRecord.dnsProviderAccess } } continue } - const cnameRecord = cnameMap[mainDomain] + const cnameRecord:CnameRecordEntity = cnameMap[mainDomain] if (cnameRecord) { domainVerifiers[domain] = { domain, mainDomain, type: 'cname', cname: { - cnameRecord: cnameRecord.cnameRecord + domain: cnameRecord.domain, + hostRecord: cnameRecord.hostRecord, + recordValue: cnameRecord.recordValue } } continue From 0b3158fdd5fe5bb0a98c4e65715dbc3de2c38047 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sun, 13 Jul 2025 23:14:28 +0800 Subject: [PATCH 17/34] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=9F=90?= =?UTF-8?q?=E4=BA=9B=E9=A1=B5=E9=9D=A2=E7=BF=BB=E8=AF=91=E4=B8=8D=E5=85=A8?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=94=99=E8=AF=AF=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../access/access-selector/access/crud.tsx | 2 +- .../src/views/certd/access/crud.tsx | 2 +- .../src/views/certd/access/index.vue | 2 +- .../src/views/certd/cert/domain/index.vue | 2 +- .../src/views/certd/cname/record/crud.tsx | 2 +- .../src/views/certd/cname/record/index.vue | 2 +- .../src/views/certd/history/crud.tsx | 2 +- .../src/views/certd/history/index.vue | 2 +- .../certd/mine/change-password-button.vue | 2 +- .../src/views/certd/mine/security/index.vue | 2 +- .../src/views/certd/mine/user-profile.vue | 2 +- .../src/views/certd/monitor/cert/crud.tsx | 2 +- .../src/views/certd/monitor/cert/index.vue | 2 +- .../src/views/certd/monitor/site/crud.tsx | 2 +- .../src/views/certd/monitor/site/index.vue | 2 +- .../src/views/certd/monitor/site/ip/crud.tsx | 2 +- .../certd/monitor/site/setting/index.vue | 2 +- .../src/views/certd/monitor/site/use.tsx | 2 +- .../notification-selector/index.vue | 2 +- .../src/views/certd/open/openkey/crud.tsx | 2 +- .../pipeline/components/change-trigger.vue | 2 +- .../src/views/certd/pipeline/index.vue | 2 +- .../component/notification-form/index.vue | 2 +- .../pi-notification-form-email.vue | 2 +- .../views/certd/pipeline/sub-domain/crud.tsx | 2 +- .../views/certd/pipeline/sub-domain/index.vue | 2 +- .../views/certd/pipeline/template/index.vue | 2 +- .../src/views/certd/suite/order-modal.vue | 22 +++++++++---------- .../src/views/certd/trade/crud.tsx | 2 +- .../views/framework/home/dashboard/index.vue | 2 +- .../src/views/framework/home/index.vue | 2 +- .../views/sys/authority/permission/crud.tsx | 2 +- .../permission/fs-permission-tree.vue | 2 +- .../views/sys/authority/permission/index.vue | 2 +- .../src/views/sys/authority/role/crud.tsx | 2 +- .../src/views/sys/authority/role/index.vue | 2 +- .../src/views/sys/authority/user/crud.tsx | 2 +- .../src/views/sys/cname/provider/crud.tsx | 2 +- .../src/views/sys/cname/provider/index.vue | 2 +- .../src/views/sys/plugin/crud.tsx | 2 +- .../src/views/sys/plugin/index.vue | 2 +- .../src/views/sys/settings/email/index.vue | 2 +- .../views/sys/settings/header-menus/crud.tsx | 2 +- .../src/views/sys/settings/tabs/base.vue | 2 +- .../src/views/sys/settings/tabs/register.vue | 2 +- .../src/views/sys/settings/tabs/safe.vue | 2 +- .../src/views/sys/suite/product/crud.tsx | 2 +- .../src/views/sys/suite/trade/crud.tsx | 2 +- 48 files changed, 58 insertions(+), 58 deletions(-) diff --git a/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx b/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx index 9093eeb5..23c54a12 100644 --- a/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx @@ -2,7 +2,7 @@ import { ref } from "vue"; import { getCommonColumnDefine } from "/@/views/certd/access/common"; import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; -import { useI18n } from "vue-i18n"; +import { useI18n } from "/src/locales"; export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { const { t } = useI18n(); diff --git a/packages/ui/certd-client/src/views/certd/access/crud.tsx b/packages/ui/certd-client/src/views/certd/access/crud.tsx index ff6ad138..00323872 100644 --- a/packages/ui/certd-client/src/views/certd/access/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/access/crud.tsx @@ -1,5 +1,5 @@ // @ts-ignore -import { useI18n } from "vue-i18n"; +import { useI18n } from "/src/locales"; import { ref } from "vue"; import { getCommonColumnDefine } from "/@/views/certd/access/common"; import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; diff --git a/packages/ui/certd-client/src/views/certd/access/index.vue b/packages/ui/certd-client/src/views/certd/access/index.vue index aeec1c9c..25d31265 100644 --- a/packages/ui/certd-client/src/views/certd/access/index.vue +++ b/packages/ui/certd-client/src/views/certd/access/index.vue @@ -15,7 +15,7 @@ import { defineComponent, onActivated, onMounted } from "vue"; import { useFs } from "@fast-crud/fast-crud"; import createCrudOptions from "./crud"; import { createAccessApi } from "/@/views/certd/access/api"; -import { useI18n } from "vue-i18n"; +import { useI18n } from "/src/locales"; export default defineComponent({ name: "AccessManager", diff --git a/packages/ui/certd-client/src/views/certd/cert/domain/index.vue b/packages/ui/certd-client/src/views/certd/cert/domain/index.vue index b7c1f5b0..2ffd486e 100644 --- a/packages/ui/certd-client/src/views/certd/cert/domain/index.vue +++ b/packages/ui/certd-client/src/views/certd/cert/domain/index.vue @@ -24,7 +24,7 @@ import { useFs } from "@fast-crud/fast-crud"; import createCrudOptions from "./crud"; import { message, Modal } from "ant-design-vue"; import { DeleteBatch } from "./api"; -import { useI18n } from "vue-i18n"; +import { useI18n } from "/src/locales"; const { t } = useI18n(); diff --git a/packages/ui/certd-client/src/views/certd/cname/record/crud.tsx b/packages/ui/certd-client/src/views/certd/cname/record/crud.tsx index 769da2de..ddad615d 100644 --- a/packages/ui/certd-client/src/views/certd/cname/record/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/cname/record/crud.tsx @@ -1,5 +1,5 @@ import * as api from "./api"; -import { useI18n } from "vue-i18n"; +import { useI18n } from "/src/locales"; import { Ref, ref } from "vue"; import { useRouter } from "vue-router"; import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; diff --git a/packages/ui/certd-client/src/views/certd/cname/record/index.vue b/packages/ui/certd-client/src/views/certd/cname/record/index.vue index 52eadb50..4ed382d3 100644 --- a/packages/ui/certd-client/src/views/certd/cname/record/index.vue +++ b/packages/ui/certd-client/src/views/certd/cname/record/index.vue @@ -26,7 +26,7 @@ import { useFs } from "@fast-crud/fast-crud"; import createCrudOptions from "./crud"; import { message, Modal } from "ant-design-vue"; import { DeleteBatch } from "./api"; -import { useI18n } from "vue-i18n"; +import { useI18n } from "/src/locales"; const { t } = useI18n(); diff --git a/packages/ui/certd-client/src/views/certd/history/crud.tsx b/packages/ui/certd-client/src/views/certd/history/crud.tsx index c745721c..2c2b2a66 100644 --- a/packages/ui/certd-client/src/views/certd/history/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/history/crud.tsx @@ -1,5 +1,5 @@ import * as api from "./api"; -import { useI18n } from "vue-i18n"; +import { useI18n } from "/src/locales"; import { computed, Ref, ref } from "vue"; import { useRouter } from "vue-router"; import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud"; diff --git a/packages/ui/certd-client/src/views/certd/history/index.vue b/packages/ui/certd-client/src/views/certd/history/index.vue index 17bfb9bc..dea2c720 100644 --- a/packages/ui/certd-client/src/views/certd/history/index.vue +++ b/packages/ui/certd-client/src/views/certd/history/index.vue @@ -19,7 +19,7 @@ import { useFs } from "@fast-crud/fast-crud"; import createCrudOptions from "./crud"; import { message, Modal } from "ant-design-vue"; import { DeleteBatch } from "./api"; -import { useI18n } from "vue-i18n"; +import { useI18n } from "/src/locales"; const { t } = useI18n(); diff --git a/packages/ui/certd-client/src/views/certd/mine/change-password-button.vue b/packages/ui/certd-client/src/views/certd/mine/change-password-button.vue index 1fc265e2..b6615fbe 100644 --- a/packages/ui/certd-client/src/views/certd/mine/change-password-button.vue +++ b/packages/ui/certd-client/src/views/certd/mine/change-password-button.vue @@ -6,7 +6,7 @@