mirror of
https://github.com/certd/certd.git
synced 2025-11-25 09:10:11 +08:00
174 lines
5.0 KiB
TypeScript
174 lines
5.0 KiB
TypeScript
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";
|
||
import crypto from 'crypto'
|
||
|
||
@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() {
|
||
}
|
||
|
||
static parseCertInfo(certPem: string) {
|
||
const certificateArray = certPem
|
||
.trim()
|
||
.split('-----END CERTIFICATE-----')
|
||
.filter(cert => cert.trim() !== '')
|
||
.map(cert => (cert + '-----END CERTIFICATE-----').trim());
|
||
|
||
const currentInfo = new crypto.X509Certificate(certificateArray[0])
|
||
|
||
const dnsNames = currentInfo.subjectAltName.split(',')
|
||
.map(it => it.trim())
|
||
.filter(it => it.startsWith('DNS:'))
|
||
.map(it => it.substring(4))
|
||
|
||
const commonNames = certificateArray.map(it => {
|
||
const info = new crypto.X509Certificate(it)
|
||
|
||
const subjectCN = info.issuer.trim()
|
||
.split('\n')
|
||
.map(it => it.trim())
|
||
.find((part) => part.trim().startsWith('CN='))
|
||
?.split('=')[1]
|
||
?.trim();
|
||
|
||
return subjectCN
|
||
})
|
||
|
||
return {
|
||
commonNames: commonNames,
|
||
dnsNames: dnsNames,
|
||
timeBeginAt: Math.floor((new Date(currentInfo.validFrom)).getTime() / 1000),
|
||
timeEndAt: Math.floor((new Date(currentInfo.validTo)).getTime() / 1000),
|
||
}
|
||
}
|
||
|
||
//插件执行方法
|
||
async execute(): Promise<void> {
|
||
const access: FlexCDNAccess = await this.getAccess<FlexCDNAccess>(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
|
||
}
|
||
});
|
||
|
||
const sslCert = JSON.parse(this.ctx.utils.hash.base64Decode(res.sslCertJSON))
|
||
this.logger.info(`证书信息:${sslCert.name},${sslCert.dnsNames}`);
|
||
const body = {
|
||
...sslCert, // inherit old cert info like name and description
|
||
...FlexCDNRefreshCert.parseCertInfo(this.cert.crt),
|
||
name: sslCert.name,
|
||
sslCertId: item,
|
||
certData: this.ctx.utils.hash.base64(this.cert.crt),
|
||
keyData: this.ctx.utils.hash.base64(this.cert.key)
|
||
};
|
||
await client.doRequest({
|
||
url: `/SSLCertService/updateSSLCert`,
|
||
data: {
|
||
...body
|
||
}
|
||
});
|
||
|
||
this.logger.info(`----------- 更新证书${item}成功`);
|
||
}
|
||
|
||
this.logger.info("部署完成");
|
||
}
|
||
|
||
async onGetCertList() {
|
||
const access: FlexCDNAccess = await this.getAccess<FlexCDNAccess>(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 = JSON.parse(this.ctx.utils.hash.base64Decode(res.sslCertsJSON));
|
||
if (!list || list.length === 0) {
|
||
throw new Error("没有找到证书,请先在控制台上传一次证书且关联网站");
|
||
}
|
||
|
||
const options = list.map((item: any) => {
|
||
return {
|
||
label: `${item.name}<${item.id}-${item.dnsNames[0]}>`,
|
||
value: item.id,
|
||
domain: item.dnsNames
|
||
};
|
||
});
|
||
return this.ctx.utils.options.buildGroupOptions(options, this.certDomains);
|
||
}
|
||
}
|
||
|
||
//实例化一下,注册插件
|
||
new FlexCDNRefreshCert();
|