From bf040d4c428d29c06fbaca5e29100e0c583b2b0b Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 16 May 2025 00:04:52 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=B7=BB=E5=8A=A0=20FlexCDN=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AF=81=E4=B9=A6=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 FlexCDNRefreshCert 插件类,实现更新证书功能 - 添加 FlexCDNAccess 授权类和 FlexCDNClient 客户端类 - 实现获取证书列表和更新证书的 API 调用 - 提供插件配置界面和执行逻辑 --- .../src/plugins/plugin-flex/access.ts | 110 +++++++++++++++ .../src/plugins/plugin-flex/client.ts | 81 +++++++++++ .../src/plugins/plugin-flex/index.ts | 3 + .../src/plugins/plugin-flex/plugins/index.ts | 1 + .../plugins/plugin-refresh-cert.ts | 128 ++++++++++++++++++ 5 files changed, 323 insertions(+) create mode 100644 packages/ui/certd-server/src/plugins/plugin-flex/access.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-flex/client.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-flex/index.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-flex/plugins/index.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-flex/plugins/plugin-refresh-cert.ts diff --git a/packages/ui/certd-server/src/plugins/plugin-flex/access.ts b/packages/ui/certd-server/src/plugins/plugin-flex/access.ts new file mode 100644 index 00000000..3ea67c05 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-flex/access.ts @@ -0,0 +1,110 @@ +import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline"; +import { HttpClient } from "@certd/basic"; +import { FlexCDNClient } from "./client.js"; + +/** + */ +@IsAccess({ + name: "flexcdn", + title: "FlexCDN授权", + desc: "", + icon: "svg:icon-lucky" +}) +export class FlexCDNAccess extends BaseAccess { + @AccessInput({ + title: "接口地址", + component: { + placeholder: "http://xxxxxxx:8080", + name: "a-input", + vModel: "value" + }, + required: true + }) + endpoint!: string; + + @AccessInput({ + title: "用户类型", + component: { + placeholder: "请选择", + name: "a-select", + vModel: "value", + options: [ + { + value: "user", + label: "普通用户" + }, + { + value: "admin", + label: "管理员" + } + ] + }, + required: true + }) + type!: string; + + @AccessInput({ + title: "accessKeyId", + component: { + placeholder: "accessKeyId", + component: { + name: "a-input", + vModel: "value" + } + }, + encrypt: false, + required: true + }) + accessKeyId!: string; + + @AccessInput({ + title: "accessKey", + component: { + placeholder: "accessKey", + component: { + name: "a-input", + vModel: "value" + } + }, + encrypt: true, + required: true + }) + accessKey!: string; + + @AccessInput({ + title: "忽略证书校验", + component: { + name: "a-switch", + vModel: "checked" + }, + encrypt: false, + required: true + }) + skipSslVerify!: boolean; + + @AccessInput({ + title: "测试", + component: { + name: "api-test", + action: "TestRequest" + }, + helper: "点击测试接口看是否正常" + }) + testRequest = true; + + async onTestRequest() { + const http: HttpClient = this.ctx.http; + const client = new FlexCDNClient({ + logger: this.ctx.logger, + http, + access: this + }); + const token = await client.getToken(); + if (token) { + return "ok"; + } + throw "测试失败,未知错误"; + } +} + +new FlexCDNAccess(); diff --git a/packages/ui/certd-server/src/plugins/plugin-flex/client.ts b/packages/ui/certd-server/src/plugins/plugin-flex/client.ts new file mode 100644 index 00000000..036158e5 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-flex/client.ts @@ -0,0 +1,81 @@ +import { HttpClient, HttpRequestConfig, ILogger } from "@certd/basic"; +import { FlexCDNAccess } from "./access.js"; + +export class FlexCDNClient { + http: HttpClient; + logger: ILogger; + access: FlexCDNAccess; + token: string; + + constructor(opts: { logger: ILogger; http: HttpClient; access: FlexCDNAccess }) { + this.logger = opts.logger; + this.http = opts.http; + this.access = opts.access; + } + + async getToken() { + + /* + 步骤2:调用API获取AccessToken +接口地址 +/APIAccessTokenService/getAPIAccessToken +请求方法 +POST。 + +请求参数 +{ + "type": "admin", + "accessKeyId": "zr9cmR42AEZxRyIV", + "accessKey": "2w5p5NSZZuplUPsfPMzM7dFmTrI7xyja" +} +其中 +type - 如果是用户(即平台用户)AccessKey,则值为 user;如果是管理员(即系统用户)AccessKey,则值为 admin; +accessKeyId 和 accessKey 换成你在步骤1中创建的AccessKey对应的数据。 +响应结果 +{ + "code": 200, + "data": { + "token": "IKNSMufZ1vDiXp5rSd9QR01m1174Oum5sah4amWFgbRb7lOKjuk62Spl7hgcazctzGhGG7jPgfmYUPojulC0FK5cLbrj8n7kxW7BtSawH9gWW14IWOzBY6UcpyXQndFu", + "expiresAt": 1609686945 + }, + "message": "ok" +} + */ + + const res = await this.doRequest({ + url: "/APIAccessTokenService/getAPIAccessToken", + method: "POST", + data: { + type: this.access.type, + accessKeyId: this.access.accessKeyId, + accessKey: this.access.accessKey, + }, + }); + this.token = res.token + return this.token + } + + async doRequest(req: HttpRequestConfig) { + + const headers = { + ...req.headers, + } + if(this.token){ + headers[ "X-Cloud-Access-Token"] = this.token + } + const res = await this.http.request({ + ...req, + headers, + baseURL: this.access.endpoint, + logRes:false, + logParams:false, + skipSslVerify: true, + }); + if (res.code === 200) { + return res.data; + } else { + throw new Error(res.message); + } + } + +} diff --git a/packages/ui/certd-server/src/plugins/plugin-flex/index.ts b/packages/ui/certd-server/src/plugins/plugin-flex/index.ts new file mode 100644 index 00000000..09ca4f9f --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-flex/index.ts @@ -0,0 +1,3 @@ +export * from "./plugins/index.js"; +export * from "./access.js"; +export * from "./client.js"; diff --git a/packages/ui/certd-server/src/plugins/plugin-flex/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-flex/plugins/index.ts new file mode 100644 index 00000000..b8237e4f --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-flex/plugins/index.ts @@ -0,0 +1 @@ +export * from "./plugin-refresh-cert.js"; diff --git a/packages/ui/certd-server/src/plugins/plugin-flex/plugins/plugin-refresh-cert.ts b/packages/ui/certd-server/src/plugins/plugin-flex/plugins/plugin-refresh-cert.ts new file mode 100644 index 00000000..6846cac8 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-flex/plugins/plugin-refresh-cert.ts @@ -0,0 +1,128 @@ +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; +import { FlexCDNAccess } from "../access.js"; +import { FlexCDNClient } from "../client.js"; + +@IsTaskPlugin({ + //命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名 + name: "FlexCDNRefreshCert", + title: "FlexCDN-更新证书", + icon: "svg:icon-lucky", + //插件分组 + group: pluginGroups.cdn.key, + needPlus: false, + default: { + //默认值配置照抄即可 + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed, + }, + }, +}) +//类名规范,跟上面插件名称(name)一致 +export class FlexCDNRefreshCert extends AbstractTaskPlugin { + //证书选择,此项必须要有 + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames], + }, + // required: true, // 必填 + }) + cert!: CertInfo; + + @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + certDomains!: string[]; + + //授权选择框 + @TaskInput({ + title: "FlexCDN授权", + component: { + name: "access-selector", + type: "FlexCDN", //固定授权类型 + }, + required: true, //必填 + }) + accessId!: string; + // + + @TaskInput( + createRemoteSelectInputDefine({ + title: "证书Id", + helper: "要更新的Flex证书id", + action: FlexCDNRefreshCert.prototype.onGetCertList.name, + }) + ) + certList!: number[]; + + //插件实例化时执行的方法 + async onInstance() {} + + //插件执行方法 + async execute(): Promise { + const access: FlexCDNAccess = await this.getAccess(this.accessId); + + const client = new FlexCDNClient({ + http: this.ctx.http, + logger: this.logger, + access, + }); + await client.getToken(); + for (const item of this.certList) { + this.logger.info(`开始更新证书:${item}`); + + const res = await client.doRequest({ + url: `/SSLCertService/findEnabledSSLCertConfig`, + data: { + sslCertId: item, + }, + }); + + await client.doRequest({ + url: `/SSLCertService/updateSSLCert`, + data: { + ...res, + sslCertId: item, + certData: this.cert.crt, + keyData: this.cert.key, + }, + }); + + this.logger.info(`更新证书${item}成功`); + } + + this.logger.info("部署完成"); + } + + async onGetCertList() { + const access: FlexCDNAccess = await this.getAccess(this.accessId); + const client = new FlexCDNClient({ + http: this.ctx.http, + logger: this.logger, + access, + }); + await client.getToken(); + const res = await client.doRequest({ + url: "/SSLCertService/listSSLCerts", + data: { size: 1000}, + method: "POST", + }); + const list = res.sslCertsJSON; + if (!list || list.length === 0) { + throw new Error("没有找到证书,请先在控制台上传一次证书且关联网站"); + } + + const options = list.map((item: any) => { + return { + label: `${item.name}<${item.id}-${item.firstServerName}>`, + value: item.id, + domain: JSON.parse(item.serverNamesJSON), + }; + }); + return this.ctx.utils.options.buildGroupOptions(options, this.certDomains); + } +} +//实例化一下,注册插件 +new FlexCDNRefreshCert();