Compare commits

..

16 Commits

Author SHA1 Message Date
xiaojunnuo 7ceb0f6306 v1.40.5 2026-05-26 14:00:57 +08:00
xiaojunnuo b26a1944c6 build: prepare to build 2026-05-26 13:31:45 +08:00
xiaojunnuo 235aec3e42 chore: 1 2026-05-26 13:29:12 +08:00
xiaojunnuo 346fb730a3 fix: 修复查询阿里云cdn Dcdn 域名太多无法选择的bug 2026-05-26 12:30:58 +08:00
xiaojunnuo c87bc22a5f chore: package 2026-05-26 11:55:04 +08:00
xiaojunnuo 7198e24945 chore: 1 2026-05-26 11:54:04 +08:00
xiaojunnuo 1a08bd340e fix: 安装glibc,增加Alpine镜像下 dns解析结果的兼容性 2026-05-26 11:35:06 +08:00
xiaojunnuo af9047bf3c fix: 修复阿里云证书订单orderid 选择出错的问题 2026-05-26 11:28:14 +08:00
xiaojunnuo 9566fc4e03 chore: 阿里云订单优化只获取一个订单id 2026-05-26 11:28:07 +08:00
xiaojunnuo f721cefb4a build: release 2026-05-25 00:32:36 +08:00
xiaojunnuo fc2c947afe build: publish 2026-05-25 00:23:24 +08:00
xiaojunnuo d0272095cc build: trigger build image 2026-05-25 00:23:12 +08:00
xiaojunnuo 4a09cf289d v1.40.4 2026-05-25 00:22:01 +08:00
xiaojunnuo 89c23fef35 build: prepare to build 2026-05-25 00:18:32 +08:00
xiaojunnuo 5e59651d45 fix(pipeline-service): 修复流水线运行时超过套餐部署次数仍然能够正常运行的bug 2026-05-25 00:15:23 +08:00
xiaojunnuo 5e72f75395 perf: 商业版套餐只支持设置为可叠加 2026-05-24 23:53:55 +08:00
187 changed files with 677 additions and 3578 deletions
+19
View File
@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
### Bug Fixes
* 安装glibc,增加Alpine镜像下 dns解析结果的兼容性 ([1a08bd3](https://github.com/certd/certd/commit/1a08bd340e1e7d3f9acf5d40f7bba7998459b8fb))
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/certd/certd/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
* 修复查询阿里云cdn Dcdn 域名太多无法选择的bug ([346fb73](https://github.com/certd/certd/commit/346fb730a37e035576f5d9ea5c0d74c052b34aeb))
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Bug Fixes
* **pipeline-service:** 修复流水线运行时超过套餐部署次数仍然能够正常运行的bug ([5e59651](https://github.com/certd/certd/commit/5e59651d45bc91919629e35995ff1b3cff6b87ea))
### Performance Improvements
* 商业版套餐只支持设置为可叠加 ([5e72f75](https://github.com/certd/certd/commit/5e72f75395fb632a30e80c07d35d8ba40ef631fa))
* 新增阿里云直播证书部署插件 ([8edb6f8](https://github.com/certd/certd/commit/8edb6f8727bd148f106801bef25567880fd35e9e))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
### Bug Fixes
+11
View File
@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Bug Fixes
* **pipeline-service:** 修复流水线运行时超过套餐部署次数仍然能够正常运行的bug ([5e59651](https://github.com/certd/certd/commit/5e59651d45bc91919629e35995ff1b3cff6b87ea))
### Performance Improvements
* 商业版套餐只支持设置为可叠加 ([5e72f75](https://github.com/certd/certd/commit/5e72f75395fb632a30e80c07d35d8ba40ef631fa))
* 新增阿里云直播证书部署插件 ([8edb6f8](https://github.com/certd/certd/commit/8edb6f8727bd148f106801bef25567880fd35e9e))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
### Bug Fixes
+9 -8
View File
@@ -1,5 +1,5 @@
# 任务插件
`131` 款任务插件
`132` 款任务插件
## 1. 证书申请
| 序号 | 名称 | 说明 |
@@ -93,13 +93,14 @@
| 9.| **阿里云-部署至ESA** | 部署证书到阿里云ESA(边缘安全加速),自动删除过期证书 |
| 10.| **阿里云-部署至阿里云FC(3.0)** | 部署证书到阿里云函数计算(FC3.0) |
| 11.| **阿里云-部署至GA** | 部署证书到阿里云GA(全球加速),支持更新默认证书和扩展证书 |
| 12.| **阿里云-部署至NLB(网络负载均衡)** | NLB,网络负载均衡,更新监听器的默认证书 |
| 13.| **阿里云-部署证书至OSS** | 部署域名证书至阿里云OSS自定义域名,不是上传到阿里云oss |
| 14.| **阿里云-部署至CLB(传统负载均衡)** | 部署证书到阿里云CLB(传统负载均衡) |
| 15.| **阿里云-部署至VOD** | 部署证书到阿里云视频点播(vod |
| 16.| **阿里云-部署至阿里云WAF(云产品接入)** | 部署证书到阿里云WAF(云产品接入),CNAME方式接入的请选择另外一个waf插件 |
| 17.| **阿里云-部署至阿里云WAF(cname接入)** | 部署证书到阿里云WAF(cname接入),云资源的请选择另外一个waf插件 |
| 18.| **阿里云-上传证书到CAS** | 上传证书到阿里云证书管理服务(CAS),如果不想在阿里云上同一份证书上传多次,可以把此任务作为前置任务,其他阿里云任务证书那一项选择此任务的输出 |
| 12.| **阿里云-部署至直播(Live** | 部署证书到阿里云视频直播(Live)域名 |
| 13.| **阿里云-部署至NLB(网络负载均衡)** | NLB,网络负载均衡,更新监听器的默认证书 |
| 14.| **阿里云-部署证书至OSS** | 部署域名证书至阿里云OSS自定义域名,不是上传到阿里云oss |
| 15.| **阿里云-部署至CLB(传统负载均衡)** | 部署证书到阿里云CLB(传统负载均衡) |
| 16.| **阿里云-部署至VOD** | 部署证书到阿里云视频点播(vod |
| 17.| **阿里云-部署至阿里云WAF(云产品接入)** | 部署证书到阿里云WAF(云产品接入)CNAME方式接入的请选择另外一个waf插件 |
| 18.| **阿里云-部署至阿里云WAF(cname接入)** | 部署证书到阿里云WAF(cname接入),云资源的请选择另外一个waf插件 |
| 19.| **阿里云-上传证书到CAS** | 上传证书到阿里云证书管理服务(CAS),如果不想在阿里云上同一份证书上传多次,可以把此任务作为前置任务,其他阿里云任务证书那一项选择此任务的输出 |
## 6. 华为云
| 序号 | 名称 | 说明 |
+1 -1
View File
@@ -9,5 +9,5 @@
}
},
"npmClient": "pnpm",
"version": "1.40.3"
"version": "1.40.5"
}
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/publishlab/node-acme-client/compare/v1.40.4...v1.40.5) (2026-05-26)
### Bug Fixes
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/publishlab/node-acme-client/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
## [1.40.4](https://github.com/publishlab/node-acme-client/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/acme-client
## [1.40.3](https://github.com/publishlab/node-acme-client/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/acme-client
+3 -3
View File
@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client",
"private": false,
"author": "nmorsman",
"version": "1.40.3",
"version": "1.40.5",
"type": "module",
"module": "./dist/index.js",
"main": "./dist/index.js",
@@ -18,7 +18,7 @@
"types"
],
"dependencies": {
"@certd/basic": "^1.40.3",
"@certd/basic": "^1.40.5",
"@peculiar/x509": "^1.11.0",
"asn1js": "^3.0.5",
"axios": "^1.9.0",
@@ -76,5 +76,5 @@
"bugs": {
"url": "https://github.com/publishlab/node-acme-client/issues"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
-4
View File
@@ -467,10 +467,6 @@ class AcmeClient {
return createHash('sha256').update(result).digest('base64url');
}
if (challenge.type === 'dns-persist-01') {
return '';
}
/* https://datatracker.ietf.org/doc/html/rfc8737 */
if (challenge.type === 'tls-alpn-01') {
return result;
+1 -5
View File
@@ -97,11 +97,7 @@ export interface DnsChallenge extends ChallengeAbstract {
token: string;
}
export interface DnsPersistChallenge extends ChallengeAbstract {
type: "dns-persist-01";
}
export type Challenge = HttpChallenge | DnsChallenge | DnsPersistChallenge;
export type Challenge = HttpChallenge | DnsChallenge;
/**
* Certificate
+1 -20
View File
@@ -170,7 +170,7 @@ export function createChallengeFn(opts = {}) {
if (txtRecords.length === 0) {
throw new Error(`没有找到TXT解析记录(${recordName},请稍后重试`);
throw new Error(`没有找到TXT解析记录(${recordName}`);
}
return txtRecords;
}
@@ -203,24 +203,6 @@ export function createChallengeFn(opts = {}) {
return true;
}
async function verifyDnsPersistChallenge(authz, challenge, keyAuthorization, prefix = '_validation-persist.') {
const recordName = `${prefix}${authz.identifier.value.replace(/^\*\./, '')}`;
log(`本地校验DNS持久验证TXT记录: ${recordName}`);
let recordValues = await walkTxtRecord(recordName, 0, walkFromAuthoritative);
recordValues = [...new Set(recordValues)];
const expected = challenge.expectedRecordValue;
if (!expected) {
log(`未提供dns-persist-01本地校验期望值,跳过精确匹配,仅确认TXT记录存在`);
return true;
}
log(`DNS查询成功, 找到 ${recordValues.length} 条TXT记录:${recordValues}`);
if (!recordValues.length || !recordValues.includes(expected)) {
throw new Error(`没有找到需要的DNS持久验证TXT记录: ${recordName},请稍后重试,期望:${expected},结果:${recordValues}`);
}
log(`DNS持久验证记录匹配成功(${challenge.type}/${recordName}:${expected}`);
return true;
}
/**
* Verify ACME TLS ALPN challenge
*
@@ -252,7 +234,6 @@ export function createChallengeFn(opts = {}) {
challenges: {
'http-01': verifyHttpChallenge,
'dns-01': verifyDnsChallenge,
'dns-persist-01': verifyDnsPersistChallenge,
'tls-alpn-01': verifyTlsAlpnChallenge,
},
walkTxtRecord,
+1 -1
View File
@@ -57,7 +57,7 @@ export interface ClientExternalAccountBindingOptions {
export interface ClientAutoOptions {
csr: CsrBuffer | CsrString;
challengeCreateFn: (authz: Authorization, keyAuthorization: (challenge:rfc8555.Challenge)=>Promise<string>) => Promise<{recordReq?:any,recordRes?:any,dnsProvider?:any,challenge: rfc8555.Challenge,keyAuthorization:string,httpUploader?:any}>;
challengeCreateFn: (authz: Authorization, keyAuthorization: (challenge:rfc8555.Challenge)=>Promise<string>) => Promise<{recordReq?:any,recordRes?:any,dnsProvider?:any,challenge: rfc8555.Challenge,keyAuthorization:string}>;
challengeRemoveFn: (authz: Authorization, challenge: rfc8555.Challenge, keyAuthorization: string,recordReq:any, recordRes:any,dnsProvider:any,httpUploader:any) => Promise<any>;
email?: string;
termsOfServiceAgreed?: boolean;
+1 -5
View File
@@ -97,11 +97,7 @@ export interface DnsChallenge extends ChallengeAbstract {
token: string;
}
export interface DnsPersistChallenge extends ChallengeAbstract {
type: 'dns-persist-01';
}
export type Challenge = HttpChallenge | DnsChallenge | DnsPersistChallenge;
export type Challenge = HttpChallenge | DnsChallenge;
/**
* Certificate
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
**Note:** Version bump only for package @certd/basic
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/basic
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/basic
+1 -1
View File
@@ -1 +1 @@
22:57
13:31
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/basic",
"private": false,
"version": "1.40.3",
"version": "1.40.5",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -52,5 +52,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
### Bug Fixes
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/certd/certd/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/pipeline
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/pipeline
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/pipeline",
"private": false,
"version": "1.40.3",
"version": "1.40.5",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -19,8 +19,8 @@
"compile": "tsc --skipLibCheck --watch"
},
"dependencies": {
"@certd/basic": "^1.40.3",
"@certd/plus-core": "^1.40.3",
"@certd/basic": "^1.40.5",
"@certd/plus-core": "^1.40.5",
"dayjs": "^1.11.7",
"lodash-es": "^4.17.21",
"reflect-metadata": "^0.1.13"
@@ -49,5 +49,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
-1
View File
@@ -19,7 +19,6 @@ export type AccessInputDefine = FormItemProps & {
};
export type AccessDefine = Registrable & {
icon?: string;
subtype?: string;
input?: {
[key: string]: AccessInputDefine;
};
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
**Note:** Version bump only for package @certd/lib-huawei
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/lib-huawei
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/lib-huawei
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-huawei",
"private": false,
"version": "1.40.3",
"version": "1.40.5",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
"types": "./dist/d/index.d.ts",
@@ -27,5 +27,5 @@
"prettier": "^2.8.8",
"tslib": "^2.8.1"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
**Note:** Version bump only for package @certd/lib-iframe
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/lib-iframe
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/lib-iframe
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-iframe",
"private": false,
"version": "1.40.3",
"version": "1.40.5",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -34,5 +34,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
**Note:** Version bump only for package @certd/jdcloud
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/jdcloud
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/jdcloud
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/jdcloud",
"version": "1.40.3",
"version": "1.40.5",
"description": "jdcloud openApi sdk",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
@@ -59,5 +59,5 @@
"fetch"
]
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
**Note:** Version bump only for package @certd/lib-k8s
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/lib-k8s
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/lib-k8s
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-k8s",
"private": false,
"version": "1.40.3",
"version": "1.40.5",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -19,7 +19,7 @@
"compile": "tsc --skipLibCheck --watch"
},
"dependencies": {
"@certd/basic": "^1.40.3",
"@certd/basic": "^1.40.5",
"@kubernetes/client-node": "0.21.0"
},
"devDependencies": {
@@ -36,5 +36,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
### Bug Fixes
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/certd/certd/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Performance Improvements
* 商业版套餐只支持设置为可叠加 ([5e72f75](https://github.com/certd/certd/commit/5e72f75395fb632a30e80c07d35d8ba40ef631fa))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/lib-server
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/lib-server",
"version": "1.40.3",
"version": "1.40.5",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -29,11 +29,11 @@
],
"license": "AGPL",
"dependencies": {
"@certd/acme-client": "^1.40.3",
"@certd/basic": "^1.40.3",
"@certd/pipeline": "^1.40.3",
"@certd/plugin-lib": "^1.40.3",
"@certd/plus-core": "^1.40.3",
"@certd/acme-client": "^1.40.5",
"@certd/basic": "^1.40.5",
"@certd/pipeline": "^1.40.5",
"@certd/plugin-lib": "^1.40.5",
"@certd/plus-core": "^1.40.5",
"@midwayjs/cache": "3.14.0",
"@midwayjs/core": "3.20.11",
"@midwayjs/i18n": "3.20.13",
@@ -69,5 +69,5 @@
"typeorm": "^0.3.11",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
@@ -245,6 +245,8 @@ export class SysSuiteSetting extends BaseSettings {
enabled: boolean = false;
allowSuiteStack: boolean = false;
registerGift?: {
productId: number;
duration: number;
@@ -19,9 +19,6 @@ export class AccessEntity {
@Column({ comment: '类型', length: 100 })
type: string;
@Column({ name: 'subtype', comment: '子类型', length: 100, nullable: true })
subtype: string;
@Column({ name: 'setting', comment: '设置', length: 10240, nullable: true })
setting: string;
@@ -1,4 +1,4 @@
import { IAccessService } from "@certd/pipeline";
import { IAccessService } from '@certd/pipeline';
export class AccessGetter implements IAccessService {
userId: number;
@@ -15,6 +15,6 @@ export class AccessGetter implements IAccessService {
}
async getCommonById<T = any>(id: any) {
return await this.getter<T>(id, 0, null);
return await this.getter<T>(id, 0,null);
}
}
@@ -1,16 +1,14 @@
import assert from "assert";
import esmock from "esmock";
import { AccessService } from "./access-service.js";
describe("AccessService", () => {
it("does not write id into access setting when updating selected fields", async () => {
let updateParam: any;
const service = new AccessService();
service.info = async () =>
({
id: 12,
type: "eab",
}) as any;
service.info = async () => ({
id: 12,
type: "eab",
} as any);
service.decryptAccessEntity = () => ({
kid: "kid-1",
});
@@ -29,82 +27,4 @@ describe("AccessService", () => {
accountKey: "account-key",
});
});
it("writes subtype from access define field", async () => {
const { AccessService: MockedAccessService } = await esmock("./access-service.js", {
"@certd/pipeline": {
accessRegistry: {
getDefine(type: string) {
assert.equal(type, "acmeAccount");
return {
name: "acmeAccount",
subtype: "caType",
input: {
caType: {},
account: {
encrypt: true,
},
},
};
},
},
},
});
const service = new MockedAccessService();
service.encryptService = {
encrypt(value: string) {
return `encrypted:${value}`;
},
};
const param: any = {
type: "acmeAccount",
setting: JSON.stringify({
caType: "letsencrypt",
account: JSON.stringify({
accountKey: "key",
accountUri: "https://example.com/acct/1",
caType: "letsencrypt",
}),
}),
};
service.encryptSetting(param);
assert.equal(param.subtype, "letsencrypt");
});
it("allows acme account access to be saved before account generation", async () => {
const { AccessService: MockedAccessService } = await esmock("./access-service.js", {
"@certd/pipeline": {
accessRegistry: {
getDefine() {
return {
name: "acmeAccount",
subtype: "caType",
input: {
caType: {},
account: {
encrypt: true,
},
},
};
},
},
},
});
const service = new MockedAccessService();
const param: any = {
type: "acmeAccount",
setting: JSON.stringify({
caType: "letsencrypt",
}),
};
service.encryptSetting(param);
assert.equal(param.subtype, "letsencrypt");
assert.deepEqual(JSON.parse(param.setting), {
caType: "letsencrypt",
});
});
});
@@ -1,17 +1,17 @@
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
import { InjectEntityModel } from "@midwayjs/typeorm";
import {Inject, Provide, Scope, ScopeEnum} from '@midwayjs/core';
import {InjectEntityModel} from '@midwayjs/typeorm';
import { In, Repository } from "typeorm";
import { AccessGetter, BaseService, PageReq, PermissionException, ValidateException } from "../../../index.js";
import { AccessEntity } from "../entity/access.js";
import { AccessDefine, accessRegistry, newAccess } from "@certd/pipeline";
import { EncryptService } from "./encrypt-service.js";
import { logger, utils } from "@certd/basic";
import {AccessGetter, BaseService, PageReq, PermissionException, ValidateException} from '../../../index.js';
import {AccessEntity} from '../entity/access.js';
import {AccessDefine, accessRegistry, newAccess} from '@certd/pipeline';
import {EncryptService} from './encrypt-service.js';
import { logger, utils } from '@certd/basic';
/**
*
*/
@Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
@Scope(ScopeEnum.Request, {allowDowngrade: true})
export class AccessService extends BaseService<AccessEntity> {
@InjectEntityModel(AccessEntity)
repository: Repository<AccessEntity>;
@@ -36,16 +36,16 @@ export class AccessService extends BaseService<AccessEntity> {
async add(param) {
let oldEntity = null;
if (param._copyFrom) {
if (param._copyFrom){
oldEntity = await this.info(param._copyFrom);
if (oldEntity == null) {
throw new ValidateException("该授权配置不存在,请确认是否已被删除");
throw new ValidateException('该授权配置不存在,请确认是否已被删除');
}
if (oldEntity.userId !== param.userId) {
throw new ValidateException("您无权查看该授权配置");
if (oldEntity.userId !== param.userId) {
throw new ValidateException('您无权查看该授权配置');
}
}
delete param._copyFrom;
delete param._copyFrom
this.encryptSetting(param, oldEntity);
param.keyId = "ac_" + utils.id.simpleNanoId();
return await super.add(param);
@@ -62,20 +62,17 @@ export class AccessService extends BaseService<AccessEntity> {
return;
}
const json = JSON.parse(setting);
if (accessDefine.subtype) {
param.subtype = json[accessDefine.subtype] || null;
}
let oldSetting = {};
let encryptSetting = {};
const firstEncrypt = !oldSettingEntity || !oldSettingEntity.encryptSetting || oldSettingEntity.encryptSetting === "{}";
const firstEncrypt = !oldSettingEntity || !oldSettingEntity.encryptSetting || oldSettingEntity.encryptSetting === '{}';
if (oldSettingEntity) {
oldSetting = JSON.parse(oldSettingEntity.setting || "{}");
encryptSetting = JSON.parse(oldSettingEntity.encryptSetting || "{}");
oldSetting = JSON.parse(oldSettingEntity.setting || '{}');
encryptSetting = JSON.parse(oldSettingEntity.encryptSetting || '{}');
}
for (const key in json) {
//加密
let value = json[key];
if (value && typeof value === "string") {
if (value && typeof value === 'string') {
//去除前后空格
value = value.trim();
json[key] = value;
@@ -84,7 +81,7 @@ export class AccessService extends BaseService<AccessEntity> {
if (!accessInputDefine) {
continue;
}
if (!accessInputDefine.encrypt || !value || typeof value !== "string") {
if (!accessInputDefine.encrypt || !value || typeof value !== 'string') {
//定义无需加密、value为空、不是字符串 这些不需要加密
encryptSetting[key] = {
value: value,
@@ -99,7 +96,7 @@ export class AccessService extends BaseService<AccessEntity> {
const subIndex = Math.min(2, length);
let starLength = length - subIndex * 2;
starLength = Math.max(2, starLength);
const starString = "*".repeat(starLength);
const starString = '*'.repeat(starLength);
json[key] = value.substring(0, subIndex) + starString + value.substring(value.length - subIndex);
encryptSetting[key] = {
value: this.encryptService.encrypt(value),
@@ -119,21 +116,21 @@ export class AccessService extends BaseService<AccessEntity> {
async update(param) {
const oldEntity = await this.info(param.id);
if (oldEntity == null) {
throw new ValidateException("该授权配置不存在,请确认是否已被删除");
throw new ValidateException('该授权配置不存在,请确认是否已被删除');
}
this.encryptSetting(param, oldEntity);
delete param.keyId;
delete param.keyId
return await super.update(param);
}
async updateAccess(access: any) {
const oldEntity = await this.info(access.id);
if (oldEntity == null) {
throw new ValidateException("该授权配置不存在,请确认是否已被删除");
throw new ValidateException('该授权配置不存在,请确认是否已被删除');
}
const setting = this.decryptAccessEntity(oldEntity);
for (const key of Object.keys(access)) {
if (key === "id") {
if (key === 'id') {
continue;
}
setting[key] = access[key];
@@ -148,13 +145,11 @@ export class AccessService extends BaseService<AccessEntity> {
async getSimpleInfo(id: number) {
const entity = await this.info(id);
if (entity == null) {
throw new ValidateException("该授权配置不存在,请确认是否已被删除");
throw new ValidateException('该授权配置不存在,请确认是否已被删除');
}
return {
id: entity.id,
name: entity.name,
type: entity.type,
subtype: entity.subtype,
userId: entity.userId,
projectId: entity.projectId,
};
@@ -167,14 +162,14 @@ export class AccessService extends BaseService<AccessEntity> {
}
if (checkUserId) {
if (userId == null) {
throw new ValidateException("userId不能为空");
throw new ValidateException('userId不能为空');
}
if (userId !== entity.userId) {
throw new PermissionException("您对该Access授权无访问权限");
throw new PermissionException('您对该Access授权无访问权限');
}
}
if (projectId != null && projectId !== entity.projectId) {
throw new PermissionException("您对该Access授权无访问权限");
throw new PermissionException('您对该Access授权无访问权限');
}
// const access = accessRegistry.get(entity.type);
@@ -183,8 +178,8 @@ export class AccessService extends BaseService<AccessEntity> {
id: entity.id,
...setting,
};
const accessGetter = new AccessGetter(userId, projectId, this.getById.bind(this));
return await newAccess(entity.type, input, accessGetter);
const accessGetter = new AccessGetter(userId,projectId, this.getById.bind(this));
return await newAccess(entity.type, input,accessGetter);
}
async getById(id: any, userId: number, projectId?: number): Promise<any> {
@@ -193,7 +188,7 @@ export class AccessService extends BaseService<AccessEntity> {
decryptAccessEntity(entity: AccessEntity): any {
let setting = {};
if (entity.encryptSetting && entity.encryptSetting !== "{}") {
if (entity.encryptSetting && entity.encryptSetting !== '{}') {
setting = JSON.parse(entity.encryptSetting);
for (const key in setting) {
//解密
@@ -218,11 +213,12 @@ export class AccessService extends BaseService<AccessEntity> {
return accessRegistry.getDefine(type);
}
async getSimpleByIds(ids: number[], userId: any, projectId?: number) {
if (ids.length === 0) {
return [];
}
if (userId == null) {
if (userId==null) {
return [];
}
return await this.repository.find({
@@ -235,24 +231,24 @@ export class AccessService extends BaseService<AccessEntity> {
id: true,
name: true,
type: true,
subtype: true,
userId: true,
projectId: true,
userId:true,
projectId:true,
},
});
}
/**
*
* @param accessId
* @param projectId
* @param accessId
* @param projectId
*/
async copyTo(accessId: number, projectId?: number) {
async copyTo(accessId: number,projectId?: number) {
const access = await this.info(accessId);
if (access == null) {
throw new Error(`该授权配置不存在,请确认是否已被删除:id=${accessId}`);
}
const keyId = access.keyId;
//检查目标项目里是否已经有相同keyId的配置
const existAccess = await this.repository.findOne({
@@ -267,10 +263,10 @@ export class AccessService extends BaseService<AccessEntity> {
}
const newAccess = {
...access,
userId: -1,
userId:-1,
id: undefined,
projectId,
};
}
await this.repository.save(newAccess);
return newAccess.id;
}
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/midway-flyway-js
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/midway-flyway-js",
"version": "1.40.3",
"version": "1.40.5",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -49,5 +49,5 @@
"typeorm": "^0.3.11",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
### Bug Fixes
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/certd/certd/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/plugin-cert
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/plugin-cert
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-cert",
"private": false,
"version": "1.40.3",
"version": "1.40.5",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -18,10 +18,10 @@
"compile": "tsc --skipLibCheck --watch"
},
"dependencies": {
"@certd/acme-client": "^1.40.3",
"@certd/basic": "^1.40.3",
"@certd/pipeline": "^1.40.3",
"@certd/plugin-lib": "^1.40.3",
"@certd/acme-client": "^1.40.5",
"@certd/basic": "^1.40.5",
"@certd/pipeline": "^1.40.5",
"@certd/plugin-lib": "^1.40.5",
"psl": "^1.9.0",
"punycode.js": "^2.3.1"
},
@@ -41,5 +41,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
### Bug Fixes
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/certd/certd/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Performance Improvements
* 新增阿里云直播证书部署插件 ([8edb6f8](https://github.com/certd/certd/commit/8edb6f8727bd148f106801bef25567880fd35e9e))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/plugin-lib
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-lib",
"private": false,
"version": "1.40.3",
"version": "1.40.5",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -23,10 +23,10 @@
"@alicloud/pop-core": "^1.7.10",
"@alicloud/tea-util": "^1.4.11",
"@aws-sdk/client-s3": "^3.964.0",
"@certd/acme-client": "^1.40.3",
"@certd/basic": "^1.40.3",
"@certd/pipeline": "^1.40.3",
"@certd/plus-core": "^1.40.3",
"@certd/acme-client": "^1.40.5",
"@certd/basic": "^1.40.5",
"@certd/pipeline": "^1.40.5",
"@certd/plus-core": "^1.40.5",
"@kubernetes/client-node": "0.21.0",
"ali-oss": "^6.22.0",
"basic-ftp": "^5.0.5",
@@ -61,5 +61,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "4a09cf289d3f360c830f1a203fa11baa6af20f1c"
}
@@ -34,7 +34,7 @@ describe("plugin-lib common util", () => {
title: "选择资源",
action: "ListResource",
typeName: "resource",
multi: false,
single: true,
search: true,
watches: ["region"],
});
@@ -46,8 +46,8 @@ describe("plugin-lib common util", () => {
vModel: "value",
action: "ListResource",
typeName: "resource",
mode: "default",
multi: false,
mode: "tags",
single: true,
search: true,
});
expect(define.component.watches).to.deep.equal(["certDomains", "accessId", "region"]);
@@ -35,7 +35,7 @@ export function createRemoteSelectInputDefine(opts?: {
helper?: string;
formItem?: any;
mode?: string;
multi?: boolean;
single?: boolean;
required?: boolean;
rules?: any;
mergeScript?: string;
@@ -59,11 +59,8 @@ export function createRemoteSelectInputDefine(opts?: {
const helper = opts?.helper || "请选择";
const search = opts?.search ?? false;
const pager = opts?.pager ?? false;
let mode = "default";
const multi = opts?.multi ?? true;
if (multi) {
mode = "tags";
}
const mode = "tags";
const single = opts?.single ?? false;
const item = {
title,
component: {
@@ -75,7 +72,7 @@ export function createRemoteSelectInputDefine(opts?: {
action,
search,
pager,
multi,
single,
pageSize: opts?.pageSize,
watches: [certDomainsInputKey, accessIdInputKey, ...watches],
uploadCert: opts?.uploadCert,
+1
View File
@@ -36,6 +36,7 @@ EXPOSE 7002
RUN apk add --no-cache openssl
RUN apk add --no-cache openjdk8
RUN apk add --no-cache gcompat
WORKDIR /app/
COPY --from=builder /workspace/certd-server/ /app/
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
### Bug Fixes
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/certd/certd/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Performance Improvements
* 商业版套餐只支持设置为可叠加 ([5e72f75](https://github.com/certd/certd/commit/5e72f75395fb632a30e80c07d35d8ba40ef631fa))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
### Bug Fixes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/ui-client",
"version": "1.40.3",
"version": "1.40.5",
"private": true,
"scripts": {
"dev": "vite --open",
@@ -106,8 +106,8 @@
"zod-defaults": "^0.1.3"
},
"devDependencies": {
"@certd/lib-iframe": "^1.40.3",
"@certd/pipeline": "^1.40.3",
"@certd/lib-iframe": "^1.40.5",
"@certd/pipeline": "^1.40.5",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.12",
@@ -11,16 +11,14 @@
<td class="record-value" :title="cnameRecord.recordValue">
<fs-copyable v-model="cnameRecord.recordValue"></fs-copyable>
</td>
<td class="status center">
<span class="status-content">
<fs-values-format v-model="cnameRecord.status" :dict="statusDict" />
<a-tooltip v-if="cnameRecord.error" :title="cnameRecord.error">
<fs-icon class="ml-5 color-red" icon="ion:warning-outline"></fs-icon>
</a-tooltip>
<a-tooltip v-if="cnameRecord.status === 'valid'" :title="t('certd.verifyPlan.resetStatusTooltip')">
<fs-icon class="ml-2 color-yellow text-md pointer" icon="solar:undo-left-square-bold" @click="resetStatus"></fs-icon>
</a-tooltip>
</span>
<td class="status center flex-center">
<fs-values-format v-model="cnameRecord.status" :dict="statusDict" />
<a-tooltip v-if="cnameRecord.error" :title="cnameRecord.error">
<fs-icon class="ml-5 color-red" icon="ion:warning-outline"></fs-icon>
</a-tooltip>
<a-tooltip v-if="cnameRecord.status === 'valid'" :title="t('certd.verifyPlan.resetStatusTooltip')">
<fs-icon class="ml-2 color-yellow text-md pointer" icon="solar:undo-left-square-bold" @click="resetStatus"></fs-icon>
</a-tooltip>
</td>
<td class="center">
<template v-if="cnameRecord.status !== 'valid'">
@@ -144,10 +142,5 @@ async function resetStatus() {
.fs-copyable {
width: 100%;
}
.status-content {
display: inline-flex;
align-items: center;
justify-content: center;
}
}
</style>
@@ -2,11 +2,11 @@
<table class="cname-verify-plan">
<thead>
<tr>
<td class="col-host">{{ t("certd.verifyPlan.hostRecord") }}</td>
<td class="col-type center">{{ t("certd.verifyPlan.recordType") }}</td>
<td class="col-value">{{ t("certd.verifyPlan.setCnameRecord") }}</td>
<td class="col-status center">{{ t("certd.status") }}</td>
<td class="col-action center">{{ t("certd.verifyPlan.operation") }}</td>
<td style="width: 160px">{{ t("certd.verifyPlan.hostRecord") }}</td>
<td style="width: 100px; text-align: center">{{ t("certd.verifyPlan.recordType") }}</td>
<td style="width: 250px">{{ t("certd.verifyPlan.setCnameRecord") }}</td>
<td style="width: 120px" class="center">{{ t("certd.status") }}</td>
<td style="width: 90px" class="center">{{ t("certd.verifyPlan.operation") }}</td>
</tr>
</thead>
<template v-for="key in domains" :key="key">
@@ -49,21 +49,6 @@ function onRecordChange(domain: string, record: CnameRecord) {
.cname-verify-plan {
width: 100%;
table-layout: fixed;
.col-host {
width: 220px;
}
.col-type {
width: 100px;
}
.col-value {
width: 360px;
}
.col-status {
width: 120px;
}
.col-action {
width: 150px;
}
tbody tr td {
border-top: 1px solid #e8e8e8 !important;
}
@@ -1,144 +0,0 @@
<template>
<tbody class="dns-persist-record-info">
<tr v-if="dnsPersistRecord">
<td class="host-record" :title="dnsPersistRecord.hostRecord">
<fs-copyable v-model="dnsPersistRecord.hostRecord"></fs-copyable>
</td>
<td style="text-align: center">TXT</td>
<td class="record-value" :title="dnsPersistRecord.recordValue">
<fs-copyable v-model="dnsPersistRecord.recordValue"></fs-copyable>
</td>
<td class="status center">
<fs-values-format v-model="dnsPersistRecord.status" :dict="statusDict" />
</td>
<td class="center">
<template v-if="dnsPersistRecord.status !== 'valid'">
<a-space>
<a-button type="primary" size="small" @click="openSettingDialog">设置TXT</a-button>
<a-button type="primary" size="small" :loading="loading" @click="doVerify">校验</a-button>
</a-space>
</template>
<div v-else class="helper">请勿删除TXT记录</div>
</td>
</tr>
<tr v-else>
<td colspan="5" class="color-red">{{ errorMessage || "请先选择ACME账号授权" }}</td>
</tr>
</tbody>
</template>
<script lang="ts" setup>
import { dict } from "@fast-crud/fast-crud";
import { message } from "ant-design-vue";
import { ref, watch } from "vue";
import { GetByDomain, Verify } from "/@/views/certd/cert/dns-persist/api";
import { useDnsPersistSettingDialog } from "/@/views/certd/cert/dns-persist/use-setting-dialog";
import { DnsPersistRecord } from "./type";
defineOptions({
name: "DnsPersistRecordInfo",
});
const props = defineProps<{
domain: string;
caType?: string;
acmeAccountAccessId?: number;
commonAcmeAccountAccessId?: number;
wildcard?: boolean;
persistUntil?: number;
}>();
const emit = defineEmits<{
change: [DnsPersistRecord];
}>();
const statusDict = dict({
data: [
{ value: "pending", label: "待设置", color: "warning" },
{ value: "validating", label: "校验中", color: "blue" },
{ value: "valid", label: "有效", color: "green" },
{ value: "failed", label: "请重试", color: "red" },
],
});
const dnsPersistRecord = ref<DnsPersistRecord | null>(null);
const loading = ref(false);
const errorMessage = ref("");
const { openDnsPersistSettingDialog } = useDnsPersistSettingDialog();
function onRecordChange() {
if (dnsPersistRecord.value) {
emit("change", dnsPersistRecord.value);
} else {
emit("change", {
domain: props.domain,
status: null,
} as any);
}
}
async function loadRecord() {
errorMessage.value = "";
dnsPersistRecord.value = null;
if (!props.domain || (!props.acmeAccountAccessId && !props.commonAcmeAccountAccessId)) {
onRecordChange();
return;
}
try {
dnsPersistRecord.value = await GetByDomain({
domain: props.domain,
caType: props.caType,
acmeAccountAccessId: props.acmeAccountAccessId,
commonAcmeAccountAccessId: props.commonAcmeAccountAccessId,
wildcard: props.wildcard,
persistUntil: props.persistUntil,
createOnNotFound: true,
});
onRecordChange();
} catch (e: any) {
errorMessage.value = e.message;
}
}
watch(
() => [props.domain, props.caType, props.acmeAccountAccessId, props.commonAcmeAccountAccessId, props.wildcard, props.persistUntil],
async () => {
await loadRecord();
},
{
immediate: true,
}
);
async function doVerify() {
if (!dnsPersistRecord.value?.id) {
return;
}
loading.value = true;
try {
const ok = await Verify(dnsPersistRecord.value.id);
message[ok ? "success" : "error"](ok ? "校验成功" : "未找到匹配的TXT记录,请稍后重试");
await loadRecord();
} finally {
loading.value = false;
}
}
function openSettingDialog() {
if (!dnsPersistRecord.value) {
return;
}
openDnsPersistSettingDialog({
record: dnsPersistRecord.value,
onDone: loadRecord,
});
}
</script>
<style lang="less">
.dns-persist-record-info {
.fs-copyable {
width: 100%;
}
}
</style>
@@ -1,94 +0,0 @@
<template>
<table class="dns-persist-verify-plan">
<thead>
<tr>
<td class="col-host">TXT主机名</td>
<td class="col-type center">记录类型</td>
<td class="col-value">请设置TXT记录验证成功以后不要删除</td>
<td class="col-status center">状态</td>
<td class="col-action center">操作</td>
</tr>
</thead>
<template v-for="key in domains" :key="key">
<dns-persist-record-info
:domain="key"
:ca-type="caType"
:acme-account-access-id="acmeAccountAccessId"
:common-acme-account-access-id="commonAcmeAccountAccessId"
:wildcard="modelValue[key]?.wildcard"
:persist-until="modelValue[key]?.persistUntil"
@change="onRecordChange(key, $event)"
/>
</template>
</table>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import DnsPersistRecordInfo from "./dns-persist-record-info.vue";
import { DnsPersistRecord } from "./type";
defineOptions({
name: "DnsPersistVerifyPlan",
});
const emit = defineEmits(["update:modelValue", "change"]);
const props = defineProps<{
modelValue: Record<string, DnsPersistRecord>;
caType?: string;
acmeAccountAccessId?: number;
commonAcmeAccountAccessId?: number;
}>();
const domains = computed(() => {
return Object.keys(props.modelValue || {});
});
function onRecordChange(domain: string, record: DnsPersistRecord) {
const value = { ...props.modelValue };
value[domain] = {
...value[domain],
...record,
};
emit("update:modelValue", value);
emit("change", value);
}
</script>
<style lang="less">
.dns-persist-verify-plan {
width: 100%;
table-layout: fixed;
.col-host {
width: 220px;
}
.col-type {
width: 100px;
}
.col-value {
width: 360px;
}
.col-status {
width: 120px;
}
.col-action {
width: 150px;
}
tbody tr td {
border-top: 1px solid #e8e8e8 !important;
}
tr {
td {
border: 0 !important;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&.center {
text-align: center;
}
}
}
}
</style>
@@ -46,28 +46,13 @@
<div class="form-item">
<span class="label">{{ t("certd.verifyPlan.dnsAccess") }}:</span>
<span class="input">
<access-selector
v-model="item.dnsProviderAccessId"
size="small"
:type="item.dnsProviderAccessType || item.dnsProviderType"
:placeholder="t('certd.verifyPlan.pleaseSelect')"
@change="onPlanChanged"
></access-selector>
<access-selector v-model="item.dnsProviderAccessId" size="small" :type="item.dnsProviderAccessType || item.dnsProviderType" :placeholder="t('certd.verifyPlan.pleaseSelect')" @change="onPlanChanged"></access-selector>
</span>
</div>
</div>
<div v-if="item.type === 'cname'" class="plan-cname">
<cname-verify-plan v-model="item.cnameVerifyPlan" @change="onPlanChanged" />
</div>
<div v-if="item.type === 'dns-persist'" class="plan-dns-persist">
<dns-persist-verify-plan
v-model="item.dnsPersistVerifyPlan"
:ca-type="caType"
:acme-account-access-id="acmeAccountAccessId"
:common-acme-account-access-id="commonAcmeAccountAccessId"
@change="onPlanChanged"
/>
</div>
<div v-if="item.type === 'http'" class="plan-http">
<http-verify-plan v-model="item.httpVerifyPlan" @change="onPlanChanged" />
<div class="helper">{{ t("certd.verifyPlan.httpHelper") }}</div>
@@ -91,7 +76,6 @@ import { useI18n } from "vue-i18n";
import { dict, FsDictSelect } from "@fast-crud/fast-crud";
import AccessSelector from "/@/views/certd/access/access-selector/index.vue";
import CnameVerifyPlan from "./cname-verify-plan.vue";
import DnsPersistVerifyPlan from "./dns-persist-verify-plan.vue";
import HttpVerifyPlan from "./http-verify-plan.vue";
import { Form } from "ant-design-vue";
import { DomainsVerifyPlanInput } from "./type";
@@ -108,10 +92,6 @@ const challengeTypeOptions = ref<any[]>([
label: t("certd.verifyPlan.dnsChallenge"),
value: "dns",
},
{
label: "DNS持久验证",
value: "dns-persist",
},
{
label: t("certd.verifyPlan.cnameChallenge"),
value: "cname",
@@ -126,9 +106,6 @@ const props = defineProps<{
modelValue?: DomainsVerifyPlanInput;
domains?: string[];
defaultType?: string;
caType?: string;
acmeAccountAccessId?: number;
commonAcmeAccountAccessId?: number;
}>();
const emit = defineEmits<{
@@ -212,15 +189,11 @@ async function onDomainsChanged(domains: string[]) {
const cnameOrigin = planItem.cnameVerifyPlan;
const httpOrigin = planItem.httpVerifyPlan;
const dnsPersistOrigin = planItem.dnsPersistVerifyPlan;
planItem.cnameVerifyPlan = {};
planItem.httpVerifyPlan = {};
planItem.dnsPersistVerifyPlan = {};
const cnamePlan = planItem.cnameVerifyPlan;
const httpPlan = planItem.httpVerifyPlan;
const dnsPersistPlan = planItem.dnsPersistVerifyPlan;
for (const subDomain of domainGroupItem.keySubDomains) {
const wildcard = true;
if (!cnameOrigin[subDomain]) {
//@ts-ignore
planItem.cnameVerifyPlan[subDomain] = {
@@ -252,19 +225,6 @@ async function onDomainsChanged(domains: string[]) {
domain: subDomain,
};
}
if (!dnsPersistOrigin?.[subDomain]) {
//@ts-ignore
dnsPersistPlan[subDomain] = {
domain: subDomain,
wildcard,
};
} else {
dnsPersistPlan[subDomain] = {
...dnsPersistOrigin[subDomain],
wildcard,
};
}
}
for (const subDomain of Object.keys(cnamePlan)) {
@@ -278,12 +238,6 @@ async function onDomainsChanged(domains: string[]) {
delete httpPlan[subDomain];
}
}
for (const subDomain of Object.keys(dnsPersistPlan)) {
if (!domainGroupItem.keySubDomains.includes(subDomain)) {
delete dnsPersistPlan[subDomain];
}
}
}
for (const domain of Object.keys(planRef.value)) {
const mainDomains = Object.keys(domainGroups);
@@ -314,7 +268,6 @@ watch(
overflow-x: auto;
.fullscreen-modal {
display: none;
background-color: rgba(0, 0, 0, 0.42);
}
&.fullscreen {
@@ -7,32 +7,15 @@ export type HttpRecord = {
httpUploadRootDir: string;
};
export type DnsPersistRecord = {
id?: number;
domain: string;
mainDomain?: string;
status?: string;
hostRecord?: string;
recordValue?: string;
caType?: string;
acmeAccountAccessId?: number;
accountUri?: string;
wildcard?: boolean;
persistUntil?: number;
dnsProviderType?: string;
dnsProviderAccess?: number;
};
export type DomainVerifyPlanInput = {
domain: string;
domains: string[];
type: "cname" | "dns" | "http" | "dns-persist";
type: "cname" | "dns" | "http";
dnsProviderType?: string;
dnsProviderAccessType?: string;
dnsProviderAccessId?: number;
cnameVerifyPlan?: Record<string, CnameRecord>;
httpVerifyPlan?: Record<string, HttpRecord>;
dnsPersistVerifyPlan?: Record<string, DnsPersistRecord>;
};
export type DomainsVerifyPlanInput = {
[key: string]: DomainVerifyPlanInput;
@@ -46,14 +46,6 @@ function checkDomainVerifyPlan(rule: any, value: DomainsVerifyPlanInput) {
if (!value[domain].dnsProviderType || !value[domain].dnsProviderAccessId) {
throw new Error($t("certd.verifyPlan.errors.dnsProviderRequired", { domain }));
}
} else if (type === "dns-persist") {
const subDomains = Object.keys(value[domain].dnsPersistVerifyPlan || {});
for (const subDomain of subDomains) {
const plan = value[domain].dnsPersistVerifyPlan[subDomain];
if (plan.status !== "valid") {
throw new Error(`DNS持久验证记录(${subDomain})还未校验成功`);
}
}
}
}
return true;
@@ -1,8 +1,8 @@
<template>
<div class="refresh-input">
<div class="refresh-input-line">
<a-input class="refresh-input-control" :value="value" :placeholder="placeholder" :allow-clear="!disabled" :disabled="disabled" @update:value="emit('update:value', $event)"></a-input>
<fs-button :loading="loading" :disabled="disabled" type="primary" :text="buttonText" :icon="icon" @click="doRefresh"></fs-button>
<a-input class="refresh-input-control" :value="value" :placeholder="placeholder" allow-clear @update:value="emit('update:value', $event)"></a-input>
<fs-button :loading="loading" type="primary" :text="buttonText" :icon="icon" @click="doRefresh"></fs-button>
</div>
<div class="helper" :class="{ error: hasError }">
{{ message }}
@@ -25,7 +25,6 @@ type RefreshInputProps = ComponentPropsType & {
icon?: string;
placeholder?: string;
successMessage?: string;
disabled?: boolean;
};
const fromType: any = inject("getFromType");
@@ -50,9 +49,6 @@ const placeholder = computed(() => props.placeholder || "");
const successMessage = computed(() => props.successMessage || "刷新成功,请保存配置");
const doRefresh = async () => {
if (props.disabled) {
return;
}
if (loading.value) {
return;
}
@@ -69,7 +69,7 @@ const props = defineProps<
watches?: string[];
search?: boolean;
pager?: boolean;
multi?: boolean;
single?: boolean;
pageSize?: number;
uploadCert?: UploadCertProps;
} & ComponentPropsType
@@ -79,15 +79,15 @@ const emit = defineEmits<{
}>();
function updateValue(value: any) {
// if (props.multi !== false) {
// emit("update:value", value);
// } else {
// const last = value?.[value.length - 1];
// emit("update:value", last);
// selectRef.value.blur();
// }
if (props.single === true) {
const last = value?.[value.length - 1];
emit("update:value", last);
selectRef.value.blur();
} else {
emit("update:value", value);
}
emit("update:value", value);
// emit("update:value", value);
}
const attrs = useAttrs();
@@ -5,7 +5,6 @@ function createChallengeTypeDict() {
return dict({
data: [
{ value: "dns", label: $t("certd.verifyPlan.dnsChallenge"), color: "green" },
{ value: "dns-persist", label: "DNS持久验证", color: "cyan" },
{ value: "cname", label: $t("certd.verifyPlan.cnameProxyChallenge"), color: "blue" },
{ value: "http", label: $t("certd.verifyPlan.httpChallenge"), color: "yellow" },
],
@@ -40,12 +39,7 @@ export const Dicts = {
sslProviderDict: dict({
data: [
{ value: "letsencrypt", label: "Let's Encrypt" },
{ value: "letsencrypt_staging", label: "Let's Encrypt测试环境" },
{ value: "google", label: "Google" },
{ value: "zerossl", label: "ZeroSSL" },
{ value: "sslcom", label: "SSL.com" },
{ value: "litessl", label: "litessl" },
{ value: "custom", label: "自定义ACME" },
],
}),
get challengeTypeDict() {
@@ -11,7 +11,6 @@ export default {
siteMonitor: "Site Certificate Monitor",
settings: "Settings",
accessManager: "Access Management",
dnsPersistRecord: "DNS Persist Records",
subDomain: "Subdomain Delegation Settings",
pipelineGroup: "Pipeline Group Management",
openKey: "Open API Key",
@@ -11,7 +11,6 @@ export default {
siteMonitor: "站点证书监控",
settings: "设置",
accessManager: "授权管理",
dnsPersistRecord: "DNS持久验证记录",
subDomain: "子域名托管设置",
pipelineGroup: "流水线分组管理",
openKey: "开放接口密钥",
@@ -186,17 +186,6 @@ export const certdResources = [
keepAlive: true,
},
},
{
title: "certd.dnsPersistRecord",
name: "DnsPersistRecord",
path: "/certd/cert/dns-persist",
component: "/certd/cert/dns-persist/index.vue",
meta: {
icon: "ion:shield-half-outline",
auth: true,
keepAlive: true,
},
},
{
title: "certd.subDomain",
name: "SubDomain",
@@ -12,12 +12,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
const { props, ctx, api } = context;
const lastResRef = ref();
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
query.query = query.query || {};
if (props.subtype) {
query.query.subtype = props.subtype;
} else {
delete query.query.subtype;
}
return await context.api.GetList(query);
};
const editRequest = async (req: EditReq) => {
@@ -53,7 +47,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
const { myProjectDict } = useDicts();
const typeRef = ref("aliyun");
context.typeRef = typeRef;
const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api, props.subtype);
const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api);
commonColumnsDefine.type.form.component.disabled = true;
const projectStore = useProjectStore();
return {
@@ -21,10 +21,6 @@ export default defineComponent({
type: String, //user | sys
default: "user",
},
subtype: {
type: String,
default: "",
},
modelValue: {},
},
emits: ["update:modelValue"],
@@ -34,17 +30,10 @@ export default defineComponent({
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
// crud
function refreshSearch() {
const form: any = { type: props.type };
if (props.subtype) {
form.subtype = props.subtype;
}
crudExpose.setSearchFormData({ form, mergeForm: true });
crudExpose.doRefresh();
}
function onTypeChanged(value: any) {
context.typeRef.value = value;
refreshSearch();
crudExpose.setSearchFormData({ form: { type: value }, mergeForm: true });
crudExpose.doRefresh();
}
watch(
() => {
@@ -55,14 +44,6 @@ export default defineComponent({
onTypeChanged(value);
}
);
watch(
() => {
return props.subtype;
},
() => {
refreshSearch();
}
);
//
onMounted(() => {
onTypeChanged(props.type);
@@ -9,7 +9,7 @@
<a-form-item-rest v-if="chooseForm.show">
<a-modal v-model:open="chooseForm.show" title="选择授权提供者" width="900px" @ok="chooseForm.ok">
<div style="height: 400px; position: relative">
<cert-access-modal v-model="selectedId" :type="type" :subtype="subtype" :from="from"></cert-access-modal>
<cert-access-modal v-model="selectedId" :type="type" :from="from"></cert-access-modal>
</div>
</a-modal>
</a-form-item-rest>
@@ -35,10 +35,6 @@ export default defineComponent({
type: String,
default: "aliyun",
},
subtype: {
type: String,
default: "",
},
placeholder: {
type: String,
default: "请选择",
@@ -1,11 +1,11 @@
import { ColumnCompositionProps, dict } from "@fast-crud/fast-crud";
import { provide, ref, toRef } from "vue";
import { computed, provide, ref, toRef } from "vue";
import { useReference } from "/@/use/use-refrence";
import { forEach, get, merge, set } from "lodash-es";
import SecretPlainGetter from "/@/views/certd/access/access-selector/access/secret-plain-getter.vue";
import { utils } from "/@/utils";
export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any, fixedSubtype?: string) {
export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
provide("getFromType", api.from);
provide("accessApi", api);
provide("get:plugin:type", () => {
@@ -34,13 +34,6 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any, f
}
}
console.log('crudBinding.value[mode + "Form"].columns', columnsRef.value);
if (mode === "add" && define.subtype && fixedSubtype) {
form.access = form.access || {};
const subtypeKey = `access.${define.subtype}`;
if (get(form, subtypeKey) == null) {
set(form, subtypeKey, fixedSubtype);
}
}
forEach(define.input, (value: any, mapKey: any) => {
const key = "access." + mapKey;
const field = {
@@ -1,83 +0,0 @@
import { request } from "/src/api/service";
const apiPrefix = "/cert/dns-persist";
export async function GetList(query: any) {
return await request({
url: apiPrefix + "/page",
method: "post",
data: query,
});
}
export async function AddObj(obj: any) {
return await request({
url: apiPrefix + "/add",
method: "post",
data: obj,
});
}
export async function UpdateObj(obj: any) {
return await request({
url: apiPrefix + "/update",
method: "post",
data: obj,
});
}
export async function DelObj(id: any) {
return await request({
url: apiPrefix + "/delete",
method: "post",
params: { id },
});
}
export async function BuildRecord(body: { domain: string; accountUri: string; wildcard?: boolean; persistUntil?: number }) {
return await request({
url: apiPrefix + "/build",
method: "post",
data: body,
});
}
export async function GetByDomain(body: { domain: string; caType?: string; acmeAccountAccessId?: number; commonAcmeAccountAccessId?: number; wildcard?: boolean; persistUntil?: number; createOnNotFound?: boolean }) {
return await request({
url: apiPrefix + "/getByDomain",
method: "post",
data: body,
});
}
export async function CheckRecord(body: { hostRecord: string; recordValue: string }) {
return await request({
url: apiPrefix + "/check",
method: "post",
data: body,
});
}
export async function Verify(id: number) {
return await request({
url: apiPrefix + "/verify",
method: "post",
data: { id },
});
}
export async function TriggerVerify(id: number) {
return await request({
url: apiPrefix + "/triggerVerify",
method: "post",
data: { id },
});
}
export async function CreateTxt(body: { id: number; dnsProviderType?: string; dnsProviderAccess?: number }) {
return await request({
url: apiPrefix + "/createTxt",
method: "post",
data: body,
});
}
@@ -1,349 +0,0 @@
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { message, Modal, notification } from "ant-design-vue";
import * as api from "./api";
import { Dicts } from "/@/components/plugins/lib/dicts";
import { createAccessApi } from "/@/views/certd/access/api";
import { useDnsPersistSettingDialog } from "./use-setting-dialog";
function parseAccount(account: any) {
if (!account) {
return null;
}
if (typeof account === "string") {
return JSON.parse(account);
}
return account;
}
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const accessApi = createAccessApi();
const { openDnsPersistSettingDialog } = useDnsPersistSettingDialog();
const accessDict = dict({
value: "id",
label: "name",
url: "accessDict",
async getNodesByValues(ids: number[]) {
return await accessApi.GetDictByIds(ids);
},
});
const dnsProviderTypeDict = dict({
url: "pi/dnsProvider/dnsProviderTypeDict",
});
const statusDict = dict({
data: [
{ value: "pending", label: "待设置", color: "warning" },
{ value: "created", label: "已创建", color: "blue" },
{ value: "validating", label: "校验中", color: "blue" },
{ value: "valid", label: "有效", color: "green" },
{ value: "failed", label: "请重试", color: "red" },
],
});
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
form.id = row.id;
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
const res = await api.DelObj(row.id);
if (res?.message) {
notification.warning({
message: "请到供应商删除TXT记录",
description: res.message,
duration: 0,
});
}
return res;
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
async function fillRecord(form: any) {
if (!form.domain || !form.acmeAccountAccessId) {
return;
}
const access: any = await accessApi.GetObj(form.acmeAccountAccessId);
const setting = JSON.parse(access.setting || "{}");
const account = parseAccount(setting.account);
if (!account?.accountUri) {
message.error("ACME账号授权缺少accountUri,请重新生成账号");
return;
}
const record = await api.BuildRecord({
domain: form.domain,
accountUri: account.accountUri,
wildcard: true,
persistUntil: form.persistUntil,
});
form.caType = account.caType;
form.accountUri = account.accountUri;
form.hostRecord = record.hostRecord;
form.recordValue = record.recordValue;
form.status = "pending";
}
async function verifyRecord(row: any) {
const ok = await api.Verify(row.id);
message[ok ? "success" : "error"](ok ? "校验成功" : "未找到匹配的TXT记录,请稍后重试");
await crudExpose.doRefresh();
return ok;
}
function showRecordHelp(row: any) {
openDnsPersistSettingDialog({
record: row,
async onDone() {
await crudExpose.doRefresh();
},
});
}
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest,
},
actionbar: {
buttons: {
add: {
icon: "ion:add-circle-outline",
},
},
},
rowHandle: {
minWidth: 120,
fixed: "right",
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: { width: 80, order: -999 },
form: { show: false },
},
domain: {
title: "域名",
type: "text",
search: { show: true },
form: {
required: true,
valueChange({ form }) {
fillRecord(form);
},
},
},
mainDomain: {
title: "主域名",
type: "text",
form: {
show: false,
},
column: {
width: 160,
order: 901,
},
},
wildcard: {
title: "通配符",
type: "dict-switch",
form: {
show: false,
value: true,
},
column: { show: false },
},
acmeAccountAccessId: {
title: "ACME账号授权",
type: "dict-select",
dict: accessDict,
form: {
required: true,
order: -9,
component: {
name: "AccessSelector",
vModel: "modelValue",
type: "acmeAccount",
subtype: compute(({ form }) => {
return form.caType;
}),
},
valueChange({ form }) {
fillRecord(form);
},
},
column: {
width: 180,
},
},
caType: {
title: "颁发机构",
type: "dict-select",
dict: Dicts.sslProviderDict,
form: {
required: true,
value: "letsencrypt",
order: -10,
valueChange({ form }) {
form.acmeAccountAccessId = null;
fillRecord(form);
},
},
column: { width: 120 },
},
persistUntil: {
title: "有效期至",
type: "datetime",
form: {
helper: "可选;为空表示长期有效",
order: 20,
valueChange({ form }) {
fillRecord(form);
},
},
column: { width: 180, order: 900 },
},
hostRecord: {
title: "TXT主机名",
type: "copyable",
form: {
show: false,
},
column: {
width: 220,
cellRender({ value }) {
return (
<a-tooltip title={value}>
<fs-copyable modelValue={value}></fs-copyable>
</a-tooltip>
);
},
},
},
recordValue: {
title: "请设置TXT记录",
type: "copyable",
form: {
show: false,
},
column: {
width: 380,
cellRender({ value }) {
return (
<a-tooltip title={value}>
<fs-copyable modelValue={value}></fs-copyable>
</a-tooltip>
);
},
},
},
dnsProviderType: {
title: "DNS服务商",
type: "dict-select",
dict: dnsProviderTypeDict,
form: {
show: false,
component: {
name: "DnsProviderSelector",
},
},
column: { show: false },
},
dnsProviderAccess: {
title: "DNS授权",
type: "dict-select",
dict: accessDict,
form: {
show: false,
component: {
name: "AccessSelector",
vModel: "modelValue",
type: compute(({ form }) => {
const type = form.dnsProviderType || "aliyun";
return dnsProviderTypeDict?.dataMap[type]?.accessType || type;
}),
},
},
column: { show: false },
},
status: {
title: "状态",
type: "dict-select",
dict: statusDict,
form: {
show: false,
value: "pending",
},
column: {
width: 120,
cellRender({ value, row }) {
async function resetStatus() {
Modal.confirm({
title: "重新校验",
content: "确认将该记录状态重置为待设置,并重新校验吗?",
onOk: async () => {
await api.UpdateObj({ id: row.id, status: "pending" });
await verifyRecord(row);
},
});
}
return (
<div class={"flex flex-left"}>
<fs-values-format modelValue={value} dict={statusDict}></fs-values-format>
{row.status === "valid" && (
<a-tooltip title="撤销并重新校验">
<fs-icon class={"ml-5 pointer color-yellow"} icon="solar:undo-left-square-bold" onClick={resetStatus}></fs-icon>
</a-tooltip>
)}
</div>
);
},
},
},
triggerValidate: {
title: "校验",
type: "text",
form: {
show: false,
},
column: {
conditionalRenderDisabled: true,
width: 210,
align: "center",
cellRender({ row }) {
return (
<a-space>
{row.status === "valid" ? (
<span class="text-gray-500">TXT记录</span>
) : (
<>
<a-button type="primary" size="small" onClick={() => showRecordHelp(row)}>
TXT
</a-button>
<a-button type="primary" size="small" onClick={() => verifyRecord(row)}>
</a-button>
</>
)}
</a-space>
);
},
},
},
accountUri: {
title: "Account URI",
type: "text",
form: { show: false },
column: { show: false },
},
},
},
};
}
@@ -1,33 +0,0 @@
<template>
<fs-page class="page-cert-dns-persist">
<template #header>
<div>
<div class="title">DNS持久验证记录</div>
<div class="text-orange-500 mt-5">当前仅 Let's Encrypt 测试环境可以申请 DNS 持久验证证书</div>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding"></fs-crud>
</fs-page>
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
defineOptions({
name: "DnsPersistRecord",
});
const context: any = {
permission: { isProjectPermission: true },
};
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
onMounted(() => {
crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -1,133 +0,0 @@
import { message } from "ant-design-vue";
import { reactive } from "vue";
import AccessSelector from "/@/views/certd/access/access-selector/index.vue";
import DnsProviderSelector from "/@/components/plugins/cert/dns-provider-selector/index.vue";
import { useFormDialog } from "/@/use/use-dialog";
import { CreateTxt, TriggerVerify } from "./api";
export type DnsPersistSettingRecord = {
id?: number;
mainDomain?: string;
hostRecord?: string;
recordValue?: string;
dnsProviderType?: string;
dnsProviderAccess?: number;
};
export function useDnsPersistSettingDialog() {
const { openFormDialog } = useFormDialog();
function copyableRow(label: string, value?: string) {
return (
<div class="mb-10 flex items-center">
<div style={{ width: "90px", flexShrink: 0 }}>{label}</div>
<div style={{ flex: 1, minWidth: 0 }}>
<fs-copyable class="w-full" model-value={value || ""}></fs-copyable>
</div>
</div>
);
}
async function openDnsPersistSettingDialog(req: { record: DnsPersistSettingRecord; onDone?: () => Promise<void> | void }) {
const record = req.record;
const form = reactive({
mode: "manual",
dnsProviderType: record.dnsProviderType || "",
dnsProviderAccessType: "",
dnsProviderAccess: record.dnsProviderAccess || null,
});
async function submit() {
if (!record.id) {
return;
}
if (form.mode === "manual") {
await TriggerVerify(record.id);
message.success("已提交校验");
await req.onDone?.();
return;
}
if (!form.dnsProviderType || !form.dnsProviderAccess) {
throw new Error("请选择DNS服务商和授权");
}
await CreateTxt({
id: record.id,
dnsProviderType: form.dnsProviderType,
dnsProviderAccess: form.dnsProviderAccess,
});
message.success("TXT记录已创建");
await req.onDone?.();
}
await openFormDialog({
title: "设置DNS TXT记录",
wrapper: {
width: 680,
buttons: {
reset: {
show: false,
},
ok: {
show: true,
text: "确定",
},
},
},
body: () => (
<div>
<a-radio-group value={form.mode} buttonStyle="solid" class="mb-10" onUpdate:value={(value: string) => (form.mode = value)}>
<a-radio-button value="manual"></a-radio-button>
<a-radio-button value="auto"></a-radio-button>
</a-radio-group>
{form.mode === "manual" ? (
<div>
<a-alert class="mb-10" type="info" show-icon message="请到DNS解析控制台添加以下TXT记录,添加后点击确定会立即校验。" />
{copyableRow("主域名", record.mainDomain)}
{copyableRow("TXT主机名", record.hostRecord)}
{copyableRow("TXT值", record.recordValue)}
</div>
) : (
<div>
<a-alert class="mb-10" type="info" show-icon message="请选择DNS服务商和授权,系统会创建TXT记录,后续校验由后台完成。" />
{copyableRow("主域名", record.mainDomain)}
<div class="mb-10 flex items-center">
<div style={{ width: "90px", flexShrink: 0 }}>DNS服务商</div>
<div style={{ flex: 1, minWidth: 0 }}>
<DnsProviderSelector
class="w-full"
style={{ width: "100%" }}
modelValue={form.dnsProviderType}
onUpdate:modelValue={(value: string) => {
form.dnsProviderType = value;
form.dnsProviderAccess = null;
}}
onSelectedChange={(option: any) => {
form.dnsProviderAccessType = option?.accessType || form.dnsProviderType;
}}
/>
</div>
</div>
<div class="mb-10 flex items-center">
<div style={{ width: "90px", flexShrink: 0 }}>DNS授权</div>
<div style={{ flex: 1, minWidth: 0 }}>
<AccessSelector
modelValue={form.dnsProviderAccess}
type={form.dnsProviderAccessType || form.dnsProviderType || "aliyun"}
onUpdate:modelValue={(value: number) => {
form.dnsProviderAccess = value;
}}
/>
</div>
</div>
</div>
)}
</div>
),
onSubmit: submit,
});
}
return {
openDnsPersistSettingDialog,
};
}
@@ -92,9 +92,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
if (form.challengeType === "cname") {
throw new Error(t("certd.domain.cnameManagedInCnamePage"));
}
if (form.challengeType === "dns-persist") {
throw new Error("DNS持久验证记录请在DNS持久验证记录页面管理");
}
if (form.challengeType === "dns") {
const isSubdomain = await api.IsSubdomain({ domain: form.domain });
if (isSubdomain && !subdomainConfirmed.value) {
@@ -224,17 +221,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
crudExpose.getFormWrapperRef().close();
},
});
} else if (value === "dns-persist") {
Modal.confirm({
title: "请前往DNS持久验证记录页面添加记录",
content: "DNS持久验证需要先配置ACME账号和_validation-persist持久TXT记录,续期时不再增删DNS记录;当前仅 Let's Encrypt 测试环境可以申请。",
async onOk() {
router.push({
path: "/certd/cert/dns-persist",
});
crudExpose.getFormWrapperRef().close();
},
});
}
},
},
@@ -213,10 +213,6 @@ function useStepForm() {
const stepOpen = (step: any, emit: any) => {
callback.value = emit;
currentStep.value = merge({ input: {}, strategy: {} }, step);
// version 1
if (mode.value === "edit" && currentStep.value.type === "CertApply" && currentStep.value.input?.version == null) {
currentStep.value.input.version = 1;
}
if (step.type) {
changeCurrentPlugin(currentStep.value);
}
@@ -8,7 +8,7 @@
<a-col :span="24">
<a-card>
<div class="suite-intro-box">
<div>说明 同一时间只有最新购买的一个套餐生效 可以购买多个加量包加量包立即生效 套餐和加量包内的数量可以叠加</div>
<div>{{ buyHelperText }}</div>
<div v-if="suiteIntro" v-html="suiteIntro"></div>
</div>
</a-card>
@@ -31,7 +31,7 @@
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { computed, ref } from "vue";
import * as api from "./api";
import ProductInfo from "/@/views/certd/suite/product-info.vue";
import OrderModal from "/@/views/certd/suite/order-modal.vue";
@@ -55,9 +55,17 @@ async function doOrder(req: any) {
}
const suiteIntro = ref("");
const allowSuiteStack = ref(false);
const buyHelperText = computed(() => {
if (allowSuiteStack.value) {
return "说明:可以购买多个套餐和加量包,套餐和加量包内的数量可以叠加";
}
return "说明:① 同一时间只有最新购买的一个套餐生效;② 可以购买多个加量包,加量包立即生效;③ 套餐和加量包内的数量可以叠加";
});
async function loadSuiteIntro() {
const res = await api.GetSuiteSetting();
suiteIntro.value = res.intro;
allowSuiteStack.value = !!res.allowSuiteStack;
}
loadSuiteIntro();
</script>
@@ -4,8 +4,14 @@
<a-popover>
<template #content>
<div style="width: 300px">
<div v-if="detail.addonList.length > 0" class="flex flex-wrap">
<a-tag v-for="(item, index) of detail.addonList" :key="index" color="green" class="pointer flex-o m-1">
<div v-if="hiddenSuiteList.length > 0 || detail.addonList.length > 0" class="flex flex-wrap">
<a-tag v-for="(item, index) of hiddenSuiteList" :key="`suite-${index}`" color="green" class="pointer flex-o m-1">
<span class="mr-5">
{{ item.title }}
</span>
<span>(<expires-time-text :value="item.expiresTime" />)</span>
</a-tag>
<a-tag v-for="(item, index) of detail.addonList" :key="`addon-${index}`" color="green" class="pointer flex-o m-1">
<span class="mr-5">
{{ item.title }}
</span>
@@ -43,13 +49,13 @@
</template>
<div class="flex-o">
<fs-icon icon="ant-design:gift-outlined" class="color-green mr-5" />
<a-tag v-for="(item, index) of detail.suiteList" :key="index" color="green" class="pointer flex-o">
<a-tag v-if="currentSuite" color="green" class="pointer flex-o">
<span class="mr-5">
{{ item.title }}
{{ currentSuite.title }}
</span>
<span>(<expires-time-text :value="item.expiresTime" />)</span>
<span>(<expires-time-text :value="currentSuite.expiresTime" />)</span>
<span v-if="hiddenCount > 0" class="ml-5">+{{ hiddenCount }}</span>
</a-tag>
<a-tag v-if="detail.addonList.length > 0" color="green" class="pointer flex-o">加量包+{{ detail.addonList.length }}</a-tag>
<div v-if="detail.suites?.length === 0" class="flex-o ml-5">暂无套餐 <a-button class="ml-5" type="primary" size="small" @click="goBuy">去购买</a-button></div>
</div>
</a-popover>
@@ -59,7 +65,7 @@
<script lang="ts" setup>
import SuiteValue from "/@/views/sys/suite/product/suite-value.vue";
import { ref } from "vue";
import { computed, ref } from "vue";
import ExpiresTimeText from "/@/components/expires-time-text.vue";
import { mySuiteApi, SuiteDetail } from "/@/views/certd/suite/mine/api";
import { FsIcon } from "@fast-crud/fast-crud";
@@ -71,6 +77,10 @@ defineOptions({
const detail = ref<SuiteDetail>({});
const currentSuite = computed(() => detail.value.suiteList?.[0]);
const hiddenSuiteList = computed(() => detail.value.suiteList?.slice(1) || []);
const hiddenCount = computed(() => hiddenSuiteList.value.length + (detail.value.addonList?.length || 0));
async function loadSuiteDetail() {
detail.value = await mySuiteApi.SuiteDetailGet();
const suites = detail.value.suites.filter(item => item.productType === "suite");
@@ -6,7 +6,7 @@
<div class="sys-plugin-config settings-form">
<a-form :model="formState" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off" @finish="onFinish" @finish-failed="onFinishFailed">
<a-form-item v-show="false" label="公共Google EAB授权" :name="['CertApply', 'sysSetting', 'input', 'googleCommonEabAccessId']">
<a-form-item label="公共Google EAB授权" :name="['CertApply', 'sysSetting', 'input', 'googleCommonEabAccessId']">
<access-selector v-model:model-value="formState.CertApply.sysSetting.input.googleCommonEabAccessId" type="eab" from="sys"></access-selector>
<div class="helper">
<div>设置公共Google EAB授权给用户使用避免用户自己去翻墙获取Google EAB授权</div>
@@ -16,14 +16,7 @@
</div>
</a-form-item>
<a-form-item label="公共Google ACME账号" :name="['CertApply', 'sysSetting', 'input', 'googleCommonAcmeAccountAccessId']">
<access-selector v-model:model-value="formState.CertApply.sysSetting.input.googleCommonAcmeAccountAccessId" type="acmeAccount" subtype="google" from="sys"></access-selector>
<div class="helper">
<div>优先推荐配置公共ACME账号配置后普通用户申请Google证书时无需选择账号也不会重复消费公共EAB</div>
</div>
</a-form-item>
<a-form-item v-show="false" label="公共ZeroSSL EAB授权" :name="['CertApply', 'sysSetting', 'input', 'zerosslCommonEabAccessId']">
<a-form-item label="公共ZeroSSL EAB授权" :name="['CertApply', 'sysSetting', 'input', 'zerosslCommonEabAccessId']">
<access-selector v-model:model-value="formState.CertApply.sysSetting.input.zerosslCommonEabAccessId" type="eab" from="sys"></access-selector>
<div class="helper">
<div>设置公共ZeroSSL EAB授权给用户使用避免用户自己去翻墙获取Zero EAB授权</div>
@@ -33,11 +26,7 @@
</div>
</a-form-item>
<a-form-item label="公共ZeroSSL ACME账号" :name="['CertApply', 'sysSetting', 'input', 'zerosslCommonAcmeAccountAccessId']">
<access-selector v-model:model-value="formState.CertApply.sysSetting.input.zerosslCommonAcmeAccountAccessId" type="acmeAccount" subtype="zerossl" from="sys"></access-selector>
</a-form-item>
<a-form-item v-show="false" label="公共litessl EAB授权" :name="['CertApply', 'sysSetting', 'input', 'litesslCommonEabAccessId']">
<a-form-item label="公共litessl EAB授权" :name="['CertApply', 'sysSetting', 'input', 'litesslCommonEabAccessId']">
<access-selector v-model:model-value="formState.CertApply.sysSetting.input.litesslCommonEabAccessId" type="eab" from="sys"></access-selector>
<div class="helper">
<div>设置公共litessl EAB授权给用户使用避免用户自己获取litessl EAB授权</div>
@@ -47,10 +36,6 @@
</div>
</a-form-item>
<a-form-item label="公共litessl ACME账号" :name="['CertApply', 'sysSetting', 'input', 'litesslCommonAcmeAccountAccessId']">
<access-selector v-model:model-value="formState.CertApply.sysSetting.input.litesslCommonAcmeAccountAccessId" type="acmeAccount" subtype="litessl" from="sys"></access-selector>
</a-form-item>
<a-form-item label="其他配置">
<a-button type="primary" @click="doPluginConfig">证书申请插件默认值设置</a-button>
<div class="helper">
@@ -21,6 +21,11 @@
<div class="helper">不建议设置免费套餐可以在下方配置注册赠送套餐或者在用户套餐管理中手动赠送套餐</div>
</a-form-item>
<a-form-item label="套餐支持叠加" name="allowSuiteStack">
<a-switch v-model:checked="formState.allowSuiteStack" />
<div class="helper">默认只有一个套餐生效开启此开关可以让多个套餐可以叠加加量包无论是否开启此开关都可以叠加</div>
</a-form-item>
<a-form-item label="注册赠送套餐" name="registerGift">
<suite-duration-selector ref="suiteDurationSelectedRef" v-model="formState.registerGift"></suite-duration-selector>
<div class="helper">添加套餐后再选择</div>
@@ -73,6 +78,7 @@ const formRef = ref<any>(null);
const formState = reactive<
Partial<{
enabled: boolean;
allowSuiteStack: boolean;
registerGift?: {
productId?: number;
duration?: number;
+1 -1
View File
@@ -1,2 +1,2 @@
link-workspace-packages=deep
prefer-workspace-packages=true
prefer-workspace-packages=true
+17
View File
@@ -3,6 +3,23 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
### Bug Fixes
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/certd/certd/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
* 修复查询阿里云cdn Dcdn 域名太多无法选择的bug ([346fb73](https://github.com/certd/certd/commit/346fb730a37e035576f5d9ea5c0d74c052b34aeb))
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Bug Fixes
* **pipeline-service:** 修复流水线运行时超过套餐部署次数仍然能够正常运行的bug ([5e59651](https://github.com/certd/certd/commit/5e59651d45bc91919629e35995ff1b3cff6b87ea))
### Performance Improvements
* 新增阿里云直播证书部署插件 ([8edb6f8](https://github.com/certd/certd/commit/8edb6f8727bd148f106801bef25567880fd35e9e))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
### Bug Fixes
@@ -1,31 +0,0 @@
ALTER TABLE cd_access ADD COLUMN subtype varchar(100);
CREATE INDEX "index_access_subtype" ON "cd_access" ("subtype");
CREATE TABLE "cd_dns_persist_record"
(
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"user_id" integer NOT NULL,
"project_id" integer,
"domain" varchar(255) NOT NULL,
"main_domain" varchar(255) NOT NULL,
"ca_type" varchar(50) NOT NULL,
"acme_account_access_id" integer NOT NULL,
"account_uri" varchar(512) NOT NULL,
"host_record" varchar(255) NOT NULL,
"record_value" text NOT NULL,
"policy" varchar(50),
"persist_until" integer,
"status" varchar(50) NOT NULL DEFAULT 'pending',
"dns_provider_type" varchar(50),
"dns_provider_access" integer,
"record_res" text,
"disabled" integer NOT NULL DEFAULT 0,
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE INDEX "index_dns_persist_user_id" ON "cd_dns_persist_record" ("user_id");
CREATE INDEX "index_dns_persist_project_id" ON "cd_dns_persist_record" ("project_id");
CREATE INDEX "index_dns_persist_domain" ON "cd_dns_persist_record" ("domain");
CREATE INDEX "index_dns_persist_main_domain" ON "cd_dns_persist_record" ("main_domain");
CREATE INDEX "index_dns_persist_account" ON "cd_dns_persist_record" ("acme_account_access_id");
@@ -54,7 +54,7 @@ input:
action: onGetNodes
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -54,7 +54,7 @@ input:
action: onGetNodes
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -83,7 +83,7 @@ input:
action: onGetSSLIds
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -51,7 +51,7 @@ input:
action: onGetWebsiteList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -66,13 +66,13 @@ input:
component:
name: remote-select
vModel: value
mode: default
mode: tags
type: plugin
typeName: AliyunDeployCertToALB
action: onGetRegionList
search: false
pager: false
multi: false
single: true
watches:
- certDomains
- accessId
@@ -101,7 +101,7 @@ input:
action: onGetLoadBalanceList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -130,7 +130,7 @@ input:
action: onGetListenerList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -116,7 +116,7 @@ input:
action: onGetProductList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -146,7 +146,7 @@ input:
action: onGetContactList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -80,7 +80,7 @@ input:
action: onGetSiteList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -111,7 +111,7 @@ input:
action: onGetDomainList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -62,12 +62,12 @@ input:
component:
name: remote-select
vModel: value
mode: default
mode: tags
type: plugin
action: onGetAcceleratorList
search: false
pager: false
multi: false
single: true
watches:
- certDomains
- accessId
@@ -95,7 +95,7 @@ input:
action: onGetListenerList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -137,7 +137,7 @@ input:
action: onGetAdditionalDomainList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -66,13 +66,13 @@ input:
component:
name: remote-select
vModel: value
mode: default
mode: tags
type: plugin
typeName: AliyunDeployCertToNLB
action: onGetRegionList
search: false
pager: false
multi: false
single: true
watches:
- certDomains
- accessId
@@ -101,7 +101,7 @@ input:
action: onGetLoadBalanceList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -130,7 +130,7 @@ input:
action: onGetListenerList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -66,12 +66,12 @@ input:
component:
name: remote-select
vModel: value
mode: default
mode: tags
type: plugin
action: onGetRegionList
search: false
pager: false
multi: false
single: true
watches:
- certDomains
- accessId
@@ -99,7 +99,7 @@ input:
action: onGetLoadBalanceList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -127,7 +127,7 @@ input:
action: onGetListenerList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -169,7 +169,7 @@ input:
action: onGetExtensionDomainList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -68,7 +68,7 @@ input:
action: onGetDomainList
search: true
pager: true
multi: true
single: false
watches:
- certDomains
- accessId
@@ -84,7 +84,7 @@ input:
action: onGetCnameList
search: true
pager: true
multi: true
single: false
watches:
- certDomains
- accessId
@@ -84,7 +84,7 @@ input:
action: onGetCloudResourceList
search: true
pager: true
multi: true
single: false
watches:
- certDomains
- accessId
@@ -51,7 +51,7 @@ input:
action: onGetCertList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -71,7 +71,7 @@ input:
action: onGetDistributions
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -133,7 +133,7 @@ input:
action: onGetDistributions
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -63,7 +63,7 @@ input:
action: onGetCertList
search: true
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -92,7 +92,7 @@ input:
action: onGetSiteList
search: true
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -80,7 +80,7 @@ input:
action: onGetOrderList
search: false
pager: true
multi: true
single: true
pageSize: 50
watches:
- certDomains
@@ -51,7 +51,7 @@ input:
action: onGetDomainList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -76,7 +76,7 @@ input:
action: onGetDomainList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -101,7 +101,7 @@ input:
action: onGetSiteList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -56,7 +56,7 @@ input:
action: onGetRegionList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -85,7 +85,7 @@ input:
action: onGetGroupList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -114,7 +114,7 @@ input:
action: onGetDomainList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -53,7 +53,7 @@ input:
action: onGetRegionList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -94,7 +94,7 @@ input:
action: onGetDomainList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId
@@ -98,9 +98,10 @@ input:
type: plugin
typeName: DeployCertToAliyunCDN
action: onGetDomainList
search: false
search: true
pager: true
multi: true
single: false
pageSize: 100
watches:
- certDomains
- accessId
@@ -68,9 +68,10 @@ input:
mode: tags
type: plugin
action: onGetDomainList
search: false
search: true
pager: true
multi: true
single: false
pageSize: 100
watches:
- certDomains
- accessId
@@ -0,0 +1,96 @@
showRunStrategy: false
default:
strategy:
runStrategy: 1
name: DeployCertToAliyunLive
title: 阿里云-部署至直播(Live
icon: svg:icon-aliyun
group: aliyun
desc: 部署证书到阿里云视频直播(Live)域名
needPlus: false
input:
cert:
title: 域名证书
helper: 请选择前置任务输出的域名证书
component:
name: output-selector
from:
- ':cert:'
- uploadCertToAliyun
template: false
required: true
order: 0
certDomains:
title: 当前证书域名
component:
name: cert-domains-getter
mergeScript: |2-
return {
component:{
inputKey: ctx.compute(({form})=>{
return form.cert
}),
}
}
template: false
required: false
order: 0
accessId:
title: Access授权
helper: 阿里云授权AccessKeyId、AccessKeySecret
component:
name: access-selector
type: aliyun
required: true
order: 0
endpoint:
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
order: 0
domainList:
title: 直播域名
component:
name: remote-select
vModel: value
mode: tags
type: plugin
typeName: DeployCertToAliyunLive
action: onGetDomainList
search: true
pager: true
single: false
watches:
- certDomains
- accessId
- certDomains
- accessId
required: true
mergeScript: |2-
return {
component:{
form: ctx.compute(({form})=>{
return form
})
},
}
helper: 请选择要部署证书的直播域名
order: 0
output: {}
pluginType: deploy
type: builtIn
scriptFilePath: /plugins/plugin-aliyun/plugin/deploy-to-live/index.js
@@ -149,7 +149,7 @@ input:
action: onGetDomainList
search: false
pager: false
multi: true
single: false
watches:
- certDomains
- accessId

Some files were not shown because too many files have changed in this diff Show More