mirror of
https://github.com/certd/certd.git
synced 2026-04-23 19:57:27 +08:00
Merge branch 'certd:v2' into v2
This commit is contained in:
@@ -9,7 +9,6 @@ export * from './plugin-other/index.js';
|
||||
export * from './plugin-west/index.js';
|
||||
export * from './plugin-doge/index.js';
|
||||
export * from './plugin-qiniu/index.js';
|
||||
export * from './plugin-jdcloud/index.js';
|
||||
export * from './plugin-woai/index.js';
|
||||
export * from './plugin-cachefly/index.js';
|
||||
export * from './plugin-gcore/index.js';
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import { Autowire, ILogger } from '@certd/pipeline';
|
||||
import { Autowire } from '@certd/pipeline';
|
||||
import { ILogger } from '@certd/basic';
|
||||
|
||||
import { AliyunAccess, AliyunClient } from '@certd/plugin-plus';
|
||||
|
||||
@IsDnsProvider({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import dayjs from 'dayjs';
|
||||
import { AliyunAccess, AliyunClient } from "@certd/plugin-plus";
|
||||
import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-plus';
|
||||
import { optionsUtils } from '@certd/basic/dist/utils/util.options.js';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'DeployCertToAliyunCDN',
|
||||
title: '部署证书至阿里云CDN',
|
||||
@@ -15,29 +16,35 @@ import { AliyunAccess, AliyunClient } from "@certd/plugin-plus";
|
||||
})
|
||||
export class DeployCertToAliyunCDN extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: 'CDN加速域名',
|
||||
helper: '你在阿里云上配置的CDN加速域名,比如:certd.docmirror.cn',
|
||||
title: '证书服务接入点',
|
||||
helper: '不会选就按默认',
|
||||
value: 'cas.aliyuncs.com',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
options: [
|
||||
{ value: 'cas.aliyuncs.com', label: '中国大陆' },
|
||||
{ value: 'cas.ap-southeast-1.aliyuncs.com', label: '新加坡' },
|
||||
{ value: 'cas.eu-central-1.aliyuncs.com', label: '德国(法兰克福)' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
domainName!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '证书名称',
|
||||
helper: '上传后将以此名称作为前缀备注',
|
||||
})
|
||||
certName!: string;
|
||||
endpoint!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: ['CertApply', 'CertApplyLego'],
|
||||
from: ['CertApply', 'CertApplyLego', 'uploadCertToAliyun'],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: string;
|
||||
|
||||
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||
certDomains!: string[];
|
||||
|
||||
@TaskInput({
|
||||
title: 'Access授权',
|
||||
helper: '阿里云授权AccessKeyId、AccessKeySecret',
|
||||
@@ -49,47 +56,84 @@ export class DeployCertToAliyunCDN extends AbstractTaskPlugin {
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: 'CDN加速域名',
|
||||
helper: '你在阿里云上配置的CDN加速域名,比如:certd.docmirror.cn',
|
||||
typeName: 'DeployCertToAliyunCDN',
|
||||
action: DeployCertToAliyunCDN.prototype.onGetDomainList.name,
|
||||
watches: ['certDomains', 'accessId'],
|
||||
required: true,
|
||||
})
|
||||
)
|
||||
domainName!: string | string[];
|
||||
|
||||
@TaskInput({
|
||||
title: '证书名称',
|
||||
helper: '上传后将以此名称作为前缀备注',
|
||||
})
|
||||
certName!: string;
|
||||
|
||||
async onInstance() {}
|
||||
async execute(): Promise<void> {
|
||||
this.logger.info('开始部署证书到阿里云cdn');
|
||||
const access = (await this.accessService.getById(this.accessId)) as AliyunAccess;
|
||||
const access = await this.accessService.getById<AliyunAccess>(this.accessId);
|
||||
const sslClient = new AliyunSslClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
endpoint: this.endpoint || 'cas.aliyuncs.com',
|
||||
});
|
||||
|
||||
let certId: any = this.cert;
|
||||
if (typeof this.cert === 'object') {
|
||||
certId = await sslClient.uploadCert({
|
||||
name: this.appendTimeSuffix('certd'),
|
||||
cert: this.cert,
|
||||
});
|
||||
}
|
||||
|
||||
const client = await this.getClient(access);
|
||||
const params = await this.buildParams();
|
||||
await this.doRequest(client, params);
|
||||
|
||||
if (typeof this.domainName === 'string') {
|
||||
this.domainName = [this.domainName];
|
||||
}
|
||||
for (const domain of this.domainName) {
|
||||
await this.SetCdnDomainSSLCertificate(client, {
|
||||
CertId: certId,
|
||||
DomainName: domain,
|
||||
});
|
||||
}
|
||||
|
||||
this.logger.info('部署完成');
|
||||
}
|
||||
|
||||
async getClient(access: AliyunAccess) {
|
||||
const client = new AliyunClient({logger:this.logger})
|
||||
const client = new AliyunClient({ logger: this.logger });
|
||||
await client.init({
|
||||
accessKeyId: access.accessKeyId,
|
||||
accessKeySecret: access.accessKeySecret,
|
||||
endpoint: 'https://cdn.aliyuncs.com',
|
||||
apiVersion: '2018-05-10',
|
||||
})
|
||||
return client
|
||||
});
|
||||
return client;
|
||||
}
|
||||
|
||||
async buildParams() {
|
||||
const CertName = (this.certName ?? 'certd') + '-' + dayjs().format('YYYYMMDDHHmmss');
|
||||
const cert: any = this.cert;
|
||||
return {
|
||||
DomainName: this.domainName,
|
||||
SSLProtocol: 'on',
|
||||
CertName: CertName,
|
||||
CertType: 'upload',
|
||||
SSLPub: cert.crt,
|
||||
SSLPri: cert.key,
|
||||
};
|
||||
}
|
||||
|
||||
async doRequest(client: any, params: any) {
|
||||
async SetCdnDomainSSLCertificate(client: any, params: { CertId: number; DomainName: string }) {
|
||||
const requestOption = {
|
||||
method: 'POST',
|
||||
formatParams: false,
|
||||
};
|
||||
const ret: any = await client.request('SetCdnDomainSSLCertificate', params, requestOption);
|
||||
|
||||
const ret: any = await client.request(
|
||||
'SetCdnDomainSSLCertificate',
|
||||
{
|
||||
SSLProtocol: 'on',
|
||||
...params,
|
||||
},
|
||||
requestOption
|
||||
);
|
||||
this.checkRet(ret);
|
||||
this.logger.info('设置cdn证书成功:', ret.RequestId);
|
||||
this.logger.info(`设置CDN: ${params.DomainName} 证书成功:`, ret.RequestId);
|
||||
}
|
||||
|
||||
checkRet(ret: any) {
|
||||
@@ -97,5 +141,39 @@ export class DeployCertToAliyunCDN extends AbstractTaskPlugin {
|
||||
throw new Error('执行失败:' + ret.Message);
|
||||
}
|
||||
}
|
||||
|
||||
async onGetDomainList(data: any) {
|
||||
if (!this.accessId) {
|
||||
throw new Error('请选择Access授权');
|
||||
}
|
||||
const access = await this.accessService.getById<AliyunAccess>(this.accessId);
|
||||
|
||||
const client = await this.getClient(access);
|
||||
|
||||
const params = {
|
||||
// 'DomainName': 'aaa',
|
||||
PageSize: 500,
|
||||
};
|
||||
|
||||
const requestOption = {
|
||||
method: 'POST',
|
||||
formatParams: false,
|
||||
};
|
||||
|
||||
const res = await client.request('DescribeUserDomains', params, requestOption);
|
||||
this.checkRet(res);
|
||||
const pageData = res?.Domains?.PageData;
|
||||
if (!pageData || pageData.length === 0) {
|
||||
throw new Error('找不到CDN域名,您可以手动输入');
|
||||
}
|
||||
const options = pageData.map((item: any) => {
|
||||
return {
|
||||
value: item.DomainName,
|
||||
label: item.DomainName,
|
||||
domain: item.DomainName,
|
||||
};
|
||||
});
|
||||
return optionsUtils.buildGroupOptions(options, this.certDomains);
|
||||
}
|
||||
}
|
||||
new DeployCertToAliyunCDN();
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { AliyunAccess } from '@certd/plugin-plus';
|
||||
import { CertInfo } from '@certd/plugin-cert';
|
||||
@IsTaskPlugin({
|
||||
name: 'DeployCertToAliyunOSS',
|
||||
title: '部署证书至阿里云OSS',
|
||||
icon: 'ant-design:aliyun-outlined',
|
||||
group: pluginGroups.aliyun.key,
|
||||
desc: '自动部署域名证书至阿里云OSS',
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
})
|
||||
export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: '大区',
|
||||
component: {
|
||||
name: 'a-auto-complete',
|
||||
vModel: 'value',
|
||||
options: [
|
||||
{ value: 'oss-cn-hangzhou', label: '华东1(杭州)' },
|
||||
{ value: 'oss-cn-shanghai', label: '华东2(上海)' },
|
||||
{ value: 'oss-cn-nanjing', label: '华东5(南京-本地地域)' },
|
||||
{ value: 'oss-cn-fuzhou', label: '华东6(福州-本地地域)' },
|
||||
{ value: 'oss-cn-wuhan-lr', label: '华中1(武汉-本地地域)' },
|
||||
{ value: 'oss-cn-qingdao', label: '华北1(青岛)' },
|
||||
{ value: 'oss-cn-beijing', label: '华北2(北京)' },
|
||||
{ value: 'oss-cn-zhangjiakou', label: '华北 3(张家口)' },
|
||||
{ value: 'oss-cn-huhehaote', label: '华北5(呼和浩特)' },
|
||||
{ value: 'oss-cn-wulanchabu', label: '华北6(乌兰察布)' },
|
||||
{ value: 'oss-cn-shenzhen', label: '华南1(深圳)' },
|
||||
{ value: 'oss-cn-heyuan', label: '华南2(河源)' },
|
||||
{ value: 'oss-cn-guangzhou', label: '华南3(广州)' },
|
||||
{ value: 'oss-cn-chengdu', label: '西南1(成都)' },
|
||||
{ value: 'oss-cn-hongkong', label: '中国香港' },
|
||||
{ value: 'oss-us-west-1', label: '美国(硅谷)①' },
|
||||
{ value: 'oss-us-east-1', label: '美国(弗吉尼亚)①' },
|
||||
{ value: 'oss-ap-northeast-1', label: '日本(东京)①' },
|
||||
{ value: 'oss-ap-northeast-2', label: '韩国(首尔)' },
|
||||
{ value: 'oss-ap-southeast-1', label: '新加坡①' },
|
||||
{ value: 'oss-ap-southeast-2', label: '澳大利亚(悉尼)①' },
|
||||
{ value: 'oss-ap-southeast-3', label: '马来西亚(吉隆坡)①' },
|
||||
{ value: 'oss-ap-southeast-5', label: '印度尼西亚(雅加达)①' },
|
||||
{ value: 'oss-ap-southeast-6', label: '菲律宾(马尼拉)' },
|
||||
{ value: 'oss-ap-southeast-7', label: '泰国(曼谷)' },
|
||||
{ value: 'oss-eu-central-1', label: '德国(法兰克福)①' },
|
||||
{ value: 'oss-eu-west-1', label: '英国(伦敦)' },
|
||||
{ value: 'oss-me-east-1', label: '阿联酋(迪拜)①' },
|
||||
{ value: 'oss-rg-china-mainland', label: '无地域属性(中国内地)' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
region!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: 'Bucket',
|
||||
helper: '存储桶名称',
|
||||
required: true,
|
||||
})
|
||||
bucket!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '绑定的域名',
|
||||
helper: '你在阿里云OSS上绑定的域名,比如:certd.docmirror.cn',
|
||||
required: true,
|
||||
})
|
||||
domainName!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '证书名称',
|
||||
helper: '上传后将以此名称作为前缀备注',
|
||||
})
|
||||
certName!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: ['CertApply', 'CertApplyLego'],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput({
|
||||
title: 'Access授权',
|
||||
helper: '阿里云授权AccessKeyId、AccessKeySecret',
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'aliyun',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
async onInstance() {}
|
||||
async execute(): Promise<void> {
|
||||
this.logger.info('开始部署证书到阿里云OSS');
|
||||
const access = (await this.accessService.getById(this.accessId)) as AliyunAccess;
|
||||
this.logger.info(`bucket: ${this.bucket}, region: ${this.region}, domainName: ${this.domainName}`);
|
||||
const client = await this.getClient(access);
|
||||
await this.doRequest(client, {});
|
||||
this.logger.info('部署完成');
|
||||
}
|
||||
|
||||
async getClient(access: AliyunAccess) {
|
||||
// @ts-ignore
|
||||
const OSS = await import('ali-oss');
|
||||
return new OSS.default({
|
||||
accessKeyId: access.accessKeyId,
|
||||
accessKeySecret: access.accessKeySecret,
|
||||
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
|
||||
region: this.region,
|
||||
//@ts-ignore
|
||||
authorizationV4: true,
|
||||
// yourBucketName填写Bucket名称。
|
||||
bucket: this.bucket,
|
||||
});
|
||||
}
|
||||
|
||||
async doRequest(client: any, params: any) {
|
||||
params = client._bucketRequestParams('POST', this.bucket, {
|
||||
cname: '',
|
||||
comp: 'add',
|
||||
});
|
||||
const xml = `
|
||||
<BucketCnameConfiguration>
|
||||
<Cname>
|
||||
<Domain>${this.domainName}</Domain>
|
||||
<CertificateConfiguration>
|
||||
<PrivateKey>${this.cert.key}</PrivateKey>
|
||||
<Certificate>${this.cert.crt}</Certificate>
|
||||
</CertificateConfiguration>
|
||||
</Cname>
|
||||
</BucketCnameConfiguration>`;
|
||||
params.content = xml;
|
||||
params.mime = 'xml';
|
||||
params.successStatuses = [200];
|
||||
const res = await client.request(params);
|
||||
this.checkRet(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
checkRet(ret: any) {
|
||||
if (ret.code != null) {
|
||||
throw new Error('执行失败:' + ret.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
new DeployCertToAliyunOSS();
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './deploy-to-cdn/index.js';
|
||||
export * from './deploy-to-dcdn/index.js';
|
||||
export * from './deploy-to-oss/index.js';
|
||||
export * from './upload-to-aliyun/index.js';
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import { Autowire, HttpClient, ILogger } from '@certd/pipeline';
|
||||
import { Autowire } from '@certd/pipeline';
|
||||
import { HttpClient, ILogger } from '@certd/basic';
|
||||
|
||||
import { CloudflareAccess } from './access.js';
|
||||
|
||||
export type CloudflareRecord = {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import { Autowire, HttpClient, ILogger } from '@certd/pipeline';
|
||||
import { Autowire } from '@certd/pipeline';
|
||||
import { HttpClient, ILogger } from '@certd/basic';
|
||||
|
||||
import { DemoAccess } from './access.js';
|
||||
import { isDev } from "../../utils/env.js";
|
||||
import { isDev } from '../../utils/env.js';
|
||||
|
||||
type DemoRecord = {
|
||||
// 这里定义Record记录的数据结构,跟对应云平台接口返回值一样即可,一般是拿到id就行,用于删除txt解析记录,清理申请痕迹
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
||||
import { isDev } from '../../../utils/env.js';
|
||||
import { isDev } from '@certd/basic';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'demoTest',
|
||||
title: 'Demo测试插件',
|
||||
icon: 'clarity:plugin-line',
|
||||
//插件分组
|
||||
group: pluginGroups.other.key,
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
// 你开发的插件要删除此项,否则不会在生产环墋中显示
|
||||
deprecated: isDev() ? '测试插件,生产环境不显示' : undefined,
|
||||
})
|
||||
export class DemoTestPlugin extends AbstractTaskPlugin {
|
||||
//测试参数
|
||||
@TaskInput({
|
||||
title: '属性示例',
|
||||
value: '默认值',
|
||||
component: {
|
||||
//前端组件配置,具体配置见组件文档 https://www.antdv.com/components/input-cn
|
||||
name: 'a-input',
|
||||
@@ -57,7 +61,7 @@ export class DemoTestPlugin extends AbstractTaskPlugin {
|
||||
name: 'output-selector',
|
||||
from: ['CertApply', 'CertApplyLego'],
|
||||
},
|
||||
// required: true,
|
||||
// required: true, // 必填
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@@ -70,6 +74,7 @@ export class DemoTestPlugin extends AbstractTaskPlugin {
|
||||
type: 'demo', //固定授权类型
|
||||
},
|
||||
// rules: [{ required: true, message: '此项必填' }],
|
||||
// required: true, //必填
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@@ -98,8 +103,5 @@ export class DemoTestPlugin extends AbstractTaskPlugin {
|
||||
this.logger.info('授权id:', accessId);
|
||||
}
|
||||
}
|
||||
//TODO 这里实例化插件,进行注册
|
||||
if (isDev()) {
|
||||
//你的实现 要去掉这个if,不然生产环境将不会显示
|
||||
new DemoTestPlugin();
|
||||
}
|
||||
//实例化一下,注册插件
|
||||
new DemoTestPlugin();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import crypto from 'crypto';
|
||||
import querystring from 'querystring';
|
||||
import { DogeCloudAccess } from '../access.js';
|
||||
import { HttpClient } from '@certd/pipeline';
|
||||
import { HttpClient } from '@certd/basic';
|
||||
|
||||
export class DogeClient {
|
||||
accessKey: string;
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { AccessInput, BaseAccess, IsAccess } from '@certd/pipeline';
|
||||
|
||||
/**
|
||||
* 这个注解将注册一个授权配置
|
||||
* 在certd的后台管理系统中,用户可以选择添加此类型的授权
|
||||
*/
|
||||
@IsAccess({
|
||||
name: 'dynadot',
|
||||
title: 'dynadot授权',
|
||||
desc: '************\n注意:申请证书时会覆盖已有的域名解析配置,慎用\n************\n待优化,主要是dynadot的接口一言难尽',
|
||||
})
|
||||
export class DynadotAccess extends BaseAccess {
|
||||
/**
|
||||
* 授权属性配置
|
||||
*/
|
||||
@AccessInput({
|
||||
title: 'API Production Key',
|
||||
component: {
|
||||
placeholder: '授权key',
|
||||
},
|
||||
helper: '前往 [Dynadot API](https://www.dynadot.com/account/domain/setting/api.html) 获取 API Production Key',
|
||||
required: true,
|
||||
encrypt: true,
|
||||
})
|
||||
apiProductionKey = '';
|
||||
}
|
||||
|
||||
new DynadotAccess();
|
||||
@@ -1,94 +0,0 @@
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import { Autowire, ILogger } from '@certd/pipeline';
|
||||
import { DynadotAccess } from './access.js';
|
||||
import querystring from 'querystring';
|
||||
|
||||
// 这里通过IsDnsProvider注册一个dnsProvider
|
||||
@IsDnsProvider({
|
||||
name: 'dynadot',
|
||||
title: 'dynadot',
|
||||
desc: 'dynadot dns provider',
|
||||
// 这里是对应的 cloudflare的access类型名称
|
||||
accessType: 'dynadot',
|
||||
deprecated: '暂不支持',
|
||||
})
|
||||
export class DynadotDnsProvider extends AbstractDnsProvider {
|
||||
// 通过Autowire传递context
|
||||
@Autowire()
|
||||
logger!: ILogger;
|
||||
access!: DynadotAccess;
|
||||
async onInstance() {
|
||||
this.access = this.ctx.access as DynadotAccess;
|
||||
}
|
||||
|
||||
private async doRequest(command: string, query: any) {
|
||||
const baseUrl = 'https://api.dynadot.com/api3.json?key=' + this.access.apiProductionKey;
|
||||
const qs = querystring.stringify(query);
|
||||
const url = `${baseUrl}&command=${command}&${qs}`;
|
||||
const res = await this.ctx.http.request<any, any>({
|
||||
url,
|
||||
method: 'get',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
/*
|
||||
"SetDnsResponse": {
|
||||
"ResponseCode": 0,
|
||||
"Status": "success"
|
||||
}
|
||||
*/
|
||||
for (const resKey in res) {
|
||||
if (res[resKey].ResponseCode != null && res[resKey].ResponseCode !== 0) {
|
||||
throw new Error(`请求失败:${res[resKey].Status}`);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建dns解析记录,用于验证域名所有权
|
||||
*/
|
||||
async createRecord(options: CreateRecordOptions) {
|
||||
/**
|
||||
* fullRecord: '_acme-challenge.test.example.com',
|
||||
* value: 一串uuid
|
||||
* type: 'TXT',
|
||||
* domain: 'example.com'
|
||||
*/
|
||||
const { fullRecord, value, type, domain } = options;
|
||||
this.logger.info('添加域名解析:', fullRecord, value, type, domain);
|
||||
|
||||
//先获取域名原始解析记录
|
||||
//https://api.dynadot.com/api3.xml?key=[API Key]&command=domain_info&domain=domain1.com
|
||||
const res1 = await this.doRequest('domain_info', {
|
||||
domain: domain,
|
||||
});
|
||||
// this.logger.info(`域名信息:${JSON.stringify(res1)}`);
|
||||
// "DomainInfoResponse.NameServerSettings":{"Type":"Dynadot DNS","SubDomains":[{"Subhost":"_acme-challenge","RecordType":"TXT","Value":"43XrhFA6pJpE7a-20y7BmC6CsN20TMt5l-Zl-CL_-4I"}],"TTL":"300"}
|
||||
this.logger.info('原始域名解析记录:', JSON.stringify(res1.DomainInfoResponse?.DomainInfo?.NameServerSettings));
|
||||
const prefix = fullRecord.replace(`.${domain}`, '');
|
||||
// 给domain下创建txt类型的dns解析记录,fullRecord
|
||||
const res = await this.doRequest('set_dns2', {
|
||||
domain: domain,
|
||||
subdomain0: prefix,
|
||||
sub_record_type0: 'TXT',
|
||||
sub_record0: value,
|
||||
});
|
||||
this.logger.info(`添加域名解析成功:fullRecord=${fullRecord},value=${value}`);
|
||||
this.logger.info(`请求结果:${JSON.stringify(res)}`);
|
||||
|
||||
//本接口需要返回本次创建的dns解析记录,这个记录会在删除的时候用到
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除dns解析记录,清理申请痕迹
|
||||
* @param options
|
||||
*/
|
||||
async removeRecord(options: RemoveRecordOptions<any>): Promise<void> {}
|
||||
}
|
||||
|
||||
//实例化这个provider,将其自动注册到系统中
|
||||
new DynadotDnsProvider();
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './dns-provider.js';
|
||||
export * from './plugins/index.js';
|
||||
export * from './access.js';
|
||||
@@ -2,7 +2,7 @@
|
||||
import ssh2, { ConnectConfig, ExecOptions } from 'ssh2';
|
||||
import path from 'path';
|
||||
import * as _ from 'lodash-es';
|
||||
import { ILogger } from '@certd/pipeline';
|
||||
import { ILogger } from '@certd/basic';
|
||||
import { SshAccess } from '../access/index.js';
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import { SocksClient } from 'socks';
|
||||
@@ -86,6 +86,7 @@ export class AsyncSsh2Client {
|
||||
sftp.fastPut(localPath, remotePath, (err: Error) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
this.logger.error('请确认路径是否包含文件名,路径本身不能是目录,路径不能有*?之类的特殊符号,要有写入权限');
|
||||
return;
|
||||
}
|
||||
this.logger.info(`上传文件成功:${localPath} => ${remotePath}`);
|
||||
|
||||
@@ -17,12 +17,47 @@ import path from 'path';
|
||||
},
|
||||
})
|
||||
export class CopyCertToLocalPlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: ['CertApply', 'CertApplyLego'],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput({
|
||||
title: '证书类型',
|
||||
helper: '要部署的证书格式,支持pem、pfx、der、jks格式',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
options: [
|
||||
{ value: 'pem', label: 'pem,用于Nginx等大部分应用' },
|
||||
{ value: 'pfx', label: 'pfx,一般用于IIS' },
|
||||
{ value: 'der', label: 'der,一般用于Apache' },
|
||||
{ value: 'jks', label: 'jks,一般用于JAVA应用' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
certType!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '证书保存路径',
|
||||
helper: '全链证书,路径要包含文件名' + '\n推荐使用相对路径,将写入与数据库同级目录,无需映射,例如:tmp/cert.pem',
|
||||
component: {
|
||||
placeholder: 'tmp/full_chain.pem',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'pem';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
crtPath!: string;
|
||||
@@ -32,6 +67,14 @@ export class CopyCertToLocalPlugin extends AbstractTaskPlugin {
|
||||
component: {
|
||||
placeholder: 'tmp/cert.key',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'pem';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
keyPath!: string;
|
||||
@@ -42,6 +85,13 @@ export class CopyCertToLocalPlugin extends AbstractTaskPlugin {
|
||||
component: {
|
||||
placeholder: '/root/deploy/nginx/intermediate.pem',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'pem';
|
||||
})
|
||||
}
|
||||
`,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
icPath!: string;
|
||||
@@ -52,6 +102,14 @@ export class CopyCertToLocalPlugin extends AbstractTaskPlugin {
|
||||
component: {
|
||||
placeholder: 'tmp/cert.pfx',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'pfx';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
pfxPath!: string;
|
||||
@@ -63,30 +121,35 @@ export class CopyCertToLocalPlugin extends AbstractTaskPlugin {
|
||||
component: {
|
||||
placeholder: 'tmp/cert.der 或 tmp/cert.cer',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'der';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
derPath!: string;
|
||||
|
||||
// @TaskInput({
|
||||
// title: 'jks证书保存路径',
|
||||
// helper: '用于java,路径要包含文件名,例如:tmp/cert.jks',
|
||||
// component: {
|
||||
// placeholder: 'tmp/cert.jks',
|
||||
// },
|
||||
// rules: [{ type: 'filepath' }],
|
||||
// })
|
||||
jksPath!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
title: 'jks证书保存路径',
|
||||
helper: '用于java,路径要包含文件名,例如:tmp/cert.jks',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: ['CertApply', 'CertApplyLego'],
|
||||
placeholder: 'tmp/cert.jks',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'jks';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
cert!: CertInfo;
|
||||
jksPath!: string;
|
||||
|
||||
@TaskOutput({
|
||||
title: '证书保存路径',
|
||||
|
||||
@@ -18,12 +18,47 @@ import dayjs from 'dayjs';
|
||||
},
|
||||
})
|
||||
export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: ['CertApply', 'CertApplyLego'],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput({
|
||||
title: '证书格式',
|
||||
helper: '要部署的证书格式,支持pem、pfx、der、jks',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
options: [
|
||||
{ value: 'pem', label: 'pem,Nginx等大部分应用' },
|
||||
{ value: 'pfx', label: 'pfx,一般用于IIS' },
|
||||
{ value: 'der', label: 'der,一般用于Apache' },
|
||||
{ value: 'jks', label: 'jks,一般用于JAVA应用' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
certType!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '证书保存路径',
|
||||
helper: '全链证书,需要有写入权限,路径要包含证书文件名,例如:/tmp/cert.pem',
|
||||
helper: '填写应用原本的证书保存路径,路径要包含证书文件名,例如:/tmp/cert.pem',
|
||||
component: {
|
||||
placeholder: '/root/deploy/nginx/full_chain.pem',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'pem';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
crtPath!: string;
|
||||
@@ -33,6 +68,14 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
||||
component: {
|
||||
placeholder: '/root/deploy/nginx/cert.key',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'pem';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
keyPath!: string;
|
||||
@@ -43,50 +86,70 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
||||
component: {
|
||||
placeholder: '/root/deploy/nginx/intermediate.pem',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'pem';
|
||||
})
|
||||
}
|
||||
`,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
icPath!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: 'PFX证书保存路径',
|
||||
helper: '用于IIS证书部署,需要有写入权限,路径要包含证书文件名,例如:/tmp/cert.pfx',
|
||||
helper: '填写应用原本的证书保存路径,路径要包含证书文件名,例如:D:\\iis\\cert.pfx',
|
||||
component: {
|
||||
placeholder: '/root/deploy/nginx/cert.pfx',
|
||||
placeholder: 'D:\\iis\\cert.pfx',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'pfx';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
pfxPath!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: 'DER证书保存路径',
|
||||
helper: '用于Apache证书部署,需要有写入权限,路径要包含证书文件名,例如:/tmp/cert.der',
|
||||
helper: '填写应用原本的证书保存路径,路径要包含证书文件名,例如:/tmp/cert.der',
|
||||
component: {
|
||||
placeholder: '/root/deploy/nginx/cert.der',
|
||||
placeholder: '/root/deploy/apache/cert.der',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'der';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
derPath!: string;
|
||||
|
||||
// @TaskInput({
|
||||
// title: 'jks证书保存路径',
|
||||
// helper: '需要有写入权限,路径要包含证书文件名,例如:/tmp/cert.jks',
|
||||
// component: {
|
||||
// placeholder: '/root/deploy/nginx/cert.jks',
|
||||
// },
|
||||
// rules: [{ type: 'filepath' }],
|
||||
// })
|
||||
jksPath!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
title: 'jks证书保存路径',
|
||||
helper: '填写应用原本的证书保存路径,路径要包含证书文件名,例如:/tmp/cert.jks',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: ['CertApply', 'CertApplyLego'],
|
||||
placeholder: '/root/deploy/java_app/cert.jks',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'jks';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
cert!: CertInfo;
|
||||
jksPath!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '主机登录配置',
|
||||
|
||||
+3
-1
@@ -1,6 +1,8 @@
|
||||
import * as _ from 'lodash-es';
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import { Autowire, ILogger } from '@certd/pipeline';
|
||||
import { Autowire } from '@certd/pipeline';
|
||||
import { ILogger } from '@certd/basic';
|
||||
|
||||
import { HuaweiAccess } from '../access/index.js';
|
||||
import { ApiRequestOptions, HuaweiYunClient } from '@certd/lib-huawei';
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, resetLogConfigure, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { HuaweiAccess } from '../../access/index.js';
|
||||
import { CertInfo } from '@certd/plugin-cert';
|
||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-plus';
|
||||
import { resetLogConfigure } from '@certd/basic';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'HauweiDeployCertToCDN',
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import { AccessInput, BaseAccess, IsAccess } from '@certd/pipeline';
|
||||
|
||||
/**
|
||||
* 这个注解将注册一个授权配置
|
||||
* 在certd的后台管理系统中,用户可以选择添加此类型的授权
|
||||
*/
|
||||
@IsAccess({
|
||||
name: 'jdcloud',
|
||||
title: '京东云授权',
|
||||
desc: '暂时无法成功申请,还没测试通过',
|
||||
})
|
||||
export class JDCloudAccess extends BaseAccess {
|
||||
/**
|
||||
* 授权属性配置
|
||||
*/
|
||||
@AccessInput({
|
||||
title: 'AccessKeyId',
|
||||
component: {
|
||||
placeholder: 'AK',
|
||||
},
|
||||
helper: '前往 [AccessKey管理](https://uc.jdcloud.com/account/accesskey) 获取 API Production Key',
|
||||
required: true,
|
||||
encrypt: true,
|
||||
})
|
||||
accessKeyId = '';
|
||||
|
||||
@AccessInput({
|
||||
title: 'AccessKeySecret',
|
||||
component: {
|
||||
placeholder: 'SK',
|
||||
},
|
||||
helper: 'SK',
|
||||
required: true,
|
||||
encrypt: true,
|
||||
})
|
||||
accessKeySecret = '';
|
||||
}
|
||||
|
||||
new JDCloudAccess();
|
||||
@@ -1,124 +0,0 @@
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import { Autowire, ILogger } from '@certd/pipeline';
|
||||
import { JDCloudAccess } from './access.js';
|
||||
function promisfy(func: any) {
|
||||
return (params: any, regionId: string) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
func(params, regionId, (err, result) => {
|
||||
if (err) {
|
||||
reject(err.error || err);
|
||||
return;
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// 这里通过IsDnsProvider注册一个dnsProvider
|
||||
@IsDnsProvider({
|
||||
name: 'jdcloud',
|
||||
title: '京东云',
|
||||
desc: '京东云 dns provider',
|
||||
// 这里是对应的 cloudflare的access类型名称
|
||||
accessType: 'jdcloud',
|
||||
deprecated: '暂不支持',
|
||||
})
|
||||
export class JDCloudDnsProvider extends AbstractDnsProvider {
|
||||
// 通过Autowire传递context
|
||||
@Autowire()
|
||||
logger!: ILogger;
|
||||
access!: JDCloudAccess;
|
||||
service!: any;
|
||||
regionId: string;
|
||||
async onInstance() {
|
||||
this.access = this.ctx.access as JDCloudAccess;
|
||||
const { DomainService } = await import('@certd/lib-jdcloud');
|
||||
// @ts-ignore
|
||||
this.regionId = 'cn-north-1';
|
||||
this.service = new DomainService({
|
||||
credentials: {
|
||||
accessKeyId: this.access.accessKeyId,
|
||||
secretAccessKey: this.access.accessKeySecret,
|
||||
},
|
||||
regionId: this.regionId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建dns解析记录,用于验证域名所有权
|
||||
*/
|
||||
async createRecord(options: CreateRecordOptions) {
|
||||
/**
|
||||
* fullRecord: '_acme-challenge.test.example.com',
|
||||
* value: 一串uuid
|
||||
* type: 'TXT',
|
||||
* domain: 'example.com'
|
||||
*/
|
||||
const { fullRecord, value, type, domain } = options;
|
||||
this.logger.info('添加域名解析:', fullRecord, value, type, domain);
|
||||
|
||||
const describeDomains = promisfy((a, b, c) => {
|
||||
this.service.describeDomains(a, b, c);
|
||||
});
|
||||
|
||||
const res: any = await describeDomains({ domainName: domain, pageNumber: 1, pageSize: 10 }, this.regionId);
|
||||
this.logger.info('请求成功:', JSON.stringify(res.result));
|
||||
const dataList = res.result.dataList;
|
||||
if (dataList.length === 0) {
|
||||
throw new Error('账号下找不到域名:' + domain);
|
||||
}
|
||||
const domainId = dataList[0].id;
|
||||
this.logger.info('domainId:', domainId);
|
||||
|
||||
//开始创建解析记录
|
||||
const createResourceRecord = promisfy((a, b, c) => {
|
||||
this.service.createResourceRecord(a, b, c);
|
||||
});
|
||||
const res2: any = await createResourceRecord(
|
||||
{
|
||||
domainId,
|
||||
req: {
|
||||
hostRecord: fullRecord,
|
||||
hostValue: value,
|
||||
type: 'TXT',
|
||||
},
|
||||
},
|
||||
this.regionId
|
||||
);
|
||||
this.logger.info('请求成功:', JSON.stringify(res.result));
|
||||
const recordList = res2.result.dataList;
|
||||
const recordId = recordList[0].id;
|
||||
|
||||
this.logger.info(`添加域名解析成功:fullRecord=${fullRecord},value=${value}`);
|
||||
this.logger.info(`请求结果:recordId:${recordId}`);
|
||||
|
||||
//本接口需要返回本次创建的dns解析记录,这个记录会在删除的时候用到
|
||||
return { id: recordId, domainId };
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除dns解析记录,清理申请痕迹
|
||||
* @param options
|
||||
*/
|
||||
async removeRecord(options: RemoveRecordOptions<any>): Promise<void> {
|
||||
// const { fullRecord, value, domain } = options.recordReq;
|
||||
const record = options.recordRes;
|
||||
const deleteResourceRecord = promisfy(this.service.deleteResourceRecord);
|
||||
const res: any = await deleteResourceRecord(
|
||||
{
|
||||
domainId: record.domainId,
|
||||
resourceRecordId: record.id,
|
||||
},
|
||||
this.regionId
|
||||
);
|
||||
this.logger.info(`删除dns解析记录成功:${JSON.stringify(res)}`);
|
||||
}
|
||||
}
|
||||
|
||||
//实例化这个provider,将其自动注册到系统中
|
||||
new JDCloudDnsProvider();
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './dns-provider.js';
|
||||
export * from './plugins/index.js';
|
||||
export * from './access.js';
|
||||
@@ -21,7 +21,7 @@ export type CustomScriptContext = {
|
||||
export class CustomScriptPlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: '脚本',
|
||||
helper: '自定义js脚本',
|
||||
helper: '自定义js脚本,[脚本编写帮助文档](https://certd.docmirror.cn/guide/use/custom-script/)',
|
||||
component: {
|
||||
name: 'a-textarea',
|
||||
vModel: 'value',
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
import { Autowire, HttpClient, ILogger } from '@certd/pipeline';
|
||||
import { Autowire } from '@certd/pipeline';
|
||||
import { HttpClient, ILogger } from '@certd/basic';
|
||||
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import * as _ from 'lodash-es';
|
||||
import { DnspodAccess } from '../access/index.js';
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
import { Autowire, HttpClient, ILogger } from '@certd/pipeline';
|
||||
import { Autowire } from '@certd/pipeline';
|
||||
import { HttpClient, ILogger } from '@certd/basic';
|
||||
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import { TencentAccess } from '@certd/plugin-plus';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { TencentAccess } from '@certd/plugin-plus';
|
||||
import { CertInfo } from '@certd/plugin-cert';
|
||||
import { ILogger } from '@certd/pipeline';
|
||||
import { ILogger } from '@certd/basic';
|
||||
export class TencentSslClient {
|
||||
access: TencentAccess;
|
||||
logger: ILogger;
|
||||
|
||||
+3
-2
@@ -94,14 +94,15 @@ export class TencentDeleteExpiringCert extends AbstractPlusTaskPlugin {
|
||||
};
|
||||
const res = await sslClient.DescribeCertificates(params);
|
||||
let certificates = res?.Certificates;
|
||||
if (!certificates && !certificates.length) {
|
||||
if (!certificates && certificates.length === 0) {
|
||||
this.logger.info('没有找到证书');
|
||||
return;
|
||||
}
|
||||
|
||||
const lastDay = dayjs().add(this.expiringDays, 'day');
|
||||
certificates = certificates.filter((item: any) => {
|
||||
const endTime = item.CertEndTime;
|
||||
return dayjs(endTime).add(this.expiringDays, 'day').isBefore(dayjs());
|
||||
return dayjs(endTime).isBefore(lastDay);
|
||||
});
|
||||
for (const certificate of certificates) {
|
||||
this.logger.info(`证书ID:${certificate.CertificateId}, 过期时间:${certificate.CertEndTime},Alias:${certificate.Alias},证书域名:${certificate.Domain}`);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from '@certd/pipeline';
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { TencentAccess } from '@certd/plugin-plus';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@@ -131,10 +131,10 @@ export class DeployCertToTencentCLB extends AbstractTaskPlugin {
|
||||
}
|
||||
|
||||
try {
|
||||
await utils.sleep(2000);
|
||||
await this.ctx.utils.sleep(2000);
|
||||
let newCertId = await this.getCertIdFromProps(client);
|
||||
if ((lastCertId && newCertId === lastCertId) || (!lastCertId && !newCertId)) {
|
||||
await utils.sleep(2000);
|
||||
await this.ctx.utils.sleep(2000);
|
||||
newCertId = await this.getCertIdFromProps(client);
|
||||
}
|
||||
if (newCertId === lastCertId) {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { CertInfo } from '@certd/plugin-cert';
|
||||
import { AbstractPlusTaskPlugin, createRemoteSelectInputDefine } from '@certd/plugin-plus';
|
||||
import { createRemoteSelectInputDefine } from '@certd/plugin-plus';
|
||||
import { TencentSslClient } from '../../lib/index.js';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'DeployCertToTencentCosPlugin',
|
||||
title: '部署证书到腾讯云COS',
|
||||
needPlus: true,
|
||||
needPlus: false,
|
||||
icon: 'svg:icon-tencentcloud',
|
||||
group: pluginGroups.tencent.key,
|
||||
desc: '部署到腾讯云COS源站域名证书【注意:很不稳定,需要重试很多次偶尔才能成功一次】',
|
||||
@@ -16,7 +16,7 @@ import { TencentSslClient } from '../../lib/index.js';
|
||||
},
|
||||
},
|
||||
})
|
||||
export class DeployCertToTencentCosPlugin extends AbstractPlusTaskPlugin {
|
||||
export class DeployCertToTencentCosPlugin extends AbstractTaskPlugin {
|
||||
/**
|
||||
* AccessProvider的id
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import { Autowire, HttpClient, ILogger } from '@certd/pipeline';
|
||||
import { Autowire } from '@certd/pipeline';
|
||||
import { HttpClient, ILogger } from '@certd/basic';
|
||||
|
||||
|
||||
import { WestAccess } from './access.js';
|
||||
|
||||
type westRecord = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { AbstractTaskPlugin, HttpClient, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { CertInfo } from '@certd/plugin-cert';
|
||||
import { WoaiAccess } from '../access.js';
|
||||
import { HttpClient } from '@certd/basic';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'WoaiCDN',
|
||||
|
||||
Reference in New Issue
Block a user