mirror of
https://github.com/certd/certd.git
synced 2026-05-15 20:47:31 +08:00
Merge branch 'v2-dev' into v2-dev-buy
This commit is contained in:
@@ -83,7 +83,7 @@ export class CodeService {
|
||||
}
|
||||
const smsType = sysSettings.sms.type;
|
||||
const smsConfig = sysSettings.sms.config;
|
||||
const sender: ISmsService = SmsServiceFactory.createSmsService(smsType);
|
||||
const sender: ISmsService = await SmsServiceFactory.createSmsService(smsType);
|
||||
const accessGetter = new AccessSysGetter(this.accessService);
|
||||
sender.setCtx({
|
||||
accessService: accessGetter,
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
import { AliyunSmsService } from './aliyun-sms.js';
|
||||
import { YfySmsService } from './yfy-sms.js';
|
||||
|
||||
export class SmsServiceFactory {
|
||||
static createSmsService(type: string) {
|
||||
const cls = this.GetClassByType(type);
|
||||
static async createSmsService(type: string) {
|
||||
const cls = await this.GetClassByType(type);
|
||||
return new cls();
|
||||
}
|
||||
|
||||
static GetClassByType(type: string) {
|
||||
static async GetClassByType(type: string) {
|
||||
switch (type) {
|
||||
case 'aliyun':
|
||||
const {AliyunSmsService} = await import("./aliyun-sms.js")
|
||||
return AliyunSmsService;
|
||||
case 'yfysms':
|
||||
const {YfySmsService} = await import("./yfy-sms.js")
|
||||
return YfySmsService;
|
||||
case 'tencent':
|
||||
const {TencentSmsService} = await import("./tencent-sms.js")
|
||||
return TencentSmsService;
|
||||
default:
|
||||
throw new Error('不支持的短信服务类型');
|
||||
}
|
||||
}
|
||||
|
||||
static getDefine(type: string) {
|
||||
const cls = this.GetClassByType(type);
|
||||
static async getDefine(type: string) {
|
||||
const cls = await this.GetClassByType(type);
|
||||
return cls.getDefine();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
import {ISmsService, PluginInputs, SmsPluginCtx} from './api.js';
|
||||
import {TencentAccess} from "@certd/plugin-lib";
|
||||
|
||||
export type TencentSmsConfig = {
|
||||
accessId: string;
|
||||
signName: string;
|
||||
codeTemplateId: string;
|
||||
appId: string;
|
||||
region: string;
|
||||
};
|
||||
|
||||
export class TencentSmsService implements ISmsService {
|
||||
static getDefine() {
|
||||
return {
|
||||
name: 'tencent',
|
||||
desc: '腾讯云短信服务',
|
||||
input: {
|
||||
accessId: {
|
||||
title: '腾讯云授权',
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'tencent',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
region: {
|
||||
title: '区域',
|
||||
value:"ap-beijing",
|
||||
component: {
|
||||
name: 'a-select',
|
||||
vModel: 'value',
|
||||
options:[
|
||||
{value:"ap-beijing",label:"华北地区(北京)"},
|
||||
{value:"ap-guangzhou",label:"华南地区(广州)"},
|
||||
{value:"ap-nanjing",label:"华东地区(南京)"},
|
||||
]
|
||||
},
|
||||
helper:"随便选一个",
|
||||
required: true,
|
||||
},
|
||||
signName: {
|
||||
title: '签名',
|
||||
component: {
|
||||
name: 'a-input',
|
||||
vModel: 'value',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
appId: {
|
||||
title: '应用ID',
|
||||
component: {
|
||||
name: 'a-input',
|
||||
vModel: 'value',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
codeTemplateId: {
|
||||
title: '验证码模板Id',
|
||||
component: {
|
||||
name: 'a-input',
|
||||
vModel: 'value',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
} as PluginInputs<TencentSmsConfig>,
|
||||
};
|
||||
}
|
||||
|
||||
ctx: SmsPluginCtx<TencentSmsConfig>;
|
||||
|
||||
setCtx(ctx: any) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
|
||||
async getClient() {
|
||||
const sdk = await import('tencentcloud-sdk-nodejs/tencentcloud/services/sms/v20210111/index.js');
|
||||
const client = sdk.v20210111.Client;
|
||||
const access = await this.ctx.accessService.getById<TencentAccess>(this.ctx.config.accessId);
|
||||
|
||||
|
||||
// const region = this.region;
|
||||
const clientConfig = {
|
||||
credential: {
|
||||
secretId: access.secretId,
|
||||
secretKey: access.secretKey,
|
||||
},
|
||||
region: this.ctx.config.region,
|
||||
profile: {
|
||||
httpProfile: {
|
||||
endpoint: `sms.${access.intlDomain()}tencentcloudapi.com`,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return new client(clientConfig);
|
||||
}
|
||||
|
||||
async sendSmsCode(opts: { mobile: string; code: string; phoneCode: string }) {
|
||||
const { mobile, code, phoneCode } = opts;
|
||||
|
||||
const client = await this.getClient();
|
||||
const smsConfig = this.ctx.config;
|
||||
const params = {
|
||||
"PhoneNumberSet": [
|
||||
`+${phoneCode}${mobile}`
|
||||
],
|
||||
"SmsSdkAppId": smsConfig.appId,
|
||||
"TemplateId": smsConfig.codeTemplateId,
|
||||
"SignName": smsConfig.signName,
|
||||
"TemplateParamSet": [
|
||||
code
|
||||
]
|
||||
};
|
||||
const ret = await client.SendSms(params);
|
||||
this.checkRet(ret);
|
||||
}
|
||||
|
||||
checkRet(ret: any) {
|
||||
if (!ret || ret.Error) {
|
||||
throw new Error('执行失败:' + ret.Error.Code + ',' + ret.Error.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export class CertInfoFacade {
|
||||
@Inject()
|
||||
userSettingsService : UserSettingsService
|
||||
|
||||
async getCertInfo(req: { domains?: string; certId?: number; userId: number,autoApply?:boolean }) {
|
||||
async getCertInfo(req: { domains?: string; certId?: number; userId: number,autoApply?:boolean,format?:string }) {
|
||||
const { domains, certId, userId } = req;
|
||||
if (certId) {
|
||||
return await this.certInfoService.getCertInfoById({ id: certId, userId });
|
||||
@@ -41,7 +41,7 @@ export class CertInfoFacade {
|
||||
const domainArr = domains.split(',');
|
||||
|
||||
const matchedList = await this.certInfoService.getMatchCertList({domains:domainArr,userId})
|
||||
let matched: CertInfoEntity = null
|
||||
|
||||
if (matchedList.length === 0 ) {
|
||||
if(req.autoApply === true){
|
||||
//自动申请,先创建自动申请流水线
|
||||
@@ -54,13 +54,7 @@ export class CertInfoFacade {
|
||||
});
|
||||
}
|
||||
}
|
||||
matched = null;
|
||||
for (const item of matchedList) {
|
||||
if (item.expiresTime>0 && item.expiresTime > new Date().getTime()) {
|
||||
matched = item;
|
||||
break
|
||||
}
|
||||
}
|
||||
let matched = this.getMinixMatched(matchedList);
|
||||
if (!matched) {
|
||||
if(req.autoApply === true){
|
||||
//如果没有找到有效期内的证书,则自动触发一次申请
|
||||
@@ -75,7 +69,38 @@ export class CertInfoFacade {
|
||||
}
|
||||
}
|
||||
|
||||
return await this.certInfoService.getCertInfoById({ id: matched.id, userId: userId });
|
||||
return await this.certInfoService.getCertInfoById({ id: matched.id, userId: userId,format:req.format });
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public getMinixMatched(matchedList: CertInfoEntity[]) {
|
||||
let matched: CertInfoEntity = null;
|
||||
for (const item of matchedList) {
|
||||
if (item.expiresTime > 0 && item.expiresTime > new Date().getTime()) {
|
||||
if (matched) {
|
||||
//如果前面已经有match的值,判断范围是否比上一个小
|
||||
const currentStars = `-${item.domains}`.split("*");
|
||||
const matchedStars = `-${matched.domains}`.split("*");
|
||||
|
||||
const currentLength = item.domains.split(",");
|
||||
const matchedLength = matched.domains.split(",");
|
||||
if (currentStars.length < matchedStars.length) {
|
||||
//如果*的数量比上一个少,则替换为当前
|
||||
matched = item;
|
||||
} else if (currentStars.length == matchedStars.length) {
|
||||
//如果*的数量相同,则比较域名数量
|
||||
if (currentLength.length < matchedLength.length) {
|
||||
matched = item;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
matched = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
async createAutoPipeline(req:{domains:string[],userId:number}){
|
||||
|
||||
@@ -113,7 +113,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||
});
|
||||
}
|
||||
|
||||
async getCertInfoById(req: { id: number; userId: number }) {
|
||||
async getCertInfoById(req: { id: number; userId: number,format?:string }) {
|
||||
const entity = await this.info(req.id);
|
||||
if (!entity || entity.userId !== req.userId) {
|
||||
throw new CodeException(Constants.res.openCertNotFound);
|
||||
@@ -124,7 +124,14 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||
}
|
||||
const certInfo = JSON.parse(entity.certInfo) as CertInfo;
|
||||
const certReader = new CertReader(certInfo);
|
||||
return certReader.toCertInfo();
|
||||
return {
|
||||
...certReader.toCertInfo(req.format),
|
||||
detail: {
|
||||
id: entity.id,
|
||||
domains: entity.domains.split(','),
|
||||
notAfter: certReader.expires,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async updateCertByPipelineId(pipelineId: number, cert: CertInfo,file?:string,fromType = 'pipeline') {
|
||||
|
||||
@@ -3,9 +3,10 @@ import { PluginService } from './plugin-service.js';
|
||||
|
||||
export type PluginConfig = {
|
||||
name: string;
|
||||
disabled: boolean;
|
||||
disabled?: boolean;
|
||||
sysSetting: {
|
||||
input?: Record<string, any>;
|
||||
metadata?: Record<string, any>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -37,10 +38,12 @@ export class PluginConfigService {
|
||||
}
|
||||
|
||||
async saveCommPluginConfig(config: CommPluginConfig) {
|
||||
await this.savePluginConfig('CertApply', config.CertApply);
|
||||
config.CertApply.name = 'CertApply';
|
||||
await this.savePluginConfig(config.CertApply);
|
||||
}
|
||||
|
||||
async savePluginConfig(name: string, config: PluginConfig) {
|
||||
async savePluginConfig( config: PluginConfig) {
|
||||
const name = config.name;
|
||||
const sysSetting = config?.sysSetting;
|
||||
if (!sysSetting) {
|
||||
throw new Error(`${name}.sysSetting is required`);
|
||||
@@ -57,7 +60,14 @@ export class PluginConfigService {
|
||||
author: "certd",
|
||||
});
|
||||
} else {
|
||||
await this.pluginService.getRepository().update({ name }, { sysSetting: JSON.stringify(sysSetting) });
|
||||
let setting = JSON.parse(pluginEntity.sysSetting || "{}");
|
||||
if (sysSetting.metadata) {
|
||||
setting.metadata = sysSetting.metadata;
|
||||
}
|
||||
if (sysSetting.input) {
|
||||
setting.input = sysSetting.input;
|
||||
}
|
||||
await this.pluginService.getRepository().update({ name }, { sysSetting: JSON.stringify(setting) });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||
import { BaseService, PageReq } from "@certd/lib-server";
|
||||
import { PluginEntity } from "../entity/plugin.js";
|
||||
import { InjectEntityModel } from "@midwayjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { isComm } from "@certd/plus-core";
|
||||
import { BuiltInPluginService } from "../../pipeline/service/builtin-plugin-service.js";
|
||||
import { merge } from "lodash-es";
|
||||
import { accessRegistry, notificationRegistry, pluginRegistry } from "@certd/pipeline";
|
||||
import { dnsProviderRegistry } from "@certd/plugin-cert";
|
||||
import { logger } from "@certd/basic";
|
||||
import {Inject, Provide, Scope, ScopeEnum} from "@midwayjs/core";
|
||||
import {BaseService, PageReq} from "@certd/lib-server";
|
||||
import {PluginEntity} from "../entity/plugin.js";
|
||||
import {InjectEntityModel} from "@midwayjs/typeorm";
|
||||
import {IsNull, Not, Repository} from "typeorm";
|
||||
import {isComm} from "@certd/plus-core";
|
||||
import {BuiltInPluginService} from "../../pipeline/service/builtin-plugin-service.js";
|
||||
import {merge} from "lodash-es";
|
||||
import {accessRegistry, notificationRegistry, pluginRegistry} from "@certd/pipeline";
|
||||
import {dnsProviderRegistry} from "@certd/plugin-cert";
|
||||
import {logger} from "@certd/basic";
|
||||
import yaml from "js-yaml";
|
||||
import { getDefaultAccessPlugin, getDefaultDeployPlugin, getDefaultDnsPlugin } from "./default-plugin.js";
|
||||
import {getDefaultAccessPlugin, getDefaultDeployPlugin, getDefaultDnsPlugin} from "./default-plugin.js";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
@@ -57,9 +57,9 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
};
|
||||
}
|
||||
|
||||
async getEnabledBuildInGroup(isSimple = false) {
|
||||
async getEnabledBuildInGroup(opts?:{isSimple?:boolean,withSetting?:boolean}) {
|
||||
const groups = this.builtInPluginService.getGroups();
|
||||
if (isSimple) {
|
||||
if (opts?.isSimple) {
|
||||
for (const key in groups) {
|
||||
const group = groups[key];
|
||||
group.plugins.forEach(item => {
|
||||
@@ -72,9 +72,43 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
if (!isComm()) {
|
||||
return groups;
|
||||
}
|
||||
|
||||
// 初始化设置
|
||||
const settingPlugins = await this.repository.find({
|
||||
select:{
|
||||
id:true,
|
||||
name:true,
|
||||
sysSetting:true
|
||||
},
|
||||
where: {
|
||||
sysSetting : Not(IsNull())
|
||||
}
|
||||
})
|
||||
//合并插件配置
|
||||
const pluginSettingMap:any = {}
|
||||
for (const item of settingPlugins) {
|
||||
if (!item.sysSetting) {
|
||||
continue;
|
||||
}
|
||||
pluginSettingMap[item.name] = JSON.parse(item.sysSetting);
|
||||
}
|
||||
for (const key in groups) {
|
||||
const group = groups[key];
|
||||
if (!group.plugins) {
|
||||
continue;
|
||||
}
|
||||
for (const item of group.plugins) {
|
||||
const pluginSetting = pluginSettingMap[item.name];
|
||||
if (pluginSetting){
|
||||
item.sysSetting = pluginSetting
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//排除禁用的
|
||||
const list = await this.list({
|
||||
query: {
|
||||
type: "builtIn",
|
||||
disabled: true
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user