mirror of
https://github.com/certd/certd.git
synced 2026-04-14 04:20:52 +08:00
perf: 阿里云dcdn支持根据证书域名匹配模式
This commit is contained in:
@@ -4,7 +4,7 @@ import { FileStore } from "../core/file-store.js";
|
||||
import { accessRegistry, IAccessService } from "../access/index.js";
|
||||
import { ICnameProxyService, IEmailService, IServiceGetter, IUrlService } from "../service/index.js";
|
||||
import { CancelError, IContext, RunHistory, RunnableCollection } from "../core/index.js";
|
||||
import { HttpRequestConfig, ILogger, logger, utils } from "@certd/basic";
|
||||
import { HttpRequestConfig, ILogger, logger, optionsUtils, utils } from "@certd/basic";
|
||||
import { HttpClient } from "@certd/basic";
|
||||
import dayjs from "dayjs";
|
||||
import { IPluginConfigService } from "../service/config.js";
|
||||
@@ -315,6 +315,11 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||
getLastOutput(key: string) {
|
||||
return this.getLastStatus().status?.output?.[key];
|
||||
}
|
||||
|
||||
getMatchedDomains(domainList: string[], certDomains: string[]): string[] {
|
||||
const { matched } = optionsUtils.groupByDomain(domainList, certDomains);
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
|
||||
export type OutputVO = {
|
||||
|
||||
@@ -589,11 +589,11 @@ export default {
|
||||
userValidityPeriodHelper: "有效期内用户可正常使用,失效后用户的流水线将被停用",
|
||||
enableUsernameRegistration: "开启用户名注册",
|
||||
enableEmailRegistration: "开启邮箱注册",
|
||||
proFeature: "专业版功能",
|
||||
proFeature: "Certd专业版功能",
|
||||
emailServerSetup: "设置邮箱服务器",
|
||||
enableSmsLoginRegister: "开启手机号登录、注册",
|
||||
defaultLoginType: "默认登录方式",
|
||||
commFeature: "商业版功能",
|
||||
commFeature: "Certd商业版功能",
|
||||
smsProvider: "短信提供商",
|
||||
aliyunSms: "阿里云短信",
|
||||
tencentSms: "腾讯云短信",
|
||||
|
||||
@@ -88,13 +88,13 @@ export default {
|
||||
activation_code_one_use: "激活码使用过一次之后,不可再次使用,如果要更换站点,请",
|
||||
bind_account: "绑定账号",
|
||||
transfer_vip: '然后"转移VIP"即可',
|
||||
needVipTip: "此为专业版功能,请先开通专业版",
|
||||
needVipTip: "此为Certd专业版功能,请先开通Certd专业版",
|
||||
manual_activation: "激活码手动激活",
|
||||
close: "关闭",
|
||||
have_activation_code: "已经有激活码了?",
|
||||
buy: "立即购买",
|
||||
already_plus: "已经是专业版了,是否升级为商业版?注意:专业版时长将被覆盖",
|
||||
already_comm: "已经是商业版了,不能降级为专业版",
|
||||
already_plus: "已经是Certd专业版了,是否升级为商业版?注意:Certd专业版时长将被覆盖",
|
||||
already_comm: "已经是Certd商业版了,不能降级为专业版",
|
||||
already_perpetual_plus: "您已经是永久专业版了,无法继续升级",
|
||||
confirm: "确认",
|
||||
not_effective: "VIP没有生效/时长未同步?",
|
||||
|
||||
@@ -80,7 +80,7 @@ onMounted(() => {
|
||||
await settingStore.doBindUrl();
|
||||
notification.success({
|
||||
message: "更新成功",
|
||||
description: "专业版/商业版已激活",
|
||||
description: "Certd专业版/商业版已激活",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ export class UserTwoFactorSettingController extends BaseController {
|
||||
@Post("/save", { description: Constants.per.authOnly, summary: "保存双因子认证设置" })
|
||||
async save(@Body(ALL) bean: any) {
|
||||
if (!isPlus()) {
|
||||
throw new Error('本功能需要开通专业版')
|
||||
throw new Error('本功能需要开通Certd专业版')
|
||||
}
|
||||
const userId = this.getUserId();
|
||||
const setting = new UserTwoFactorSetting();
|
||||
@@ -57,7 +57,7 @@ export class UserTwoFactorSettingController extends BaseController {
|
||||
@Post("/authenticator/save", { description: Constants.per.authOnly, summary: "保存验证器设置" })
|
||||
async authenticatorSave(@Body(ALL) bean: any) {
|
||||
if (!isPlus()) {
|
||||
throw new Error('本功能需要开通专业版')
|
||||
throw new Error('本功能需要开通Certd专业版')
|
||||
}
|
||||
const userId = this.getUserId();
|
||||
await this.twoFactorService.saveAuthenticator({
|
||||
|
||||
@@ -81,7 +81,7 @@ export class UserSettingsController extends CrudController<UserSettingsService>
|
||||
@Post("/grant/save", { description: Constants.per.authOnly, summary: "保存授权设置" })
|
||||
async grantSettingsSave(@Body(ALL) bean: UserGrantSetting) {
|
||||
if (!isPlus()) {
|
||||
throw new Error('本功能需要开通专业版')
|
||||
throw new Error('本功能需要开通Certd专业版')
|
||||
}
|
||||
const userId = this.getUserId();
|
||||
const setting = new UserGrantSetting();
|
||||
|
||||
@@ -180,7 +180,7 @@ export class LoginService {
|
||||
async loginByTwoFactor(req: { loginId: string; verifyCode: string }) {
|
||||
//检查是否开启多重认证
|
||||
if (!isPlus()) {
|
||||
throw new Error('本功能需要开通专业版')
|
||||
throw new Error('本功能需要开通Certd专业版')
|
||||
}
|
||||
const userId = cache.get(`login_2fa_code:${req.loginId}`)
|
||||
if (!userId) {
|
||||
|
||||
@@ -83,7 +83,7 @@ export class NotificationService extends BaseService<NotificationEntity> {
|
||||
const define = this.getDefineByType(type)
|
||||
//@ts-ignore
|
||||
if (define.needPlus && !isPlus()) {
|
||||
throw new NeedVIPException("此通知类型为专业版功能,请升级到专业版或以上级别");
|
||||
throw new NeedVIPException("此通知类型为Certd专业版功能,请升级到专业版或以上级别");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -941,7 +941,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
|
||||
async batchDelete(ids: number[], userId?: number, projectId?: number) {
|
||||
if (!isPlus()) {
|
||||
throw new NeedVIPException("此功能需要升级专业版");
|
||||
throw new NeedVIPException("此功能需要升级Certd专业版");
|
||||
}
|
||||
for (const id of ids) {
|
||||
if (userId && userId > 0) {
|
||||
@@ -956,7 +956,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
|
||||
async batchUpdateGroup(ids: number[], groupId: number, userId: any, projectId?: number) {
|
||||
if (!isPlus()) {
|
||||
throw new NeedVIPException("此功能需要升级专业版");
|
||||
throw new NeedVIPException("此功能需要升级Certd专业版");
|
||||
}
|
||||
const query: any = {}
|
||||
if (userId && userId > 0) {
|
||||
@@ -982,7 +982,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
*/
|
||||
async batchTransfer(ids: number[], projectId: number) {
|
||||
if (!isPlus()) {
|
||||
throw new NeedVIPException("此功能需要升级专业版");
|
||||
throw new NeedVIPException("此功能需要升级Certd专业版");
|
||||
}
|
||||
if (!isEnterprise()) {
|
||||
throw new Error("当前为非企业模式,不允许转移到其他项目");
|
||||
@@ -1075,7 +1075,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
|
||||
async batchUpdateTrigger(ids: number[], trigger: any, userId: any, projectId?: number) {
|
||||
if (!isPlus()) {
|
||||
throw new NeedVIPException("此功能需要升级专业版");
|
||||
throw new NeedVIPException("此功能需要升级Certd专业版");
|
||||
}
|
||||
//允许管理员修改,userId=null
|
||||
const query: any = {}
|
||||
@@ -1128,7 +1128,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
|
||||
async batchUpdateNotifications(ids: number[], notification: Notification, userId: any, projectId?: number) {
|
||||
if (!isPlus()) {
|
||||
throw new NeedVIPException("此功能需要升级专业版");
|
||||
throw new NeedVIPException("此功能需要升级Certd专业版");
|
||||
}
|
||||
//允许管理员修改,userId=null
|
||||
const query: any = {}
|
||||
@@ -1167,7 +1167,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
|
||||
async batchRerun(ids: number[], force: boolean, userId: any, projectId?: number) {
|
||||
if (!isPlus()) {
|
||||
throw new NeedVIPException("此功能需要升级专业版");
|
||||
throw new NeedVIPException("此功能需要升级Certd专业版");
|
||||
}
|
||||
//允许userId为空,为空则为管理员触发
|
||||
if (ids.length === 0) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
createCertDomainGetterInputDefine,
|
||||
@@ -55,6 +55,19 @@ export class DeployCertToAliyunDCDN extends AbstractTaskPlugin {
|
||||
})
|
||||
certName!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '域名匹配模式',
|
||||
helper: '选择域名匹配方式',
|
||||
component: {
|
||||
name: 'select',
|
||||
options: [
|
||||
{ label: '手动选择', value: 'manual' },
|
||||
{ label: '根据证书匹配', value: 'auto' },
|
||||
],
|
||||
},
|
||||
default: 'manual',
|
||||
})
|
||||
domainMatchMode!: 'manual' | 'auto';
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
@@ -63,6 +76,13 @@ export class DeployCertToAliyunDCDN extends AbstractTaskPlugin {
|
||||
action: DeployCertToAliyunDCDN.prototype.onGetDomainList.name,
|
||||
watches: ['certDomains', 'accessId'],
|
||||
required: true,
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return domainMatchMode === "manual"
|
||||
})
|
||||
}
|
||||
`,
|
||||
})
|
||||
)
|
||||
domainName!: string | string[];
|
||||
@@ -71,15 +91,30 @@ export class DeployCertToAliyunDCDN extends AbstractTaskPlugin {
|
||||
async onInstance() { }
|
||||
async execute(): Promise<void> {
|
||||
this.logger.info('开始部署证书到阿里云DCDN');
|
||||
if (!this.domainName) {
|
||||
throw new Error('您还未选择DCDN域名');
|
||||
}
|
||||
const access = (await this.getAccess(this.accessId)) as AliyunAccess;
|
||||
const client = await this.getClient(access);
|
||||
if (typeof this.domainName === 'string') {
|
||||
this.domainName = [this.domainName];
|
||||
|
||||
let domains: string[] = [];
|
||||
|
||||
if (this.domainMatchMode === 'auto') {
|
||||
this.logger.info('使用根据证书匹配模式');
|
||||
if (!this.certDomains || this.certDomains.length === 0) {
|
||||
throw new Error('未获取到证书域名信息');
|
||||
}
|
||||
domains = await this.getAutoMatchedDomains(this.certDomains);
|
||||
if (domains.length === 0) {
|
||||
this.logger.warn('未找到匹配的DCDN域名');
|
||||
return;
|
||||
}
|
||||
this.logger.info(`找到 ${domains.length} 个匹配的DCDN域名`);
|
||||
} else {
|
||||
if (!this.domainName) {
|
||||
throw new Error('您还未选择DCDN域名');
|
||||
}
|
||||
domains = typeof this.domainName === 'string' ? [this.domainName] : this.domainName;
|
||||
}
|
||||
for (const domainName of this.domainName) {
|
||||
|
||||
for (const domainName of domains) {
|
||||
this.logger.info(`[${domainName}]开始部署`)
|
||||
const params = await this.buildParams(domainName);
|
||||
await this.doRequest(client, params);
|
||||
@@ -152,7 +187,36 @@ export class DeployCertToAliyunDCDN extends AbstractTaskPlugin {
|
||||
}
|
||||
|
||||
|
||||
async onGetDomainList(data: any) {
|
||||
async getAutoMatchedDomains(certDomains: string[]): Promise<string[]> {
|
||||
const matchedDomains: string[] = [];
|
||||
let pageNumber = 1;
|
||||
|
||||
while (true) {
|
||||
const result = await this.onGetDomainList({ pageNo: pageNumber });
|
||||
const pageData = result.list;
|
||||
this.logger.info(`获取到 ${pageData.length} 个DCDN域名`);
|
||||
|
||||
if (!pageData || pageData.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const matched = this.getMatchedDomains(pageData, certDomains);
|
||||
matchedDomains.push(...matched);
|
||||
|
||||
const totalCount = result.total || 0;
|
||||
if (pageNumber * 500 >= totalCount) {
|
||||
break;
|
||||
}
|
||||
|
||||
pageNumber++;
|
||||
}
|
||||
|
||||
return matchedDomains;
|
||||
}
|
||||
|
||||
|
||||
|
||||
async onGetDomainList(data: PageSearch) {
|
||||
if (!this.accessId) {
|
||||
throw new Error('请选择Access授权');
|
||||
}
|
||||
@@ -161,7 +225,7 @@ export class DeployCertToAliyunDCDN extends AbstractTaskPlugin {
|
||||
const client = await this.getClient(access);
|
||||
|
||||
const params = {
|
||||
// 'DomainName': 'aaa',
|
||||
PageNumber: data.pageNo || 1,
|
||||
PageSize: 500,
|
||||
};
|
||||
|
||||
@@ -172,10 +236,9 @@ export class DeployCertToAliyunDCDN extends AbstractTaskPlugin {
|
||||
|
||||
const res = await client.request('DescribeDcdnUserDomains', params, requestOption);
|
||||
this.checkRet(res);
|
||||
const pageData = res?.Domains?.PageData;
|
||||
if (!pageData || pageData.length === 0) {
|
||||
throw new Error('找不到CDN域名,您可以手动输入');
|
||||
}
|
||||
const pageData = res?.Domains?.PageData || [];
|
||||
const total = res?.Domains?.TotalCount || 0;
|
||||
|
||||
const options = pageData.map((item: any) => {
|
||||
return {
|
||||
value: item.DomainName,
|
||||
@@ -183,7 +246,11 @@ export class DeployCertToAliyunDCDN extends AbstractTaskPlugin {
|
||||
domain: item.DomainName,
|
||||
};
|
||||
});
|
||||
return optionsUtils.buildGroupOptions(options, this.certDomains);
|
||||
|
||||
return {
|
||||
list: optionsUtils.buildGroupOptions(options, this.certDomains),
|
||||
total: total,
|
||||
};
|
||||
}
|
||||
}
|
||||
new DeployCertToAliyunDCDN();
|
||||
|
||||
Reference in New Issue
Block a user