diff --git a/packages/core/pipeline/src/plugin/group.ts b/packages/core/pipeline/src/plugin/group.ts index a56a8288..cf2c5d72 100644 --- a/packages/core/pipeline/src/plugin/group.ts +++ b/packages/core/pipeline/src/plugin/group.ts @@ -19,14 +19,15 @@ export class PluginGroup { export const pluginGroups = { cert: new PluginGroup("cert", "证书申请", 1, "ph:certificate"), + host: new PluginGroup("host", "主机", 2, "clarity:host-line"), + cdn: new PluginGroup("cdn", "CDN", 2, "svg:icon-cdn"), + panel: new PluginGroup("panel", "面板", 2, "fluent:panel-left-header-32-filled"), aliyun: new PluginGroup("aliyun", "阿里云", 2, "svg:icon-aliyun"), huawei: new PluginGroup("huawei", "华为云", 3, "svg:icon-huawei"), tencent: new PluginGroup("tencent", "腾讯云", 4, "svg:icon-tencentcloud"), volcengine: new PluginGroup("volcengine", "火山引擎", 4, "svg:icon-volcengine"), + jdcloud: new PluginGroup("jdcloud", "京东云", 4, "svg:icon-jdcloud"), qiniu: new PluginGroup("qiniu", "七牛云", 5, "svg:icon-qiniuyun"), aws: new PluginGroup("aws", "亚马逊云", 6, "svg:icon-aws"), - host: new PluginGroup("host", "主机", 7, "clarity:host-line"), - cdn: new PluginGroup("cdn", "CDN", 8, "svg:icon-cdn"), - panel: new PluginGroup("panel", "面板", 9, "fluent:panel-left-header-32-filled"), other: new PluginGroup("other", "其他", 10, "clarity:plugin-line"), }; diff --git a/packages/core/pipeline/src/registry/registry.ts b/packages/core/pipeline/src/registry/registry.ts index 199e9415..eeaeaf89 100644 --- a/packages/core/pipeline/src/registry/registry.ts +++ b/packages/core/pipeline/src/registry/registry.ts @@ -6,6 +6,7 @@ export type Registrable = { desc?: string; group?: string; deprecated?: string; + order?: number; }; export type RegistryItem = { diff --git a/packages/libs/lib-jdcloud/src/index.ts b/packages/libs/lib-jdcloud/src/index.ts index 3c34209c..d870f61c 100644 --- a/packages/libs/lib-jdcloud/src/index.ts +++ b/packages/libs/lib-jdcloud/src/index.ts @@ -2,6 +2,10 @@ import jdCloud from "./lib/core.js"; import jdService from './lib/service.js' import domainService from './repo/domainservice/v2/domainservice.js' +import cdnService from './repo/cdn/v1/cdn.js' +import sslService from './repo/ssl/v1/ssl.js' export const JDCloud = jdCloud; export const JDService = jdService; -export const JDDomainService = domainService; \ No newline at end of file +export const JDDomainService = domainService; +export const JDCdnService = cdnService; +export const JDSslService = sslService; \ No newline at end of file diff --git a/packages/ui/certd-server/src/modules/pipeline/service/builtin-plugin-service.ts b/packages/ui/certd-server/src/modules/pipeline/service/builtin-plugin-service.ts index c3f654ee..7004e50b 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/builtin-plugin-service.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/builtin-plugin-service.ts @@ -7,7 +7,7 @@ import { cloneDeep } from 'lodash-es'; export class BuiltInPluginService { getList() { const collection = pluginRegistry.storage; - const list = []; + let list = []; for (const key in collection) { const Plugin = collection[key]; if (Plugin?.define?.deprecated) { @@ -15,11 +15,21 @@ export class BuiltInPluginService { } list.push({ ...Plugin.define, key }); } + list = list.sort((a, b) => { + return (a.order ?? 10 )- (b.order ?? 10); + }); return list; } getGroups() { - return cloneDeep(pluginGroups); + const groups:any = cloneDeep(pluginGroups); + for (const key in groups) { + const group = groups[key]; + group.plugins = group.plugins.sort((a, b) => { + return (a.order ?? 10 )- (b.order ?? 10); + }); + } + return groups; } getByType(type: string) { diff --git a/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts b/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts index 5595fef4..9c7b4624 100644 --- a/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts @@ -9,6 +9,7 @@ import { CertApplyPluginNames} from '@certd/plugin-cert'; icon: 'line-md:uploading-loop', group: pluginGroups.host.key, desc: 'SFTP上传证书到主机,然后SSH执行部署脚本命令', + order: 1, default: { strategy: { runStrategy: RunStrategy.SkipWhenSucceed, diff --git a/packages/ui/certd-server/src/plugins/plugin-jdcloud/index.ts b/packages/ui/certd-server/src/plugins/plugin-jdcloud/index.ts index 35fce254..1d8d9573 100644 --- a/packages/ui/certd-server/src/plugins/plugin-jdcloud/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-jdcloud/index.ts @@ -1,2 +1,3 @@ export * from './access.js'; export * from './dns-provider.js'; +export * from './plugins/index.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/index.ts new file mode 100644 index 00000000..7571a96a --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/index.ts @@ -0,0 +1,3 @@ +export * from './plugin-deploy-to-cdn.js' +export * from './plugin-update-cert.js' +export * from './plugin-upload-cert.js' diff --git a/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/plugin-deploy-to-cdn.ts b/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/plugin-deploy-to-cdn.ts new file mode 100644 index 00000000..c9347abd --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/plugin-deploy-to-cdn.ts @@ -0,0 +1,175 @@ +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { optionsUtils } from "@certd/basic/dist/utils/util.options.js"; +import { JDCloudAccess } from "../access.js"; + +@IsTaskPlugin({ + name: "JDCloudDeployToCDN", + title: "京东云-部署证书至CDN", + icon: "svg:icon-jdcloud", + group: pluginGroups.jdcloud.key, + desc: "京东云内容分发网络", + default: { + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed + } + } +}) +export class JDCloudDeployToCDN extends AbstractTaskPlugin { + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames, "JDCloudUploadCert"] + }, + required: true + }) + cert!: CertInfo | number; + + @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + certDomains!: string[]; + + + @TaskInput({ + title: "Access授权", + helper: "京东云AccessKeyId、AccessKeySecret", + component: { + name: "access-selector", + type: "jdcloud" + }, + required: true + }) + accessId!: string; + + + @TaskInput( + createRemoteSelectInputDefine({ + title: "CDN加速域名", + helper: "你在京东云上配置的CDN加速域名,比如:certd.docmirror.cn", + action: JDCloudDeployToCDN.prototype.onGetDomainList.name, + watches: ["certDomains", "accessId"], + required: true + }) + ) + domainName!: string | string[]; + + + async onInstance() { + } + + async execute(): Promise { + this.logger.info("开始部署证书到京东云CDN"); + const access = await this.accessService.getById(this.accessId); + + const service = await this.getClient(access); + let certId = this.cert; + const certName = this.appendTimeSuffix("certd"); + if (typeof certId === "object") { + const certInfo = this.cert as CertInfo; + this.logger.info(`开始上传证书`); + + const sslService = await this.getSslClient(access); + const res = await sslService.uploadCert({ + // certName String True 证书名称 + // keyFile String True 私钥 + // certFile String True 证书 + // aliasName String False 证书别名 + certName: certName, + keyFile: certInfo.key, + certFile: certInfo.crt, + aliasName: certName + }); + certId = res.result.certId; + } + + // const certInfo = this.cert as CertInfo; + for (const domain of this.domainName) { + this.logger.info(`开始部署域名${domain}证书`); + const res = await service.setHttpType({ + /** + * @param {string} opts.domain - 用户域名 + * @param {} [opts.httpType] - http类型,只能为http或者https,默认为http.当设为https时,需要调用“设置通讯协议”接口上传证书和私钥 optional + * @param {} [opts.certificate] - 用户证书,当Type为https时必须设置 optional + * @param {} [opts.rsaKey] - 证书私钥 optional + * @param {} [opts.jumpType] - 有三种类型:default、http、https optional + * @param {} [opts.certFrom] - 证书来源有两种类型:default,ssl optional + * @param {} [opts.sslCertId] - ssl证书id optional + * @param {} [opts.syncToSsl] - 是否同步到ssl,boolean值,取值true或者false optional + * @param {} [opts.certName] - syncToSsl是true时,certName是必填项 optional + */ + domain, + httpType: "https", + // certificate: certInfo.crt, + // rsaKey: certInfo.key, + jumpType: "default", + certFrom: "ssl", + sslCertId: certId, // 不用certId 方式,会报证书已存在错误,目前还没找到怎么查询重复证书 + syncToSsl: false, + certName: certName + }); + this.logger.info(`部署域名${domain}证书成功:${JSON.stringify(res)}`); + await this.ctx.utils.sleep(2000); + } + + this.logger.info("部署完成"); + } + + + async getClient(access: JDCloudAccess) { + const { JDCdnService } = await import("@certd/jdcloud"); + const service = new JDCdnService({ + credentials: { + accessKeyId: access.accessKeyId, + secretAccessKey: access.secretAccessKey + }, + regionId: "cn-north-1" //地域信息,某个api调用可以单独传参regionId,如果不传则会使用此配置中的regionId + }); + return service; + } + + async getSslClient(access: JDCloudAccess) { + const { JDSslService } = await import("@certd/jdcloud"); + const service = new JDSslService({ + credentials: { + accessKeyId: access.accessKeyId, + secretAccessKey: access.secretAccessKey + }, + regionId: "cn-north-1" //地域信息,某个api调用可以单独传参regionId,如果不传则会使用此配置中的regionId + }); + return service; + } + + async onGetDomainList(data: any) { + if (!this.accessId) { + throw new Error("请选择Access授权"); + } + const access = await this.accessService.getById(this.accessId); + + const service = await this.getClient(access); + /** + * pageNumber Integer False 1 pageNumber,默认值1 + * pageSize + */ + const res = await service.getDomainList({ + pageNumber: 1, + pageSize: 50 + }); + // @ts-ignore + const list = res?.result?.domains; + if (!list || list.length === 0) { + throw new Error("找不到加速域名,您可以手动输入"); + } + const options = list.map((item: any) => { + return { + value: item.domain, + label: item.domain, + domain: item.domain + }; + }); + return optionsUtils.buildGroupOptions(options, this.certDomains); + } +} + +new JDCloudDeployToCDN(); diff --git a/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/plugin-update-cert.ts b/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/plugin-update-cert.ts new file mode 100644 index 00000000..a17f6a92 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/plugin-update-cert.ts @@ -0,0 +1,148 @@ +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { optionsUtils } from "@certd/basic/dist/utils/util.options.js"; +import { JDCloudAccess } from "../access.js"; + +@IsTaskPlugin({ + name: 'JDCloudUpdateCert', + title: '京东云-更新已有证书', + icon: 'svg:icon-jdcloud', + group: pluginGroups.jdcloud.key, + desc: '更新SSL数字证书中的证书', + default: { + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed, + }, + }, +}) +export class JDCloudUpdateCert extends AbstractTaskPlugin { + @TaskInput({ + title: '域名证书', + helper: '请选择前置任务输出的域名证书', + component: { + name: 'output-selector', + from: [...CertApplyPluginNames, 'JDCloudUploadCert'], + }, + required: true, + }) + cert!: CertInfo | string; + + @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + certDomains!: string[]; + + + @TaskInput({ + title: 'Access授权', + helper: '京东云AccessKeyId、AccessKeySecret', + component: { + name: 'access-selector', + type: 'jdcloud', + }, + required: true, + }) + accessId!: string; + + + + @TaskInput( + createRemoteSelectInputDefine({ + title: '要更新的证书id', + helper: '您在京东云上已有的证书Id', + action: JDCloudUpdateCert.prototype.onGetCertList.name, + watches: ['certDomains', 'accessId'], + required: true, + }) + ) + certIds!: string[]; + + + async onInstance() {} + async execute(): Promise { + this.logger.info('开始部署证书到京东云CDN'); + const access = await this.accessService.getById(this.accessId); + + const service = await this.getClient(access) + // let certId = this.cert + // const certName = this.appendTimeSuffix("certd"); + // if (typeof certId !== 'string') { + // const certInfo = this.cert as CertInfo + // this.logger.info(`开始上传证书`) + // + // const res = await service.uploadCert({ + // // certName String True 证书名称 + // // keyFile String True 私钥 + // // certFile String True 证书 + // // aliasName String False 证书别名 + // certName: certName, + // keyFile: certInfo.key, + // certFile: certInfo.crt, + // aliasName: certName + // }) + // certId = res.result.certId + // } + + const certInfo = this.cert as CertInfo + for (const certId of this.certIds) { + this.logger.info(`开始更新证书:${certId}`) + const res = await service.updateCert({ + /* + @param {string} opts.certId - 证书Id +@param {string} opts.certId - 证书ID +@param {string} opts.keyFile - 私钥 +@param {string} opts.certFile - 证书 +@param {string} callback - callback + */ + certId, + certFile: certInfo.crt, + keyFile:certInfo.key, + }) + this.logger.info(`更新证书${certId}成功:${JSON.stringify(res)}`); + await this.ctx.utils.sleep(2000) + } + } + + + async getClient(access: JDCloudAccess) { + const {JDSslService} = await import("@certd/jdcloud") + const service = new JDSslService({ + credentials: { + accessKeyId: access.accessKeyId, + secretAccessKey: access.secretAccessKey + }, + regionId: "cn-north-1" //地域信息,某个api调用可以单独传参regionId,如果不传则会使用此配置中的regionId + }); + return service; + } + + async onGetCertList(data: any) { + if (!this.accessId) { + throw new Error('请选择Access授权'); + } + const access = await this.accessService.getById(this.accessId); + + const service = await this.getClient(access); + /** + * pageNumber Integer False 1 pageNumber,默认值1 + * pageSize + */ + const res = await service.describeCerts({ + pageNumber: 1, + pageSize: 100, + }) + // @ts-ignore + const list = res?.result?.certListDetails + if (!list || list.length === 0) { + throw new Error('找不到证书,您可以手动输入证书id'); + } + const options = list.map((item: any) => { + return { + value: item.certId, + label: `${item.certName}<${item.certId}_${item.commonName}>`, + domain: item.commonName, // or item.dnsNames 证书所有域名 + }; + }); + return optionsUtils.buildGroupOptions(options, this.certDomains); + } +} +new JDCloudUpdateCert(); diff --git a/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/plugin-upload-cert.ts b/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/plugin-upload-cert.ts new file mode 100644 index 00000000..6041aa02 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-jdcloud/plugins/plugin-upload-cert.ts @@ -0,0 +1,92 @@ +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { JDCloudAccess } from "../access.js"; + +@IsTaskPlugin({ + name: "JDCloudUploadCert", + title: "京东云-上传新证书", + icon: "svg:icon-jdcloud", + group: pluginGroups.jdcloud.key, + desc: "上传证书到SSL数字证书中心", + default: { + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed + } + } +}) +export class JDCloudUploadCert extends AbstractTaskPlugin { + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames, "JDCloudUploadCert"] + }, + required: true + }) + cert!: CertInfo | string; + + + @TaskInput({ + title: "Access授权", + helper: "京东云AccessKeyId、AccessKeySecret", + component: { + name: "access-selector", + type: "jdcloud" + }, + required: true + }) + accessId!: string; + + + @TaskInput({ + title: "证书名称前缀", + helper: "证书形成,默认为certd", + required: false + }) + certName!: string; + + @TaskOutput({ + title: "上传成功后的京东云CertId" + }) + jdcloudCertId!: number; + + async onInstance() { + } + + async execute(): Promise { + this.logger.info("开始上传证书到京东云数字证书中心"); + const access = await this.accessService.getById(this.accessId); + + const service = await this.getClient(access); + + const certInfo = this.cert as CertInfo; + const res = await service.uploadCert({ + /* + @param {string} opts.certName - 证书名称 +@param {string} opts.keyFile - 私钥 +@param {string} opts.certFile - 证书 +@param {string} [opts.aliasName] - 证书别名 optional + */ + certName: this.appendTimeSuffix(this.certName || "certd"), + certFile: certInfo.crt, + keyFile: certInfo.key + }); + this.jdcloudCertId = res.result.certId; + this.logger.info(`上传证书成功:${JSON.stringify(res)}`); + } + + async getClient(access: JDCloudAccess) { + const { JDSslService } = await import("@certd/jdcloud"); + const service = new JDSslService({ + credentials: { + accessKeyId: access.accessKeyId, + secretAccessKey: access.secretAccessKey + }, + regionId: "cn-north-1" //地域信息,某个api调用可以单独传参regionId,如果不传则会使用此配置中的regionId + }); + return service; + } +} + +new JDCloudUploadCert();