From c3da026b33106f5195959825a68cadbe49efef00 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 10 Jul 2025 23:30:33 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=E8=AF=81=E4=B9=A6=E5=88=B0=E7=BD=91=E5=AE=BFCDN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/certd-server/src/configuration.ts | 10 +- packages/ui/certd-server/src/plugins/index.ts | 1 + .../src/plugins/plugin-wangsu/access.ts | 161 ++++++++++++++++++ .../src/plugins/plugin-wangsu/index.ts | 2 + .../plugin-wangsu/lib/auth/AkSkAuth.ts | 87 ++++++++++ .../plugin-wangsu/lib/common/Constant.ts | 19 +++ .../lib/exception/ApiAuthException.ts | 9 + .../src/plugins/plugin-wangsu/lib/index.ts | 4 + .../plugin-wangsu/lib/model/AkSkConfig.ts | 56 ++++++ .../plugin-wangsu/lib/model/HttpRequestMsg.ts | 75 ++++++++ .../plugin-wangsu/lib/util/CryptoUtils.ts | 23 +++ .../plugin-wangsu/lib/util/HttpUtils.ts | 30 ++++ .../plugins/plugin-wangsu/plugins/index.ts | 1 + .../plugins/plugin-refresh-cert.ts | 121 +++++++++++++ 14 files changed, 594 insertions(+), 5 deletions(-) create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/access.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/index.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/lib/auth/AkSkAuth.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/lib/common/Constant.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/lib/exception/ApiAuthException.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/lib/index.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/lib/model/AkSkConfig.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/lib/model/HttpRequestMsg.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/lib/util/CryptoUtils.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/lib/util/HttpUtils.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/plugins/index.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-wangsu/plugins/plugin-refresh-cert.ts diff --git a/packages/ui/certd-server/src/configuration.ts b/packages/ui/certd-server/src/configuration.ts index 00d4ddff..a730e592 100644 --- a/packages/ui/certd-server/src/configuration.ts +++ b/packages/ui/certd-server/src/configuration.ts @@ -26,11 +26,11 @@ process.on('uncaughtException', error => { }); @Configuration({ - // detectorOptions: { - // ignore: [ - // '**/plugins/**' - // ] - // }, + detectorOptions: { + ignore: [ + '**/plugins/**' + ] + }, imports: [ koa, orm, diff --git a/packages/ui/certd-server/src/plugins/index.ts b/packages/ui/certd-server/src/plugins/index.ts index 485b2216..902f87fb 100644 --- a/packages/ui/certd-server/src/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/index.ts @@ -25,3 +25,4 @@ 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-wangsu/index.js' diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/access.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/access.ts new file mode 100644 index 00000000..a55f0075 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/access.ts @@ -0,0 +1,161 @@ +import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline"; +import { HttpRequestConfig } from "@certd/basic"; +import { CertInfo } from "@certd/plugin-cert"; + + + +/** + */ +@IsAccess({ + name: "wangsu", + title: "网宿授权", + desc: "", + icon: "svg:icon-lucky" +}) +export class WangsuAccess extends BaseAccess { + + @AccessInput({ + title: "accessKeyId", + component: { + placeholder: "accessKeyId", + component: { + name: "a-input", + vModel: "value" + } + }, + helper: "[点击前往获取AccessKey](https://console.wangsu.com/account/accessKey?rsr=ws)", + encrypt: false, + required: true + }) + accessKeyId!: string; + + @AccessInput({ + title: "accessKeySecret", + component: { + placeholder: "accessKeySecret", + component: { + name: "a-input", + vModel: "value" + } + }, + encrypt: true, + required: true + }) + accessKeySecret!: string; + + + @AccessInput({ + title: "测试", + component: { + name: "api-test", + action: "TestRequest" + }, + helper: "点击测试接口是否正常" + }) + testRequest = true; + + async onTestRequest() { + await this.getCertList({ }); + return "ok"; + } + + async getCertList(req: { }) { + /** + * certificate-id + * name + * dns-names + */ + const res = await this.doRequest({ + url: "/api/ssl/certificate", + method: "GET", + }); + + return res["ssl-certificate"] + } + + async getCertInfo(req:{certId:string}){ + return await this.doRequest({ + url: `/api/certificate/${req.certId}`, + method:"GET", + }); + } + + async updateCert(req: { + certId: string, + cert: CertInfo, + }) { + + const certInfo= await this.getCertInfo({certId:req.certId}); + + const name = certInfo.name; + const {cert,certId} = req; + return await this.doRequest({ + url: `/api/certificate/${certId}`, + method:"PUT", + data: { + /** + * name: string; + * certificate?: string; + * privateKey?: string; + * autoRenew?: string; + * isNeedAlarm?: string; + * csrId?: number; + * comment?: string; + */ + name:name, + certificate: cert.crt, + privateKey: cert.key, + autoRenew:"false", + isNeedAlarm:"false", + comment: "certd" + } + }); + } + + + + + async doRequest(req: HttpRequestConfig) { + + const data: any = req.data; + + const {AkSkConfig,AkSkAuth} = await import("./lib/index.js"); + + const akskConfig = new AkSkConfig(); + akskConfig.accessKey = this.accessKeyId; + akskConfig.secretKey = this.accessKeySecret; + akskConfig.endPoint = "open.chinanetcenter.com"; + akskConfig.uri = req.url; + akskConfig.method = req.method; + + const requestMsg = AkSkAuth.transferHttpRequestMsg(akskConfig,data?JSON.stringify(data):""); + AkSkAuth.getAuthAndSetHeaders(requestMsg, akskConfig.accessKey, akskConfig.secretKey); + + let response = undefined + try{ + response = await this.ctx.http.request({ + method: requestMsg.method, + url: requestMsg.url, + headers: requestMsg.headers, + data: requestMsg.body + }); + }catch (e) { + if (e.response?.data?.result) { + throw new Error(e.response?.data?.result); + } + throw e; + } + + if (response.code != null && response.code != 0){ + throw new Error(response.message); + } + if (response.data != null && response.code!==null){ + return response.data; + } + return response; + + } +} + + +new WangsuAccess(); diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/index.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/index.ts new file mode 100644 index 00000000..02dc3945 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/index.ts @@ -0,0 +1,2 @@ +export * from "./plugins/index.js"; +export * from "./access.js"; diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/auth/AkSkAuth.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/auth/AkSkAuth.ts new file mode 100644 index 00000000..c3cd2ca8 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/auth/AkSkAuth.ts @@ -0,0 +1,87 @@ +import { HttpRequestMsg } from "../model/HttpRequestMsg.js"; +import { AkSkConfig } from "../model/AkSkConfig.js"; +import { CryptoUtils } from "../util/CryptoUtils.js"; +import { HttpUtils } from "../util/HttpUtils.js"; +import { Constant } from "../common/Constant.js"; + +export class AkSkAuth { + + public static invoke(akSkConfig: AkSkConfig, jsonBody: string): Promise { + const requestMsg = AkSkAuth.transferHttpRequestMsg(akSkConfig, jsonBody); + AkSkAuth.getAuthAndSetHeaders(requestMsg, akSkConfig.accessKey, akSkConfig.secretKey); + return HttpUtils.call(requestMsg); + } + + static transferHttpRequestMsg(akSkConfig: AkSkConfig, jsonBody: string): HttpRequestMsg { + const requestMsg = new HttpRequestMsg(); + requestMsg.uri = akSkConfig.uri; + if (akSkConfig.endPoint && akSkConfig.endPoint !== Constant.END_POINT) { + requestMsg.host = akSkConfig.endPoint; + requestMsg.url = `${Constant.HTTPS_REQUEST_PREFIX}${akSkConfig.endPoint}${requestMsg.uri}`; + } else { + requestMsg.host = Constant.HTTP_DOMAIN; + requestMsg.url = `${Constant.HTTP_REQUEST_PREFIX}${requestMsg.uri}`; + } + requestMsg.method = akSkConfig.method; + requestMsg.signedHeaders = AkSkAuth.getSignedHeaders(akSkConfig.signedHeaders); + if (['POST', 'PUT', 'PATCH', 'DELETE'].indexOf(akSkConfig.method) !== -1) { + requestMsg.body = jsonBody; + } + return requestMsg; + } + + static getAuthAndSetHeaders(requestMsg: HttpRequestMsg, accessKey: string, secretKey: string): void { + const timeStamp = (Date.now() / 1000 | 0).toString(); + requestMsg.headers['Host'] = requestMsg.host; + requestMsg.headers[Constant.HEAD_SIGN_ACCESS_KEY] = accessKey; + requestMsg.headers[Constant.HEAD_SIGN_TIMESTAMP] = timeStamp; + requestMsg.headers["Accept"] = Constant.APPLICATION_JSON; + const signature = AkSkAuth.getSignature(requestMsg, secretKey, timeStamp); + requestMsg.headers['Authorization'] = AkSkAuth.genAuthorization(accessKey, AkSkAuth.getSignedHeaders(requestMsg.signedHeaders), signature); + } + + private static genAuthorization(accessKey: string, signedHeaders: string, signature: string): string { + return `${Constant.HEAD_SIGN_ALGORITHM} Credential=${accessKey}, SignedHeaders=${signedHeaders}, Signature=${signature}`; + } + + private static getSignature(requestMsg: HttpRequestMsg, secretKey: string, timestamp: string): string { + let bodyStr = requestMsg.body || ""; + const hashedRequestPayload = CryptoUtils.sha256Hex(bodyStr); + const canonicalRequest = `${requestMsg.method}\n${requestMsg.uri.split("?")[0]}\n${decodeURIComponent(requestMsg.getQueryString())}\n${AkSkAuth.getCanonicalHeaders(requestMsg.headers, AkSkAuth.getSignedHeaders(requestMsg.signedHeaders))}\n${AkSkAuth.getSignedHeaders(requestMsg.signedHeaders)}\n${hashedRequestPayload}`; + const stringToSign = `${Constant.HEAD_SIGN_ALGORITHM}\n${timestamp}\n${CryptoUtils.sha256Hex(canonicalRequest)}`; + return CryptoUtils.hmac256(secretKey, stringToSign).toLowerCase(); + } + + private static getCanonicalHeaders(headers: Record, signedHeaders: string): string { + const headerNames = signedHeaders.split(";"); + let canonicalHeaders = ""; + for (const headerName of headerNames) { + const headerValue = AkSkAuth.getValueByHeader(headerName, headers); + if (headerValue !== null) { + canonicalHeaders += `${headerName}:${headerValue.toLowerCase()}\n`; + } else { + // Handle missing headers if necessary, e.g., log a warning or skip + console.warn(`Header ${headerName} not found in provided headers.`); + } + } + return canonicalHeaders; + } + + + private static getSignedHeaders(signedHeaders: string): string { + if (!signedHeaders) { + return "content-type;host"; + } + const headers = signedHeaders.split(";"); + return headers.map(header => header.toLowerCase()).sort().join(";"); + } + + private static getValueByHeader(name: string, customHeaderMap: { [key: string]: string }): string | null { + for (const key in customHeaderMap) { + if (key.toLowerCase() === name.toLowerCase()) { + return customHeaderMap[key]; + } + } + return null; + } +} diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/common/Constant.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/common/Constant.ts new file mode 100644 index 00000000..6d860509 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/common/Constant.ts @@ -0,0 +1,19 @@ +export class Constant { + private constructor() {} + + public static readonly HTTP_REQUEST_PREFIX: string = "https://open.chinanetcenter.com"; + public static readonly HTTPS_REQUEST_PREFIX: string = "https://"; + public static readonly HTTP_DOMAIN: string = "open.chinanetcenter.com"; + + public static readonly APPLICATION_JSON: string = "application/json"; + + public static readonly HEAD_SIGN_ACCESS_KEY: string = "x-cnc-accessKey"; + public static readonly HEAD_SIGN_TIMESTAMP: string = "x-cnc-timestamp"; + public static readonly HEAD_SIGN_ALGORITHM: string = "CNC-HMAC-SHA256"; + + public static readonly X_CNC_AUTH_METHOD: string = "x-cnc-auth-method"; + + public static readonly AUTH_METHOD: string = "AKSK"; + + public static readonly END_POINT: string = "{endPoint}"; +} diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/exception/ApiAuthException.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/exception/ApiAuthException.ts new file mode 100644 index 00000000..5117760d --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/exception/ApiAuthException.ts @@ -0,0 +1,9 @@ +export class ApiAuthException extends Error { + public cause?: any; + + constructor(message: string, cause?: any) { + super(message); + this.cause = cause; + this.name = 'ApiAuthException'; + } +} diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/index.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/index.ts new file mode 100644 index 00000000..ebdf314e --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/index.ts @@ -0,0 +1,4 @@ +import { AkSkConfig } from "./model/AkSkConfig.js"; +import { AkSkAuth } from "./auth/AkSkAuth.js"; + +export { AkSkAuth, AkSkConfig} diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/model/AkSkConfig.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/model/AkSkConfig.ts new file mode 100644 index 00000000..ab41c4af --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/model/AkSkConfig.ts @@ -0,0 +1,56 @@ +export class AkSkConfig { + private _accessKey: string | undefined; + private _secretKey: string | undefined; + private _uri: string | undefined; + private _endPoint: string | undefined; + private _method: string | undefined; + private _signedHeaders: string | undefined; + + public get accessKey(): string { + return this._accessKey; + } + + public set accessKey(value: string) { + this._accessKey = value; + } + + public get secretKey(): string { + return this._secretKey; + } + + public set secretKey(value: string) { + this._secretKey = value; + } + + public get uri(): string { + return this._uri; + } + + public set uri(value: string) { + this._uri = value; + } + + public get endPoint(): string { + return this._endPoint; + } + + public set endPoint(value: string) { + this._endPoint = value; + } + + public get method(): string { + return this._method; + } + + public set method(value: string) { + this._method = value; + } + + public get signedHeaders(): string { + return this._signedHeaders; + } + + public set signedHeaders(value: string) { + this._signedHeaders = value; + } +} diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/model/HttpRequestMsg.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/model/HttpRequestMsg.ts new file mode 100644 index 00000000..89c761ef --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/model/HttpRequestMsg.ts @@ -0,0 +1,75 @@ +import { Constant } from '../common/Constant.js'; // Assuming you have a TypeScript version of this + +export class HttpRequestMsg { + uri: string ; + url: string; + host: string; + method: string; + protocol: string; + params: Record; + headers: Record; + body: string; + signedHeaders: string; + msg: any; + + constructor() { + this.params = {}; + this.headers = {}; + this.putHeader('Content-Type', Constant.APPLICATION_JSON); + this.putHeader(Constant.X_CNC_AUTH_METHOD, Constant.AUTH_METHOD); + } + + putParam(name: string, value: string): void { + this.params[name] = value; + } + + getParam(name: string): string | null { + const value = this.params[name]; + return value && value.trim() !== '' ? value : null; + } + + getQueryString(): string { + if(this.uri == undefined) + return ""; + const index = this.uri.indexOf("?"); + if (this.method === 'POST' || index === -1) { + return ""; + } + return this.uri.substring(index + 1); + } + + putHeader(name: string, value: string): void { + this.headers[name] = value; + } + + getHeader(name: string): string | null { + for (const key in this.headers) { + if (key.toLowerCase() === name.toLowerCase()) { + return this.headers[key]; + } + } + return null; + } + + getHeaderByNames(...names: string[]): string | null { + for (const name of names) { + const value = this.getHeader(name); + if (value) { + return value; + } + } + return null; + } + + removeHeader(name: string): void { + for (const key in this.headers) { + if (key.toLowerCase() === name.toLowerCase()) { + delete this.headers[key]; + } + } + } + + setJsonBody(object: any): void { + this.body = JSON.stringify(object); + } +} diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/util/CryptoUtils.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/util/CryptoUtils.ts new file mode 100644 index 00000000..11a310e7 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/util/CryptoUtils.ts @@ -0,0 +1,23 @@ +import CryptoJS from 'crypto-js'; + +export class CryptoUtils { + private constructor() {} + + /** + * hmac+sha256+hex + */ + public static sha256Hex(s: string): string { + const hash = CryptoJS.SHA256(s); + return hash.toString(CryptoJS.enc.Hex).toLowerCase(); + } + + /** + * hmac+sha256 + */ + public static hmac256(secretKey: string, message: string): string { + const keyWordArray = CryptoJS.enc.Utf8.parse(secretKey); + const messageWordArray = CryptoJS.enc.Utf8.parse(message); + const hash = CryptoJS.HmacSHA256(messageWordArray, keyWordArray); + return hash.toString(CryptoJS.enc.Hex).toLowerCase(); + } +} diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/util/HttpUtils.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/util/HttpUtils.ts new file mode 100644 index 00000000..81c33249 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/lib/util/HttpUtils.ts @@ -0,0 +1,30 @@ +import { HttpRequestMsg } from '../model/HttpRequestMsg.js'; // Assuming you have a TypeScript version of this +import { ApiAuthException } from '../exception/ApiAuthException.js'; // Assuming you have a TypeScript version of this +import axios, { AxiosError } from 'axios'; + +export class HttpUtils { + private constructor() { } + public static async call(requestMsg: HttpRequestMsg): Promise { + var response; + try { + response = await axios({ + method: requestMsg.method, + url: requestMsg.url, + headers: requestMsg.headers, + data: requestMsg.body + }); + console.info("API invoke success. Response:", response.data); + return response.data; + } catch (error) { + if (error instanceof AxiosError) { + // Handle AxiosError specifically + console.error('API invoke failed. Response:', error.response.data); + return error.response.data; + } else { + // Handle other types of errors + console.error('API invoke failed.', error); + } + throw new ApiAuthException('API invoke failed.'); + } + } +} diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/plugins/index.ts new file mode 100644 index 00000000..b8237e4f --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/plugins/index.ts @@ -0,0 +1 @@ +export * from "./plugin-refresh-cert.js"; diff --git a/packages/ui/certd-server/src/plugins/plugin-wangsu/plugins/plugin-refresh-cert.ts b/packages/ui/certd-server/src/plugins/plugin-wangsu/plugins/plugin-refresh-cert.ts new file mode 100644 index 00000000..f7f12eb5 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-wangsu/plugins/plugin-refresh-cert.ts @@ -0,0 +1,121 @@ +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 { WangsuAccess } from "../access.js"; + +@IsTaskPlugin({ + //命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名 + name: "WangsuRefreshCert", + title: "网宿-更新证书", + desc: "网宿证书自动更新", + icon: "svg:icon-lucky", + //插件分组 + group: pluginGroups.cdn.key, + needPlus: false, + default: { + //默认值配置照抄即可 + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed + } + } +}) +//类名规范,跟上面插件名称(name)一致 +export class WangsuRefreshCert extends AbstractTaskPlugin { + //证书选择,此项必须要有 + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames] + } + // required: true, // 必填 + }) + cert!: CertInfo; + + @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + certDomains!: string[]; + + //授权选择框 + @TaskInput({ + title: "网宿授权", + component: { + name: "access-selector", + type: "wangsu" //固定授权类型 + }, + required: true //必填 + }) + accessId!: string; + // + + @TaskInput( + createRemoteSelectInputDefine({ + title: "证书Id", + helper: "要更新的网宿证书id", + action: WangsuRefreshCert.prototype.onGetCertList.name, + pager: false, + search: false + }) + ) + certList!: string[]; + + //插件实例化时执行的方法 + async onInstance() { + } + + //插件执行方法 + async execute(): Promise { + const access = await this.getAccess(this.accessId); + + for (const item of this.certList) { + this.logger.info(`----------- 开始更新证书:${item}`); + await access.updateCert({ + certId: item, + cert: this.cert + }); + this.logger.info(`----------- 更新证书${item}成功`); + } + + this.logger.info("部署完成"); + } + + async onGetCertList(data: PageSearch = {}) { + const access = await this.getAccess(this.accessId); + + const list = await access.getCertList({}); + if (!list || list.length === 0) { + throw new Error("没有找到证书,请先在控制台上传一次证书且关联域名"); + } + + /** + * certificate-id + * name + * dns-names + */ + const options = list.map((item: any) => { + const domains = item["dns-names"] + const certId = item["certificate-id"]; + return { + label: `${item.name}<${certId}-${domains[0]}>`, + value: certId, + domain: item["dns-names"] + }; + }); + return { + list: this.ctx.utils.options.buildGroupOptions(options, this.certDomains), + total: list.length, + pageNo: 1, + pageSize: list.length + }; + } +} + +//实例化一下,注册插件 +new WangsuRefreshCert();