2025-12-27 01:54:47 +08:00
|
|
|
|
import { IsAccess, AccessInput, BaseAccess } from '@certd/pipeline';
|
|
|
|
|
|
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 这个注解将注册一个授权配置
|
|
|
|
|
|
* 在certd的后台管理系统中,用户可以选择添加此类型的授权
|
|
|
|
|
|
*/
|
|
|
|
|
|
@IsAccess({
|
|
|
|
|
|
name: 'ucloud',
|
|
|
|
|
|
title: 'UCloud授权',
|
2025-12-27 02:20:01 +08:00
|
|
|
|
icon: 'svg:icon-ucloud',
|
2025-12-27 01:54:47 +08:00
|
|
|
|
desc: '优刻得授权',
|
|
|
|
|
|
})
|
|
|
|
|
|
export class UCloudAccess extends BaseAccess {
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 授权属性配置
|
|
|
|
|
|
*/
|
|
|
|
|
|
@AccessInput({
|
|
|
|
|
|
title: '项目Id',
|
|
|
|
|
|
component: {
|
|
|
|
|
|
placeholder: '项目Id',
|
|
|
|
|
|
},
|
|
|
|
|
|
helper: "[项目管理](https://console.ucloud.cn/uaccount/iam/project_manage)项目ID列获取",
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
encrypt: false,
|
|
|
|
|
|
})
|
|
|
|
|
|
projectId = '';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 授权属性配置
|
|
|
|
|
|
*/
|
|
|
|
|
|
@AccessInput({
|
|
|
|
|
|
title: '公钥',
|
|
|
|
|
|
component: {
|
|
|
|
|
|
placeholder: '公钥',
|
|
|
|
|
|
},
|
|
|
|
|
|
helper: "[Api管理](https://console.ucloud.cn/uaccount/api_manage)获取",
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
encrypt: false,
|
|
|
|
|
|
})
|
|
|
|
|
|
publicKey = '';
|
|
|
|
|
|
|
|
|
|
|
|
@AccessInput({
|
|
|
|
|
|
title: '私钥',
|
|
|
|
|
|
component: {
|
|
|
|
|
|
name: "a-input-password",
|
|
|
|
|
|
vModel: "value",
|
|
|
|
|
|
placeholder: '私钥',
|
|
|
|
|
|
},
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
encrypt: true,
|
|
|
|
|
|
})
|
|
|
|
|
|
privateKey = '';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@AccessInput({
|
|
|
|
|
|
title: "测试",
|
|
|
|
|
|
component: {
|
|
|
|
|
|
name: "api-test",
|
|
|
|
|
|
action: "TestRequest"
|
|
|
|
|
|
},
|
|
|
|
|
|
helper: "点击测试接口是否正常"
|
|
|
|
|
|
})
|
|
|
|
|
|
testRequest = true;
|
|
|
|
|
|
|
|
|
|
|
|
client: any;
|
|
|
|
|
|
|
|
|
|
|
|
async onTestRequest() {
|
|
|
|
|
|
await this.ProjectList();
|
|
|
|
|
|
return "ok";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async getClient() {
|
|
|
|
|
|
if (this.client) {
|
|
|
|
|
|
return this.client;
|
|
|
|
|
|
}
|
|
|
|
|
|
const { Client } = await import('@ucloud-sdks/ucloud-sdk-js');
|
|
|
|
|
|
const client = new Client({
|
|
|
|
|
|
config: {
|
|
|
|
|
|
region: 'cn-bj2',
|
|
|
|
|
|
projectId: this.projectId || "",
|
|
|
|
|
|
baseUrl: "https://api.ucloud.cn"
|
|
|
|
|
|
},
|
|
|
|
|
|
credential: {
|
|
|
|
|
|
publicKey: this.publicKey,
|
|
|
|
|
|
privateKey: this.privateKey,
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
this.client = client;
|
|
|
|
|
|
return client
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async ProjectList() {
|
|
|
|
|
|
const client = await this.getClient();
|
|
|
|
|
|
const resp = await client.uaccount().getProjectList({
|
|
|
|
|
|
"Action": "GetProjectList"
|
|
|
|
|
|
});
|
|
|
|
|
|
this.ctx.logger.info(`获取到项目列表:${JSON.stringify(resp)}`);
|
|
|
|
|
|
return resp;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async GetRegion() {
|
|
|
|
|
|
const client = await this.getClient();
|
|
|
|
|
|
const res = await client.uaccount().getRegion({
|
|
|
|
|
|
"Action": "GetRegion"
|
|
|
|
|
|
});
|
|
|
|
|
|
this.ctx.logger.info(`获取到区域列表:${JSON.stringify(res)}`);
|
|
|
|
|
|
return res;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async CdnDominList(req: { PageNo: number, PageSize: number }) {
|
|
|
|
|
|
const client = await this.getClient();
|
|
|
|
|
|
const resp = await client.ucdn().getUcdnDomainInfoList({
|
|
|
|
|
|
"Action": "GetUcdnDomainInfoList",
|
|
|
|
|
|
"ProjectId": this.projectId || "",
|
|
|
|
|
|
"PageNo": req.PageNo,
|
|
|
|
|
|
"PageSize": req.PageSize,
|
|
|
|
|
|
});
|
|
|
|
|
|
this.ctx.logger.info(`获取到CDN域名列表:${JSON.stringify(resp)}`);
|
|
|
|
|
|
return resp;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async CdnAddCert(req: { certName: string, cert: CertInfo }) {
|
|
|
|
|
|
const client = await this.getClient();
|
|
|
|
|
|
const resp = await client.ucdn().addCertificate({
|
|
|
|
|
|
"Action": "AddCertificate",
|
|
|
|
|
|
"ProjectId": this.projectId || "",
|
|
|
|
|
|
"CertName": req.certName,
|
|
|
|
|
|
"UserCert": req.cert.crt,
|
|
|
|
|
|
"PrivateKey": req.cert.key
|
|
|
|
|
|
});
|
|
|
|
|
|
this.ctx.logger.info(`添加CDN证书:${JSON.stringify(resp)}`);
|
|
|
|
|
|
return resp;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async SslUploadCert(req: { cert: CertInfo }) {
|
|
|
|
|
|
const { cert } = req
|
|
|
|
|
|
/**
|
|
|
|
|
|
&SslPublicKey=lXUzWbSR
|
|
|
|
|
|
&SslCaKey=lXUzWbSR
|
|
|
|
|
|
&SslMD5=lXUzWbSR
|
|
|
|
|
|
&CertificateName=GoodCertcification
|
|
|
|
|
|
*/
|
|
|
|
|
|
const certReader = new CertReader(cert)
|
|
|
|
|
|
const certName = certReader.buildCertName()
|
|
|
|
|
|
const crtBase64 = this.ctx.utils.hash.base64(cert.crt)
|
|
|
|
|
|
const keyBase64 = this.ctx.utils.hash.base64(cert.key)
|
|
|
|
|
|
const allDomains = certReader.getAllDomains().join(",")
|
2025-12-27 22:57:26 +08:00
|
|
|
|
|
2025-12-27 01:54:47 +08:00
|
|
|
|
this.ctx.logger.info(`----------- 上传USSL证书,certName:${certName},domains:${allDomains}`);
|
|
|
|
|
|
try {
|
|
|
|
|
|
const resp = await this.invoke({
|
|
|
|
|
|
Action: "UploadNormalCertificate",
|
|
|
|
|
|
"SslPublicKey": crtBase64,
|
|
|
|
|
|
"SslPrivateKey": keyBase64,
|
|
|
|
|
|
"CertificateName": certName,
|
|
|
|
|
|
"SslMD5": this.ctx.utils.hash.md5(crtBase64 + keyBase64)
|
|
|
|
|
|
});
|
|
|
|
|
|
this.ctx.logger.info(`----------- 上传USSL证书成功,certId:${resp.CertificateID}`);
|
2025-12-27 22:57:26 +08:00
|
|
|
|
return { type: "ussl", id: resp.CertificateID, name: certName, resourceId: resp.LongResourceID, domains: allDomains }
|
2025-12-27 01:54:47 +08:00
|
|
|
|
} catch (err) {
|
|
|
|
|
|
|
2025-12-27 22:57:26 +08:00
|
|
|
|
if (err.message.includes("重复上传证书")) {
|
2025-12-27 01:54:47 +08:00
|
|
|
|
//查找证书
|
|
|
|
|
|
const certList = await this.SslGetCertList(certReader.getMainDomain());
|
2025-12-27 22:57:26 +08:00
|
|
|
|
|
2025-12-27 01:54:47 +08:00
|
|
|
|
const cert = certList.find((item: any) => item.Domains === allDomains)
|
2025-12-27 22:57:26 +08:00
|
|
|
|
if (cert) {
|
2025-12-27 01:54:47 +08:00
|
|
|
|
this.ctx.logger.info(`----------- 找到已存在证书,certId:${cert.CertificateID}`);
|
|
|
|
|
|
return { type: "ussl", id: cert.CertificateID, name: certName, domains: cert.Domains }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.ctx.logger.error(`上传USSL证书失败:${err}`);
|
|
|
|
|
|
throw err;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async SslGetCertList(domain: string) {
|
|
|
|
|
|
const resp = await this.invoke({
|
|
|
|
|
|
Action: "GetCertificateList",
|
|
|
|
|
|
Mode: "trust",
|
|
|
|
|
|
Domain: domain,
|
2025-12-27 22:57:26 +08:00
|
|
|
|
Sort: "2"
|
2025-12-27 01:54:47 +08:00
|
|
|
|
});
|
2025-12-27 22:57:26 +08:00
|
|
|
|
return resp.CertificateList || [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async WafSiteList(req: { PageNo: number, PageSize: number , FullDomain?: string }):Promise<{DomainHostList?:{RecordId:string,FullDomain:string}[],TotalCount:number}> {
|
|
|
|
|
|
const resp = await this.invoke({
|
|
|
|
|
|
"Action": "DescribeWafDomainHostInfo",
|
|
|
|
|
|
"ProjectId": this.projectId,
|
|
|
|
|
|
"Limit": req.PageSize,
|
|
|
|
|
|
"Offset": (req.PageNo - 1) * req.PageSize,
|
|
|
|
|
|
"FullDomain": req.FullDomain || undefined
|
|
|
|
|
|
});
|
|
|
|
|
|
this.ctx.logger.info(`获取到WAF站点列表:${JSON.stringify(resp)}`);
|
|
|
|
|
|
return resp;
|
2025-12-27 01:54:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async invoke(req: { Action: string, [key: string]: any }) {
|
|
|
|
|
|
const { Request } = await import('@ucloud-sdks/ucloud-sdk-js');
|
|
|
|
|
|
const client = await this.getClient();
|
|
|
|
|
|
const resp = await client.invoke(new Request({
|
|
|
|
|
|
...req
|
|
|
|
|
|
}));
|
|
|
|
|
|
this.ctx.logger.info(`请求UCloud API:${JSON.stringify(resp)}`);
|
|
|
|
|
|
const res = resp.data || {}
|
|
|
|
|
|
if (res.RetCode !== 0) {
|
|
|
|
|
|
throw new Error(res.Message)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
new UCloudAccess();
|