mirror of
https://github.com/certd/certd.git
synced 2026-04-14 12:30:54 +08:00
Compare commits
21 Commits
v1.36.17
...
v2-dev-plu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ca20be197 | ||
|
|
17f23f3751 | ||
|
|
8e3d699856 | ||
|
|
f1a168fa53 | ||
|
|
3575113655 | ||
|
|
9feb9d04b3 | ||
|
|
5419b1439a | ||
|
|
e4489343fe | ||
|
|
d9f4a5793d | ||
|
|
70fcdc9ebb | ||
|
|
78e7a81638 | ||
|
|
58e82d5dbd | ||
|
|
06d15be43a | ||
|
|
e1e7011853 | ||
|
|
eff7645035 | ||
|
|
eb75e52278 | ||
|
|
15e6148272 | ||
|
|
ccd448a675 | ||
|
|
db54c019ad | ||
|
|
b762b4d72c | ||
|
|
2f8faa839d |
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Plugin Apply
|
name: Plugin Apply
|
||||||
about: 请求支持新部署插件
|
about: 部署插件申请支持
|
||||||
title: "[Plugin] "
|
title: "[Plugin] "
|
||||||
labels: feature
|
labels: feature
|
||||||
---
|
---
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: DNS Provider Apply
|
name: DNS Provider Apply
|
||||||
about: 请求支持新的域名提供商
|
about: 域名提供商申请支持
|
||||||
title: "[DNS] "
|
title: "[DNS] "
|
||||||
labels: feature
|
labels: feature
|
||||||
---
|
---
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: 报告一个错误或问题
|
about: 错误或问题报告
|
||||||
title: "[BUG] "
|
title: "[BUG] "
|
||||||
labels: bug
|
labels: bug
|
||||||
---
|
---
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Feature Request
|
name: Feature Request
|
||||||
about: 新需求、新特性
|
about: 新需求、新特性申请支持
|
||||||
title: "[Feature] "
|
title: "[Feature] "
|
||||||
labels: feature
|
labels: feature
|
||||||
---
|
---
|
||||||
@@ -9,7 +9,8 @@ labels: feature
|
|||||||
> 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
> 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||||
|
|
||||||
|
|
||||||
# 新需求申请
|
# 新特性申请
|
||||||
|
>注意:这里仅供如果是要申请新的部署插件,请提交插件申请
|
||||||
|
|
||||||
## 1. 需求描述,需求背景
|
## 1. 需求描述,需求背景
|
||||||
`请在此处简要描述你所遇到的问题,必要时请贴出相关截图辅助理解`
|
`请在此处简要描述你所遇到的问题,必要时请贴出相关截图辅助理解`
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
name: sync-to-gitee-dev
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ['v2-dev']
|
|
||||||
paths:
|
|
||||||
- "build.trigger"
|
|
||||||
# schedule:
|
|
||||||
# - # 国际时间 19:17 执行,北京时间3:17 ↙↙↙ 改成你想要每天自动执行的时间
|
|
||||||
# - cron: '17 19 * * *'
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
sync:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
lfs: true
|
|
||||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
|
||||||
run: |
|
|
||||||
git config --global user.name "xiaojunnuo"
|
|
||||||
git config --global user.email "xiaojunnuo@qq.com"
|
|
||||||
|
|
||||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
|
||||||
uses: de-vri-es/setup-git-credentials@v2
|
|
||||||
with: # token 格式为: username:password
|
|
||||||
credentials: https://${{secrets.PUSH_TOKEN_GITEE}}@gitee.com
|
|
||||||
|
|
||||||
- name: push to gitee # 4. 执行同步
|
|
||||||
run: |
|
|
||||||
sleep 10
|
|
||||||
git remote add upstream https://gitee.com/certd/certd
|
|
||||||
git push --set-upstream upstream v2-dev
|
|
||||||
|
|
||||||
@@ -1 +1 @@
|
|||||||
12:51
|
23:58
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ services:
|
|||||||
# 设置环境变量即可自定义certd配置
|
# 设置环境变量即可自定义certd配置
|
||||||
# 配置项见: packages/ui/certd-server/src/config/config.default.ts
|
# 配置项见: packages/ui/certd-server/src/config/config.default.ts
|
||||||
# 配置规则: certd_ + 配置项, 点号用_代替
|
# 配置规则: certd_ + 配置项, 点号用_代替
|
||||||
# #↓↓↓↓ ----------------------------- 如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false
|
# #↓↓↓↓ ----------------------------- 如果忘记管理员密码,可以设置为true,docker compose up -d 重建容器之后,管理员密码将改成123456,然后请及时修改回false
|
||||||
- certd_system_resetAdminPasswd=false
|
- certd_system_resetAdminPasswd=false
|
||||||
|
|
||||||
# 默认使用sqlite文件数据库,如果需要使用其他数据库,请设置以下环境变量
|
# 默认使用sqlite文件数据库,如果需要使用其他数据库,请设置以下环境变量
|
||||||
|
|||||||
@@ -3,6 +3,19 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.36.17](https://github.com/certd/certd/compare/v1.36.16...v1.36.17) (2025-08-17)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复新部署的无法保存公共eab配置的bug ([d5dee75](https://github.com/certd/certd/commit/d5dee75df3bd635a597436e448b2de1407531f3a))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 阿里云 FC3.0 不在要求证书加密方式为旧版, 修复支持的协议类型可以正常选择 ([a34db74](https://github.com/certd/certd/commit/a34db7449eff6ad1dda01de673bf85579fa3865a))
|
||||||
|
* 部署到腾讯云cdn,每个域名增加3每秒延迟 ([f7d43ad](https://github.com/certd/certd/commit/f7d43ad5af4663d4be369820a80d1fd9817ca4ab))
|
||||||
|
* 腾讯云关闭证书通知增加开关选项,在腾讯云授权里面 ([a77c777](https://github.com/certd/certd/commit/a77c777980dd38d97d983124eeed1596879bba95))
|
||||||
|
* 证书申请任务默认不发送申请成功通知 ([0283bd2](https://github.com/certd/certd/commit/0283bd2f978dbcd13d361129135e439dd9fbc180))
|
||||||
|
|
||||||
## [1.36.16](https://github.com/certd/certd/compare/v1.36.15...v1.36.16) (2025-08-16)
|
## [1.36.16](https://github.com/certd/certd/compare/v1.36.15...v1.36.16) (2025-08-16)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
"init": "lerna run build",
|
"init": "lerna run build",
|
||||||
"init:dev": "lerna run build",
|
"init:dev": "lerna run build",
|
||||||
"docs:dev": "vitepress dev docs",
|
"docs:dev": "vitepress dev docs",
|
||||||
"docs:build": "vitepress build docs",
|
"docs:build": "npm run copylogs && vitepress build docs",
|
||||||
"docs:preview": "vitepress preview docs",
|
"docs:preview": "vitepress preview docs",
|
||||||
"pub": "echo 1"
|
"pub": "echo 1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -69,5 +69,5 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,5 +45,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,5 +44,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,5 +24,5 @@
|
|||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"tslib": "^2.8.1"
|
"tslib": "^2.8.1"
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,5 +31,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,5 +61,5 @@
|
|||||||
"fetch"
|
"fetch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,5 +32,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,5 +61,5 @@
|
|||||||
"typeorm": "^0.3.11",
|
"typeorm": "^0.3.11",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,5 +46,5 @@
|
|||||||
"typeorm": "^0.3.11",
|
"typeorm": "^0.3.11",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,5 +43,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export type CertInfo = {
|
|||||||
der?: string;
|
der?: string;
|
||||||
jks?: string;
|
jks?: string;
|
||||||
one?: string;
|
one?: string;
|
||||||
|
p7b?: string;
|
||||||
};
|
};
|
||||||
export type SSLProvider = "letsencrypt" | "google" | "zerossl";
|
export type SSLProvider = "letsencrypt" | "google" | "zerossl";
|
||||||
export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521";
|
export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521";
|
||||||
|
|||||||
@@ -125,6 +125,10 @@ export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
|
|||||||
cert.jks = res.jks;
|
cert.jks = res.jks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cert.p7b == null && res.p7b) {
|
||||||
|
cert.p7b = res.p7b;
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.info("转换证书格式成功");
|
this.logger.info("转换证书格式成功");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.error("转换证书格式失败", e);
|
this.logger.error("转换证书格式失败", e);
|
||||||
@@ -150,6 +154,7 @@ export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
|
|||||||
zip.file("intermediate.crt", cert.ic);
|
zip.file("intermediate.crt", cert.ic);
|
||||||
zip.file("origin.crt", cert.oc);
|
zip.file("origin.crt", cert.oc);
|
||||||
zip.file("one.pem", cert.one);
|
zip.file("one.pem", cert.one);
|
||||||
|
zip.file("cert.p7b", cert.p7b);
|
||||||
if (cert.pfx) {
|
if (cert.pfx) {
|
||||||
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
|
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export type CertReaderHandleContext = {
|
|||||||
tmpIcPath?: string;
|
tmpIcPath?: string;
|
||||||
tmpJksPath?: string;
|
tmpJksPath?: string;
|
||||||
tmpOnePath?: string;
|
tmpOnePath?: string;
|
||||||
|
tmpP7bPath?: string;
|
||||||
};
|
};
|
||||||
export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise<void>;
|
export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise<void>;
|
||||||
export type HandleOpts = { logger: ILogger; handle: CertReaderHandle };
|
export type HandleOpts = { logger: ILogger; handle: CertReaderHandle };
|
||||||
@@ -124,7 +125,7 @@ export class CertReader {
|
|||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveToFile(type: "crt" | "key" | "pfx" | "der" | "oc" | "one" | "ic" | "jks", filepath?: string) {
|
saveToFile(type: "crt" | "key" | "pfx" | "der" | "oc" | "one" | "ic" | "jks" | "p7b", filepath?: string) {
|
||||||
if (!this.cert[type]) {
|
if (!this.cert[type]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -138,7 +139,7 @@ export class CertReader {
|
|||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
}
|
}
|
||||||
if (type === "crt" || type === "key" || type === "ic" || type === "oc" || type === "one") {
|
if (type === "crt" || type === "key" || type === "ic" || type === "oc" || type === "one" || type === "p7b") {
|
||||||
fs.writeFileSync(filepath, this.cert[type]);
|
fs.writeFileSync(filepath, this.cert[type]);
|
||||||
} else {
|
} else {
|
||||||
fs.writeFileSync(filepath, Buffer.from(this.cert[type], "base64"));
|
fs.writeFileSync(filepath, Buffer.from(this.cert[type], "base64"));
|
||||||
@@ -157,17 +158,19 @@ export class CertReader {
|
|||||||
const tmpDerPath = this.saveToFile("der");
|
const tmpDerPath = this.saveToFile("der");
|
||||||
const tmpJksPath = this.saveToFile("jks");
|
const tmpJksPath = this.saveToFile("jks");
|
||||||
const tmpOnePath = this.saveToFile("one");
|
const tmpOnePath = this.saveToFile("one");
|
||||||
|
const tmpP7bPath = this.saveToFile("p7b");
|
||||||
logger.info("本地文件写入成功");
|
logger.info("本地文件写入成功");
|
||||||
try {
|
try {
|
||||||
return await opts.handle({
|
return await opts.handle({
|
||||||
reader: this,
|
reader: this,
|
||||||
tmpCrtPath: tmpCrtPath,
|
tmpCrtPath,
|
||||||
tmpKeyPath: tmpKeyPath,
|
tmpKeyPath,
|
||||||
tmpPfxPath: tmpPfxPath,
|
tmpPfxPath,
|
||||||
tmpDerPath: tmpDerPath,
|
tmpDerPath,
|
||||||
tmpIcPath: tmpIcPath,
|
tmpIcPath,
|
||||||
tmpJksPath: tmpJksPath,
|
tmpJksPath,
|
||||||
tmpOcPath: tmpOcPath,
|
tmpOcPath,
|
||||||
|
tmpP7bPath,
|
||||||
tmpOnePath,
|
tmpOnePath,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -189,6 +192,7 @@ export class CertReader {
|
|||||||
removeFile(tmpIcPath);
|
removeFile(tmpIcPath);
|
||||||
removeFile(tmpJksPath);
|
removeFile(tmpJksPath);
|
||||||
removeFile(tmpOnePath);
|
removeFile(tmpOnePath);
|
||||||
|
removeFile(tmpP7bPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ export class CertConverter {
|
|||||||
pfx: string;
|
pfx: string;
|
||||||
der: string;
|
der: string;
|
||||||
jks: string;
|
jks: string;
|
||||||
|
p7b: string;
|
||||||
}> {
|
}> {
|
||||||
const certReader = new CertReader(opts.cert);
|
const certReader = new CertReader(opts.cert);
|
||||||
let pfx: string;
|
let pfx: string;
|
||||||
let der: string;
|
let der: string;
|
||||||
let jks: string;
|
let jks: string;
|
||||||
|
let p7b: string;
|
||||||
const handle = async (ctx: CertReaderHandleContext) => {
|
const handle = async (ctx: CertReaderHandleContext) => {
|
||||||
// 调用openssl 转pfx
|
// 调用openssl 转pfx
|
||||||
pfx = await this.convertPfx(ctx, opts.pfxPassword, opts.pfxArgs);
|
pfx = await this.convertPfx(ctx, opts.pfxPassword, opts.pfxArgs);
|
||||||
@@ -31,6 +33,8 @@ export class CertConverter {
|
|||||||
der = await this.convertDer(ctx);
|
der = await this.convertDer(ctx);
|
||||||
|
|
||||||
jks = await this.convertJks(ctx, opts.pfxPassword);
|
jks = await this.convertJks(ctx, opts.pfxPassword);
|
||||||
|
|
||||||
|
p7b = await this.convertP7b(ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
await certReader.readCertFile({ logger: this.logger, handle });
|
await certReader.readCertFile({ logger: this.logger, handle });
|
||||||
@@ -39,6 +43,7 @@ export class CertConverter {
|
|||||||
pfx,
|
pfx,
|
||||||
der,
|
der,
|
||||||
jks,
|
jks,
|
||||||
|
p7b,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +100,23 @@ export class CertConverter {
|
|||||||
return derCert;
|
return derCert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async convertP7b(opts: CertReaderHandleContext) {
|
||||||
|
const { tmpCrtPath } = opts;
|
||||||
|
const p7bPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + `_cert.p7b`);
|
||||||
|
const dir = path.dirname(p7bPath);
|
||||||
|
if (!fs.existsSync(dir)) {
|
||||||
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
|
}
|
||||||
|
//openssl crl2pkcs7 -nocrl \
|
||||||
|
// -certfile your_domain.crt \
|
||||||
|
// -certfile intermediate.crt \
|
||||||
|
// -out chain.p7b
|
||||||
|
await this.exec(`openssl crl2pkcs7 -nocrl -certfile ${tmpCrtPath} -out ${p7bPath}`);
|
||||||
|
const fileBuffer = fs.readFileSync(p7bPath);
|
||||||
|
const p7bCert = fileBuffer.toString();
|
||||||
|
fs.unlinkSync(p7bPath);
|
||||||
|
return p7bCert;
|
||||||
|
}
|
||||||
async convertJks(opts: CertReaderHandleContext, pfxPassword = "") {
|
async convertJks(opts: CertReaderHandleContext, pfxPassword = "") {
|
||||||
const jksPassword = pfxPassword || "123456";
|
const jksPassword = pfxPassword || "123456";
|
||||||
try {
|
try {
|
||||||
@@ -113,9 +135,7 @@ export class CertConverter {
|
|||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
}
|
}
|
||||||
await this.exec(
|
await this.exec(`keytool -importkeystore -srckeystore ${p12Path} -srcstoretype PKCS12 -srcstorepass "${jksPassword}" -destkeystore ${jksPath} -deststoretype PKCS12 -deststorepass "${jksPassword}" `);
|
||||||
`keytool -importkeystore -srckeystore ${p12Path} -srcstoretype PKCS12 -srcstorepass "${jksPassword}" -destkeystore ${jksPath} -deststoretype PKCS12 -deststorepass "${jksPassword}" `
|
|
||||||
);
|
|
||||||
fs.unlinkSync(p12Path);
|
fs.unlinkSync(p12Path);
|
||||||
|
|
||||||
const fileBuffer = fs.readFileSync(jksPath);
|
const fileBuffer = fs.readFileSync(jksPath);
|
||||||
|
|||||||
@@ -53,5 +53,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "e979e9c9fb5d4e29aa4946e9c5206c222ceb0f75"
|
"gitHead": "831c325c6383ba0a6f2dfa7496451ec714784e93"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ export type AliyunClientV2Req = {
|
|||||||
// 接口 HTTP 方法
|
// 接口 HTTP 方法
|
||||||
method?: "GET" | "POST";
|
method?: "GET" | "POST";
|
||||||
authType?: "AK";
|
authType?: "AK";
|
||||||
style?: "RPC";
|
style?: "RPC" | "ROA";
|
||||||
// 接口 PATH
|
// 接口 PATH
|
||||||
pathname?: `/`;
|
pathname?: string;
|
||||||
|
|
||||||
data?: any;
|
data?: any;
|
||||||
};
|
};
|
||||||
@@ -63,10 +63,10 @@ export class AliyunClientV2 {
|
|||||||
protocol: "HTTPS",
|
protocol: "HTTPS",
|
||||||
// 接口 HTTP 方法
|
// 接口 HTTP 方法
|
||||||
method: req.method ?? "POST",
|
method: req.method ?? "POST",
|
||||||
authType: "AK",
|
authType: req.authType ?? "AK",
|
||||||
style: "RPC",
|
style: req.style ?? "RPC",
|
||||||
// 接口 PATH
|
// 接口 PATH
|
||||||
pathname: `/`,
|
pathname: req.pathname ?? `/`,
|
||||||
// 接口请求体内容格式
|
// 接口请求体内容格式
|
||||||
reqBodyType: "json",
|
reqBodyType: "json",
|
||||||
// 接口响应体内容格式
|
// 接口响应体内容格式
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ export type AliyunCertInfo = {
|
|||||||
export type AliyunSslClientOpts = {
|
export type AliyunSslClientOpts = {
|
||||||
access: AliyunAccess;
|
access: AliyunAccess;
|
||||||
logger: ILogger;
|
logger: ILogger;
|
||||||
endpoint: string;
|
endpoint?: string;
|
||||||
|
region?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AliyunSslGetResourceListReq = {
|
export type AliyunSslGetResourceListReq = {
|
||||||
@@ -48,10 +49,19 @@ export class AliyunSslClient {
|
|||||||
async getClient() {
|
async getClient() {
|
||||||
const access = this.opts.access;
|
const access = this.opts.access;
|
||||||
const client = new AliyunClient({ logger: this.opts.logger });
|
const client = new AliyunClient({ logger: this.opts.logger });
|
||||||
|
|
||||||
|
let endpoint = this.opts.endpoint || "cas.aliyuncs.com";
|
||||||
|
if (this.opts.endpoint == null && this.opts.region) {
|
||||||
|
if (this.opts.region === "cn-hangzhou") {
|
||||||
|
endpoint = "cas.aliyuncs.com";
|
||||||
|
} else {
|
||||||
|
endpoint = `cas.${this.opts.region}.aliyuncs.com`;
|
||||||
|
}
|
||||||
|
}
|
||||||
await client.init({
|
await client.init({
|
||||||
accessKeyId: access.accessKeyId,
|
accessKeyId: access.accessKeyId,
|
||||||
accessKeySecret: access.accessKeySecret,
|
accessKeySecret: access.accessKeySecret,
|
||||||
endpoint: `https://${this.opts.endpoint || "cas.aliyuncs.com"}`,
|
endpoint: `https://${endpoint}`,
|
||||||
apiVersion: "2020-04-07",
|
apiVersion: "2020-04-07",
|
||||||
});
|
});
|
||||||
return client;
|
return client;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
|||||||
title: "天翼云授权",
|
title: "天翼云授权",
|
||||||
desc: "",
|
desc: "",
|
||||||
icon: "ant-design:aliyun-outlined",
|
icon: "ant-design:aliyun-outlined",
|
||||||
|
order: 2,
|
||||||
})
|
})
|
||||||
export class CtyunAccess extends BaseAccess {
|
export class CtyunAccess extends BaseAccess {
|
||||||
@AccessInput({
|
@AccessInput({
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline";
|
|||||||
desc: "",
|
desc: "",
|
||||||
icon: "svg:icon-qiniuyun",
|
icon: "svg:icon-qiniuyun",
|
||||||
input: {},
|
input: {},
|
||||||
|
order: 2,
|
||||||
})
|
})
|
||||||
export class QiniuAccess extends BaseAccess {
|
export class QiniuAccess extends BaseAccess {
|
||||||
@AccessInput({
|
@AccessInput({
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline";
|
|||||||
desc: "",
|
desc: "",
|
||||||
icon: "clarity:host-line",
|
icon: "clarity:host-line",
|
||||||
input: {},
|
input: {},
|
||||||
|
order: 0,
|
||||||
})
|
})
|
||||||
export class SshAccess extends BaseAccess {
|
export class SshAccess extends BaseAccess {
|
||||||
@AccessInput({
|
@AccessInput({
|
||||||
|
|||||||
@@ -247,6 +247,9 @@ export class AsyncSsh2Client {
|
|||||||
const err = this.convert(iconv, ret);
|
const err = this.convert(iconv, ret);
|
||||||
stdErr += err;
|
stdErr += err;
|
||||||
hasErrorLog = true;
|
hasErrorLog = true;
|
||||||
|
if (err.includes("sudo: a password is required")) {
|
||||||
|
this.logger.warn("请配置sudo免密,否则命令无法执行");
|
||||||
|
}
|
||||||
this.logger.error(`[${this.connConf.host}][error]: ` + err.trimEnd());
|
this.logger.error(`[${this.connConf.host}][error]: ` + err.trimEnd());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
|||||||
name: "tencent",
|
name: "tencent",
|
||||||
title: "腾讯云",
|
title: "腾讯云",
|
||||||
icon: "svg:icon-tencentcloud",
|
icon: "svg:icon-tencentcloud",
|
||||||
|
order: 0,
|
||||||
})
|
})
|
||||||
export class TencentAccess extends BaseAccess {
|
export class TencentAccess extends BaseAccess {
|
||||||
@AccessInput({
|
@AccessInput({
|
||||||
@@ -59,4 +60,8 @@ export class TencentAccess extends BaseAccess {
|
|||||||
isIntl() {
|
isIntl() {
|
||||||
return this.accountType === "intl";
|
return this.accountType === "intl";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intlDomain() {
|
||||||
|
return this.isIntl() ? "intl." : "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export class TencentSslClient {
|
|||||||
region: this.region,
|
region: this.region,
|
||||||
profile: {
|
profile: {
|
||||||
httpProfile: {
|
httpProfile: {
|
||||||
endpoint: "ssl.tencentcloudapi.com",
|
endpoint: this.access.isIntl() ? "ssl.intl.tencentcloudapi.com" : "ssl.tencentcloudapi.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
"@tailwindcss/typography": "^0.5.16",
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
"@tanstack/vue-store": "^0.7.0",
|
"@tanstack/vue-store": "^0.7.0",
|
||||||
"@vee-validate/zod": "^4.15.0",
|
"@vee-validate/zod": "^4.15.0",
|
||||||
"@vue-js-cron/light": "^4.0.5",
|
"@certd/vue-js-cron-light": "^4.0.14",
|
||||||
"@vue/shared": "^3.5.13",
|
"@vue/shared": "^3.5.13",
|
||||||
"@vueuse/core": "^10.11.0",
|
"@vueuse/core": "^10.11.0",
|
||||||
"ant-design-vue": "^4.2.6",
|
"ant-design-vue": "^4.2.6",
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import vip from "./vip-button/install.js";
|
|||||||
import { CheckCircleOutlined, InfoCircleOutlined, UndoOutlined } from "@ant-design/icons-vue";
|
import { CheckCircleOutlined, InfoCircleOutlined, UndoOutlined } from "@ant-design/icons-vue";
|
||||||
import CronEditor from "./cron-editor/index.vue";
|
import CronEditor from "./cron-editor/index.vue";
|
||||||
import FoldBox from "./fold-box.vue";
|
import FoldBox from "./fold-box.vue";
|
||||||
import { CronLight } from "@vue-js-cron/light";
|
import { CronLight } from "@certd/vue-js-cron-light";
|
||||||
import "@vue-js-cron/light/dist/light.css";
|
import "@certd/vue-js-cron-light/dist/light.css";
|
||||||
import Plugins from "./plugins/index";
|
import Plugins from "./plugins/index";
|
||||||
import LoadingButton from "./loading-button.vue";
|
import LoadingButton from "./loading-button.vue";
|
||||||
import IconSelect from "./icon-select.vue";
|
import IconSelect from "./icon-select.vue";
|
||||||
|
|||||||
@@ -564,7 +564,7 @@ export default {
|
|||||||
ipv6Priority: "IPv6 Priority",
|
ipv6Priority: "IPv6 Priority",
|
||||||
dualStackNetworkHelper: "If IPv6 priority is selected, enable IPv6 in docker-compose.yaml",
|
dualStackNetworkHelper: "If IPv6 priority is selected, enable IPv6 in docker-compose.yaml",
|
||||||
enableCommonCnameService: "Enable Public CNAME Service",
|
enableCommonCnameService: "Enable Public CNAME Service",
|
||||||
commonCnameHelper: "Allow use of public CNAME service. If disabled and no <router-link to='/sys/cname/provider'>custom CNAME service</router-link> is set, CNAME proxy certificate application will not work.",
|
commonCnameHelper: "Allow use of public CNAME service. If disabled and no <a href='#/sys/cname/provider'>custom CNAME service</a> is set, CNAME proxy certificate application will not work.",
|
||||||
enableCommonSelfServicePasswordRetrieval: "Enable self-service password recovery",
|
enableCommonSelfServicePasswordRetrieval: "Enable self-service password recovery",
|
||||||
saveButton: "Save",
|
saveButton: "Save",
|
||||||
stopSuccess: "Stopped successfully",
|
stopSuccess: "Stopped successfully",
|
||||||
|
|||||||
@@ -570,7 +570,7 @@ export default {
|
|||||||
ipv6Priority: "IPV6优先",
|
ipv6Priority: "IPV6优先",
|
||||||
dualStackNetworkHelper: "如果选择IPv6优先,需要在docker-compose.yaml中启用ipv6",
|
dualStackNetworkHelper: "如果选择IPv6优先,需要在docker-compose.yaml中启用ipv6",
|
||||||
enableCommonCnameService: "启用公共CNAME服务",
|
enableCommonCnameService: "启用公共CNAME服务",
|
||||||
commonCnameHelper: "是否可以使用公共CNAME服务,如果禁用,且没有设置<router-link to='/sys/cname/provider'>自定义CNAME服务</router-link>,则无法使用CNAME代理方式申请证书",
|
commonCnameHelper: "是否可以使用公共CNAME服务,如果禁用,且没有设置<a href='#/sys/cname/provider'>自定义CNAME服务</a>,则无法使用CNAME代理方式申请证书",
|
||||||
enableCommonSelfServicePasswordRetrieval: "启用自助找回密码",
|
enableCommonSelfServicePasswordRetrieval: "启用自助找回密码",
|
||||||
saveButton: "保存",
|
saveButton: "保存",
|
||||||
stopSuccess: "停止成功",
|
stopSuccess: "停止成功",
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ export const sysResources = [
|
|||||||
title: "certd.sysResources.sysPluginConfig",
|
title: "certd.sysResources.sysPluginConfig",
|
||||||
name: "SysPluginConfig",
|
name: "SysPluginConfig",
|
||||||
path: "/sys/plugin/config",
|
path: "/sys/plugin/config",
|
||||||
component: "/sys/plugin/config.vue",
|
component: "/sys/plugin/config-common.vue",
|
||||||
meta: {
|
meta: {
|
||||||
show: () => {
|
show: () => {
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import * as api from "./api.plugin";
|
import * as api from "./api.plugin";
|
||||||
import { DynamicType, FormItemProps } from "@fast-crud/fast-crud";
|
import { DynamicType, FormItemProps, useMerge } from "@fast-crud/fast-crud";
|
||||||
import { i18n } from "/src/locales/i18n";
|
import { i18n } from "/src/locales/i18n";
|
||||||
|
import { cloneDeep } from "lodash-es";
|
||||||
interface PluginState {
|
interface PluginState {
|
||||||
group?: PluginGroups;
|
group?: PluginGroups;
|
||||||
}
|
}
|
||||||
@@ -32,14 +33,17 @@ export class PluginGroups {
|
|||||||
groups!: { [key: string]: PluginGroup };
|
groups!: { [key: string]: PluginGroup };
|
||||||
map!: { [key: string]: PluginDefine };
|
map!: { [key: string]: PluginDefine };
|
||||||
t: any;
|
t: any;
|
||||||
constructor(groups: { [key: string]: PluginGroup }) {
|
mergeSetting?: boolean;
|
||||||
|
constructor(groups: { [key: string]: PluginGroup }, opts?: { mergeSetting?: boolean }) {
|
||||||
this.groups = groups;
|
this.groups = groups;
|
||||||
this.t = i18n.global.t;
|
this.t = i18n.global.t;
|
||||||
|
this.mergeSetting = opts?.mergeSetting ?? false;
|
||||||
this.initGroup(groups);
|
this.initGroup(groups);
|
||||||
this.initMap();
|
this.initMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
private initGroup(groups: { [p: string]: PluginGroup }) {
|
private initGroup(groups: { [p: string]: PluginGroup }) {
|
||||||
|
const { merge } = useMerge();
|
||||||
const all: PluginGroup = {
|
const all: PluginGroup = {
|
||||||
key: "all",
|
key: "all",
|
||||||
title: this.t("certd.all"),
|
title: this.t("certd.all"),
|
||||||
@@ -48,6 +52,14 @@ export class PluginGroups {
|
|||||||
icon: "material-symbols:border-all-rounded",
|
icon: "material-symbols:border-all-rounded",
|
||||||
};
|
};
|
||||||
for (const key in groups) {
|
for (const key in groups) {
|
||||||
|
if (this.mergeSetting) {
|
||||||
|
for (const plugin of groups[key].plugins) {
|
||||||
|
if (plugin.sysSetting) {
|
||||||
|
merge(plugin.input, plugin.sysSetting.metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
all.plugins.push(...groups[key].plugins);
|
all.plugins.push(...groups[key].plugins);
|
||||||
}
|
}
|
||||||
this.groups = {
|
this.groups = {
|
||||||
@@ -132,11 +144,15 @@ export const usePluginStore = defineStore({
|
|||||||
id: "app.plugin",
|
id: "app.plugin",
|
||||||
state: (): PluginState => ({
|
state: (): PluginState => ({
|
||||||
group: null,
|
group: null,
|
||||||
|
originGroup: null,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async reload() {
|
async reload() {
|
||||||
const groups = await api.GetGroups({});
|
const groups = await api.GetGroups({});
|
||||||
this.group = new PluginGroups(groups);
|
this.group = new PluginGroups(groups, { mergeSetting: true });
|
||||||
|
this.originGroup = new PluginGroups(cloneDeep(groups));
|
||||||
|
console.log("group", this.group);
|
||||||
|
console.log("originGroup", this.originGroup);
|
||||||
},
|
},
|
||||||
async init() {
|
async init() {
|
||||||
if (!this.group) {
|
if (!this.group) {
|
||||||
@@ -159,6 +175,10 @@ export const usePluginStore = defineStore({
|
|||||||
await this.init();
|
await this.init();
|
||||||
return this.group.get(name);
|
return this.group.get(name);
|
||||||
},
|
},
|
||||||
|
async getPluginDefineFromOrigin(name: string): Promise<PluginDefine> {
|
||||||
|
await this.init();
|
||||||
|
return this.originGroup.get(name);
|
||||||
|
},
|
||||||
async getPluginConfig(query: any) {
|
async getPluginConfig(query: any) {
|
||||||
return await api.GetPluginConfig(query);
|
return await api.GetPluginConfig(query);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -304,3 +304,11 @@ h6 {
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
color: #6e6e6e;
|
color: #6e6e6e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-modal-body{
|
||||||
|
.fs-form-body{
|
||||||
|
max-height: 66vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -84,6 +84,7 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
|||||||
component: {
|
component: {
|
||||||
color: "auto",
|
color: "auto",
|
||||||
},
|
},
|
||||||
|
order: -1,
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
component: {
|
component: {
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 300,
|
width: 300,
|
||||||
|
order: -11,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
from: {
|
from: {
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ export function useCertPipelineCreator() {
|
|||||||
form: {
|
form: {
|
||||||
doSubmit,
|
doSubmit,
|
||||||
wrapper: {
|
wrapper: {
|
||||||
|
wrapClassName: "cert_pipeline_create_form",
|
||||||
width: 1350,
|
width: 1350,
|
||||||
saveRemind: false,
|
saveRemind: false,
|
||||||
title: t("certd.pipelineForm.createTitle"),
|
title: t("certd.pipelineForm.createTitle"),
|
||||||
|
|||||||
@@ -115,4 +115,13 @@ function batchRerun() {
|
|||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cert_pipeline_create_form {
|
||||||
|
.ant-collapse {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
.ant-collapse-header {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-button type="primary" size="large" html-type="submit" :loading="loading" class="login-button">
|
<a-button type="primary" size="large" html-type="button" :loading="loading" class="login-button" @click="handleFinish">
|
||||||
{{ t("authentication.loginButton") }}
|
{{ t("authentication.loginButton") }}
|
||||||
</a-button>
|
</a-button>
|
||||||
|
|
||||||
@@ -217,7 +217,6 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
||||||
.login-page.main {
|
.login-page.main {
|
||||||
//margin: 20px !important;
|
//margin: 20px !important;
|
||||||
margin-bottom: 100px;
|
margin-bottom: 100px;
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ export type CertApplyPluginSysInput = {
|
|||||||
export type PluginSysSetting<T> = {
|
export type PluginSysSetting<T> = {
|
||||||
sysSetting: {
|
sysSetting: {
|
||||||
input?: T;
|
input?: T;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export type CommPluginConfig = {
|
export type CommPluginConfig = {
|
||||||
@@ -118,6 +119,14 @@ export async function SaveCommPluginConfigs(data: CommPluginConfig): Promise<voi
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function savePluginSetting(req: { id: number; metadata: any }): Promise<void> {
|
||||||
|
return await request({
|
||||||
|
url: apiPrefix + "/saveSetting",
|
||||||
|
method: "post",
|
||||||
|
data: req,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function DoTest(req: { id: number; input: any }): Promise<void> {
|
export async function DoTest(req: { id: number; input: any }): Promise<void> {
|
||||||
return await request({
|
return await request({
|
||||||
url: apiPrefix + "/doTest",
|
url: apiPrefix + "/doTest",
|
||||||
|
|||||||
177
packages/ui/certd-client/src/views/sys/plugin/config-editor.vue
Normal file
177
packages/ui/certd-client/src/views/sys/plugin/config-editor.vue
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
<template>
|
||||||
|
<div class="plugin-config">
|
||||||
|
<div class="origin-metadata w-100%">
|
||||||
|
<div class="block-title">
|
||||||
|
自定义插件参数配置
|
||||||
|
<div class="helper">1111</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-10">
|
||||||
|
<div ref="formRef" class="config-form w-full" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||||
|
<table class="table-fixed w-full">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-left p-5" width="200px">插件参数</th>
|
||||||
|
<th class="text-left p-5" width="100px">参数配置</th>
|
||||||
|
<th class="text-left flex-1 p-5">自定义</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<template v-for="(item, key) in originInputs" :key="key">
|
||||||
|
<template v-for="prop in editableKeys" :key="prop.key">
|
||||||
|
<tr>
|
||||||
|
<td v-if="prop.key === 'value'" class="border-t-2 p-5" rowspan="3" :class="{ 'border-t-2': prop.key === 'value' }">{{ item.title }}</td>
|
||||||
|
<td class="border-t p-5" :class="{ 'border-t-2': prop.key === 'value' }">{{ prop.label }}</td>
|
||||||
|
<td class="border-t p-5" :class="{ 'border-t-2': prop.key === 'value' }">
|
||||||
|
<rollbackable :value="configForm[key][prop.key]" @set="configForm[key][prop.key] = item[prop.key] ?? null" @clear="delete configForm[key][prop.key]">
|
||||||
|
<template #default>
|
||||||
|
<fs-render :render-func="prop.defaultRender(key, item)"></fs-render>
|
||||||
|
</template>
|
||||||
|
<template #edit>
|
||||||
|
<fs-render :render-func="prop.editRender(key, item)"></fs-render>
|
||||||
|
</template>
|
||||||
|
</rollbackable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="tsx">
|
||||||
|
import { computed, nextTick, onMounted, reactive, ref, Ref, unref } from "vue";
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
import * as api from "./api";
|
||||||
|
import { usePluginStore } from "/@/store/plugin";
|
||||||
|
import { cloneDeep, get, merge, set, unset } from "lodash-es";
|
||||||
|
import Rollbackable from "./rollbackable.vue";
|
||||||
|
import { FsRender } from "@fast-crud/fast-crud";
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const pluginStore = usePluginStore();
|
||||||
|
const props = defineProps<{
|
||||||
|
plugin: any;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const pluginMetadata = ref<any>("");
|
||||||
|
const currentPlugin = ref();
|
||||||
|
const labelCol = ref({
|
||||||
|
span: null,
|
||||||
|
style: {
|
||||||
|
width: "145px",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const wrapperCol = ref({ span: 16 });
|
||||||
|
const configForm: any = reactive({});
|
||||||
|
|
||||||
|
function getScope() {
|
||||||
|
return {
|
||||||
|
form: configForm,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function getScopeFunc() {
|
||||||
|
return getScope;
|
||||||
|
}
|
||||||
|
function getForm() {
|
||||||
|
return configForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
const editableKeys = ref([
|
||||||
|
{
|
||||||
|
key: "value",
|
||||||
|
label: "默认值",
|
||||||
|
defaultRender(key: string, item: any) {
|
||||||
|
return () => {
|
||||||
|
return item["value"] ?? "";
|
||||||
|
};
|
||||||
|
},
|
||||||
|
editRender(key: string, item: any) {
|
||||||
|
return () => {
|
||||||
|
return <fs-component-render {...item.component} vModel:modelValue={configForm[key]["value"]} scope={getScope()} />;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "show",
|
||||||
|
label: "是否显示",
|
||||||
|
defaultRender(key: string, item: any) {
|
||||||
|
return () => {
|
||||||
|
const value = item["show"];
|
||||||
|
return value === false ? "不显示" : "显示";
|
||||||
|
};
|
||||||
|
},
|
||||||
|
editRender(key: string, item: any) {
|
||||||
|
return () => {
|
||||||
|
return <a-switch vModel:checked={configForm[key]["show"]} />;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "helper",
|
||||||
|
label: "帮助说明",
|
||||||
|
defaultRender(key: string, item: any) {
|
||||||
|
return () => {
|
||||||
|
return <pre class={"helper"}>{item["helper"]}</pre>;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
editRender(key: string, item: any) {
|
||||||
|
return () => {
|
||||||
|
return <a-textarea rows={5} vModel:value={configForm[key]["helper"]} />;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const originInputs = computed(() => {
|
||||||
|
if (!currentPlugin.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const input = cloneDeep(currentPlugin.value.input);
|
||||||
|
const newInputs: any = {};
|
||||||
|
|
||||||
|
for (const key in input) {
|
||||||
|
const value = input[key];
|
||||||
|
value.key = key;
|
||||||
|
const newInput: any = cloneDeep(value);
|
||||||
|
newInputs[key] = newInput;
|
||||||
|
}
|
||||||
|
return newInputs;
|
||||||
|
});
|
||||||
|
|
||||||
|
function clearFormValue(key: string) {
|
||||||
|
unset(configForm, key);
|
||||||
|
console.log(key, configForm);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadPluginSetting() {
|
||||||
|
currentPlugin.value = await pluginStore.getPluginDefineFromOrigin(props.plugin.name);
|
||||||
|
for (const key in currentPlugin.value.input) {
|
||||||
|
configForm[key] = {};
|
||||||
|
}
|
||||||
|
const setting = props.plugin.sysSetting;
|
||||||
|
if (setting) {
|
||||||
|
const settingJson = JSON.parse(setting);
|
||||||
|
merge(configForm, settingJson.metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await loadPluginSetting();
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
getForm,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.plugin-config {
|
||||||
|
pre {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
import { useI18n } from "/src/locales";
|
import { useI18n } from "/src/locales";
|
||||||
import { Ref, ref } from "vue";
|
import { Ref, ref, computed } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, useFormWrapper, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||||
import { Modal, notification } from "ant-design-vue";
|
import { Modal } from "ant-design-vue";
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
|
import { usePluginImport } from "./use-import";
|
||||||
|
import { usePluginConfig } from "./use-config";
|
||||||
|
import { useSettingStore } from "/src/store/settings/index";
|
||||||
|
|
||||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -35,75 +38,11 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||||||
|
|
||||||
const selectedRowKeys: Ref<any[]> = ref([]);
|
const selectedRowKeys: Ref<any[]> = ref([]);
|
||||||
context.selectedRowKeys = selectedRowKeys;
|
context.selectedRowKeys = selectedRowKeys;
|
||||||
const { openCrudFormDialog } = useFormWrapper();
|
|
||||||
|
|
||||||
async function openImportDialog() {
|
const { openImportDialog } = usePluginImport();
|
||||||
function createCrudOptions() {
|
const { openConfigDialog } = usePluginConfig();
|
||||||
return {
|
|
||||||
crudOptions: {
|
const settingStore = useSettingStore();
|
||||||
columns: {
|
|
||||||
content: {
|
|
||||||
title: t("certd.pluginFile"),
|
|
||||||
type: "text",
|
|
||||||
form: {
|
|
||||||
component: {
|
|
||||||
name: "pem-input",
|
|
||||||
vModel: "modelValue",
|
|
||||||
textarea: {
|
|
||||||
rows: 8,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
col: {
|
|
||||||
span: 24,
|
|
||||||
},
|
|
||||||
helper: t("certd.selectPluginFile"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
override: {
|
|
||||||
title: t("certd.overrideSameName"),
|
|
||||||
type: "dict-switch",
|
|
||||||
dict: dict({
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
value: true,
|
|
||||||
label: t("certd.override"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: false,
|
|
||||||
label: t("certd.noOverride"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
form: {
|
|
||||||
value: false,
|
|
||||||
col: {
|
|
||||||
span: 24,
|
|
||||||
},
|
|
||||||
helper: t("certd.overrideHelper"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
form: {
|
|
||||||
wrapper: {
|
|
||||||
title: t("certd.importPlugin"),
|
|
||||||
saveRemind: false,
|
|
||||||
},
|
|
||||||
afterSubmit() {
|
|
||||||
notification.success({ message: t("certd.operationSuccess") });
|
|
||||||
crudExpose.doRefresh();
|
|
||||||
},
|
|
||||||
async doSubmit({ form }: any) {
|
|
||||||
return await api.ImportPlugin({
|
|
||||||
...form,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const { crudOptions } = createCrudOptions();
|
|
||||||
await openCrudFormDialog({ crudOptions });
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
settings: {
|
settings: {
|
||||||
@@ -139,7 +78,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||||||
text: t("certd.import"),
|
text: t("certd.import"),
|
||||||
type: "primary",
|
type: "primary",
|
||||||
async click() {
|
async click() {
|
||||||
await openImportDialog();
|
await openImportDialog({ crudExpose });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -186,6 +125,21 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
config: {
|
||||||
|
show: computed(() => {
|
||||||
|
return settingStore.isComm;
|
||||||
|
}),
|
||||||
|
text: null,
|
||||||
|
icon: "ion:settings-outline",
|
||||||
|
title: t("certd.config"),
|
||||||
|
type: "link",
|
||||||
|
async click({ row }) {
|
||||||
|
await openConfigDialog({
|
||||||
|
row,
|
||||||
|
crudExpose,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { defineProps } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{ value: any }>();
|
||||||
|
|
||||||
|
const emits = defineEmits(["set", "clear"]);
|
||||||
|
function setValue() {
|
||||||
|
emits("set");
|
||||||
|
}
|
||||||
|
function clearValue() {
|
||||||
|
emits("clear");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="rollbackable">
|
||||||
|
<div class="flex">
|
||||||
|
<div style="width: 100px">
|
||||||
|
<a-tag v-if="value === undefined" color="green" size="small" class="pointer flex-inline items-center" @click.stop="setValue">
|
||||||
|
<fs-icon icon="material-symbols:edit" class="mr-5"></fs-icon>
|
||||||
|
自定义
|
||||||
|
</a-tag>
|
||||||
|
<a-tag v-else color="red" size="small" class="pointer flex-inline items-center" @click.stop="clearValue">
|
||||||
|
<fs-icon icon="material-symbols:undo" class="mr-5"></fs-icon>
|
||||||
|
还原
|
||||||
|
</a-tag>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 overflow-hidden value-render">
|
||||||
|
<slot v-if="value === undefined" name="default"></slot>
|
||||||
|
<slot v-else name="edit"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.rollbackable {
|
||||||
|
.value-render {
|
||||||
|
.ant-select,
|
||||||
|
.ant-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
73
packages/ui/certd-client/src/views/sys/plugin/use-config.tsx
Normal file
73
packages/ui/certd-client/src/views/sys/plugin/use-config.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import * as api from "/@/views/sys/plugin/api";
|
||||||
|
import { useFormWrapper } from "@fast-crud/fast-crud";
|
||||||
|
import { useI18n } from "/@/locales";
|
||||||
|
import { Modal, notification } from "ant-design-vue";
|
||||||
|
import ConfigEditor from "./config-editor.vue";
|
||||||
|
import { useModal } from "/@/use/use-modal";
|
||||||
|
import { ref } from "vue";
|
||||||
|
export function usePluginConfig() {
|
||||||
|
const { openCrudFormDialog } = useFormWrapper();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const modal = useModal();
|
||||||
|
async function openConfigDialog({ row, crudExpose }) {
|
||||||
|
const configEditorRef = ref();
|
||||||
|
function createCrudOptions() {
|
||||||
|
return {
|
||||||
|
crudOptions: {
|
||||||
|
columns: {},
|
||||||
|
form: {
|
||||||
|
wrapper: {
|
||||||
|
width: "80%",
|
||||||
|
title: "插件元数据配置",
|
||||||
|
saveRemind: false,
|
||||||
|
slots: {
|
||||||
|
"form-body-top": () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ConfigEditor ref={configEditorRef} plugin={row}></ConfigEditor>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
afterSubmit() {
|
||||||
|
notification.success({ message: t("certd.operationSuccess") });
|
||||||
|
crudExpose.doRefresh();
|
||||||
|
},
|
||||||
|
async doSubmit({}: any) {
|
||||||
|
const form = configEditorRef.value.getForm();
|
||||||
|
const newForm: any = {};
|
||||||
|
for (const key in form) {
|
||||||
|
const value = form[key];
|
||||||
|
if (value && Object.keys(value).length > 0) {
|
||||||
|
newForm[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return await api.savePluginSetting({
|
||||||
|
name: row.name,
|
||||||
|
sysSetting: {
|
||||||
|
metadata: newForm,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const { crudOptions } = createCrudOptions();
|
||||||
|
await openCrudFormDialog({ crudOptions });
|
||||||
|
|
||||||
|
// modal.confirm({
|
||||||
|
// title: "插件元数据配置",
|
||||||
|
// width: "80%",
|
||||||
|
// content: () => {
|
||||||
|
// return <ConfigEditor plugin={row}></ConfigEditor>;
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
openConfigDialog,
|
||||||
|
};
|
||||||
|
}
|
||||||
80
packages/ui/certd-client/src/views/sys/plugin/use-import.ts
Normal file
80
packages/ui/certd-client/src/views/sys/plugin/use-import.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import * as api from "/@/views/sys/plugin/api";
|
||||||
|
import { useFormWrapper } from "@fast-crud/fast-crud";
|
||||||
|
import { useI18n } from "/@/locales";
|
||||||
|
import { Modal, notification } from "ant-design-vue";
|
||||||
|
export function usePluginImport() {
|
||||||
|
const { openCrudFormDialog } = useFormWrapper();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
async function openImportDialog({ crudExpose }) {
|
||||||
|
function createCrudOptions() {
|
||||||
|
return {
|
||||||
|
crudOptions: {
|
||||||
|
columns: {
|
||||||
|
content: {
|
||||||
|
title: t("certd.pluginFile"),
|
||||||
|
type: "text",
|
||||||
|
form: {
|
||||||
|
component: {
|
||||||
|
name: "pem-input",
|
||||||
|
vModel: "modelValue",
|
||||||
|
textarea: {
|
||||||
|
rows: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
col: {
|
||||||
|
span: 24,
|
||||||
|
},
|
||||||
|
helper: t("certd.selectPluginFile"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
override: {
|
||||||
|
title: t("certd.overrideSameName"),
|
||||||
|
type: "dict-switch",
|
||||||
|
dict: dict({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
label: t("certd.override"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: false,
|
||||||
|
label: t("certd.noOverride"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
form: {
|
||||||
|
value: false,
|
||||||
|
col: {
|
||||||
|
span: 24,
|
||||||
|
},
|
||||||
|
helper: t("certd.overrideHelper"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
wrapper: {
|
||||||
|
title: t("certd.importPlugin"),
|
||||||
|
saveRemind: false,
|
||||||
|
},
|
||||||
|
afterSubmit() {
|
||||||
|
notification.success({ message: t("certd.operationSuccess") });
|
||||||
|
crudExpose.doRefresh();
|
||||||
|
},
|
||||||
|
async doSubmit({ form }: any) {
|
||||||
|
return await api.ImportPlugin({
|
||||||
|
...form,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const { crudOptions } = createCrudOptions();
|
||||||
|
await openCrudFormDialog({ crudOptions });
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
openImportDialog,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<a-form-item v-if="formState.yizhifu.enabled" label="易支付配置" :name="['yizhifu', 'accessId']" :required="true">
|
<a-form-item v-if="formState.yizhifu.enabled" label="易支付配置" :name="['yizhifu', 'accessId']" :required="true">
|
||||||
<access-selector v-model="formState.yizhifu.accessId" type="yizhifu" from="sys" />
|
<access-selector v-model="formState.yizhifu.accessId" type="yizhifu" from="sys" />
|
||||||
<div class="helper">
|
<div class="helper">
|
||||||
<a href="https://certd.docmirror.cn/comm/payments/yizhifu.html">彩虹易支付配置帮助文档</a>
|
<a href="https://certd.docmirror.cn/guide/use/comm/payments/yizhifu.html">彩虹易支付配置帮助文档</a>
|
||||||
</div>
|
</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="formState.alipay.enabled" label="支付宝配置" :name="['alipay', 'accessId']" :required="true">
|
<a-form-item v-if="formState.alipay.enabled" label="支付宝配置" :name="['alipay', 'accessId']" :required="true">
|
||||||
<access-selector v-model="formState.alipay.accessId" type="alipay" from="sys" />
|
<access-selector v-model="formState.alipay.accessId" type="alipay" from="sys" />
|
||||||
<div class="helper">需要开通电脑网站支付, <a href="https://certd.docmirror.cn/comm/payments/alipay.html">支付宝配置帮助文档</a></div>
|
<div class="helper">需要开通电脑网站支付, <a href="https://certd.docmirror.cn/guide/use/comm/payments/alipay.html">支付宝配置帮助文档</a></div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item label="微信支付" :name="['wxpay', 'enabled']" :required="true">
|
<a-form-item label="微信支付" :name="['wxpay', 'enabled']" :required="true">
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="formState.wxpay.enabled" label="微信支付配置" :name="['wxpay', 'accessId']" :required="true">
|
<a-form-item v-if="formState.wxpay.enabled" label="微信支付配置" :name="['wxpay', 'accessId']" :required="true">
|
||||||
<access-selector v-model="formState.wxpay.accessId" type="wxpay" from="sys" />
|
<access-selector v-model="formState.wxpay.accessId" type="wxpay" from="sys" />
|
||||||
<div class="helper">需要开通Native支付, <a href="https://certd.docmirror.cn/comm/payments/wxpay.html">微信配置帮助文档</a></div>
|
<div class="helper">需要开通Native支付, <a href="https://certd.docmirror.cn/guide/use/comm/payments/wxpay.html">微信配置帮助文档</a></div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item label=" " :colon="false" :wrapper-col="{ span: 16 }">
|
<a-form-item label=" " :colon="false" :wrapper-col="{ span: 16 }">
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
npm run heap
|
npm run heap
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
|
"esdk-obs-nodejs": "^3.25.6",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"glob": "^11.0.0",
|
"glob": "^11.0.0",
|
||||||
"https-proxy-agent": "^7.0.5",
|
"https-proxy-agent": "^7.0.5",
|
||||||
@@ -91,7 +92,6 @@
|
|||||||
"jsonwebtoken": "^9.0.0",
|
"jsonwebtoken": "^9.0.0",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"koa-send": "^5.0.1",
|
"koa-send": "^5.0.1",
|
||||||
"ksyun-sdk-node": "^1.2.4",
|
|
||||||
"kubernetes-client": "^9.0.0",
|
"kubernetes-client": "^9.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"log4js": "^6.7.1",
|
"log4js": "^6.7.1",
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/c
|
|||||||
import { merge } from 'lodash-es';
|
import { merge } from 'lodash-es';
|
||||||
import { CrudController } from '@certd/lib-server';
|
import { CrudController } from '@certd/lib-server';
|
||||||
import { PluginImportReq, PluginService } from "../../../modules/plugin/service/plugin-service.js";
|
import { PluginImportReq, PluginService } from "../../../modules/plugin/service/plugin-service.js";
|
||||||
import { CommPluginConfig, PluginConfigService } from '../../../modules/plugin/service/plugin-config-service.js';
|
import {
|
||||||
|
CommPluginConfig,
|
||||||
|
PluginConfig,
|
||||||
|
PluginConfigService
|
||||||
|
} from '../../../modules/plugin/service/plugin-config-service.js';
|
||||||
/**
|
/**
|
||||||
* 插件
|
* 插件
|
||||||
*/
|
*/
|
||||||
@@ -79,7 +83,11 @@ export class PluginController extends CrudController<PluginService> {
|
|||||||
const res = await this.pluginConfigService.saveCommPluginConfig(body);
|
const res = await this.pluginConfigService.saveCommPluginConfig(body);
|
||||||
return this.ok(res);
|
return this.ok(res);
|
||||||
}
|
}
|
||||||
|
@Post('/saveSetting', { summary: 'sys:settings:edit' })
|
||||||
|
async saveSetting(@Body(ALL) body: PluginConfig) {
|
||||||
|
const res = await this.pluginConfigService.savePluginConfig(body);
|
||||||
|
return this.ok(res);
|
||||||
|
}
|
||||||
|
|
||||||
@Post('/import', { summary: 'sys:settings:edit' })
|
@Post('/import', { summary: 'sys:settings:edit' })
|
||||||
async import(@Body(ALL) body: PluginImportReq) {
|
async import(@Body(ALL) body: PluginImportReq) {
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import { PluginService } from './plugin-service.js';
|
|||||||
|
|
||||||
export type PluginConfig = {
|
export type PluginConfig = {
|
||||||
name: string;
|
name: string;
|
||||||
disabled: boolean;
|
disabled?: boolean;
|
||||||
sysSetting: {
|
sysSetting: {
|
||||||
input?: Record<string, any>;
|
input?: Record<string, any>;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -37,10 +38,12 @@ export class PluginConfigService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async saveCommPluginConfig(config: CommPluginConfig) {
|
async saveCommPluginConfig(config: CommPluginConfig) {
|
||||||
await this.savePluginConfig('CertApply', config.CertApply);
|
config.CertApply.name = 'CertApply';
|
||||||
|
await this.savePluginConfig(config.CertApply);
|
||||||
}
|
}
|
||||||
|
|
||||||
async savePluginConfig(name: string, config: PluginConfig) {
|
async savePluginConfig( config: PluginConfig) {
|
||||||
|
const name = config.name;
|
||||||
const sysSetting = config?.sysSetting;
|
const sysSetting = config?.sysSetting;
|
||||||
if (!sysSetting) {
|
if (!sysSetting) {
|
||||||
throw new Error(`${name}.sysSetting is required`);
|
throw new Error(`${name}.sysSetting is required`);
|
||||||
@@ -57,7 +60,14 @@ export class PluginConfigService {
|
|||||||
author: "certd",
|
author: "certd",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await this.pluginService.getRepository().update({ name }, { sysSetting: JSON.stringify(sysSetting) });
|
let setting = JSON.parse(pluginEntity.sysSetting || "{}");
|
||||||
|
if (sysSetting.metadata) {
|
||||||
|
setting.metadata = sysSetting.metadata;
|
||||||
|
}
|
||||||
|
if (sysSetting.input) {
|
||||||
|
setting.input = sysSetting.input;
|
||||||
|
}
|
||||||
|
await this.pluginService.getRepository().update({ name }, { sysSetting: JSON.stringify(setting) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
import {Inject, Provide, Scope, ScopeEnum} from "@midwayjs/core";
|
||||||
import { BaseService, PageReq } from "@certd/lib-server";
|
import {BaseService, PageReq} from "@certd/lib-server";
|
||||||
import { PluginEntity } from "../entity/plugin.js";
|
import {PluginEntity} from "../entity/plugin.js";
|
||||||
import { InjectEntityModel } from "@midwayjs/typeorm";
|
import {InjectEntityModel} from "@midwayjs/typeorm";
|
||||||
import { Repository } from "typeorm";
|
import {IsNull, Not, Repository} from "typeorm";
|
||||||
import { isComm } from "@certd/plus-core";
|
import {isComm} from "@certd/plus-core";
|
||||||
import { BuiltInPluginService } from "../../pipeline/service/builtin-plugin-service.js";
|
import {BuiltInPluginService} from "../../pipeline/service/builtin-plugin-service.js";
|
||||||
import { merge } from "lodash-es";
|
import {merge} from "lodash-es";
|
||||||
import { accessRegistry, notificationRegistry, pluginRegistry } from "@certd/pipeline";
|
import {accessRegistry, notificationRegistry, pluginRegistry} from "@certd/pipeline";
|
||||||
import { dnsProviderRegistry } from "@certd/plugin-cert";
|
import {dnsProviderRegistry} from "@certd/plugin-cert";
|
||||||
import { logger } from "@certd/basic";
|
import {logger} from "@certd/basic";
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
import { getDefaultAccessPlugin, getDefaultDeployPlugin, getDefaultDnsPlugin } from "./default-plugin.js";
|
import {getDefaultAccessPlugin, getDefaultDeployPlugin, getDefaultDnsPlugin} from "./default-plugin.js";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
@@ -57,9 +57,9 @@ export class PluginService extends BaseService<PluginEntity> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async getEnabledBuildInGroup(isSimple = false) {
|
async getEnabledBuildInGroup(opts?:{isSimple?:boolean,withSetting?:boolean}) {
|
||||||
const groups = this.builtInPluginService.getGroups();
|
const groups = this.builtInPluginService.getGroups();
|
||||||
if (isSimple) {
|
if (opts?.isSimple) {
|
||||||
for (const key in groups) {
|
for (const key in groups) {
|
||||||
const group = groups[key];
|
const group = groups[key];
|
||||||
group.plugins.forEach(item => {
|
group.plugins.forEach(item => {
|
||||||
@@ -72,9 +72,43 @@ export class PluginService extends BaseService<PluginEntity> {
|
|||||||
if (!isComm()) {
|
if (!isComm()) {
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化设置
|
||||||
|
const settingPlugins = await this.repository.find({
|
||||||
|
select:{
|
||||||
|
id:true,
|
||||||
|
name:true,
|
||||||
|
sysSetting:true
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
sysSetting : Not(IsNull())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//合并插件配置
|
||||||
|
const pluginSettingMap:any = {}
|
||||||
|
for (const item of settingPlugins) {
|
||||||
|
if (!item.sysSetting) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pluginSettingMap[item.name] = JSON.parse(item.sysSetting);
|
||||||
|
}
|
||||||
|
for (const key in groups) {
|
||||||
|
const group = groups[key];
|
||||||
|
if (!group.plugins) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const item of group.plugins) {
|
||||||
|
const pluginSetting = pluginSettingMap[item.name];
|
||||||
|
if (pluginSetting){
|
||||||
|
item.sysSetting = pluginSetting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//排除禁用的
|
||||||
const list = await this.list({
|
const list = await this.list({
|
||||||
query: {
|
query: {
|
||||||
type: "builtIn",
|
|
||||||
disabled: true
|
disabled: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,272 @@
|
|||||||
|
import {AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput} from '@certd/pipeline';
|
||||||
|
import {
|
||||||
|
AliyunAccess,
|
||||||
|
AliyunSslClient,
|
||||||
|
createCertDomainGetterInputDefine,
|
||||||
|
createRemoteSelectInputDefine
|
||||||
|
} from "@certd/plugin-lib";
|
||||||
|
import { CertApplyPluginNames, CertInfo, CertReader } from "@certd/plugin-cert";
|
||||||
|
import {optionsUtils} from "@certd/basic/dist/utils/util.options.js";
|
||||||
|
|
||||||
|
@IsTaskPlugin({
|
||||||
|
name: 'DeployCertToAliyunApig',
|
||||||
|
title: '阿里云-部署至云原生API网关/AI网关',
|
||||||
|
icon: 'svg:icon-aliyun',
|
||||||
|
group: pluginGroups.aliyun.key,
|
||||||
|
desc: '自动部署域名证书至云原生API网关、AI网关',
|
||||||
|
default: {
|
||||||
|
strategy: {
|
||||||
|
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export class DeployCertToAliyunApig extends AbstractTaskPlugin {
|
||||||
|
@TaskInput({
|
||||||
|
title: '域名证书',
|
||||||
|
helper: '请选择前置任务输出的域名证书',
|
||||||
|
component: {
|
||||||
|
name: 'output-selector',
|
||||||
|
from: [...CertApplyPluginNames, 'uploadCertToAliyun'],
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
cert!: CertInfo | string;
|
||||||
|
|
||||||
|
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||||
|
certDomains!: string[];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@TaskInput({
|
||||||
|
title: 'Access授权',
|
||||||
|
helper: '阿里云授权',
|
||||||
|
component: {
|
||||||
|
name: 'access-selector',
|
||||||
|
type: 'aliyun',
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
accessId!: string;
|
||||||
|
|
||||||
|
@TaskInput(
|
||||||
|
createRemoteSelectInputDefine({
|
||||||
|
title: '区域',
|
||||||
|
helper: '请选择区域',
|
||||||
|
action: DeployCertToAliyunApig.prototype.onGetRegionList.name,
|
||||||
|
watches: ['certDomains', 'accessId'],
|
||||||
|
required: true,
|
||||||
|
component:{
|
||||||
|
name:"remote-auto-complete"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
regionEndpoint!: string;
|
||||||
|
|
||||||
|
|
||||||
|
@TaskInput({
|
||||||
|
title: "网关类型",
|
||||||
|
component: {
|
||||||
|
name: "a-select",
|
||||||
|
vModel:"value",
|
||||||
|
options:[
|
||||||
|
{value:"AI",label:"AI"},
|
||||||
|
{value:"API",label:"API"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
required: true //必填
|
||||||
|
})
|
||||||
|
gatewayType!: string;
|
||||||
|
|
||||||
|
|
||||||
|
@TaskInput(
|
||||||
|
createRemoteSelectInputDefine({
|
||||||
|
title: '绑定域名',
|
||||||
|
helper: '请选择域名',
|
||||||
|
action: DeployCertToAliyunApig.prototype.onGetDomainList.name,
|
||||||
|
watches: ['region', 'accessId','gatewayType'],
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
domainList!: string[];
|
||||||
|
|
||||||
|
|
||||||
|
@TaskInput({
|
||||||
|
title: "强制HTTPS",
|
||||||
|
component: {
|
||||||
|
name: "a-select",
|
||||||
|
vModel:"value",
|
||||||
|
options:[
|
||||||
|
{value:true,label:"强制HTTPS"},
|
||||||
|
{value:false,label:"不强制HTTPS"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
required: true //必填
|
||||||
|
})
|
||||||
|
forceHttps!: boolean;
|
||||||
|
|
||||||
|
@TaskInput({
|
||||||
|
title: '证书服务接入点',
|
||||||
|
helper: '不会选就按默认',
|
||||||
|
value: 'cn-hangzhou',
|
||||||
|
component: {
|
||||||
|
name: 'a-select',
|
||||||
|
options: [
|
||||||
|
{ value: 'cn-hangzhou', label: '中国大陆' },
|
||||||
|
{ value: 'ap-southeast-1', label: '新加坡' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
casRegion!: string;
|
||||||
|
|
||||||
|
|
||||||
|
async onInstance() {}
|
||||||
|
async execute(): Promise<void> {
|
||||||
|
this.logger.info('开始部署证书到云原生Api网关');
|
||||||
|
if(!this.domainList){
|
||||||
|
throw new Error('您还未选择域名');
|
||||||
|
}
|
||||||
|
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||||||
|
const client = access.getClient(this.regionEndpoint)
|
||||||
|
|
||||||
|
|
||||||
|
let certId: any = this.cert;
|
||||||
|
if (typeof this.cert === 'object') {
|
||||||
|
const sslClient = new AliyunSslClient({
|
||||||
|
access,
|
||||||
|
logger: this.logger,
|
||||||
|
region: this.casRegion,
|
||||||
|
});
|
||||||
|
|
||||||
|
certId = await sslClient.uploadCert({
|
||||||
|
name: this.buildCertName(CertReader.getMainDomain(this.cert.crt)),
|
||||||
|
cert: this.cert,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const certIdentify = `${certId}-${this.casRegion}`
|
||||||
|
|
||||||
|
for (const domainId of this.domainList ) {
|
||||||
|
this.logger.info(`[${domainId}]开始部署`)
|
||||||
|
await this.updateCert(client, domainId,certIdentify);
|
||||||
|
this.logger.info(`[${domainId}]部署成功`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.info('部署完成');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async updateCert(client: any, domainId: string,certIdentify:string) {
|
||||||
|
|
||||||
|
const domainInfoRes = await client.doRequest({
|
||||||
|
action: "GetDomain",
|
||||||
|
version: "2024-03-27",
|
||||||
|
protocol: "HTTPS",
|
||||||
|
method: "GET",
|
||||||
|
authType: "AK",
|
||||||
|
style: "ROA",
|
||||||
|
pathname: `/v1/domains/${domainId}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tlsCipherSuitesConfig = domainInfoRes.data?.tlsCipherSuitesConfig
|
||||||
|
|
||||||
|
|
||||||
|
const ret = await client.doRequest({
|
||||||
|
action: "UpdateDomain",
|
||||||
|
version: "2024-03-27",
|
||||||
|
method: "PUT",
|
||||||
|
style: "ROA",
|
||||||
|
pathname: `/v1/domains/${domainId}`,
|
||||||
|
data:{
|
||||||
|
body:{
|
||||||
|
certIdentifier: certIdentify,
|
||||||
|
protocol: "HTTPS",
|
||||||
|
forceHttps:this.forceHttps,
|
||||||
|
tlsCipherSuitesConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.logger.info(`设置${domainId}证书成功:`, ret.requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async onGetDomainList(data: any) {
|
||||||
|
if (!this.accessId) {
|
||||||
|
throw new Error('请选择Access授权');
|
||||||
|
}
|
||||||
|
if (!this.regionEndpoint) {
|
||||||
|
throw new Error('请选择区域');
|
||||||
|
}
|
||||||
|
if (!this.gatewayType) {
|
||||||
|
throw new Error('请选择网关类型');
|
||||||
|
}
|
||||||
|
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||||||
|
|
||||||
|
const client = access.getClient(this.regionEndpoint)
|
||||||
|
|
||||||
|
const res =await client.doRequest({
|
||||||
|
action: "ListDomains",
|
||||||
|
version: "2024-03-27",
|
||||||
|
method: "GET",
|
||||||
|
style: "ROA",
|
||||||
|
pathname: `/v1/domains`,
|
||||||
|
data:{
|
||||||
|
query:{
|
||||||
|
pageSize: 100,
|
||||||
|
gatewayType: this.gatewayType ,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const list = res?.data?.items;
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const options = list.map((item: any) => {
|
||||||
|
return {
|
||||||
|
value: item.domainId,
|
||||||
|
label: `${item.name}<${item.domainId}>`,
|
||||||
|
domain: item.name,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return optionsUtils.buildGroupOptions(options, this.certDomains);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async onGetRegionList(data: any) {
|
||||||
|
const list = [
|
||||||
|
{value:"cn-qingdao",label:"华北1(青岛)",endpoint:"apig.cn-qingdao.aliyuncs.com"},
|
||||||
|
{value:"cn-beijing",label:"华北2(北京)",endpoint:"apig.cn-beijing.aliyuncs.com"},
|
||||||
|
{value:"cn-zhangjiakou",label:"华北3(张家口)",endpoint:"apig.cn-zhangjiakou.aliyuncs.com"},
|
||||||
|
{value:"cn-wulanchabu",label:"华北6(乌兰察布)",endpoint:"apig.cn-wulanchabu.aliyuncs.com"},
|
||||||
|
{value:"cn-hangzhou",label:"华东1(杭州)",endpoint:"apig.cn-hangzhou.aliyuncs.com"},
|
||||||
|
{value:"cn-shanghai",label:"华东2(上海)",endpoint:"apig.cn-shanghai.aliyuncs.com"},
|
||||||
|
{value:"cn-shenzhen",label:"华南1(深圳)",endpoint:"apig.cn-shenzhen.aliyuncs.com"},
|
||||||
|
{value:"cn-heyuan",label:"华南2(河源)",endpoint:"apig.cn-heyuan.aliyuncs.com"},
|
||||||
|
{value:"cn-guangzhou",label:"华南3(广州)",endpoint:"apig.cn-guangzhou.aliyuncs.com"},
|
||||||
|
{value:"ap-southeast-2",label:"澳大利亚(悉尼)已关停",endpoint:"apig.ap-southeast-2.aliyuncs.com"},
|
||||||
|
{value:"ap-southeast-6",label:"菲律宾(马尼拉)",endpoint:"apig.ap-southeast-6.aliyuncs.com"},
|
||||||
|
{value:"ap-northeast-2",label:"韩国(首尔)",endpoint:"apig.ap-northeast-2.aliyuncs.com"},
|
||||||
|
{value:"ap-southeast-3",label:"马来西亚(吉隆坡)",endpoint:"apig.ap-southeast-3.aliyuncs.com"},
|
||||||
|
{value:"ap-northeast-1",label:"日本(东京)",endpoint:"apig.ap-northeast-1.aliyuncs.com"},
|
||||||
|
{value:"ap-southeast-7",label:"泰国(曼谷)",endpoint:"apig.ap-southeast-7.aliyuncs.com"},
|
||||||
|
{value:"cn-chengdu",label:"西南1(成都)",endpoint:"apig.cn-chengdu.aliyuncs.com"},
|
||||||
|
{value:"ap-southeast-1",label:"新加坡",endpoint:"apig.ap-southeast-1.aliyuncs.com"},
|
||||||
|
{value:"ap-southeast-5",label:"印度尼西亚(雅加达)",endpoint:"apig.ap-southeast-5.aliyuncs.com"},
|
||||||
|
{value:"cn-hongkong",label:"中国香港",endpoint:"apig.cn-hongkong.aliyuncs.com"},
|
||||||
|
{value:"eu-central-1",label:"德国(法兰克福)",endpoint:"apig.eu-central-1.aliyuncs.com"},
|
||||||
|
{value:"us-east-1",label:"美国(弗吉尼亚)",endpoint:"apig.us-east-1.aliyuncs.com"},
|
||||||
|
{value:"us-west-1",label:"美国(硅谷)",endpoint:"apig.us-west-1.aliyuncs.com"},
|
||||||
|
{value:"eu-west-1",label:"英国(伦敦)",endpoint:"apig.eu-west-1.aliyuncs.com"},
|
||||||
|
{value:"me-east-1",label:"阿联酋(迪拜)",endpoint:"apig.me-east-1.aliyuncs.com"},
|
||||||
|
{value:"me-central-1",label:"沙特(利雅得)",endpoint:"apig.me-central-1.aliyuncs.com"},
|
||||||
|
]
|
||||||
|
return list.map((item: any) => {
|
||||||
|
return {
|
||||||
|
value: item.endpoint,
|
||||||
|
label: item.label,
|
||||||
|
endpoint: item.endpoint,
|
||||||
|
regionId : item.value
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new DeployCertToAliyunApig();
|
||||||
@@ -10,3 +10,4 @@ export * from './deploy-to-fc/index.js';
|
|||||||
export * from './deploy-to-esa/index.js';
|
export * from './deploy-to-esa/index.js';
|
||||||
export * from './deploy-to-vod/index.js';
|
export * from './deploy-to-vod/index.js';
|
||||||
export * from './deploy-to-apigateway/index.js';
|
export * from './deploy-to-apigateway/index.js';
|
||||||
|
export * from './deploy-to-apig/index.js';
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ import { CertApplyPluginNames, CertReader } from "@certd/plugin-cert";
|
|||||||
*/
|
*/
|
||||||
const regionDict = [
|
const regionDict = [
|
||||||
{ value: 'cn-hangzhou', endpoint: 'cas.aliyuncs.com', label: 'cn-hangzhou-中国大陆' },
|
{ value: 'cn-hangzhou', endpoint: 'cas.aliyuncs.com', label: 'cn-hangzhou-中国大陆' },
|
||||||
{ value: 'eu-central-1', endpoint: 'cas.eu-central-1.aliyuncs.com', label: 'eu-central-1-德国(法兰克福)' },
|
|
||||||
{ value: 'ap-southeast-1', endpoint: 'cas.ap-southeast-1.aliyuncs.com', label: 'ap-southeast-1-新加坡(国际版选这个)' },
|
{ value: 'ap-southeast-1', endpoint: 'cas.ap-southeast-1.aliyuncs.com', label: 'ap-southeast-1-新加坡(国际版选这个)' },
|
||||||
|
{ value: 'private-', endpoint: '', disabled:true, label: '以下是私有证书区域' },
|
||||||
|
{ value: 'eu-central-1', endpoint: 'cas.eu-central-1.aliyuncs.com', label: 'eu-central-1-德国(法兰克福)' },
|
||||||
{ value: 'ap-southeast-3', endpoint: 'cas.ap-southeast-3.aliyuncs.com', label: 'ap-southeast-3-马来西亚(吉隆坡)' },
|
{ value: 'ap-southeast-3', endpoint: 'cas.ap-southeast-3.aliyuncs.com', label: 'ap-southeast-3-马来西亚(吉隆坡)' },
|
||||||
{ value: 'ap-southeast-5', endpoint: 'cas.ap-southeast-5.aliyuncs.com', label: 'ap-southeast-5-印度尼西亚(雅加达)' },
|
{ value: 'ap-southeast-5', endpoint: 'cas.ap-southeast-5.aliyuncs.com', label: 'ap-southeast-5-印度尼西亚(雅加达)' },
|
||||||
{ value: 'cn-hongkong', endpoint: 'cas.cn-hongkong.aliyuncs.com', label: 'cn-hongkong-中国香港' },
|
{ value: 'cn-hongkong', endpoint: 'cas.cn-hongkong.aliyuncs.com', label: 'cn-hongkong-中国香港' },
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type DemoRecord = {
|
|||||||
icon: 'clarity:plugin-line',
|
icon: 'clarity:plugin-line',
|
||||||
// 这里是对应的云平台的access类型名称
|
// 这里是对应的云平台的access类型名称
|
||||||
accessType: 'demo',
|
accessType: 'demo',
|
||||||
|
order:99,
|
||||||
})
|
})
|
||||||
export class DemoDnsProvider extends AbstractDnsProvider<DemoRecord> {
|
export class DemoDnsProvider extends AbstractDnsProvider<DemoRecord> {
|
||||||
access!: DemoAccess;
|
access!: DemoAccess;
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||||||
{ value: 'der', label: 'der,一般用于Apache' },
|
{ value: 'der', label: 'der,一般用于Apache' },
|
||||||
{ value: 'jks', label: 'jks,一般用于JAVA应用' },
|
{ value: 'jks', label: 'jks,一般用于JAVA应用' },
|
||||||
{ value: 'one', label: '证书私钥一体,crt+key简单合并为一个pem文件' },
|
{ value: 'one', label: '证书私钥一体,crt+key简单合并为一个pem文件' },
|
||||||
|
{ value: 'p7b', label: 'p7b格式' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
required: true,
|
required: true,
|
||||||
@@ -71,7 +72,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||||||
mergeScript: `
|
mergeScript: `
|
||||||
return {
|
return {
|
||||||
show: ctx.compute(({form})=>{
|
show: ctx.compute(({form})=>{
|
||||||
return form.certType === 'pem';
|
return form.certType === 'pem' || form.certType === 'p7b' ;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -169,6 +170,24 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||||||
})
|
})
|
||||||
onePath!: string;
|
onePath!: string;
|
||||||
|
|
||||||
|
@TaskInput({
|
||||||
|
title: 'p7b证书保存路径',
|
||||||
|
helper: '填写应用原本的证书保存路径,路径要包含证书文件名,例如:/tmp/domain_cert.p7b',
|
||||||
|
component: {
|
||||||
|
placeholder: '/root/deploy/app/domain_cert.p7b',
|
||||||
|
},
|
||||||
|
mergeScript: `
|
||||||
|
return {
|
||||||
|
show: ctx.compute(({form})=>{
|
||||||
|
return form.certType === 'p7b';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
required: true,
|
||||||
|
rules: [{ type: 'filepath' }],
|
||||||
|
})
|
||||||
|
p7bPath!: string;
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: '主机登录配置',
|
title: '主机登录配置',
|
||||||
helper: 'access授权',
|
helper: 'access授权',
|
||||||
@@ -277,12 +296,17 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||||||
})
|
})
|
||||||
hostOnePath!: string;
|
hostOnePath!: string;
|
||||||
|
|
||||||
|
@TaskOutput({
|
||||||
|
title: 'p7b证书保存路径',
|
||||||
|
})
|
||||||
|
hostP7bPath!: string;
|
||||||
|
|
||||||
async onInstance() {}
|
async onInstance() {}
|
||||||
|
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
const { cert, accessId } = this;
|
const { cert, accessId } = this;
|
||||||
let { crtPath, keyPath, icPath, pfxPath, derPath, jksPath, onePath } = this;
|
let { crtPath, keyPath, icPath, pfxPath, derPath, jksPath, onePath,p7bPath } = this;
|
||||||
const certReader = new CertReader(cert);
|
const certReader = new CertReader(cert);
|
||||||
|
|
||||||
const executeCmd = async ( script:string)=> {
|
const executeCmd = async ( script:string)=> {
|
||||||
@@ -308,6 +332,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||||||
env['HOST_DER_PATH'] = this.hostDerPath || '';
|
env['HOST_DER_PATH'] = this.hostDerPath || '';
|
||||||
env['HOST_JKS_PATH'] = this.hostJksPath || '';
|
env['HOST_JKS_PATH'] = this.hostJksPath || '';
|
||||||
env['HOST_ONE_PATH'] = this.hostOnePath || '';
|
env['HOST_ONE_PATH'] = this.hostOnePath || '';
|
||||||
|
env['HOST_P7B_PATH'] = this.hostOnePath || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const scripts = script.split('\n');
|
const scripts = script.split('\n');
|
||||||
@@ -320,7 +345,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handle = async (opts: CertReaderHandleContext) => {
|
const handle = async (opts: CertReaderHandleContext) => {
|
||||||
const { tmpCrtPath, tmpKeyPath, tmpDerPath, tmpJksPath, tmpPfxPath, tmpIcPath, tmpOnePath } = opts;
|
const { tmpCrtPath, tmpKeyPath, tmpDerPath, tmpJksPath, tmpPfxPath, tmpIcPath, tmpOnePath ,tmpP7bPath} = opts;
|
||||||
|
|
||||||
if (accessId == null) {
|
if (accessId == null) {
|
||||||
this.logger.error('复制到当前主机功能已迁移到 “复制到本机”插件,请换成复制到本机插件');
|
this.logger.error('复制到当前主机功能已迁移到 “复制到本机”插件,请换成复制到本机插件');
|
||||||
@@ -392,6 +417,14 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||||||
remotePath: this.onePath,
|
remotePath: this.onePath,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (this.p7bPath) {
|
||||||
|
this.logger.info(`上传p7b证书到主机:${this.p7bPath}`);
|
||||||
|
p7bPath = this.p7bPath.trim();
|
||||||
|
transports.push({
|
||||||
|
localPath: tmpP7bPath,
|
||||||
|
remotePath: this.p7bPath,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.info('开始上传文件到服务器');
|
this.logger.info('开始上传文件到服务器');
|
||||||
await sshClient.uploadFiles({
|
await sshClient.uploadFiles({
|
||||||
@@ -410,6 +443,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||||||
this.hostDerPath = derPath;
|
this.hostDerPath = derPath;
|
||||||
this.hostJksPath = jksPath;
|
this.hostJksPath = jksPath;
|
||||||
this.hostOnePath = onePath;
|
this.hostOnePath = onePath;
|
||||||
|
this.hostP7bPath = p7bPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
//执行前置命令
|
//执行前置命令
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { IsAccess, AccessInput, BaseAccess } from '@certd/pipeline';
|
|||||||
title: '华为云授权',
|
title: '华为云授权',
|
||||||
desc: '',
|
desc: '',
|
||||||
icon: 'svg:icon-huawei',
|
icon: 'svg:icon-huawei',
|
||||||
|
order: 0,
|
||||||
})
|
})
|
||||||
export class HuaweiAccess extends BaseAccess {
|
export class HuaweiAccess extends BaseAccess {
|
||||||
@AccessInput({
|
@AccessInput({
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||||
|
import { HuaweiAccess } from "../../access/index.js";
|
||||||
|
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
|
||||||
|
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
|
||||||
|
|
||||||
|
@IsTaskPlugin({
|
||||||
|
name: 'HauweiDeployCertToOBS',
|
||||||
|
title: '华为云-部署证书至OBS',
|
||||||
|
icon: 'svg:icon-huawei',
|
||||||
|
group: pluginGroups.huawei.key,
|
||||||
|
desc: '',
|
||||||
|
default: {
|
||||||
|
strategy: {
|
||||||
|
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export class HauweiDeployCertToOBS extends AbstractTaskPlugin {
|
||||||
|
@TaskInput({
|
||||||
|
title: '域名证书',
|
||||||
|
helper: '请选择前置任务输出的域名证书\n如果你选择使用ccm证书ID,则需要在[域名管理页面右上角开启SCM授权](https://console.huaweicloud.com/cdn/#/cdn/domain)',
|
||||||
|
component: {
|
||||||
|
name: 'output-selector',
|
||||||
|
from: [...CertApplyPluginNames,'HauweiUploadToCCM'],
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
cert!: CertInfo | string;
|
||||||
|
|
||||||
|
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||||
|
certDomains!: string[];
|
||||||
|
|
||||||
|
@TaskInput({
|
||||||
|
title: 'Access授权',
|
||||||
|
helper: '华为云授权AccessKeyId、AccessKeySecret',
|
||||||
|
component: {
|
||||||
|
name: 'access-selector',
|
||||||
|
type: 'huawei',
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
accessId!: string;
|
||||||
|
|
||||||
|
|
||||||
|
@TaskInput(
|
||||||
|
createRemoteSelectInputDefine({
|
||||||
|
title: '存储桶',
|
||||||
|
helper: '请选择存储桶',
|
||||||
|
action: HauweiDeployCertToOBS.prototype.onGetBucketList.name,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
bucketList!: string[];
|
||||||
|
|
||||||
|
@TaskInput(
|
||||||
|
createRemoteSelectInputDefine({
|
||||||
|
title: '自定义域名',
|
||||||
|
helper: '请选择自定义域名',
|
||||||
|
action: HauweiDeployCertToOBS.prototype.onGetDomainList.name,
|
||||||
|
watches: ['bucketList'],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
domainList!: string[];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async execute(): Promise<void> {
|
||||||
|
if (!this.cert) {
|
||||||
|
throw new Error('域名证书不能为空');
|
||||||
|
}
|
||||||
|
this.logger.info('开始部署证书到华为云obs');
|
||||||
|
|
||||||
|
for (const domainStr of this.domainList) {
|
||||||
|
const [location, bucket,domain] = domainStr.split('_');
|
||||||
|
|
||||||
|
await this.setDomainCert({
|
||||||
|
location,
|
||||||
|
bucket,
|
||||||
|
domain,
|
||||||
|
cert: this.cert
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.info('部署证书到华为云cdn完成');
|
||||||
|
}
|
||||||
|
|
||||||
|
checkRet(ret: any){
|
||||||
|
if (ret?.CommonMsg?.Status>300){
|
||||||
|
|
||||||
|
throw new Error(`【${ret?.CommonMsg?.Code}】${ret?.CommonMsg?.Message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async getObsClient(opts:{region?:string,bucket?:string} = {}) {
|
||||||
|
const { region,bucket } = opts;
|
||||||
|
const regionStr = region? `${region}.`: 'cn-north-4.';
|
||||||
|
const bucketStr = bucket? `${bucket}.` : '';
|
||||||
|
const access = await this.getAccess<HuaweiAccess>(this.accessId);
|
||||||
|
const sdk = await import('esdk-obs-nodejs');
|
||||||
|
const obsClient = new sdk.default({
|
||||||
|
// 推荐通过环境变量获取AKSK,这里也可以使用其他外部引入方式传入,如果使用硬编码可能会存在泄露风险
|
||||||
|
// 您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
|
||||||
|
access_key_id: access.accessKeyId,
|
||||||
|
secret_access_key: access.accessKeySecret,
|
||||||
|
// 【可选】如果使用临时AK/SK和SecurityToken访问OBS,同样建议您尽量避免使用硬编码,以降低信息泄露风险。您可以通过环境变量获取访问密钥AK/SK,也可以使用其他外部引入方式传入
|
||||||
|
// security_token: process.env.SECURITY_TOKEN,
|
||||||
|
// endpoint填写Bucket对应的Endpoint, 这里以华北-北京四为例,其他地区请按实际情况填写
|
||||||
|
server: `https://${bucketStr}obs.${regionStr}myhuaweicloud.com`,
|
||||||
|
});
|
||||||
|
return obsClient
|
||||||
|
}
|
||||||
|
|
||||||
|
async onGetBucketList(data: any) {
|
||||||
|
const obsClient = await this.getObsClient();
|
||||||
|
const res = await obsClient.listBuckets({
|
||||||
|
QueryLocation:true
|
||||||
|
})
|
||||||
|
|
||||||
|
this.checkRet(res)
|
||||||
|
|
||||||
|
const list = res.InterfaceResult?.Buckets
|
||||||
|
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.map(item => {
|
||||||
|
return {
|
||||||
|
value: `${item.Location}_${item.BucketName}`,
|
||||||
|
label: `${item.BucketName}<${item.Location}>`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async onGetDomainList(data:any) {
|
||||||
|
if (!this.bucketList || this.bucketList.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const optionList = []
|
||||||
|
for (const item of this.bucketList) {
|
||||||
|
const [location,bucket] = item.split('_')
|
||||||
|
|
||||||
|
const obsClient = await this.getObsClient({region:location});
|
||||||
|
const res = await obsClient.getBucketCustomDomain({
|
||||||
|
Bucket: bucket,
|
||||||
|
})
|
||||||
|
this.checkRet(res)
|
||||||
|
|
||||||
|
const list = res.InterfaceResult?.Domains
|
||||||
|
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const options= list.map(item => {
|
||||||
|
return {
|
||||||
|
value: `${location}_${bucket}_${item.DomainName}`,
|
||||||
|
label: `${item.DomainName}<${bucket}_${location}>`,
|
||||||
|
domain: item.DomainName,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
optionList.push(...options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.ctx.utils.options.buildGroupOptions( optionList,this.certDomains)
|
||||||
|
}
|
||||||
|
|
||||||
|
async setDomainCert(opts:{location:string,bucket:string,domain:string,cert:string|CertInfo}){
|
||||||
|
const {location,bucket,domain,cert} = opts
|
||||||
|
const obsClient = await this.getObsClient({region:location});
|
||||||
|
const params:any = {
|
||||||
|
Bucket: bucket,
|
||||||
|
DomainName: domain,
|
||||||
|
Name: this.buildCertName( domain)
|
||||||
|
};
|
||||||
|
if (typeof cert === 'string'){
|
||||||
|
params.CertificateId= cert
|
||||||
|
}else{
|
||||||
|
params.Certificate= cert.crt
|
||||||
|
params.PrivateKey = cert.key
|
||||||
|
}
|
||||||
|
const res = await obsClient.setBucketCustomDomain(params)
|
||||||
|
this.checkRet(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new HauweiDeployCertToOBS();
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './deploy-to-cdn/index.js'
|
export * from './deploy-to-cdn/index.js'
|
||||||
export * from './upload-to-ccm/index.js'
|
export * from './upload-to-ccm/index.js'
|
||||||
|
export * from './deploy-to-obs/index.js'
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {AccessInput, BaseAccess, IsAccess} from '@certd/pipeline';
|
|||||||
title: '京东云',
|
title: '京东云',
|
||||||
desc: '',
|
desc: '',
|
||||||
icon: 'svg:icon-jdcloud',
|
icon: 'svg:icon-jdcloud',
|
||||||
|
order: 1,
|
||||||
})
|
})
|
||||||
export class JDCloudAccess extends BaseAccess {
|
export class JDCloudAccess extends BaseAccess {
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import { JDCloudAccess } from "./access.js";
|
|||||||
title: "京东云",
|
title: "京东云",
|
||||||
desc: "京东云DNS解析提供商",
|
desc: "京东云DNS解析提供商",
|
||||||
accessType: "jdcloud",
|
accessType: "jdcloud",
|
||||||
icon: "svg:icon-jdcloud"
|
icon: "svg:icon-jdcloud",
|
||||||
|
order:3,
|
||||||
})
|
})
|
||||||
export class JDCloudDnsProvider extends AbstractDnsProvider {
|
export class JDCloudDnsProvider extends AbstractDnsProvider {
|
||||||
access!: JDCloudAccess;
|
access!: JDCloudAccess;
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import { CertInfo } from "@certd/plugin-cert";
|
|||||||
name: "rainyun",
|
name: "rainyun",
|
||||||
title: "雨云授权",
|
title: "雨云授权",
|
||||||
desc: "https://app.rainyun.com/",
|
desc: "https://app.rainyun.com/",
|
||||||
icon: "svg:icon-lucky"
|
icon: "svg:icon-lucky",
|
||||||
|
order: 100
|
||||||
})
|
})
|
||||||
export class RainyunAccess extends BaseAccess {
|
export class RainyunAccess extends BaseAccess {
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { RainyunAccess } from "./access.js";
|
|||||||
desc: "雨云DNS解析提供商",
|
desc: "雨云DNS解析提供商",
|
||||||
accessType: "rainyun",
|
accessType: "rainyun",
|
||||||
icon: "svg:icon-lucky",
|
icon: "svg:icon-lucky",
|
||||||
order: 0
|
|
||||||
})
|
})
|
||||||
export class RainyunDnsProvider extends AbstractDnsProvider {
|
export class RainyunDnsProvider extends AbstractDnsProvider {
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ export class DeployCertToTencentAll extends AbstractTaskPlugin {
|
|||||||
region: this.region,
|
region: this.region,
|
||||||
profile: {
|
profile: {
|
||||||
httpProfile: {
|
httpProfile: {
|
||||||
endpoint: 'ssl.tencentcloudapi.com',
|
endpoint: `ssl.${access.intlDomain()}tencentcloudapi.com`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export class TencentDeployCertToCDNv2 extends AbstractTaskPlugin {
|
|||||||
region: '',
|
region: '',
|
||||||
profile: {
|
profile: {
|
||||||
httpProfile: {
|
httpProfile: {
|
||||||
endpoint: 'cdn.tencentcloudapi.com',
|
endpoint: `cdn.${accessProvider.intlDomain()}tencentcloudapi.com`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export class DeployToCdnPlugin extends AbstractTaskPlugin {
|
|||||||
region: '',
|
region: '',
|
||||||
profile: {
|
profile: {
|
||||||
httpProfile: {
|
httpProfile: {
|
||||||
endpoint: 'cdn.tencentcloudapi.com',
|
endpoint: `cdn.${accessProvider.intlDomain()}tencentcloudapi.com`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ export class DeployCertToTencentCLB extends AbstractTaskPlugin {
|
|||||||
region: region,
|
region: region,
|
||||||
profile: {
|
profile: {
|
||||||
httpProfile: {
|
httpProfile: {
|
||||||
endpoint: 'clb.tencentcloudapi.com',
|
endpoint: `clb.${accessProvider.intlDomain()}tencentcloudapi.com`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
import {AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput} from "@certd/pipeline";
|
||||||
import { TencentAccess } from "@certd/plugin-lib";
|
import {
|
||||||
|
createCertDomainGetterInputDefine,
|
||||||
|
createRemoteSelectInputDefine,
|
||||||
|
TencentAccess,
|
||||||
|
TencentSslClient
|
||||||
|
} from "@certd/plugin-lib";
|
||||||
|
import {CertApplyPluginNames, CertInfo, CertReader} from "@certd/plugin-cert";
|
||||||
|
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'DeployCertToTencentEO',
|
name: 'DeployCertToTencentEO',
|
||||||
@@ -14,16 +20,21 @@ import { TencentAccess } from "@certd/plugin-lib";
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
export class DeployCertToTencentEO extends AbstractTaskPlugin {
|
export class DeployCertToTencentEO extends AbstractTaskPlugin {
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: '已上传证书ID',
|
title: '域名证书',
|
||||||
helper: '请选择前置任务上传到腾讯云的证书',
|
helper: '请选择前置任务输出的域名证书,或者选择前置任务“上传证书到腾讯云”任务的证书ID',
|
||||||
component: {
|
component: {
|
||||||
name: 'output-selector',
|
name: 'output-selector',
|
||||||
from: 'UploadCertToTencent',
|
from: [...CertApplyPluginNames, 'UploadCertToTencent'],
|
||||||
},
|
},
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
certId!: string;
|
cert!: CertInfo | string;
|
||||||
|
|
||||||
|
|
||||||
|
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||||
|
certDomains!: string[];
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: 'Access提供者',
|
title: 'Access提供者',
|
||||||
@@ -36,31 +47,35 @@ export class DeployCertToTencentEO extends AbstractTaskPlugin {
|
|||||||
})
|
})
|
||||||
accessId!: string;
|
accessId!: string;
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput(createRemoteSelectInputDefine({
|
||||||
title: '站点ID',
|
title: '站点ID',
|
||||||
helper: '类似于zone-xxxx的字符串,在站点概览页面左上角,或者,站点列表页面站点名称下方',
|
helper: '类似于zone-xxxx的字符串,在站点概览页面左上角,或者,站点列表页面站点名称下方',
|
||||||
|
action: DeployCertToTencentEO.prototype.onGetZoneList.name,
|
||||||
|
watches: ['certDomains', 'accessId'],
|
||||||
required: true,
|
required: true,
|
||||||
})
|
component:{
|
||||||
|
name:"remote-auto-complete"
|
||||||
|
}
|
||||||
|
}))
|
||||||
zoneId!: string;
|
zoneId!: string;
|
||||||
|
|
||||||
|
@TaskInput(
|
||||||
|
createRemoteSelectInputDefine({
|
||||||
|
title: '加速域名',
|
||||||
|
helper: '请选择域名或输入域名',
|
||||||
|
action: DeployCertToTencentEO.prototype.onGetDomainList.name,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
domainNames!: string[];
|
||||||
|
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: '证书名称',
|
title: '证书名称',
|
||||||
helper: '证书上传后将以此参数作为名称前缀',
|
helper: '证书上传后将以此参数作为名称前缀',
|
||||||
})
|
})
|
||||||
certName!: string;
|
certName!: string;
|
||||||
|
|
||||||
@TaskInput({
|
|
||||||
title: 'cdn加速域名',
|
|
||||||
component: {
|
|
||||||
name: 'a-select',
|
|
||||||
vModel: 'value',
|
|
||||||
mode: 'tags',
|
|
||||||
open: false,
|
|
||||||
},
|
|
||||||
helper: '支持多个域名',
|
|
||||||
rules: [{ required: true, message: '该项必填' }],
|
|
||||||
})
|
|
||||||
domainNames!: string[];
|
|
||||||
|
|
||||||
// @TaskInput({
|
// @TaskInput({
|
||||||
// title: "CDN接口",
|
// title: "CDN接口",
|
||||||
@@ -80,16 +95,41 @@ export class DeployCertToTencentEO extends AbstractTaskPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
const accessProvider: TencentAccess = (await this.getAccess(this.accessId)) as TencentAccess;
|
const accessProvider = await this.getAccess<TencentAccess>(this.accessId)
|
||||||
const client = this.getClient(accessProvider);
|
const client = this.getClient(accessProvider);
|
||||||
const params = this.buildParams();
|
|
||||||
|
const sslClient = new TencentSslClient({
|
||||||
|
access:accessProvider,
|
||||||
|
logger: this.logger,
|
||||||
|
});
|
||||||
|
|
||||||
|
let tencentCertId = this.cert as string;
|
||||||
|
if (typeof this.cert !== 'string') {
|
||||||
|
const certReader = new CertReader(this.cert);
|
||||||
|
tencentCertId = await sslClient.uploadToTencent({
|
||||||
|
certName: certReader.buildCertName(),
|
||||||
|
cert: this.cert,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const params:any = {
|
||||||
|
ZoneId: this.zoneId,
|
||||||
|
Hosts: this.domainNames,
|
||||||
|
Mode: 'sslcert',
|
||||||
|
ServerCertInfo: [
|
||||||
|
{
|
||||||
|
CertId: tencentCertId,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
await this.doRequest(client, params);
|
await this.doRequest(client, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
getClient(accessProvider: TencentAccess) {
|
getClient(accessProvider: TencentAccess) {
|
||||||
const TeoClient = this.Client;
|
const TeoClient = this.Client;
|
||||||
|
|
||||||
const endpoint = accessProvider.isIntl()?"teo.intl.tencentcloudapi.com": "teo.tencentcloudapi.com";
|
//teo.intl.tencentcloudapi.com
|
||||||
|
const endpoint = `teo.${accessProvider.intlDomain()}tencentcloudapi.com`;
|
||||||
const clientConfig = {
|
const clientConfig = {
|
||||||
credential: {
|
credential: {
|
||||||
secretId: accessProvider.secretId,
|
secretId: accessProvider.secretId,
|
||||||
@@ -106,18 +146,6 @@ export class DeployCertToTencentEO extends AbstractTaskPlugin {
|
|||||||
return new TeoClient(clientConfig);
|
return new TeoClient(clientConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
buildParams() {
|
|
||||||
return {
|
|
||||||
ZoneId: this.zoneId,
|
|
||||||
Hosts: this.domainNames,
|
|
||||||
Mode: 'sslcert',
|
|
||||||
ServerCertInfo: [
|
|
||||||
{
|
|
||||||
CertId: this.certId,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async doRequest(client: any, params: any) {
|
async doRequest(client: any, params: any) {
|
||||||
const ret = await client.ModifyHostsCertificate(params);
|
const ret = await client.ModifyHostsCertificate(params);
|
||||||
@@ -131,6 +159,57 @@ export class DeployCertToTencentEO extends AbstractTaskPlugin {
|
|||||||
throw new Error('执行失败:' + ret.Error.Code + ',' + ret.Error.Message);
|
throw new Error('执行失败:' + ret.Error.Code + ',' + ret.Error.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async onGetZoneList(data: any) {
|
||||||
|
if (!this.accessId){
|
||||||
|
throw new Error('请选择授权');
|
||||||
|
}
|
||||||
|
const access: TencentAccess = await this.getAccess<TencentAccess>(this.accessId);
|
||||||
|
const client = await this.getClient(access);
|
||||||
|
const res = await client.DescribeZones({
|
||||||
|
Limit: 100,
|
||||||
|
});
|
||||||
|
this.checkRet(res);
|
||||||
|
const list = res.Zones;
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return list.map((item: any) => {
|
||||||
|
return {
|
||||||
|
label: `${item.ZoneName}<${item.ZoneId}>`,
|
||||||
|
value: item.ZoneId,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async onGetDomainList(data: any) {
|
||||||
|
if (!this.accessId){
|
||||||
|
throw new Error('请选择授权');
|
||||||
|
}
|
||||||
|
const access: TencentAccess = await this.getAccess<TencentAccess>(this.accessId);
|
||||||
|
const client = await this.getClient(access);
|
||||||
|
const res = await client.DescribeAccelerationDomains({
|
||||||
|
Limit: 200,
|
||||||
|
ZoneId: this.zoneId,
|
||||||
|
});
|
||||||
|
this.checkRet(res);
|
||||||
|
const list = res.AccelerationDomains
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const options = list.map((item: any) => {
|
||||||
|
return {
|
||||||
|
label: item.DomainName,
|
||||||
|
value: item.DomainName,
|
||||||
|
domain: item.DomainName
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return this.ctx.utils.options.buildGroupOptions(options, this.certDomains);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new DeployCertToTencentEO();
|
new DeployCertToTencentEO();
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export class TencentDeployCertToLive extends AbstractTaskPlugin {
|
|||||||
region: '',
|
region: '',
|
||||||
profile: {
|
profile: {
|
||||||
httpProfile: {
|
httpProfile: {
|
||||||
endpoint: 'live.tencentcloudapi.com',
|
endpoint: `live.${accessProvider.intlDomain()}tencentcloudapi.com`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
|
|||||||
region,
|
region,
|
||||||
profile: {
|
profile: {
|
||||||
httpProfile: {
|
httpProfile: {
|
||||||
endpoint: "tke.tencentcloudapi.com"
|
endpoint: `tke.${accessProvider.intlDomain()}tencentcloudapi.com`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ export class TencentActionInstancesPlugin extends AbstractTaskPlugin {
|
|||||||
region: this.region,
|
region: this.region,
|
||||||
profile: {
|
profile: {
|
||||||
httpProfile: {
|
httpProfile: {
|
||||||
endpoint: 'cvm.tencentcloudapi.com',
|
endpoint: `cvm.${accessProvider.intlDomain()}tencentcloudapi.com`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {AccessInput, BaseAccess, IsAccess} from '@certd/pipeline';
|
|||||||
title: '火山引擎',
|
title: '火山引擎',
|
||||||
desc: '',
|
desc: '',
|
||||||
icon: 'svg:icon-volcengine',
|
icon: 'svg:icon-volcengine',
|
||||||
|
order: 1,
|
||||||
})
|
})
|
||||||
export class VolcengineAccess extends BaseAccess {
|
export class VolcengineAccess extends BaseAccess {
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import { VolcengineAccess } from "./access.js";
|
|||||||
title: "火山引擎",
|
title: "火山引擎",
|
||||||
desc: "火山引擎DNS解析提供商",
|
desc: "火山引擎DNS解析提供商",
|
||||||
accessType: "volcengine",
|
accessType: "volcengine",
|
||||||
icon: "svg:icon-volcengine"
|
icon: "svg:icon-volcengine",
|
||||||
|
order:2,
|
||||||
})
|
})
|
||||||
export class VolcengineDnsProvider extends AbstractDnsProvider {
|
export class VolcengineDnsProvider extends AbstractDnsProvider {
|
||||||
client: VolcengineDnsClient;
|
client: VolcengineDnsClient;
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ import { CertApplyPluginNames} from '@certd/plugin-cert';
|
|||||||
export class WoaiCdnPlugin extends AbstractTaskPlugin {
|
export class WoaiCdnPlugin extends AbstractTaskPlugin {
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: '接口地址(可留空)',
|
title: '接口地址(可留空)',
|
||||||
helper: '请填写我爱云的地址, 默认为 [API](https://console.edeg.sxhjgy.cn) 末尾请不要携带`/`',
|
helper: '请填写我爱云的地址, 默认为 [API](https://console.edge.ttzi.cn) 末尾请不要携带`/`',
|
||||||
component: { name: 'a-input' },
|
component: { name: 'a-input' },
|
||||||
required: false,
|
required: false,
|
||||||
})
|
})
|
||||||
baseApi?: string;
|
baseApi?: string;
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: '证书ID',
|
title: '证书ID',
|
||||||
helper: '请填写 [证书列表](https://console.edge.sxhjgy.cn/site/certificate) 中的证书的ID',
|
helper: '请填写 [证书列表](https://console.edge.ttzi.cn/site/certificate) 中的证书的ID',
|
||||||
component: { name: 'a-input' },
|
component: { name: 'a-input' },
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
@@ -73,9 +73,9 @@ export class WoaiCdnPlugin extends AbstractTaskPlugin {
|
|||||||
const { baseApi, certId, cert, accessId } = this;
|
const { baseApi, certId, cert, accessId } = this;
|
||||||
const access = (await this.getAccess(accessId)) as WoaiAccess;
|
const access = (await this.getAccess(accessId)) as WoaiAccess;
|
||||||
// 使用默认值或用户输入的值
|
// 使用默认值或用户输入的值
|
||||||
const apiBase = baseApi || 'https://console.edeg.sxhjgy.cn';
|
const apiBase = baseApi || 'https://console.edge.ttzi.cn';
|
||||||
// 登录获取token
|
// 登录获取token
|
||||||
const loginResponse = await this.doRequestApi(`${apiBase}/account/login`, {
|
const loginResponse = await this.doRequestApi(`${apiBase}/login`, {
|
||||||
username: access.username,
|
username: access.username,
|
||||||
password: access.password,
|
password: access.password,
|
||||||
});
|
});
|
||||||
|
|||||||
153
pnpm-lock.yaml
generated
153
pnpm-lock.yaml
generated
@@ -49,7 +49,7 @@ importers:
|
|||||||
packages/core/acme-client:
|
packages/core/acme-client:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../basic
|
version: link:../basic
|
||||||
'@peculiar/x509':
|
'@peculiar/x509':
|
||||||
specifier: ^1.11.0
|
specifier: ^1.11.0
|
||||||
@@ -210,10 +210,10 @@ importers:
|
|||||||
packages/core/pipeline:
|
packages/core/pipeline:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../basic
|
version: link:../basic
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../pro/plus-core
|
version: link:../../pro/plus-core
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
@@ -418,7 +418,7 @@ importers:
|
|||||||
packages/libs/lib-k8s:
|
packages/libs/lib-k8s:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@kubernetes/client-node':
|
'@kubernetes/client-node':
|
||||||
specifier: 0.21.0
|
specifier: 0.21.0
|
||||||
@@ -458,16 +458,16 @@ importers:
|
|||||||
packages/libs/lib-server:
|
packages/libs/lib-server:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/acme-client':
|
'@certd/acme-client':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/acme-client
|
version: link:../../core/acme-client
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../pro/plus-core
|
version: link:../../pro/plus-core
|
||||||
'@midwayjs/cache':
|
'@midwayjs/cache':
|
||||||
specifier: ~3.14.0
|
specifier: ~3.14.0
|
||||||
@@ -610,16 +610,16 @@ importers:
|
|||||||
packages/plugins/plugin-cert:
|
packages/plugins/plugin-cert:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/acme-client':
|
'@certd/acme-client':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/acme-client
|
version: link:../../core/acme-client
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-lib':
|
'@certd/plugin-lib':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../plugin-lib
|
version: link:../plugin-lib
|
||||||
'@google-cloud/publicca':
|
'@google-cloud/publicca':
|
||||||
specifier: ^1.3.0
|
specifier: ^1.3.0
|
||||||
@@ -701,10 +701,10 @@ importers:
|
|||||||
specifier: ^3.787.0
|
specifier: ^3.787.0
|
||||||
version: 3.810.0(aws-crt@1.26.2)
|
version: 3.810.0(aws-crt@1.26.2)
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@kubernetes/client-node':
|
'@kubernetes/client-node':
|
||||||
specifier: 0.21.0
|
specifier: 0.21.0
|
||||||
@@ -792,19 +792,19 @@ importers:
|
|||||||
packages/pro/commercial-core:
|
packages/pro/commercial-core:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/lib-server':
|
'@certd/lib-server':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../libs/lib-server
|
version: link:../../libs/lib-server
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-plus':
|
'@certd/plugin-plus':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../plugin-plus
|
version: link:../plugin-plus
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../plus-core
|
version: link:../plus-core
|
||||||
'@midwayjs/core':
|
'@midwayjs/core':
|
||||||
specifier: ~3.20.3
|
specifier: ~3.20.3
|
||||||
@@ -889,22 +889,22 @@ importers:
|
|||||||
specifier: ^1.0.2
|
specifier: ^1.0.2
|
||||||
version: 1.0.3
|
version: 1.0.3
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/lib-k8s':
|
'@certd/lib-k8s':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../libs/lib-k8s
|
version: link:../../libs/lib-k8s
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-cert':
|
'@certd/plugin-cert':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../plugins/plugin-cert
|
version: link:../../plugins/plugin-cert
|
||||||
'@certd/plugin-lib':
|
'@certd/plugin-lib':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../plugins/plugin-lib
|
version: link:../../plugins/plugin-lib
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../plus-core
|
version: link:../plus-core
|
||||||
ali-oss:
|
ali-oss:
|
||||||
specifier: ^6.21.0
|
specifier: ^6.21.0
|
||||||
@@ -1007,7 +1007,7 @@ importers:
|
|||||||
packages/pro/plus-core:
|
packages/pro/plus-core:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
@@ -1082,6 +1082,9 @@ importers:
|
|||||||
'@aws-sdk/s3-request-presigner':
|
'@aws-sdk/s3-request-presigner':
|
||||||
specifier: ^3.535.0
|
specifier: ^3.535.0
|
||||||
version: 3.810.0
|
version: 3.810.0
|
||||||
|
'@certd/vue-js-cron-light':
|
||||||
|
specifier: ^4.0.14
|
||||||
|
version: 4.0.14
|
||||||
'@ctrl/tinycolor':
|
'@ctrl/tinycolor':
|
||||||
specifier: ^4.1.0
|
specifier: ^4.1.0
|
||||||
version: 4.1.0
|
version: 4.1.0
|
||||||
@@ -1121,9 +1124,6 @@ importers:
|
|||||||
'@vee-validate/zod':
|
'@vee-validate/zod':
|
||||||
specifier: ^4.15.0
|
specifier: ^4.15.0
|
||||||
version: 4.15.0(vue@3.5.14(typescript@5.8.3))(zod@3.24.4)
|
version: 4.15.0(vue@3.5.14(typescript@5.8.3))(zod@3.24.4)
|
||||||
'@vue-js-cron/light':
|
|
||||||
specifier: ^4.0.5
|
|
||||||
version: 4.0.10
|
|
||||||
'@vue/shared':
|
'@vue/shared':
|
||||||
specifier: ^3.5.13
|
specifier: ^3.5.13
|
||||||
version: 3.5.14
|
version: 3.5.14
|
||||||
@@ -1297,10 +1297,10 @@ importers:
|
|||||||
version: 0.1.3(zod@3.24.4)
|
version: 0.1.3(zod@3.24.4)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@certd/lib-iframe':
|
'@certd/lib-iframe':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../libs/lib-iframe
|
version: link:../../libs/lib-iframe
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@rollup/plugin-commonjs':
|
'@rollup/plugin-commonjs':
|
||||||
specifier: ^25.0.7
|
specifier: ^25.0.7
|
||||||
@@ -1483,46 +1483,46 @@ importers:
|
|||||||
specifier: ^3.705.0
|
specifier: ^3.705.0
|
||||||
version: 3.810.0(aws-crt@1.26.2)
|
version: 3.810.0(aws-crt@1.26.2)
|
||||||
'@certd/acme-client':
|
'@certd/acme-client':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/acme-client
|
version: link:../../core/acme-client
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/commercial-core':
|
'@certd/commercial-core':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../pro/commercial-core
|
version: link:../../pro/commercial-core
|
||||||
'@certd/cv4pve-api-javascript':
|
'@certd/cv4pve-api-javascript':
|
||||||
specifier: ^8.4.1
|
specifier: ^8.4.1
|
||||||
version: 8.4.1
|
version: 8.4.1
|
||||||
'@certd/jdcloud':
|
'@certd/jdcloud':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../libs/lib-jdcloud
|
version: link:../../libs/lib-jdcloud
|
||||||
'@certd/lib-huawei':
|
'@certd/lib-huawei':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../libs/lib-huawei
|
version: link:../../libs/lib-huawei
|
||||||
'@certd/lib-k8s':
|
'@certd/lib-k8s':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../libs/lib-k8s
|
version: link:../../libs/lib-k8s
|
||||||
'@certd/lib-server':
|
'@certd/lib-server':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../libs/lib-server
|
version: link:../../libs/lib-server
|
||||||
'@certd/midway-flyway-js':
|
'@certd/midway-flyway-js':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../libs/midway-flyway-js
|
version: link:../../libs/midway-flyway-js
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-cert':
|
'@certd/plugin-cert':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../plugins/plugin-cert
|
version: link:../../plugins/plugin-cert
|
||||||
'@certd/plugin-lib':
|
'@certd/plugin-lib':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../plugins/plugin-lib
|
version: link:../../plugins/plugin-lib
|
||||||
'@certd/plugin-plus':
|
'@certd/plugin-plus':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../pro/plugin-plus
|
version: link:../../pro/plugin-plus
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.36.15
|
specifier: ^1.36.17
|
||||||
version: link:../../pro/plus-core
|
version: link:../../pro/plus-core
|
||||||
'@huaweicloud/huaweicloud-sdk-cdn':
|
'@huaweicloud/huaweicloud-sdk-cdn':
|
||||||
specifier: ^3.1.120
|
specifier: ^3.1.120
|
||||||
@@ -1602,6 +1602,9 @@ importers:
|
|||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
version: 1.11.13
|
version: 1.11.13
|
||||||
|
esdk-obs-nodejs:
|
||||||
|
specifier: ^3.25.6
|
||||||
|
version: 3.25.6
|
||||||
form-data:
|
form-data:
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
version: 4.0.2
|
version: 4.0.2
|
||||||
@@ -1629,9 +1632,6 @@ importers:
|
|||||||
koa-send:
|
koa-send:
|
||||||
specifier: ^5.0.1
|
specifier: ^5.0.1
|
||||||
version: 5.0.1
|
version: 5.0.1
|
||||||
ksyun-sdk-node:
|
|
||||||
specifier: ^1.2.4
|
|
||||||
version: 1.2.4(encoding@0.1.13)
|
|
||||||
kubernetes-client:
|
kubernetes-client:
|
||||||
specifier: ^9.0.0
|
specifier: ^9.0.0
|
||||||
version: 9.0.0
|
version: 9.0.0
|
||||||
@@ -2769,6 +2769,12 @@ packages:
|
|||||||
'@certd/cv4pve-api-javascript@8.4.1':
|
'@certd/cv4pve-api-javascript@8.4.1':
|
||||||
resolution: {integrity: sha512-jxlRieJmCA0Z9LnwX6Ra6ZekRGJEu8o8RGYoKU0Jjkhc9jm6ChEbVyfE7Iw49/hlpA+2yaHdAXb46au/afCISg==}
|
resolution: {integrity: sha512-jxlRieJmCA0Z9LnwX6Ra6ZekRGJEu8o8RGYoKU0Jjkhc9jm6ChEbVyfE7Iw49/hlpA+2yaHdAXb46au/afCISg==}
|
||||||
|
|
||||||
|
'@certd/vue-js-cron-core@6.0.3':
|
||||||
|
resolution: {integrity: sha512-kqzoAMhYz9j6FGNWEODRYtt4NpUEUwjpkU89z5WVg2tCtOcI5VhwyUGOd8AxiBCRfd6PtXvzuqw85PaOps9wrQ==}
|
||||||
|
|
||||||
|
'@certd/vue-js-cron-light@4.0.14':
|
||||||
|
resolution: {integrity: sha512-Ebng/VvrN/WpzCMnt0MrsPNgPY3BP6jNYLSUlV5eES6dqWXFpCyIXbNI+qep8fWdn7rNXDW310uUsn3bCPvvEw==}
|
||||||
|
|
||||||
'@colors/colors@1.5.0':
|
'@colors/colors@1.5.0':
|
||||||
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
|
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
|
||||||
engines: {node: '>=0.1.90'}
|
engines: {node: '>=0.1.90'}
|
||||||
@@ -5162,12 +5168,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-W8R6+7UIhx06s2kpsJ0KF80IKAiIad71HUKssonMChyI37h5oFnPf6zONcX2ikXc5M8xdOiKFRxoCO8ChEob0g==}
|
resolution: {integrity: sha512-W8R6+7UIhx06s2kpsJ0KF80IKAiIad71HUKssonMChyI37h5oFnPf6zONcX2ikXc5M8xdOiKFRxoCO8ChEob0g==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
'@vue-js-cron/core@5.4.2':
|
|
||||||
resolution: {integrity: sha512-y5HrgLJ/0JMXUliOdJZQbB+9UHs7+b7/spe8GFt/a1iCM1ILGKxAoTfbeapoSbF9LxDgw9SsXTgdkmMKWum58A==}
|
|
||||||
|
|
||||||
'@vue-js-cron/light@4.0.10':
|
|
||||||
resolution: {integrity: sha512-ri8Or3fOkA5pSAihdTcgqrQKzCIa9QcvfilyAqEfEhkK6bTFxQVqJ9LW6tLiNaepHlU8IE68xBLM/kms67le2g==}
|
|
||||||
|
|
||||||
'@vue-macros/common@1.16.1':
|
'@vue-macros/common@1.16.1':
|
||||||
resolution: {integrity: sha512-Pn/AWMTjoMYuquepLZP813BIcq8DTZiNCoaceuNlvaYuOTd8DqBZWc5u0uOMQZMInwME1mdSmmBAcTluiV9Jtg==}
|
resolution: {integrity: sha512-Pn/AWMTjoMYuquepLZP813BIcq8DTZiNCoaceuNlvaYuOTd8DqBZWc5u0uOMQZMInwME1mdSmmBAcTluiV9Jtg==}
|
||||||
engines: {node: '>=16.14.0'}
|
engines: {node: '>=16.14.0'}
|
||||||
@@ -7390,6 +7390,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
esdk-obs-nodejs@3.25.6:
|
||||||
|
resolution: {integrity: sha512-bDEznGBoSjqmFNjkL0PvkMzF6o50wa+1PSKQ1tT5CtBP/yw7Egx0c/kIVsu5Raqcip1SjKu7muzslG4xo/skew==}
|
||||||
|
engines: {node: '>=0.12.7'}
|
||||||
|
|
||||||
eslint-config-prettier@8.10.0:
|
eslint-config-prettier@8.10.0:
|
||||||
resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
|
resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -9189,9 +9193,6 @@ packages:
|
|||||||
kolorist@1.8.0:
|
kolorist@1.8.0:
|
||||||
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
|
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
|
||||||
|
|
||||||
ksyun-sdk-node@1.2.4:
|
|
||||||
resolution: {integrity: sha512-W/c1nhnZskadPP7ObmizMh+jJeHXWka0HkS8lcZfLWxwEH83B8iMFF0DrtSaDCjQRuBpgzwDLGbbp+U1D1rXlQ==}
|
|
||||||
|
|
||||||
kubernetes-client@9.0.0:
|
kubernetes-client@9.0.0:
|
||||||
resolution: {integrity: sha512-Qy8o42dZVHB9P+cIiKdWpQbz/65l/qW1fDYvlzzeSLftmL1Ne3HEiM+0TmKAwNuRW0pTJN2tRWhcccToclxJ8g==}
|
resolution: {integrity: sha512-Qy8o42dZVHB9P+cIiKdWpQbz/65l/qW1fDYvlzzeSLftmL1Ne3HEiM+0TmKAwNuRW0pTJN2tRWhcccToclxJ8g==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
@@ -15453,6 +15454,14 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@certd/vue-js-cron-core@6.0.3':
|
||||||
|
dependencies:
|
||||||
|
mustache: 4.2.0
|
||||||
|
|
||||||
|
'@certd/vue-js-cron-light@4.0.14':
|
||||||
|
dependencies:
|
||||||
|
'@certd/vue-js-cron-core': 6.0.3
|
||||||
|
|
||||||
'@colors/colors@1.5.0':
|
'@colors/colors@1.5.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -18522,14 +18531,6 @@ snapshots:
|
|||||||
- buffer
|
- buffer
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@vue-js-cron/core@5.4.2':
|
|
||||||
dependencies:
|
|
||||||
mustache: 4.2.0
|
|
||||||
|
|
||||||
'@vue-js-cron/light@4.0.10':
|
|
||||||
dependencies:
|
|
||||||
'@vue-js-cron/core': 5.4.2
|
|
||||||
|
|
||||||
'@vue-macros/common@1.16.1(vue@3.5.14(typescript@5.8.3))':
|
'@vue-macros/common@1.16.1(vue@3.5.14(typescript@5.8.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-sfc': 3.5.14
|
'@vue/compiler-sfc': 3.5.14
|
||||||
@@ -21386,6 +21387,13 @@ snapshots:
|
|||||||
|
|
||||||
escape-string-regexp@5.0.0: {}
|
escape-string-regexp@5.0.0: {}
|
||||||
|
|
||||||
|
esdk-obs-nodejs@3.25.6:
|
||||||
|
dependencies:
|
||||||
|
fast-xml-parser: 4.5.0
|
||||||
|
log4js: 6.9.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
eslint-config-prettier@8.10.0(eslint@7.32.0):
|
eslint-config-prettier@8.10.0(eslint@7.32.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 7.32.0
|
eslint: 7.32.0
|
||||||
@@ -21527,13 +21535,13 @@ snapshots:
|
|||||||
resolve: 1.22.10
|
resolve: 1.22.10
|
||||||
semver: 6.3.1
|
semver: 6.3.1
|
||||||
|
|
||||||
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8):
|
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 7.32.0
|
eslint: 7.32.0
|
||||||
prettier: 2.8.8
|
prettier: 2.8.8
|
||||||
prettier-linter-helpers: 1.0.0
|
prettier-linter-helpers: 1.0.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
eslint-config-prettier: 8.10.0(eslint@8.57.0)
|
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
||||||
|
|
||||||
eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8):
|
eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -23518,17 +23526,6 @@ snapshots:
|
|||||||
|
|
||||||
kolorist@1.8.0: {}
|
kolorist@1.8.0: {}
|
||||||
|
|
||||||
ksyun-sdk-node@1.2.4(encoding@0.1.13):
|
|
||||||
dependencies:
|
|
||||||
abort-controller: 3.0.0
|
|
||||||
core-js: 3.42.0
|
|
||||||
crypto-js: 4.2.0
|
|
||||||
dayjs: 1.11.13
|
|
||||||
node-fetch: 2.7.0(encoding@0.1.13)
|
|
||||||
qs: 6.14.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- encoding
|
|
||||||
|
|
||||||
kubernetes-client@9.0.0:
|
kubernetes-client@9.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@kubernetes/client-node': 0.10.2
|
'@kubernetes/client-node': 0.10.2
|
||||||
@@ -24252,7 +24249,7 @@ snapshots:
|
|||||||
eslint: 7.32.0
|
eslint: 7.32.0
|
||||||
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
||||||
eslint-plugin-node: 11.1.0(eslint@7.32.0)
|
eslint-plugin-node: 11.1.0(eslint@7.32.0)
|
||||||
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8)
|
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8)
|
||||||
execa: 5.1.1
|
execa: 5.1.1
|
||||||
inquirer: 7.3.3
|
inquirer: 7.3.3
|
||||||
json5: 2.2.3
|
json5: 2.2.3
|
||||||
|
|||||||
Reference in New Issue
Block a user