From 8caab1fd9264df548f467b94202d567107b7a30b Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 26 Dec 2025 23:20:14 +0800 Subject: [PATCH 1/4] perf: aws route53 --- packages/core/acme-client/src/util.js | 2 +- .../pipeline/components/change-trigger.vue | 3 ++ .../src/plugins/plugin-aws/access.ts | 9 ++--- .../plugin-aws/aws-route53-provider.ts | 2 +- .../src/plugins/plugin-aws/libs/aws-client.ts | 35 ++++++++++--------- pnpm-lock.yaml | 30 ++++++++-------- 6 files changed, 43 insertions(+), 38 deletions(-) diff --git a/packages/core/acme-client/src/util.js b/packages/core/acme-client/src/util.js index cdfde034d..ab2a5b74e 100644 --- a/packages/core/acme-client/src/util.js +++ b/packages/core/acme-client/src/util.js @@ -247,7 +247,7 @@ async function getAuthoritativeDnsResolver(recordName, logger = log) { try { /* Resolve root domain by SOA */ - const domain = await resolveDomainBySoaRecord(recordNam,logger); + const domain = await resolveDomainBySoaRecord(recordName,logger); /* Resolve authoritative NS addresses */ logger(`获取到权威NS服务器name: ${domain}`); diff --git a/packages/ui/certd-client/src/views/certd/pipeline/components/change-trigger.vue b/packages/ui/certd-client/src/views/certd/pipeline/components/change-trigger.vue index 95a9de7a9..edb377ad3 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/components/change-trigger.vue +++ b/packages/ui/certd-client/src/views/certd/pipeline/components/change-trigger.vue @@ -63,6 +63,9 @@ async function openFormDialog() { form: { value: true, helper: "是否给流水线随机设置一个时间", + show: compute(({ form }) => { + return form.clear !== true; + }), component: { name: "fs-dict-switch", vModel: "checked", diff --git a/packages/ui/certd-server/src/plugins/plugin-aws/access.ts b/packages/ui/certd-server/src/plugins/plugin-aws/access.ts index 6f2824842..b52c6e363 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aws/access.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aws/access.ts @@ -1,9 +1,10 @@ import { AccessInput, BaseAccess, IsAccess } from '@certd/pipeline'; export const AwsRegions = [ - { label: 'cn-north-1', value: 'cn-north-1' }, - { label: 'cn-northwest-1', value: 'cn-northwest-1' }, - { label: '---------------', value: '--',disabled: true }, + { label: '------中国区------', value: 'cn',disabled: true }, + { label: '北京', value: 'cn-north-1' }, + { label: '宁夏', value: 'cn-northwest-1' }, + { label: '------海外-----', value: 'out',disabled: true }, { label: 'us-east-1', value: 'us-east-1' }, { label: 'us-east-2', value: 'us-east-2' }, { label: 'us-west-1', value: 'us-west-1' }, @@ -72,7 +73,7 @@ export class AwsAccess extends BaseAccess { options: AwsRegions, }, required: true, - helper: '请选择您的默认AWS区域,默认us-east-1', + helper: '请选择您的默认AWS区域,主要区分中国区还是海外区即可', options: AwsRegions, }) region = ''; diff --git a/packages/ui/certd-server/src/plugins/plugin-aws/aws-route53-provider.ts b/packages/ui/certd-server/src/plugins/plugin-aws/aws-route53-provider.ts index e36d49f13..0d0f7d27f 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aws/aws-route53-provider.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aws/aws-route53-provider.ts @@ -32,7 +32,7 @@ export class AwsRoute53Provider extends AbstractDnsProvider { fullRecord: fullRecord, type: type, value: value, - action: 'CREATE', + action: 'UPSERT', }); return { hostedZoneId: ZoneId, diff --git a/packages/ui/certd-server/src/plugins/plugin-aws/libs/aws-client.ts b/packages/ui/certd-server/src/plugins/plugin-aws/libs/aws-client.ts index 78640173d..f5db11aee 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aws/libs/aws-client.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aws/libs/aws-client.ts @@ -1,8 +1,8 @@ // 导入所需的 SDK 模块 import { AwsAccess } from '../access.js'; import { CertInfo } from '@certd/plugin-cert'; -import {ILogger, utils} from '@certd/basic'; -type AwsClientOptions = { access: AwsAccess; region: string, logger:ILogger }; +import { ILogger, utils } from '@certd/basic'; +type AwsClientOptions = { access: AwsAccess; region: string, logger: ILogger }; export class AwsClient { options: AwsClientOptions; @@ -52,24 +52,24 @@ export class AwsClient { }); } - async route53GetHostedZoneId(name:string) :Promise<{ZoneId:string,ZoneName:string}> { + async route53GetHostedZoneId(name: string): Promise<{ ZoneId: string, ZoneName: string }> { const hostedZones = await this.route53ListHostedZones(name); - const zoneId = hostedZones[0].Id.replace('/hostedzone/',''); + const zoneId = hostedZones[0].Id.replace('/hostedzone/', ''); this.logger.info(`获取到hostedZoneId:${zoneId},name:${hostedZones[0].Name}`); return { ZoneId: zoneId, ZoneName: hostedZones[0].Name, }; } - async route53ListHostedZones(name:string) :Promise<{Id:string,Name:string}[]> { - const { ListHostedZonesByNameCommand } =await import("@aws-sdk/client-route-53"); // ES Modules import + async route53ListHostedZones(name: string): Promise<{ Id: string, Name: string }[]> { + const { ListHostedZonesByNameCommand } = await import("@aws-sdk/client-route-53"); // ES Modules import const client = await this.route53ClientGet(); const input = { // ListHostedZonesByNameRequest DNSName: name, }; const command = new ListHostedZonesByNameCommand(input); - const response = await this.doRequest(()=>client.send(command)); + const response = await this.doRequest(() => client.send(command)); if (response.HostedZones.length === 0) { throw new Error(`找不到 HostedZone ${name}`); } @@ -77,9 +77,10 @@ export class AwsClient { return response.HostedZones; } - async route53ChangeRecord(req:{ - hostedZoneId:string,fullRecord:string,type:string, value:string, action:"CREATE"|"DELETE"}){ - const { ChangeResourceRecordSetsCommand} =await import("@aws-sdk/client-route-53"); // ES Modules import + async route53ChangeRecord(req: { + hostedZoneId: string, fullRecord: string, type: string, value: string, action: "UPSERT" | "DELETE" + }) { + const { ChangeResourceRecordSetsCommand } = await import("@aws-sdk/client-route-53"); // ES Modules import // const { Route53Client, ChangeResourceRecordSetsCommand } = require("@aws-sdk/client-route-53"); // CommonJS import // import type { Route53ClientConfig } from "@aws-sdk/client-route-53"; const client = await this.route53ClientGet(); @@ -88,9 +89,9 @@ export class AwsClient { ChangeBatch: { // ChangeBatch Changes: [ // Changes // required { // Change - Action: req.action as any , // required + Action: req.action as any, // required ResourceRecordSet: { // ResourceRecordSet - Name: req.fullRecord+".", // required + Name: req.fullRecord, // required Type: req.type.toUpperCase() as any, ResourceRecords: [ // ResourceRecords { // ResourceRecord @@ -103,9 +104,9 @@ export class AwsClient { ], }, }; - this.logger.info(`添加域名解析参数:${JSON.stringify(input)}`); + this.logger.info(`设置域名解析参数:${JSON.stringify(input)}`); const command = new ChangeResourceRecordSetsCommand(input); - const response = await this.doRequest(()=>client.send(command)); + const response = await this.doRequest(() => client.send(command)); console.log('Add record successful:', JSON.stringify(response)); await utils.sleep(3000); return response; @@ -120,10 +121,10 @@ export class AwsClient { // };*/ } - async doRequest(call:()=>Promise):Promise{ - try{ + async doRequest(call: () => Promise): Promise { + try { return await call(); - }catch(err){ + } catch (err) { this.logger.error(`调用接口失败:${err.Error?.Message || err.message},requestId:${err.requestId}`); throw err; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7a0011a03..ff5810213 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -783,19 +783,19 @@ importers: packages/pro/commercial-core: dependencies: '@certd/basic': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../../core/basic '@certd/lib-server': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../../libs/lib-server '@certd/pipeline': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../../core/pipeline '@certd/plugin-plus': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../plugin-plus '@certd/plus-core': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../plus-core '@midwayjs/core': specifier: 3.20.11 @@ -880,22 +880,22 @@ importers: specifier: ^1.0.2 version: 1.0.3 '@certd/basic': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../../core/basic '@certd/lib-k8s': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../../libs/lib-k8s '@certd/pipeline': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../../core/pipeline '@certd/plugin-cert': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../../plugins/plugin-cert '@certd/plugin-lib': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../../plugins/plugin-lib '@certd/plus-core': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../plus-core ali-oss: specifier: ^6.21.0 @@ -998,7 +998,7 @@ importers: packages/pro/plus-core: dependencies: '@certd/basic': - specifier: ^1.37.15 + specifier: ^1.37.16 version: link:../../core/basic dayjs: specifier: ^1.11.7 @@ -21364,13 +21364,13 @@ snapshots: resolve: 1.22.10 semver: 6.3.1 - eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8): + eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.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@7.32.0) + eslint-config-prettier: 8.10.0(eslint@8.57.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: @@ -23784,7 +23784,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@7.32.0))(eslint@7.32.0)(prettier@2.8.8) + eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8) execa: 5.1.1 inquirer: 7.3.3 json5: 2.2.3 From e61daaee2d0dec19710cd4ec759219a071f2435e Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 27 Dec 2025 01:54:47 +0800 Subject: [PATCH 2/4] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81ucloud=EF=BC=8C?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=88=B0ussl=EF=BC=8C=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=E5=88=B0ucdn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/pipeline/src/plugin/api.ts | 2 + packages/ui/certd-server/package.json | 1 + packages/ui/certd-server/src/plugins/index.ts | 3 +- .../src/plugins/plugin-ucloud/access.ts | 214 ++++++++++++++++++ .../src/plugins/plugin-ucloud/index.ts | 2 + .../plugins/plugin-ucloud/plugins/index.ts | 2 + .../plugins/plugin-deploy-to-cdn.ts | 189 ++++++++++++++++ .../plugins/plugin-upload-to-ussl.ts | 73 ++++++ pnpm-lock.yaml | 109 ++------- 9 files changed, 505 insertions(+), 90 deletions(-) create mode 100644 packages/ui/certd-server/src/plugins/plugin-ucloud/access.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-ucloud/index.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/index.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-deploy-to-cdn.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-upload-to-ussl.ts diff --git a/packages/core/pipeline/src/plugin/api.ts b/packages/core/pipeline/src/plugin/api.ts index 8cb10d199..8c1e2415b 100644 --- a/packages/core/pipeline/src/plugin/api.ts +++ b/packages/core/pipeline/src/plugin/api.ts @@ -185,6 +185,8 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin { if (res == null) { throw new Error("授权不存在,可能已被删除,请前往任务配置里面重新选择授权"); } + res.ctx.logger = this.logger; + res.ctx.http = this.http; // @ts-ignore if (this.logger?.addSecret) { // 隐藏加密信息,不在日志中输出 diff --git a/packages/ui/certd-server/package.json b/packages/ui/certd-server/package.json index dc7dbac6f..68c08fb62 100644 --- a/packages/ui/certd-server/package.json +++ b/packages/ui/certd-server/package.json @@ -75,6 +75,7 @@ "@midwayjs/upload": "3.20.13", "@midwayjs/validate": "3.20.13", "@peculiar/x509": "^1.11.0", + "@ucloud-sdks/ucloud-sdk-js": "^0.2.4", "@volcengine/openapi": "^1.28.1", "ali-oss": "^6.21.0", "axios": "^1.7.2", diff --git a/packages/ui/certd-server/src/plugins/index.ts b/packages/ui/certd-server/src/plugins/index.ts index f3f1ea1c6..4fdadb6b1 100644 --- a/packages/ui/certd-server/src/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/index.ts @@ -40,4 +40,5 @@ export * from './plugin-xinnet/index.js' export * from './plugin-xinnetconnet/index.js' export * from './plugin-oauth/index.js' export * from './plugin-cmcc/index.js' -export * from './plugin-template/index.js' \ No newline at end of file +export * from './plugin-template/index.js' +export * from './plugin-ucloud/index.js' \ No newline at end of file diff --git a/packages/ui/certd-server/src/plugins/plugin-ucloud/access.ts b/packages/ui/certd-server/src/plugins/plugin-ucloud/access.ts new file mode 100644 index 000000000..5736b5025 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-ucloud/access.ts @@ -0,0 +1,214 @@ +import { IsAccess, AccessInput, BaseAccess } from '@certd/pipeline'; +import { CertInfo, CertReader } from '@certd/plugin-cert'; + +/** + * 这个注解将注册一个授权配置 + * 在certd的后台管理系统中,用户可以选择添加此类型的授权 + */ +@IsAccess({ + name: 'ucloud', + title: 'UCloud授权', + icon: 'lsicon:badge-new-filled', + desc: '优刻得授权', +}) +export class UCloudAccess extends BaseAccess { + + /** + * 授权属性配置 + */ + @AccessInput({ + title: '项目Id', + component: { + placeholder: '项目Id', + }, + helper: "[项目管理](https://console.ucloud.cn/uaccount/iam/project_manage)项目ID列获取", + required: true, + encrypt: false, + }) + projectId = ''; + + + /** + * 授权属性配置 + */ + @AccessInput({ + title: '公钥', + component: { + placeholder: '公钥', + }, + helper: "[Api管理](https://console.ucloud.cn/uaccount/api_manage)获取", + required: true, + encrypt: false, + }) + publicKey = ''; + + @AccessInput({ + title: '私钥', + component: { + name: "a-input-password", + vModel: "value", + placeholder: '私钥', + }, + required: true, + encrypt: true, + }) + privateKey = ''; + + + + @AccessInput({ + title: "测试", + component: { + name: "api-test", + action: "TestRequest" + }, + helper: "点击测试接口是否正常" + }) + testRequest = true; + + client: any; + + async onTestRequest() { + await this.ProjectList(); + return "ok"; + } + + + async getClient() { + if (this.client) { + return this.client; + } + const { Client } = await import('@ucloud-sdks/ucloud-sdk-js'); + const client = new Client({ + config: { + region: 'cn-bj2', + projectId: this.projectId || "", + baseUrl: "https://api.ucloud.cn" + }, + credential: { + publicKey: this.publicKey, + privateKey: this.privateKey, + } + }); + this.client = client; + return client + } + + async ProjectList() { + const client = await this.getClient(); + const resp = await client.uaccount().getProjectList({ + "Action": "GetProjectList" + }); + this.ctx.logger.info(`获取到项目列表:${JSON.stringify(resp)}`); + return resp; + } + + async GetRegion() { + const client = await this.getClient(); + const res = await client.uaccount().getRegion({ + "Action": "GetRegion" + }); + this.ctx.logger.info(`获取到区域列表:${JSON.stringify(res)}`); + return res; + } + + async CdnDominList(req: { PageNo: number, PageSize: number }) { + const client = await this.getClient(); + const resp = await client.ucdn().getUcdnDomainInfoList({ + "Action": "GetUcdnDomainInfoList", + "ProjectId": this.projectId || "", + "PageNo": req.PageNo, + "PageSize": req.PageSize, + }); + this.ctx.logger.info(`获取到CDN域名列表:${JSON.stringify(resp)}`); + return resp; + } + + async CdnAddCert(req: { certName: string, cert: CertInfo }) { + const client = await this.getClient(); + const resp = await client.ucdn().addCertificate({ + "Action": "AddCertificate", + "ProjectId": this.projectId || "", + "CertName": req.certName, + "UserCert": req.cert.crt, + "PrivateKey": req.cert.key + }); + this.ctx.logger.info(`添加CDN证书:${JSON.stringify(resp)}`); + return resp; + } + + + async SslUploadCert(req: { cert: CertInfo }) { + const { cert } = req + /** +&SslPublicKey=lXUzWbSR +&SslCaKey=lXUzWbSR +&SslMD5=lXUzWbSR +&CertificateName=GoodCertcification + */ + const certReader = new CertReader(cert) + const certName = certReader.buildCertName() + const crtBase64 = this.ctx.utils.hash.base64(cert.crt) + const keyBase64 = this.ctx.utils.hash.base64(cert.key) + const allDomains = certReader.getAllDomains().join(",") + + this.ctx.logger.info(`----------- 上传USSL证书,certName:${certName},domains:${allDomains}`); + try { + const resp = await this.invoke({ + Action: "UploadNormalCertificate", + "SslPublicKey": crtBase64, + "SslPrivateKey": keyBase64, + "CertificateName": certName, + "SslMD5": this.ctx.utils.hash.md5(crtBase64 + keyBase64) + }); + this.ctx.logger.info(`----------- 上传USSL证书成功,certId:${resp.CertificateID}`); + return { type: "ussl", id: resp.CertificateID, name: certName, resourceId: resp.LongResourceID,domains:allDomains } + } catch (err) { + + if(err.message.includes("重复上传证书")){ + //查找证书 + const certList = await this.SslGetCertList(certReader.getMainDomain()); + + const cert = certList.find((item: any) => item.Domains === allDomains) + if(cert){ + this.ctx.logger.info(`----------- 找到已存在证书,certId:${cert.CertificateID}`); + return { type: "ussl", id: cert.CertificateID, name: certName, domains: cert.Domains } + } + } + + this.ctx.logger.error(`上传USSL证书失败:${err}`); + throw err; + } + + + } + + async SslGetCertList(domain: string) { + const resp = await this.invoke({ + Action: "GetCertificateList", + Mode: "trust", + Domain: domain, + Sort:"2" + }); + return resp.CertificateList||[]; + } + + + async invoke(req: { Action: string, [key: string]: any }) { + const { Request } = await import('@ucloud-sdks/ucloud-sdk-js'); + const client = await this.getClient(); + const resp = await client.invoke(new Request({ + ...req + })); + this.ctx.logger.info(`请求UCloud API:${JSON.stringify(resp)}`); + const res = resp.data || {} + if (res.RetCode !== 0) { + throw new Error(res.Message) + } + + return res; + } + +} + +new UCloudAccess(); diff --git a/packages/ui/certd-server/src/plugins/plugin-ucloud/index.ts b/packages/ui/certd-server/src/plugins/plugin-ucloud/index.ts new file mode 100644 index 000000000..c49d8bf88 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-ucloud/index.ts @@ -0,0 +1,2 @@ +export * from './access.js'; +export * from './plugins/index.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/index.ts new file mode 100644 index 000000000..8ba439d47 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/index.ts @@ -0,0 +1,2 @@ +export * from './plugin-deploy-to-cdn.js'; +export * from './plugin-upload-to-ussl.js'; \ No newline at end of file diff --git a/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-deploy-to-cdn.ts b/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-deploy-to-cdn.ts new file mode 100644 index 000000000..115c462f2 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-deploy-to-cdn.ts @@ -0,0 +1,189 @@ +import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; +import { UCloudAccess } from "../access.js"; + +@IsTaskPlugin({ + //命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名 + name: "UCloudDeployToCDN", + title: "UCloud-部署到CDN", + desc: "将证书部署到UCloud CDN", + icon: "svg:icon-lucky", + //插件分组 + group: pluginGroups.cdn.key, + needPlus: false, + default: { + //默认值配置照抄即可 + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed + } + } +}) +//类名规范,跟上面插件名称(name)一致 +export class UCloudDeployToCDN extends AbstractTaskPlugin { + //证书选择,此项必须要有 + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames, ":UCloudCertId:"] + } + // required: true, // 必填 + }) + cert!: CertInfo | { type: string, id: number, name: string }; + + @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + certDomains!: string[]; + + //授权选择框 + @TaskInput({ + title: "UCloud授权", + component: { + name: "access-selector", + type: "ucloud" //固定授权类型 + }, + required: true //必填 + }) + accessId!: string; + // + + @TaskInput( + createRemoteSelectInputDefine({ + title: "域名列表", + helper: "要更新的UCloud域名列表", + + action: UCloudDeployToCDN.prototype.onGetDomainList.name + }) + ) + domainList!: string[]; + + //插件实例化时执行的方法 + async onInstance() { + } + + //插件执行方法 + async execute(): Promise { + const access = await this.getAccess(this.accessId); + let certType = "ussl" + let certId = 0 + let certName = this.appendTimeSuffix("certd") + // @ts-ignore + if (this.cert?.id) { + //从上一步传过来的ssl证书 + // @ts-ignore + certId = this.cert.id + // @ts-ignore + certName = this.cert.name + + } else { + const cert = await access.SslUploadCert({ + cert: this.cert as CertInfo + }); + certId = cert.id + certName = cert.name + } + + for (const item of this.domainList) { + this.logger.info(`----------- 开始更新域名:${item}`); + await this.deployToCdn({ + access: access, + certName: certName, + domain: item, + certId: certId, + certType: certType + }); + this.logger.info(`----------- 更新域名证书${item}成功`); + } + + this.logger.info("部署完成"); + } + + + async deployToCdn(req: { access: any, domain: string, certId: number, certType: string, certName: string }) { + const { access, domain, certId, certType, certName } = req + + const domainsRes = await access.invoke({ + "Action": "GetUcdnDomainConfig", + "ProjectId": access.projectId, + "Domain": [ + domain + ] + }); + + const domainList = domainsRes.DomainList || []; + const domainConf = domainList.find((item: any) => item.Domain === domain); + if (!domainConf) { + throw new Error(`没有找到CDN域名${domain}`); + } + + const domainId = domainConf.DomainId; + const httpsStatusAbroad = domainConf.HttpsStatusAbroad; + let httpsStatusCn = domainConf.HttpsStatusCn; + if (httpsStatusAbroad === "disable" && httpsStatusCn === "disable") { + this.logger.info(`原CDN域名HTTPS未开启,将开启国内加速`); + httpsStatusCn = "enable" + } + + + const body: any = { + "Action": "UpdateUcdnDomainHttpsConfigV2", + "DomainId": domainId, + "CertName": certName, + "CertId": certId, + "CertType": certType, + EnableHttp2: domainConf.EnableHttp2 ||"0", + RedirectHttp2Https: domainConf.RedirectHttp2Https || "0", + TlsVersion: domainConf.TlsVersion || "tlsv1.0,tlsv1.1,tlsv1.2,tlsv1.3" + } + if (httpsStatusAbroad === "enable") { + body.HttpsStatusAbroad = httpsStatusAbroad; + } + if (httpsStatusCn === "enable") { + body.HttpsStatusCn = httpsStatusCn; + } + this.logger.info(`----------- 更新CDN域名HTTPS配置${domainId},${JSON.stringify(body)}`); + const resp = await access.invoke(body); + this.logger.info(`----------- 部署CDN证书${domainId}成功,${JSON.stringify(resp)}`); + } + + async onGetDomainList(req: PageSearch = {}) { + const access = await this.getAccess(this.accessId); + + const pageNo = req.pageNo ?? 1; + const pageSize = req.pageSize ?? 100; + const res = await access.CdnDominList( + { + PageNo: pageNo, + PageSize: pageSize + } + ); + const total = res.TotalCount; + const list = res.DomainInfoList || []; + if (!list || list.length === 0) { + throw new Error("没有找到CDN域名,请先在控制台创建CDN域名"); + } + + /** + * "Domain": "ucloud.certd.handsfree.work", + "DomainId": "ucdn-1kwdtph5ygbb" + */ + const options = list.map((item: any) => { + return { + label: `${item.Domain}<${item.DomainId}>`, + value: `${item.Domain}`, + domain: item.Domain + }; + }); + return { + list: this.ctx.utils.options.buildGroupOptions(options, this.certDomains), + total: total, + pageNo: pageNo, + pageSize: pageSize + }; + } + +} + +//实例化一下,注册插件 +new UCloudDeployToCDN(); diff --git a/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-upload-to-ussl.ts b/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-upload-to-ussl.ts new file mode 100644 index 000000000..ef081792f --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-upload-to-ussl.ts @@ -0,0 +1,73 @@ +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { UCloudAccess } from "../access.js"; + +@IsTaskPlugin({ + //命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名 + name: "UCloudUploadToUSSL", + title: "UCloud-上传到USSL", + desc: "将证书上传到UCloud USSL", + icon: "svg:icon-lucky", + //插件分组 + group: pluginGroups.cdn.key, + needPlus: false, + default: { + //默认值配置照抄即可 + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed + } + } +}) +//类名规范,跟上面插件名称(name)一致 +export class UCloudUploadToUSSL extends AbstractTaskPlugin { + //证书选择,此项必须要有 + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames] + } + // required: true, // 必填 + }) + cert!: CertInfo; + + + + //授权选择框 + @TaskInput({ + title: "UCloud授权", + component: { + name: "access-selector", + type: "ucloud" //固定授权类型 + }, + required: true //必填 + }) + accessId!: string; + // + + @TaskOutput({ + title: "证书ID", + type: "UCloudCertId", + }) + certId!: {type:string,id:number,name:string}; + + + //插件实例化时执行的方法 + async onInstance() { + } + + //插件执行方法 + async execute(): Promise { + const access = await this.getAccess(this.accessId); + const certId = await access.SslUploadCert({cert:this.cert}); + this.certId = certId; + this.logger.info("部署完成"); + } + + + +} + +//实例化一下,注册插件 +new UCloudUploadToUSSL(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ff5810213..24b4b217e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -214,7 +214,7 @@ importers: version: link:../basic '@certd/plus-core': specifier: ^1.37.16 - version: 1.37.16 + version: link:../../pro/plus-core dayjs: specifier: ^1.11.7 version: 1.11.13 @@ -462,7 +462,7 @@ importers: version: link:../../plugins/plugin-lib '@certd/plus-core': specifier: ^1.37.16 - version: 1.37.16 + version: link:../../pro/plus-core '@midwayjs/cache': specifier: 3.14.0 version: 3.14.0 @@ -1490,7 +1490,7 @@ importers: version: link:../../core/basic '@certd/commercial-core': specifier: ^1.37.16 - version: 1.37.16(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)) + version: link:../../pro/commercial-core '@certd/cv4pve-api-javascript': specifier: ^8.4.2 version: 8.4.2 @@ -1520,10 +1520,10 @@ importers: version: link:../../plugins/plugin-lib '@certd/plugin-plus': specifier: ^1.37.16 - version: 1.37.16(encoding@0.1.13) + version: link:../../pro/plugin-plus '@certd/plus-core': specifier: ^1.37.16 - version: 1.37.16 + version: link:../../pro/plus-core '@huaweicloud/huaweicloud-sdk-cdn': specifier: ^3.1.120 version: 3.1.149 @@ -1569,6 +1569,9 @@ importers: '@peculiar/x509': specifier: ^1.11.0 version: 1.12.3 + '@ucloud-sdks/ucloud-sdk-js': + specifier: ^0.2.4 + version: 0.2.4 '@volcengine/openapi': specifier: ^1.28.1 version: 1.30.1(buffer@6.0.3) @@ -2876,18 +2879,9 @@ packages: '@better-scroll/zoom@2.5.1': resolution: {integrity: sha512-aGvFY5ooeZWS4RcxQLD+pGLpQHQxpPy0sMZV3yadcd2QK53PK9gS4Dp+BYfRv8lZ4/P2LoNEhr6Wq1DN6+uPlA==} - '@certd/commercial-core@1.37.16': - resolution: {integrity: sha512-JH6wlx88ljh2m2QiTJ1dvI/Up3jjOTEQqD/x3cfVmXHYfT//QFIL/O6cRIFKLWxN5Q+0k4YHmCDw/DI+WWdwlQ==} - '@certd/cv4pve-api-javascript@8.4.2': resolution: {integrity: sha512-udGce7ewrVl4DmZvX+17PjsnqsdDIHEDatr8QP0AVrY2p+8JkaSPW4mXCKiLGf82C9K2+GXgT+qNIqgW7tfF9Q==} - '@certd/plugin-plus@1.37.16': - resolution: {integrity: sha512-lzxyHyq9K+sDDFlPICs/0/W1nODvxTwk7N+qI1gskTbNpPt5CY1b47sPhwLb6oRTeW2/8iVdmt283GECFEAXXg==} - - '@certd/plus-core@1.37.16': - resolution: {integrity: sha512-PAyDMlLy/r5kx03A6pH4ICUAdPR9WZroGOx/ivJJo0Auk07uHU/kyXMfSCB6LytUHH0tOy36K+zuTCTdGr2NOA==} - '@certd/vue-js-cron-core@6.0.3': resolution: {integrity: sha512-kqzoAMhYz9j6FGNWEODRYtt4NpUEUwjpkU89z5WVg2tCtOcI5VhwyUGOd8AxiBCRfd6PtXvzuqw85PaOps9wrQ==} @@ -5364,6 +5358,9 @@ packages: resolution: {integrity: sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ucloud-sdks/ucloud-sdk-js@0.2.4': + resolution: {integrity: sha512-jAE8IEagtLXoj172/YMmwnMHDH+DlwgvSmMYtEge618oa/Wkn1BwSofRAx1r5afjBkDGLRdGN9+X+53Y+akqag==} + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -15440,84 +15437,12 @@ snapshots: dependencies: '@better-scroll/core': 2.5.1 - '@certd/commercial-core@1.37.16(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.37.16(encoding@0.1.13) - '@certd/plus-core': 1.37.16 - '@midwayjs/core': 3.20.11 - '@midwayjs/koa': 3.20.13 - '@midwayjs/logger': 3.4.2 - '@midwayjs/typeorm': 3.20.11 - 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.2': dependencies: debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@certd/plugin-plus@1.37.16(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.37.16 - 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.112(encoding@0.1.13) - transitivePeerDependencies: - - encoding - - proxy-agent - - supports-color - - '@certd/plus-core@1.37.16': - dependencies: - '@certd/basic': link:packages/core/basic - dayjs: 1.11.13 - '@certd/vue-js-cron-core@6.0.3': dependencies: mustache: 4.2.0 @@ -18700,6 +18625,12 @@ snapshots: '@typescript-eslint/types': 8.32.1 eslint-visitor-keys: 4.2.0 + '@ucloud-sdks/ucloud-sdk-js@0.2.4': + dependencies: + axios: 0.21.4(debug@4.4.1) + transitivePeerDependencies: + - debug + '@ungap/structured-clone@1.3.0': {} '@uppy/companion-client@2.2.2': @@ -21364,13 +21295,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: @@ -23784,7 +23715,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 91e19bbdd3946444ddbf73ad08e502e95db36a98 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 27 Dec 2025 02:20:01 +0800 Subject: [PATCH 3/4] =?UTF-8?q?chore:=20=E4=BC=98=E5=8C=96=E5=9B=BE?= =?UTF-8?q?=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/pipeline/src/plugin/group.ts | 1 + .../public/static/icons/demo_index.html | 122 +++++++++-- .../public/static/icons/iconfont.css | 24 ++- .../public/static/icons/iconfont.js | 2 +- .../public/static/icons/iconfont.json | 42 +++- .../public/static/icons/iconfont.svg | 12 +- .../src/plugins/plugin-cmcc/access.ts | 2 +- .../plugin-cmcc/plugin-deploy-to-cdn.ts | 2 +- .../src/plugins/plugin-fnos/index.ts | 2 +- .../plugins/plugin-refresh-cert.ts | 2 +- .../src/plugins/plugin-ucloud/access.ts | 2 +- .../plugins/plugin-deploy-to-cdn.ts | 4 +- .../plugins/plugin-deploy-to-waf.ts | 189 ++++++++++++++++++ .../plugins/plugin-upload-to-ussl.ts | 4 +- .../src/plugins/plugin-wangsu/access.ts | 2 +- .../plugins/plugin-refresh-cert.ts | 2 +- .../src/plugins/plugin-xinnet/access-agent.ts | 2 +- .../src/plugins/plugin-xinnet/access.ts | 2 +- .../plugin-xinnet/dns-provider-agent.ts | 2 +- .../src/plugins/plugin-xinnet/dns-provider.ts | 2 +- .../src/plugins/plugin-xinnetconnet/access.ts | 2 +- .../plugin-xinnetconnet/dns-provider.ts | 2 +- 22 files changed, 380 insertions(+), 46 deletions(-) create mode 100644 packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-deploy-to-waf.ts diff --git a/packages/core/pipeline/src/plugin/group.ts b/packages/core/pipeline/src/plugin/group.ts index 6a4b48d3b..d0e746a32 100644 --- a/packages/core/pipeline/src/plugin/group.ts +++ b/packages/core/pipeline/src/plugin/group.ts @@ -27,6 +27,7 @@ export const pluginGroups = { tencent: new PluginGroup("tencent", "腾讯云", 4, "svg:icon-tencentcloud"), volcengine: new PluginGroup("volcengine", "火山引擎", 4, "svg:icon-volcengine"), jdcloud: new PluginGroup("jdcloud", "京东云", 4, "svg:icon-jdcloud"), + ucloud: new PluginGroup("ucloud", "UCloud", 4, "svg:icon-ucloud"), baidu: new PluginGroup("baidu", "百度云", 4, "ant-design:baidu-outlined"), qiniu: new PluginGroup("qiniu", "七牛云", 5, "svg:icon-qiniuyun"), aws: new PluginGroup("aws", "亚马逊云", 6, "svg:icon-aws"), diff --git a/packages/ui/certd-client/public/static/icons/demo_index.html b/packages/ui/certd-client/public/static/icons/demo_index.html index 14e926579..3bf288ec2 100644 --- a/packages/ui/certd-client/public/static/icons/demo_index.html +++ b/packages/ui/certd-client/public/static/icons/demo_index.html @@ -55,15 +55,39 @@
  • - -
    social-foursquare
    -
    &#xe8fb;
    + +
    飞牛
    +
    &#xe60a;
  • - -
    ksyun-logo
    -
    &#xe65a;
    + +
    金山云logo
    +
    &#xe8ad;
    +
  • + +
  • + +
    中国移动
    +
    &#xe989;
    +
  • + +
  • + +
    xinnet
    +
    &#xe643;
    +
  • + +
  • + +
    ucloud
    +
    &#xe717;
    +
  • + +
  • + +
    social-foursquare
    +
    &#xe8fb;
  • @@ -228,7 +252,7 @@
    @font-face {
       font-family: 'iconfont';
    -  src: url('iconfont.svg?t=1754884110189#iconfont') format('svg');
    +  src: url('iconfont.svg?t=1766772710945#iconfont') format('svg');
     }
     

    第二步:定义使用 iconfont 的样式

    @@ -255,23 +279,59 @@
    • - +
      - social-foursquare + 飞牛
      -
      .icon-four +
      .icon-fnos
    • - ksyun-logo + 金山云logo
      .icon-ksyun
    • +
    • + +
      + 中国移动 +
      +
      .icon-cmcc +
      +
    • + +
    • + +
      + xinnet +
      +
      .icon-xinnet +
      +
    • + +
    • + +
      + ucloud +
      +
      .icon-ucloud +
      +
    • + +
    • + +
      + social-foursquare +
      +
      .icon-four +
      +
    • +
    • @@ -517,20 +577,52 @@
    • -
      social-foursquare
      -
      #icon-four
      +
      飞牛
      +
      #icon-fnos
    • -
      ksyun-logo
      +
      金山云logo
      #icon-ksyun
    • +
    • + +
      中国移动
      +
      #icon-cmcc
      +
    • + +
    • + +
      xinnet
      +
      #icon-xinnet
      +
    • + +
    • + +
      ucloud
      +
      #icon-ucloud
      +
    • + +
    • + +
      social-foursquare
      +
      #icon-four
      +
    • +