mirror of
https://github.com/certd/certd.git
synced 2026-05-17 05:37:30 +08:00
feat: 【破坏性更新】插件改为metadata加载模式,plugin-cert、plugin-lib包部分代码转移到certd-server中,影响自定义插件,需要修改相关import引用
ssh、aliyun、tencent、qiniu、oss等 access和client需要转移import
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline";
|
||||
import { BaiduYunCertClient } from "./client.js";
|
||||
|
||||
/**
|
||||
* 这个注解将注册一个授权配置
|
||||
* 在certd的后台管理系统中,用户可以选择添加此类型的授权
|
||||
*/
|
||||
@IsAccess({
|
||||
name: "baidu",
|
||||
title: "百度云授权",
|
||||
desc: "",
|
||||
icon: "ant-design:baidu-outlined",
|
||||
order: 2,
|
||||
})
|
||||
export class BaiduAccess extends BaseAccess {
|
||||
@AccessInput({
|
||||
title: "AccessKey",
|
||||
component: {
|
||||
placeholder: "AccessKey",
|
||||
},
|
||||
helper: "[百度智能云->安全认证获取](https://console.bce.baidu.com/iam/#/iam/accesslist)",
|
||||
required: true,
|
||||
encrypt: false,
|
||||
})
|
||||
accessKey = "";
|
||||
|
||||
@AccessInput({
|
||||
title: "SecretKey",
|
||||
component: {
|
||||
placeholder: "SecretKey",
|
||||
},
|
||||
helper: "",
|
||||
required: true,
|
||||
encrypt: true,
|
||||
})
|
||||
secretKey = "";
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "onTestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
const certClient = new BaiduYunCertClient({
|
||||
access: this,
|
||||
logger: this.ctx.logger,
|
||||
http: this.ctx.http,
|
||||
});
|
||||
|
||||
const res = await certClient.getCertList();
|
||||
this.ctx.logger.info("测试接口返回", res);
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
|
||||
new BaiduAccess();
|
||||
@@ -0,0 +1,191 @@
|
||||
import { HttpClient, HttpRequestConfig, ILogger } from "@certd/basic";
|
||||
import { BaiduAccess } from "./access.js";
|
||||
import crypto from "crypto";
|
||||
import { CertInfo } from "@certd/plugin-cert";
|
||||
|
||||
export type BaiduYunClientOptions = {
|
||||
access: BaiduAccess;
|
||||
logger: ILogger;
|
||||
http: HttpClient;
|
||||
};
|
||||
export type BaiduYunReq = {
|
||||
host: string;
|
||||
uri: string;
|
||||
body?: any;
|
||||
headers?: any;
|
||||
query?: any;
|
||||
method: string;
|
||||
};
|
||||
export class BaiduYunClient {
|
||||
opts: BaiduYunClientOptions;
|
||||
constructor(opts: BaiduYunClientOptions) {
|
||||
this.opts = opts;
|
||||
}
|
||||
|
||||
// 调用百度云接口,传接口uri和json参数
|
||||
async doRequest(req: BaiduYunReq, config?: HttpRequestConfig) {
|
||||
const host = req.host;
|
||||
const timestamp = this.getTimestampString();
|
||||
const queryString = this.getQueryString(req.query);
|
||||
const Authorization = this.getAuthString(host, req.method, req.uri, queryString, timestamp);
|
||||
|
||||
const ContentType = "application/json; charset=utf-8";
|
||||
|
||||
let url = "https://" + host + req.uri;
|
||||
if (req.query) {
|
||||
url += "?" + queryString;
|
||||
}
|
||||
const res = await this.opts.http.request({
|
||||
url: url,
|
||||
method: req.method,
|
||||
data: req.body,
|
||||
headers: {
|
||||
Authorization: Authorization,
|
||||
"Content-Type": ContentType,
|
||||
Host: host,
|
||||
"x-bce-date": timestamp,
|
||||
...req.headers,
|
||||
},
|
||||
...config,
|
||||
});
|
||||
if (res.code) {
|
||||
throw new Error(`请求失败:${res.message}`);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// 获取UTC时间
|
||||
getTimestampString() {
|
||||
return new Date().toISOString().replace(/\.\d*/, "");
|
||||
}
|
||||
|
||||
// 获取参数拼接字符串
|
||||
getQueryString(params) {
|
||||
let queryString = "";
|
||||
let paramKeyArray = [];
|
||||
if (params) {
|
||||
for (const key in params) {
|
||||
paramKeyArray.push(key);
|
||||
}
|
||||
paramKeyArray = paramKeyArray.sort();
|
||||
}
|
||||
if (paramKeyArray && paramKeyArray.length > 0) {
|
||||
for (const key of paramKeyArray) {
|
||||
queryString += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]) + "&";
|
||||
}
|
||||
queryString = queryString.substring(0, queryString.length - 1);
|
||||
}
|
||||
return queryString;
|
||||
}
|
||||
|
||||
uriEncode(input: string, encodeSlash = false) {
|
||||
let result = "";
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const ch = input.charAt(i);
|
||||
|
||||
if ((ch >= "A" && ch <= "Z") || (ch >= "a" && ch <= "z") || (ch >= "0" && ch <= "9") || ch === "_" || ch === "-" || ch === "~" || ch === ".") {
|
||||
result += ch;
|
||||
} else if (ch === "/") {
|
||||
result += encodeSlash ? "%2F" : ch;
|
||||
} else {
|
||||
result += this.toHexUTF8(ch);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
toHexUTF8(ch) {
|
||||
// Convert character to UTF-8 bytes and return the hex representation
|
||||
const utf8Bytes = new TextEncoder().encode(ch);
|
||||
let hexString = "";
|
||||
|
||||
for (const byte of utf8Bytes) {
|
||||
hexString += "%" + byte.toString(16).padStart(2, "0").toUpperCase();
|
||||
}
|
||||
|
||||
return hexString;
|
||||
}
|
||||
|
||||
// 签名
|
||||
getAuthString(Host: string, Method: string, CanonicalURI: string, CanonicalQueryString: string, timestamp: string) {
|
||||
// 1
|
||||
const expirationPeriodInSeconds = 120;
|
||||
const authStringPrefix = `bce-auth-v1/${this.opts.access.accessKey}/${timestamp}/${expirationPeriodInSeconds}`;
|
||||
// 2
|
||||
const signedHeaders = "host;x-bce-date";
|
||||
const CanonicalHeaders = encodeURIComponent("host") + ":" + encodeURIComponent(Host) + "\n" + encodeURIComponent("x-bce-date") + ":" + encodeURIComponent(timestamp);
|
||||
const CanonicalRequest = Method.toUpperCase() + "\n" + this.uriEncode(CanonicalURI, false) + "\n" + CanonicalQueryString + "\n" + CanonicalHeaders;
|
||||
// 3
|
||||
const SigningKey = crypto.createHmac("sha256", this.opts.access.secretKey).update(authStringPrefix).digest().toString("hex");
|
||||
// 4
|
||||
const Signature = crypto.createHmac("sha256", SigningKey).update(CanonicalRequest).digest().toString("hex");
|
||||
// 5
|
||||
return `${authStringPrefix}/${signedHeaders}/${Signature}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class BaiduYunCertClient {
|
||||
client: BaiduYunClient;
|
||||
constructor(opts: BaiduYunClientOptions) {
|
||||
this.client = new BaiduYunClient(opts);
|
||||
}
|
||||
|
||||
async createCert(opts: { certName: string; cert: CertInfo }) {
|
||||
// /v1/certificate
|
||||
const res = await this.client.doRequest({
|
||||
host: "certificate.baidubce.com",
|
||||
uri: `/v1/certificate`,
|
||||
method: "post",
|
||||
body: {
|
||||
/**
|
||||
* certName String 必须 证书的名称。长度限制为1-65个字符,以字母开头,只允许包含字母、数字、’-‘、’/’、’.’、’’,Java正则表达式` ^[a-zA-Z]a-zA-Z0-9\-/\.]{2,64}$`
|
||||
* certServerData String 必须 服务器证书的数据内容 (Base64编码)
|
||||
* certPrivateData String 必须 证书的私钥数据内容 (Base64编码)
|
||||
*/
|
||||
certName: "certd_" + opts.certName, // 字母开头,且小于64长度
|
||||
certServerData: opts.cert.crt,
|
||||
certPrivateData: opts.cert.key,
|
||||
},
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
async getCertList() {
|
||||
/**
|
||||
* GET /v1/certificate HTTP/1.1
|
||||
* HOST: certificate.baidubce.com
|
||||
* Authorization: {authorization}
|
||||
* Content-Type: application/json; charset=utf-8
|
||||
* x-bce-date: 2014-06-01T23:00:10Z
|
||||
*/
|
||||
return await this.client.doRequest({
|
||||
host: "certificate.baidubce.com",
|
||||
uri: `/v1/certificate`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
async updateCert(opts: { certId: string; certName: string; cert: CertInfo }) {
|
||||
/**
|
||||
* /v1/certificate/{certId}?certData
|
||||
* certName String 必须 证书的名称。长度限制为1-65个字符,以字母开头,只允许包含字母、数字、’-‘、’/’、’.’、’’,Java正则表达式` ^[a-zA-Z]a-zA-Z0-9\-/\.]{2,64}$`
|
||||
* certServerData String 必须 服务器证书的数据内容 (Base64编码)
|
||||
* certPrivateData String 必须 证书的私钥数据内容 (Base64编码)
|
||||
* certLinkData String 可选 证书链数据内容 (Base64编码)
|
||||
* certType Integer 可选 证书类型,非必填,默认为1
|
||||
*/
|
||||
|
||||
return await this.client.doRequest({
|
||||
host: "certificate.baidubce.com",
|
||||
uri: `/v1/certificate/${opts.certId}`,
|
||||
method: "put",
|
||||
body: {
|
||||
certName: opts.certName,
|
||||
certServerData: opts.cert.crt,
|
||||
certPrivateData: opts.cert.key,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./plugins/index.js";
|
||||
export * from "./access.js";
|
||||
export * from "./client.js";
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./plugin-deploy-to-cdn.js";
|
||||
export * from "./plugin-deploy-to-blb.js";
|
||||
export * from "./plugin-upload-to-baidu.js";
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { CertApplyPluginNames, CertInfo, CertReader } from "@certd/plugin-cert";
|
||||
import { createCertDomainGetterInputDefine } from "@certd/plugin-lib";
|
||||
import { BaiduYunCertClient, BaiduYunClient } from "../client.js";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: "BaiduDeployToBLB",
|
||||
title: "百度云-部署证书到负载均衡",
|
||||
icon: "ant-design:baidu-outlined",
|
||||
group: pluginGroups.baidu.key,
|
||||
desc: "部署到百度云负载均衡,包括BLB、APPBLB",
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
needPlus: false,
|
||||
})
|
||||
export class BaiduDeployToBLBPlugin extends AbstractTaskPlugin {
|
||||
//证书选择,此项必须要有
|
||||
@TaskInput({
|
||||
title: "域名证书",
|
||||
helper: "请选择前置任务输出的域名证书",
|
||||
component: {
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames, "BaiduUploadCert"],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo | string;
|
||||
|
||||
@TaskInput(createCertDomainGetterInputDefine())
|
||||
certDomains!: string[];
|
||||
|
||||
@TaskInput({
|
||||
title: "区域",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
options: [
|
||||
/**
|
||||
* 北京 blb.bj.baidubce.com HTTP/HTTPS
|
||||
* 广州 blb.gz.baidubce.com HTTP/HTTPS
|
||||
* 苏州 blb.su.baidubce.com HTTP/HTTPS
|
||||
* 香港 blb.hkg.baidubce.com HTTP/HTTPS
|
||||
* 武汉 blb.fwh.baidubce.com HTTP/HTTPS
|
||||
* 保定 blb.bd.baidubce.com HTTP/HTTPS
|
||||
* 上海 blb.fsh.baidubce.com HTTP/HTTPS
|
||||
* 新加坡 blb.sin.baidubce.com HTTP/HTTPS
|
||||
*/
|
||||
{ value: "bj", label: "北京" },
|
||||
{ value: "fsh", label: "上海" },
|
||||
{ value: "gz", label: "广州" },
|
||||
{ value: "fwh", label: "武汉" },
|
||||
{ value: "su", label: "苏州" },
|
||||
{ value: "bd", label: "保定" },
|
||||
{ value: "hkg", label: "香港" },
|
||||
{ value: "sin", label: "新加坡" },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
region!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "负载均衡类型",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ value: "blb", label: "普通负载均衡" },
|
||||
{ value: "appblb", label: "应用负载均衡" },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
blbType!: string;
|
||||
|
||||
//授权选择框
|
||||
@TaskInput({
|
||||
title: "百度云授权",
|
||||
helper: "百度云授权",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "baidu",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "负载均衡ID",
|
||||
component: {
|
||||
name: "remote-select",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
action: "GetBLBList",
|
||||
watches: ["certDomains", "blbType", "accessId"],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
blbIds!: string[];
|
||||
|
||||
@TaskInput({
|
||||
title: "监听器ID",
|
||||
component: {
|
||||
name: "remote-select",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
action: "GetListenerList",
|
||||
watches: ["certDomains", "accessId", "blbIds"],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
listenerIds!: string[];
|
||||
|
||||
async onInstance() {}
|
||||
|
||||
async execute(): Promise<void> {
|
||||
this.logger.info("开始更新百度云监听器证书");
|
||||
const access = await this.getAccess(this.accessId);
|
||||
const certClient = new BaiduYunCertClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
http: this.ctx.http,
|
||||
});
|
||||
|
||||
let certId = this.cert as string;
|
||||
if (typeof this.cert !== "string") {
|
||||
this.logger.info("上传证书到百度云");
|
||||
const res = await certClient.createCert({
|
||||
cert: this.cert,
|
||||
certName: CertReader.buildCertName(this.cert),
|
||||
});
|
||||
certId = res.certId;
|
||||
this.logger.info(`上传证书到百度云成功:${certId}`);
|
||||
}
|
||||
|
||||
const baiduyunClient = new BaiduYunClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
http: this.ctx.http,
|
||||
});
|
||||
for (const listenerId of this.listenerIds) {
|
||||
const listenerParams = listenerId.split("_");
|
||||
const blbId = listenerParams[0];
|
||||
const listenerType = listenerParams[1];
|
||||
const listenerPort = listenerParams[2];
|
||||
let additionalCertHost = null;
|
||||
if (listenerParams.length > 3) {
|
||||
additionalCertHost = listenerParams[3];
|
||||
}
|
||||
this.logger.info(`更新监听器证书开始:${listenerId}`);
|
||||
if (!additionalCertHost) {
|
||||
await this.updateListenerCert({
|
||||
client: baiduyunClient,
|
||||
blbId,
|
||||
listenerType,
|
||||
listenerPort,
|
||||
certId,
|
||||
});
|
||||
} else {
|
||||
const listenerDomains = await this.getListeners(baiduyunClient, blbId, listenerType, listenerPort);
|
||||
if (!listenerDomains || listenerDomains.length === 0) {
|
||||
throw new Error(`未找到监听器:${listenerId}`);
|
||||
}
|
||||
const oldAdditionals = listenerDomains[0].additionalCertDomains;
|
||||
for (const oldAddi of oldAdditionals) {
|
||||
if (oldAddi.host === additionalCertHost) {
|
||||
oldAddi.certId = certId;
|
||||
}
|
||||
}
|
||||
await this.updateListenerCert({
|
||||
client: baiduyunClient,
|
||||
blbId,
|
||||
listenerType,
|
||||
listenerPort,
|
||||
certId,
|
||||
additionalCertDomains: oldAdditionals,
|
||||
});
|
||||
}
|
||||
this.logger.info(`更新监听器证书成功:${listenerId}`);
|
||||
await this.ctx.utils.sleep(3000);
|
||||
}
|
||||
|
||||
this.logger.info(`更新百度云监听器证书完成`);
|
||||
}
|
||||
|
||||
async onGetListenerList(data: PageSearch = {}) {
|
||||
const access = await this.getAccess(this.accessId);
|
||||
const client = new BaiduYunClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
http: this.ctx.http,
|
||||
});
|
||||
|
||||
const listeners = [];
|
||||
for (const blbId of this.blbIds) {
|
||||
/**
|
||||
* GET /v{version}/appblb/{blbId}/TCPlistener?listenerPort={listenerPort}&marker={marker}&maxKeys={maxKeys} HTTP/1.1
|
||||
* Host: blb.bj.baidubce.com
|
||||
*/
|
||||
const listenerTypes = ["HTTPSlistener", "SSLlistener"];
|
||||
for (const listenerType of listenerTypes) {
|
||||
const list = await this.getListeners(client, blbId, listenerType);
|
||||
if (list && list.length > 0) {
|
||||
for (const item of list) {
|
||||
const key = `${blbId}_${listenerType}_${item.listenerPort}`;
|
||||
listeners.push({
|
||||
value: key,
|
||||
label: key,
|
||||
});
|
||||
|
||||
if (item.additionalCertDomains && item.additionalCertDomains.length > 0) {
|
||||
for (const addi of item.additionalCertDomains) {
|
||||
const addiKey = `${key}_${addi.host}`;
|
||||
listeners.push({
|
||||
value: addiKey,
|
||||
label: `${addiKey}【扩展】`,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!listeners || listeners.length === 0) {
|
||||
throw new Error("未找到https/SSL监听器");
|
||||
}
|
||||
return listeners;
|
||||
}
|
||||
|
||||
private async getListeners(client: BaiduYunClient, blbId: string, listenerType: string, listenerPort?: number | string) {
|
||||
const query: any = {
|
||||
maxItems: 1000,
|
||||
};
|
||||
if (listenerPort) {
|
||||
query.listenerPort = listenerPort;
|
||||
}
|
||||
const res = await client.doRequest({
|
||||
host: `blb.${this.region}.baidubce.com`,
|
||||
uri: `/v1/${this.blbType}/${blbId}/${listenerType}`,
|
||||
method: "GET",
|
||||
query,
|
||||
});
|
||||
return res.listenerList;
|
||||
}
|
||||
|
||||
async onGetBLBList(data: PageSearch = {}) {
|
||||
const access = await this.getAccess(this.accessId);
|
||||
const client = new BaiduYunClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
http: this.ctx.http,
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /v{version}/appblb?address={address}&name={name}&blbId={blbId}&marker={marker}&maxKeys={maxKeys} HTTP/1.1
|
||||
* Host: blb.bj.baidubce.com
|
||||
*/
|
||||
const res = await client.doRequest({
|
||||
host: `blb.${this.region}.baidubce.com`,
|
||||
uri: `/v1/${this.blbType}`,
|
||||
method: "GET",
|
||||
query: {
|
||||
maxItems: 1000,
|
||||
},
|
||||
});
|
||||
|
||||
const list = res.blbList;
|
||||
|
||||
if (!list || list.length === 0) {
|
||||
throw new Error("没有数据,你可以手动输入");
|
||||
}
|
||||
const options: any[] = [];
|
||||
for (const item of list) {
|
||||
options.push({
|
||||
value: item.blbId,
|
||||
label: item.name,
|
||||
});
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
private async updateListenerCert(param: { client: BaiduYunClient; blbId: string; listenerType: string; listenerPort: string; certId?: any; additionalCertDomains?: any[] }) {
|
||||
/**
|
||||
* PUT /v{version}/appblb/{blbId}/SSLlistener?clientToken={clientToken}&listenerPort={listenerPort} HTTP/1.1
|
||||
* Host: blb.bj.baidubce.com
|
||||
* Authorization: authorization string
|
||||
*
|
||||
* {
|
||||
* "scheduler":scheduler,
|
||||
* "certIds":[certId],
|
||||
* "encryptionType":encryptionType,
|
||||
* "encryptionProtocols":[protocol1, protacol2],
|
||||
* "dualAuth":false,
|
||||
* "clientCertIds":[clientCertId],
|
||||
* "description":description
|
||||
* }
|
||||
*/
|
||||
const { client, blbId, listenerType, listenerPort, certId, additionalCertDomains } = param;
|
||||
const body: any = {};
|
||||
if (additionalCertDomains) {
|
||||
body.additionalCertDomains = additionalCertDomains;
|
||||
}
|
||||
if (certId) {
|
||||
body.certIds = [certId];
|
||||
}
|
||||
const res = await client.doRequest({
|
||||
host: `blb.${this.region}.baidubce.com`,
|
||||
uri: `/v1/${this.blbType}/${blbId}/${listenerType}`,
|
||||
method: "PUT",
|
||||
query: {
|
||||
listenerPort,
|
||||
},
|
||||
body,
|
||||
});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
new BaiduDeployToBLBPlugin();
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { CertApplyPluginNames, CertInfo, CertReader } from "@certd/plugin-cert";
|
||||
import { BaiduYunCertClient, BaiduYunClient } from "../client.js";
|
||||
import { createCertDomainGetterInputDefine } from "@certd/plugin-lib";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: "BaiduDeployToCDN",
|
||||
title: "百度云-部署证书到CDN",
|
||||
icon: "ant-design:baidu-outlined",
|
||||
group: pluginGroups.baidu.key,
|
||||
desc: "部署到百度云CDN",
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
needPlus: false,
|
||||
})
|
||||
export class BaiduDeployToCDNPlugin extends AbstractTaskPlugin {
|
||||
//证书选择,此项必须要有
|
||||
@TaskInput({
|
||||
title: "域名证书",
|
||||
helper: "请选择前置任务输出的域名证书",
|
||||
component: {
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames, "BaiduUploadCert"],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo | string;
|
||||
|
||||
@TaskInput(createCertDomainGetterInputDefine())
|
||||
certDomains!: string[];
|
||||
|
||||
//授权选择框
|
||||
@TaskInput({
|
||||
title: "百度云授权",
|
||||
helper: "百度云授权",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "baidu",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
//证书选择,此项必须要有
|
||||
@TaskInput({
|
||||
title: "CDN域名",
|
||||
component: {
|
||||
name: "remote-select",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
action: "GetDomainList",
|
||||
watches: ["certDomains", "accessId"],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
domains!: string[];
|
||||
|
||||
async onInstance() {}
|
||||
|
||||
async execute(): Promise<void> {
|
||||
const access = await this.getAccess(this.accessId);
|
||||
const client = new BaiduYunClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
http: this.ctx.http,
|
||||
});
|
||||
|
||||
const certClient = new BaiduYunCertClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
http: this.ctx.http,
|
||||
});
|
||||
|
||||
let certId = this.cert as string;
|
||||
if (typeof this.cert !== "string") {
|
||||
this.logger.info("上传证书到百度云");
|
||||
const res = await certClient.createCert({
|
||||
cert: this.cert,
|
||||
certName: CertReader.buildCertName(this.cert),
|
||||
});
|
||||
certId = res.certId;
|
||||
this.logger.info(`上传证书到百度云成功:${certId}`);
|
||||
}
|
||||
|
||||
const body = {
|
||||
https: {
|
||||
enabled: true,
|
||||
certId: certId,
|
||||
},
|
||||
};
|
||||
for (const domain of this.domains) {
|
||||
await client.doRequest({
|
||||
host: "cdn.baidubce.com",
|
||||
uri: `/v2/domain/${domain}/config`,
|
||||
body,
|
||||
query: {
|
||||
https: "",
|
||||
},
|
||||
method: "put",
|
||||
});
|
||||
this.logger.info(`部署证书到${domain}成功`);
|
||||
}
|
||||
}
|
||||
|
||||
async onGetDomainList() {
|
||||
// if (!isPlus()) {
|
||||
// throw new Error("自动获取站点列表为专业版功能,您可以手动输入站点域名/站点名称进行部署");
|
||||
// }
|
||||
const access = await this.getAccess(this.accessId);
|
||||
const client = new BaiduYunClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
http: this.ctx.http,
|
||||
});
|
||||
|
||||
const res = await client.doRequest({
|
||||
host: "cdn.baidubce.com",
|
||||
uri: `/v2/domain`,
|
||||
method: "GET",
|
||||
query: {
|
||||
maxItems: 1000,
|
||||
},
|
||||
});
|
||||
|
||||
const list = res.domains;
|
||||
|
||||
if (!list || list.length === 0) {
|
||||
throw new Error("未找到加速域名,你可以手动输入");
|
||||
}
|
||||
const options: any[] = [];
|
||||
for (const item of list) {
|
||||
options.push({
|
||||
value: item.name,
|
||||
label: item.name,
|
||||
domain: item.name,
|
||||
});
|
||||
}
|
||||
return this.ctx.utils.options.buildGroupOptions(options, this.certDomains);
|
||||
}
|
||||
}
|
||||
|
||||
new BaiduDeployToCDNPlugin();
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import { CertApplyPluginNames, CertReader } from "@certd/plugin-cert";
|
||||
import { BaiduAccess } from "../access.js";
|
||||
import { BaiduYunCertClient } from "../client.js";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: "BaiduUploadCert",
|
||||
title: "百度云-上传到证书托管",
|
||||
icon: "ant-design:baidu-outlined",
|
||||
desc: "上传证书到百度云证书托管中心",
|
||||
group: pluginGroups.baidu.key,
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
})
|
||||
export class BaiduUploadCert extends AbstractTaskPlugin {
|
||||
// @TaskInput({ title: '证书名称' })
|
||||
// name!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "域名证书",
|
||||
helper: "请选择前置任务输出的域名证书",
|
||||
component: {
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: any;
|
||||
|
||||
@TaskInput({
|
||||
title: "Access授权",
|
||||
helper: "access授权",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "baidu",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskOutput({
|
||||
title: "百度云CertId",
|
||||
})
|
||||
baiduCertId?: string;
|
||||
|
||||
async execute(): Promise<void> {
|
||||
const access = await this.getAccess<BaiduAccess>(this.accessId);
|
||||
|
||||
const certClient = new BaiduYunCertClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
http: this.http,
|
||||
});
|
||||
|
||||
const certItem = await certClient.createCert({
|
||||
cert: this.cert,
|
||||
certName: CertReader.buildCertName(this.cert),
|
||||
});
|
||||
|
||||
this.baiduCertId = certItem.certId;
|
||||
this.logger.info(`上传成功,证书ID:${certItem.certId}`);
|
||||
}
|
||||
}
|
||||
|
||||
new BaiduUploadCert();
|
||||
Reference in New Issue
Block a user