mirror of
https://github.com/certd/certd.git
synced 2026-04-03 22:20:51 +08:00
Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93017c044d | ||
|
|
c223ddbb9a | ||
|
|
f00aeacb8b | ||
|
|
5b49071d6b | ||
|
|
17053a882b | ||
|
|
5e723d31a4 | ||
|
|
3283bd8b75 | ||
|
|
770d3c0015 | ||
|
|
d15dfafd5d | ||
|
|
545c13d55c | ||
|
|
e2099ac9ca | ||
|
|
c937583a50 | ||
|
|
43c7a19849 | ||
|
|
83543487e7 | ||
|
|
434b259525 | ||
|
|
add8efaba8 | ||
|
|
12ed79ca60 | ||
|
|
1e863382d3 | ||
|
|
bad3504d4a | ||
|
|
d94f207162 | ||
|
|
2c4b7781a4 | ||
|
|
4574c6ff07 | ||
|
|
7b5043e87b | ||
|
|
a06f3ac5da | ||
|
|
721346a40a | ||
|
|
f252871fb8 | ||
|
|
107196122c | ||
|
|
563c02d8da | ||
|
|
765934970a | ||
|
|
9cbdfda829 | ||
|
|
c1fbc8cd68 | ||
|
|
a92107cc47 | ||
|
|
3e84e116e8 | ||
|
|
7c0cdd169e | ||
|
|
424fd96615 | ||
|
|
ebfcea88da | ||
|
|
3c7eb2f5e2 | ||
|
|
936167972f | ||
|
|
7f6070c960 | ||
|
|
0aea9c129c | ||
|
|
d20fb7daa8 | ||
|
|
a619f8a2fe | ||
|
|
0acb858d7b | ||
|
|
e459be76fe | ||
|
|
c4c59ccc75 | ||
|
|
c820315409 | ||
|
|
2a19b61b7a | ||
|
|
e1cf64ae16 | ||
|
|
d3c2f8eb43 | ||
|
|
a00453c83a | ||
|
|
2eb0e54909 | ||
|
|
ac87bc57e9 | ||
|
|
2b8ea857f0 | ||
|
|
11c52114b2 |
51
CHANGELOG.md
51
CHANGELOG.md
@@ -3,6 +3,57 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持s3 access做测试 ([f00aeac](https://github.com/certd/certd/commit/f00aeacb8b5c81f0bafa4c1b76723dec2b6b7784))
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复消息内容存在()<>等括号情况下无法发送tg通知的bug ([c937583](https://github.com/certd/certd/commit/c937583a50d8513d76adead3648f83eee2fcc6f9))
|
||||
* 修复重试次数设置无效的bug ([e2099ac](https://github.com/certd/certd/commit/e2099ac9ca344bc70bfa4219002e9138708973ae))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 授权列表类型颜色优化 ([1e86338](https://github.com/certd/certd/commit/1e863382d3d1a8cc95a1abf51e75bf6eaea3244f))
|
||||
* 支持雨云dns解析 ([8354348](https://github.com/certd/certd/commit/83543487e7418683bd79cfe3b9e0d792bdb977f7))
|
||||
* 支持雨云dns解析以及雨云证书更新 ([43c7a19](https://github.com/certd/certd/commit/43c7a1984926f5d4647760cc134bb0aede3a7b7a))
|
||||
* github 版本检查支持执行脚本 ([bad3504](https://github.com/certd/certd/commit/bad3504d4a15e6989b967b66aa9da8c6981f25bf))
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云新加坡clb无法部署证书的bug ([c1fbc8c](https://github.com/certd/certd/commit/c1fbc8cd68ae020ef342e4e92f4d9b4869ca1ead))
|
||||
* 修复阿里云新加坡clb无法部署证书的bug ([3e84e11](https://github.com/certd/certd/commit/3e84e116e863b54c6b4d7db160af372dacc5857f))
|
||||
* 修复检查github release 插件无法保存最后版本的bug ([a92107c](https://github.com/certd/certd/commit/a92107cc47133883b099d5228b06373e84c8bb50))
|
||||
* 修复站点监控定时器多次添加的bug ([9361679](https://github.com/certd/certd/commit/936167972fe83e519bc01a0dd961d9c0635d24ab))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 阿里云dns操作增加重试机制 ([424fd96](https://github.com/certd/certd/commit/424fd96615c05e949af8c837c261c1400bdffba2))
|
||||
* 优化阿里云nlb支持部署扩展证书 ([9cbdfda](https://github.com/certd/certd/commit/9cbdfda829b231733d54c66c5024d46e6fc11af3))
|
||||
* 子域名托管帮助链接优化为打开新窗口 ([7c0cdd1](https://github.com/certd/certd/commit/7c0cdd169e2f943e703e433677f2f437d4aa02ee))
|
||||
* history增加触发类型显示 ([7f6070c](https://github.com/certd/certd/commit/7f6070c960ed7bf02add5ab36436de6573f2f1fa))
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 某些证书提供商的证书确实commonName导致无法转换证书的问题 ([ac87bc5](https://github.com/certd/certd/commit/ac87bc57e957ea4679707bfd38d6840e26319bed))
|
||||
* 修复站点监控通知渠道设置无效的bug ([a00453c](https://github.com/certd/certd/commit/a00453c83a58114ce2873dd6e6aaf313f1ce0f87))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修改 HTTPS 服务器监听地址 ([e1cf64a](https://github.com/certd/certd/commit/e1cf64ae16d4abfe4299ff16d5088c30cf3c6365))
|
||||
* 优化流水线页面,增加下次执行时间、查看证书显示 ([c820315](https://github.com/certd/certd/commit/c8203154094fae3d17198747f49f5f41ddf29a4e))
|
||||
* 站点证书监控支持定时设置,重试次数设置 ([d3c2f8e](https://github.com/certd/certd/commit/d3c2f8eb436e670772d14a54acd6b541c5aa3978))
|
||||
* 证书申请支持letencrypt profile选项 ([2eb0e54](https://github.com/certd/certd/commit/2eb0e54909d8ad36708e07c12fd598998159bc43))
|
||||
* aliyun alb支持部署扩展证书 ([2a19b61](https://github.com/certd/certd/commit/2a19b61b7a78620c06396c2cc37cc77d738b6d12))
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
### Features
|
||||
|
||||
10
README.md
10
README.md
@@ -1,9 +1,9 @@
|
||||
# Certd
|
||||
|
||||
Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系统。
|
||||
后缀d取自linux守护进程的命名风格,意为证书守护进程。
|
||||
Certd® 是一个免费的全自动证书管理系统,让你的网站证书永不过期。
|
||||
首创流水线申请部署证书模式,已被多个项目“借鉴”,被抄也是一种成功。
|
||||
|
||||
关键字:证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具
|
||||
>后缀d取自linux守护进程的命名风格,意为证书守护进程。
|
||||
|
||||
> 关于证书续期:
|
||||
>* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
@@ -13,6 +13,7 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||
|
||||
> 流水线数量现已调整为无限制,欢迎大家使用
|
||||
|
||||
|
||||
## 一、特性
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
@@ -32,9 +33,6 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 二、在线体验
|
||||
|
||||
官方Demo地址,自助注册后体验
|
||||
|
||||
@@ -1 +1 @@
|
||||
23:51
|
||||
00:39
|
||||
|
||||
@@ -3,6 +3,59 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复消息内容存在()<>等括号情况下无法发送tg通知的bug ([c937583](https://github.com/certd/certd/commit/c937583a50d8513d76adead3648f83eee2fcc6f9))
|
||||
* 修复重试次数设置无效的bug ([e2099ac](https://github.com/certd/certd/commit/e2099ac9ca344bc70bfa4219002e9138708973ae))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 授权列表类型颜色优化 ([1e86338](https://github.com/certd/certd/commit/1e863382d3d1a8cc95a1abf51e75bf6eaea3244f))
|
||||
* 支持雨云dns解析 ([8354348](https://github.com/certd/certd/commit/83543487e7418683bd79cfe3b9e0d792bdb977f7))
|
||||
* 支持雨云dns解析以及雨云证书更新 ([43c7a19](https://github.com/certd/certd/commit/43c7a1984926f5d4647760cc134bb0aede3a7b7a))
|
||||
* github 版本检查支持执行脚本 ([bad3504](https://github.com/certd/certd/commit/bad3504d4a15e6989b967b66aa9da8c6981f25bf))
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云新加坡clb无法部署证书的bug ([c1fbc8c](https://github.com/certd/certd/commit/c1fbc8cd68ae020ef342e4e92f4d9b4869ca1ead))
|
||||
* 修复阿里云新加坡clb无法部署证书的bug ([3e84e11](https://github.com/certd/certd/commit/3e84e116e863b54c6b4d7db160af372dacc5857f))
|
||||
* 修复检查github release 插件无法保存最后版本的bug ([a92107c](https://github.com/certd/certd/commit/a92107cc47133883b099d5228b06373e84c8bb50))
|
||||
* 修复站点监控定时器多次添加的bug ([9361679](https://github.com/certd/certd/commit/936167972fe83e519bc01a0dd961d9c0635d24ab))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 阿里云dns操作增加重试机制 ([424fd96](https://github.com/certd/certd/commit/424fd96615c05e949af8c837c261c1400bdffba2))
|
||||
* 优化阿里云nlb支持部署扩展证书 ([9cbdfda](https://github.com/certd/certd/commit/9cbdfda829b231733d54c66c5024d46e6fc11af3))
|
||||
* 子域名托管帮助链接优化为打开新窗口 ([7c0cdd1](https://github.com/certd/certd/commit/7c0cdd169e2f943e703e433677f2f437d4aa02ee))
|
||||
* history增加触发类型显示 ([7f6070c](https://github.com/certd/certd/commit/7f6070c960ed7bf02add5ab36436de6573f2f1fa))
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 某些证书提供商的证书确实commonName导致无法转换证书的问题 ([ac87bc5](https://github.com/certd/certd/commit/ac87bc57e957ea4679707bfd38d6840e26319bed))
|
||||
* 修复站点监控通知渠道设置无效的bug ([a00453c](https://github.com/certd/certd/commit/a00453c83a58114ce2873dd6e6aaf313f1ce0f87))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修改 HTTPS 服务器监听地址 ([e1cf64a](https://github.com/certd/certd/commit/e1cf64ae16d4abfe4299ff16d5088c30cf3c6365))
|
||||
* 优化流水线页面,增加下次执行时间、查看证书显示 ([c820315](https://github.com/certd/certd/commit/c8203154094fae3d17198747f49f5f41ddf29a4e))
|
||||
* 站点证书监控支持定时设置,重试次数设置 ([d3c2f8e](https://github.com/certd/certd/commit/d3c2f8eb436e670772d14a54acd6b541c5aa3978))
|
||||
* 证书申请支持letencrypt profile选项 ([2eb0e54](https://github.com/certd/certd/commit/2eb0e54909d8ad36708e07c12fd598998159bc43))
|
||||
* aliyun alb支持部署扩展证书 ([2a19b61](https://github.com/certd/certd/commit/2a19b61b7a78620c06396c2cc37cc77d738b6d12))
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
### Features
|
||||
|
||||
* 完善注释 ([6702ca1](https://github.com/certd/certd/commit/6702ca10a17f5d7dbff789b039f7269496f66b97))
|
||||
* AWS 中国区 CloudFront 证书部署(IAM 证书) ([8a55bed](https://github.com/certd/certd/commit/8a55beda924b3be2a53b9ba80d9487cefa8bf887))
|
||||
* **lego:** support for command options ([b84159f](https://github.com/certd/certd/commit/b84159f2f11531f058837c2e82d66499f3740f20))
|
||||
|
||||
## [1.34.11](https://github.com/certd/certd/compare/v1.34.10...v1.34.11) (2025-06-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.35.0"
|
||||
"version": "1.35.4"
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"afterpublishOnly": "npm run copylogs && time /t >build.trigger && git add ./build.trigger && git commit -m \"build: trigger build image\" && TIMEOUT /T 10 && git push",
|
||||
"transform-sql": "cd ./packages/ui/certd-server/db/ && node --experimental-json-modules transform.js",
|
||||
"commitAll": "git add . && git commit -m \"build: publish\" && git push && npm run commitPro",
|
||||
"commitPro": "cd ./packages/core/ && git add . && git commit -m \"build: publish\" && git push",
|
||||
"commitPro": "cd ./packages/pro/ && git add . && git commit -m \"build: publish\" && git push",
|
||||
"copylogs": "copyfiles \"CHANGELOG.md\" ./docs/guide/changelogs/",
|
||||
"prepublishOnly1": "npm run check && lerna run build ",
|
||||
"prepublishOnly2": "npm run check && npm run before-build && lerna run build ",
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/publishlab/node-acme-client/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.35.3](https://github.com/publishlab/node-acme-client/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.35.2](https://github.com/publishlab/node-acme-client/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.35.1](https://github.com/publishlab/node-acme-client/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书申请支持letencrypt profile选项 ([2eb0e54](https://github.com/publishlab/node-acme-client/commit/2eb0e54909d8ad36708e07c12fd598998159bc43))
|
||||
|
||||
# [1.35.0](https://github.com/publishlab/node-acme-client/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"type": "module",
|
||||
"module": "scr/index.js",
|
||||
"main": "src/index.js",
|
||||
@@ -18,7 +18,7 @@
|
||||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.35.0",
|
||||
"@certd/basic": "^1.35.4",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
@@ -69,5 +69,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -75,6 +75,9 @@ export default async (client, userOpts) => {
|
||||
|
||||
log("[auto] Placing new certificate order with ACME provider");
|
||||
const orderPayload = { identifiers: uniqueDomains.map((d) => ({ type: "dns", value: d })) };
|
||||
if (opts.profile && client.sslProvider === 'letsencrypt' ){
|
||||
orderPayload.profile = opts.profile;
|
||||
}
|
||||
const order = await client.createOrder(orderPayload);
|
||||
const authorizations = await client.getAuthorizations(order);
|
||||
|
||||
@@ -213,12 +216,16 @@ export default async (client, userOpts) => {
|
||||
return promise;
|
||||
}
|
||||
|
||||
async function runPromisePa(tasks, waitTime = 5000) {
|
||||
async function runPromisePa(tasks, waitTime = 8000) {
|
||||
const results = [];
|
||||
let j = 0
|
||||
// eslint-disable-next-line no-await-in-loop,no-restricted-syntax
|
||||
for (const task of tasks) {
|
||||
j++
|
||||
log(`开始第${j}个任务`);
|
||||
results.push(task());
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
log(`wait ${waitTime}s`)
|
||||
await wait(waitTime);
|
||||
}
|
||||
return Promise.all(results);
|
||||
@@ -242,6 +249,7 @@ export default async (client, userOpts) => {
|
||||
log(`跳过本地验证(skipChallengeVerification=true),等待 60s`);
|
||||
await wait(60 * 1000);
|
||||
} else {
|
||||
log("开始本地校验")
|
||||
await runPromisePa(localVerifyTasks, 1000);
|
||||
log(`本地校验完成,等待${waitDnsDiffuseTime}s`)
|
||||
await wait(waitDnsDiffuseTime * 1000)
|
||||
|
||||
@@ -90,10 +90,12 @@ const defaultOpts = {
|
||||
*/
|
||||
|
||||
class AcmeClient {
|
||||
sslProvider
|
||||
constructor(opts) {
|
||||
if (!Buffer.isBuffer(opts.accountKey)) {
|
||||
opts.accountKey = Buffer.from(opts.accountKey);
|
||||
}
|
||||
this.sslProvider = opts.sslProvider;
|
||||
|
||||
this.opts = { ...defaultOpts, ...opts };
|
||||
this.backoffOpts = {
|
||||
|
||||
1
packages/core/acme-client/types/index.d.ts
vendored
1
packages/core/acme-client/types/index.d.ts
vendored
@@ -66,6 +66,7 @@ export interface ClientAutoOptions {
|
||||
challengePriority?: string[];
|
||||
preferredChain?: string;
|
||||
signal?: AbortSignal;
|
||||
profile?:string;
|
||||
}
|
||||
|
||||
export class Client {
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
@@ -1 +1 @@
|
||||
00:09
|
||||
12:19
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -45,5 +45,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持s3 access做测试 ([f00aeac](https://github.com/certd/certd/commit/f00aeacb8b5c81f0bafa4c1b76723dec2b6b7784))
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复消息内容存在()<>等括号情况下无法发送tg通知的bug ([c937583](https://github.com/certd/certd/commit/c937583a50d8513d76adead3648f83eee2fcc6f9))
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -17,8 +17,8 @@
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.35.0",
|
||||
"@certd/plus-core": "^1.35.0",
|
||||
"@certd/basic": "^1.35.4",
|
||||
"@certd/plus-core": "^1.35.4",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
@@ -44,5 +44,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ export type AccessContext = {
|
||||
http: HttpClient;
|
||||
logger: ILogger;
|
||||
utils: typeof utils;
|
||||
accessService: IAccessService;
|
||||
};
|
||||
|
||||
export abstract class BaseAccess implements IAccess {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// src/decorator/memoryCache.decorator.ts
|
||||
import { AccessContext, AccessDefine, AccessInputDefine } from "./api.js";
|
||||
import { AccessContext, AccessDefine, AccessInputDefine, IAccessService } from "./api.js";
|
||||
import { Decorator } from "../decorator/index.js";
|
||||
import * as _ from "lodash-es";
|
||||
import { accessRegistry } from "./registry.js";
|
||||
@@ -41,7 +41,7 @@ export function AccessInput(input?: AccessInputDefine): PropertyDecorator {
|
||||
};
|
||||
}
|
||||
|
||||
export async function newAccess(type: string, input: any, ctx?: AccessContext) {
|
||||
export async function newAccess(type: string, input: any, accessService: IAccessService, ctx?: AccessContext) {
|
||||
const register = accessRegistry.get(type);
|
||||
if (register == null) {
|
||||
throw new Error(`access ${type} not found`);
|
||||
@@ -58,6 +58,7 @@ export async function newAccess(type: string, input: any, ctx?: AccessContext) {
|
||||
http,
|
||||
logger,
|
||||
utils,
|
||||
accessService,
|
||||
};
|
||||
}
|
||||
access.setCtx(ctx);
|
||||
|
||||
@@ -121,9 +121,13 @@ export abstract class BaseNotification implements INotification {
|
||||
async onTestRequest() {
|
||||
return await this.doSend({
|
||||
userId: 0,
|
||||
title: "【Certd】测试通知【*.foo.com】,标题长度测试、测试、测试",
|
||||
content: `测试通知,*.foo.com
|
||||
title: "【标题】测试通知【*.foo.com】,标题长度测试、测试、测试",
|
||||
content: `测试通知
|
||||
域名测试: *.foo.com
|
||||
换行测试
|
||||
(括号测试)
|
||||
<尖括号测试>
|
||||
[中括号测试]
|
||||
`,
|
||||
pipeline: {
|
||||
id: 1,
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -24,5 +24,5 @@
|
||||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -31,5 +31,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/jdcloud",
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"description": "jdcloud openApi sdk",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
@@ -61,5 +61,5 @@
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -17,7 +17,7 @@
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.35.0",
|
||||
"@certd/basic": "^1.35.4",
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -32,5 +32,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持s3 access做测试 ([f00aeac](https://github.com/certd/certd/commit/f00aeacb8b5c81f0bafa4c1b76723dec2b6b7784))
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -27,10 +27,10 @@
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.35.0",
|
||||
"@certd/basic": "^1.35.0",
|
||||
"@certd/pipeline": "^1.35.0",
|
||||
"@certd/plus-core": "^1.35.0",
|
||||
"@certd/acme-client": "^1.35.4",
|
||||
"@certd/basic": "^1.35.4",
|
||||
"@certd/pipeline": "^1.35.4",
|
||||
"@certd/plus-core": "^1.35.4",
|
||||
"@midwayjs/cache": "~3.14.0",
|
||||
"@midwayjs/core": "~3.20.3",
|
||||
"@midwayjs/i18n": "~3.20.3",
|
||||
@@ -61,5 +61,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService, PageReq, PermissionException, ValidateException } from '../../../index.js';
|
||||
import { AccessEntity } from '../entity/access.js';
|
||||
import { AccessDefine, accessRegistry, newAccess } from '@certd/pipeline';
|
||||
import { EncryptService } from './encrypt-service.js';
|
||||
import {Inject, Provide, Scope, ScopeEnum} from '@midwayjs/core';
|
||||
import {InjectEntityModel} from '@midwayjs/typeorm';
|
||||
import {Repository} from 'typeorm';
|
||||
import {AccessGetter, BaseService, PageReq, PermissionException, ValidateException} from '../../../index.js';
|
||||
import {AccessEntity} from '../entity/access.js';
|
||||
import {AccessDefine, accessRegistry, newAccess} from '@certd/pipeline';
|
||||
import {EncryptService} from './encrypt-service.js';
|
||||
|
||||
/**
|
||||
* 授权
|
||||
*/
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||
@Scope(ScopeEnum.Request, {allowDowngrade: true})
|
||||
export class AccessService extends BaseService<AccessEntity> {
|
||||
@InjectEntityModel(AccessEntity)
|
||||
repository: Repository<AccessEntity>;
|
||||
@@ -95,6 +95,7 @@ export class AccessService extends BaseService<AccessEntity> {
|
||||
param.encryptSetting = JSON.stringify(encryptSetting);
|
||||
param.setting = JSON.stringify(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改
|
||||
* @param param 数据
|
||||
@@ -140,7 +141,8 @@ export class AccessService extends BaseService<AccessEntity> {
|
||||
id: entity.id,
|
||||
...setting,
|
||||
};
|
||||
return await newAccess(entity.type, input);
|
||||
const accessGetter = new AccessGetter(userId, this.getById.bind(this));
|
||||
return await newAccess(entity.type, input,accessGetter);
|
||||
}
|
||||
|
||||
async getById(id: any, userId: number): Promise<any> {
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -46,5 +46,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 某些证书提供商的证书确实commonName导致无法转换证书的问题 ([ac87bc5](https://github.com/certd/certd/commit/ac87bc57e957ea4679707bfd38d6840e26319bed))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书申请支持letencrypt profile选项 ([2eb0e54](https://github.com/certd/certd/commit/2eb0e54909d8ad36708e07c12fd598998159bc43))
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -16,10 +16,10 @@
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.35.0",
|
||||
"@certd/basic": "^1.35.0",
|
||||
"@certd/pipeline": "^1.35.0",
|
||||
"@certd/plugin-lib": "^1.35.0",
|
||||
"@certd/acme-client": "^1.35.4",
|
||||
"@certd/basic": "^1.35.4",
|
||||
"@certd/pipeline": "^1.35.4",
|
||||
"@certd/plugin-lib": "^1.35.4",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jszip": "^3.10.1",
|
||||
@@ -43,5 +43,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -327,8 +327,9 @@ export class AcmeService {
|
||||
csrInfo: any;
|
||||
isTest?: boolean;
|
||||
privateKeyType?: string;
|
||||
profile?: string;
|
||||
}): Promise<CertInfo> {
|
||||
const { email, isTest, csrInfo, dnsProvider, domainsVerifyPlan } = options;
|
||||
const { email, isTest, csrInfo, dnsProvider, domainsVerifyPlan, profile } = options;
|
||||
const client: acme.Client = await this.getAcmeClient(email, isTest);
|
||||
|
||||
let domains = options.domains;
|
||||
@@ -400,6 +401,7 @@ export class AcmeService {
|
||||
return await this.challengeRemoveFn(authz, challenge, keyAuthorization, recordReq, recordRes, dnsProvider, httpUploader);
|
||||
},
|
||||
signal: this.options.signal,
|
||||
profile,
|
||||
});
|
||||
|
||||
const crtString = crt.toString();
|
||||
|
||||
@@ -89,7 +89,10 @@ export class CertReader {
|
||||
|
||||
getAllDomains() {
|
||||
const { detail } = this.getCrtDetail();
|
||||
const domains = [detail.domains.commonName];
|
||||
const domains = [];
|
||||
if (detail.domains?.commonName) {
|
||||
domains.push(detail.domains.commonName);
|
||||
}
|
||||
domains.push(...detail.domains.altNames);
|
||||
//去重
|
||||
return uniq(domains);
|
||||
@@ -102,12 +105,23 @@ export class CertReader {
|
||||
|
||||
static getMainDomain(crt: string) {
|
||||
const { detail } = CertReader.readCertDetail(crt);
|
||||
return detail.domains.commonName;
|
||||
return CertReader.getMainDomainFromDetail(detail);
|
||||
}
|
||||
|
||||
getMainDomain() {
|
||||
const { detail } = this.getCrtDetail();
|
||||
return detail.domains.commonName;
|
||||
return CertReader.getMainDomainFromDetail(detail);
|
||||
}
|
||||
|
||||
static getMainDomainFromDetail(detail: CertificateInfo) {
|
||||
let domain = detail?.domains?.commonName;
|
||||
if (domain == null) {
|
||||
domain = detail?.domains?.altNames?.[0];
|
||||
}
|
||||
if (domain == null) {
|
||||
domain = "unknown";
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
saveToFile(type: "crt" | "key" | "pfx" | "der" | "oc" | "one" | "ic" | "jks", filepath?: string) {
|
||||
@@ -179,8 +193,7 @@ export class CertReader {
|
||||
}
|
||||
|
||||
buildCertFileName(suffix: string, applyTime: any, prefix = "cert") {
|
||||
const detail = this.getCrtDetail();
|
||||
let domain = detail.detail.domains.commonName;
|
||||
let domain = this.getMainDomain();
|
||||
domain = domain.replaceAll(".", "_").replaceAll("*", "_");
|
||||
const timeStr = dayjs(applyTime).format("YYYYMMDDHHmmss");
|
||||
return `${prefix}_${domain}_${timeStr}.${suffix}`;
|
||||
@@ -188,7 +201,7 @@ export class CertReader {
|
||||
|
||||
buildCertName() {
|
||||
let domain = this.getMainDomain();
|
||||
domain = domain.replaceAll("*", "_").replaceAll("*", "_");
|
||||
domain = domain.replaceAll(".", "_").replaceAll("*", "_");
|
||||
return `${domain}_${dayjs().format("YYYYMMDDHHmmssSSS")}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,6 +248,30 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
})
|
||||
privateKeyType!: PrivateKeyType;
|
||||
|
||||
@TaskInput({
|
||||
title: "证书配置",
|
||||
value: "classic",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ value: "classic", label: "经典(classic)" },
|
||||
{ value: "tlsserver", label: "TLS服务器(tlsserver)" },
|
||||
{ value: "shortlived", label: "短暂的(shortlived)" },
|
||||
],
|
||||
},
|
||||
helper: "如无特殊需求,默认即可",
|
||||
required: false,
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.sslProvider === 'letsencrypt'
|
||||
})
|
||||
}
|
||||
`,
|
||||
})
|
||||
certProfile!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "使用代理",
|
||||
value: false,
|
||||
@@ -395,6 +419,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
csrInfo,
|
||||
isTest: false,
|
||||
privateKeyType: this.privateKeyType,
|
||||
profile: this.certProfile,
|
||||
});
|
||||
|
||||
const certInfo = this.formatCerts(cert);
|
||||
|
||||
@@ -3,6 +3,32 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持s3 access做测试 ([f00aeac](https://github.com/certd/certd/commit/f00aeacb8b5c81f0bafa4c1b76723dec2b6b7784))
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云新加坡clb无法部署证书的bug ([3e84e11](https://github.com/certd/certd/commit/3e84e116e863b54c6b4d7db160af372dacc5857f))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化阿里云nlb支持部署扩展证书 ([9cbdfda](https://github.com/certd/certd/commit/9cbdfda829b231733d54c66c5024d46e6fc11af3))
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* aliyun alb支持部署扩展证书 ([2a19b61](https://github.com/certd/certd/commit/2a19b61b7a78620c06396c2cc37cc77d738b6d12))
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-lib",
|
||||
"private": false,
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -17,11 +17,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@alicloud/openapi-client": "^0.4.14",
|
||||
"@alicloud/openapi-util": "^0.3.2",
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@alicloud/tea-util": "^1.4.10",
|
||||
"@aws-sdk/client-s3": "^3.787.0",
|
||||
"@certd/basic": "^1.35.0",
|
||||
"@certd/pipeline": "^1.35.0",
|
||||
"@certd/basic": "^1.35.4",
|
||||
"@certd/pipeline": "^1.35.4",
|
||||
"@kubernetes/client-node": "0.21.0",
|
||||
"ali-oss": "^6.22.0",
|
||||
"basic-ftp": "^5.0.5",
|
||||
@@ -52,5 +53,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "ab3a3156f24d7fc70f8a907c5f6fc754413a89d6"
|
||||
"gitHead": "d15dfafd5d8c74c1a51c859b2586c26ca01e3bf8"
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ export class AliyunClientV2 {
|
||||
|
||||
const $OpenApi = await import("@alicloud/openapi-client");
|
||||
const $Util = await import("@alicloud/tea-util");
|
||||
|
||||
const OpenApiUtil = await import("@alicloud/openapi-util");
|
||||
const params = new $OpenApi.Params({
|
||||
// 接口名称
|
||||
action: req.action,
|
||||
@@ -74,6 +74,10 @@ export class AliyunClientV2 {
|
||||
bodyType: "json",
|
||||
});
|
||||
|
||||
if (req.data?.query) {
|
||||
//@ts-ignore
|
||||
req.data.query = OpenApiUtil.default.default.query(req.data.query);
|
||||
}
|
||||
const runtime = new $Util.RuntimeOptions({});
|
||||
const request = new $OpenApi.OpenApiRequest(req.data);
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
|
||||
@@ -29,7 +29,7 @@ export type AliyunSslUploadCertReq = {
|
||||
cert: AliyunCertInfo;
|
||||
};
|
||||
|
||||
export type CasCertInfo = { certId: number; certName: string; certIdentifier: string };
|
||||
export type CasCertInfo = { certId: number; certName: string; certIdentifier: string; notAfter: number; casRegion: string };
|
||||
|
||||
export class AliyunSslClient {
|
||||
opts: AliyunSslClientOpts;
|
||||
@@ -68,6 +68,8 @@ export class AliyunSslClient {
|
||||
certId: certId,
|
||||
certName: res.Name,
|
||||
certIdentifier: res.CertIdentifier,
|
||||
notAfter: res.NotAfter,
|
||||
casRegion: this.getCasRegionFromEndpoint(this.opts.endpoint),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -148,4 +150,24 @@ export class AliyunSslClient {
|
||||
this.checkRet(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
async deleteCert(certId: any) {
|
||||
await this.doRequest("DeleteUserCertificate", { CertId: certId }, { method: "POST" });
|
||||
}
|
||||
|
||||
getCasRegionFromEndpoint(endpoint: string) {
|
||||
if (!endpoint) {
|
||||
return "cn-hangzhou";
|
||||
}
|
||||
/**
|
||||
* {value: 'cas.aliyuncs.com', label: '中国大陆'},
|
||||
* {value: 'cas.ap-southeast-1.aliyuncs.com', label: '新加坡'},
|
||||
* {value: 'cas.eu-central-1.aliyuncs.com', label: '德国(法兰克福)'},
|
||||
*/
|
||||
const region = endpoint.replace(".aliyuncs.com", "").replace("cas.", "");
|
||||
if (region === "cas") {
|
||||
return "cn-hangzhou";
|
||||
}
|
||||
return region;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,9 @@ export default class S3OssClientImpl extends BaseOssClient<S3Access> {
|
||||
Prefix: dirKey, // The name of the object. For example, 'sample_upload.txt'.
|
||||
};
|
||||
const res = await this.client.send(new ListObjectsCommand({ ...params }));
|
||||
if (!res.Contents) {
|
||||
return [];
|
||||
}
|
||||
return res.Contents.map(item => {
|
||||
return {
|
||||
path: item.Key,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline";
|
||||
import { ossClientFactory } from "../oss/index.js";
|
||||
import S3OssClientImpl from "../oss/impls/s3.js";
|
||||
|
||||
/**
|
||||
* 这个注解将注册一个授权配置
|
||||
@@ -82,6 +84,32 @@ export class S3Access extends BaseAccess {
|
||||
required: true,
|
||||
})
|
||||
bucket!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest",
|
||||
},
|
||||
helper: "点击测试接口是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
const client: S3OssClientImpl = await ossClientFactory.createOssClientByType("s3", {
|
||||
access: this,
|
||||
rootDir: "",
|
||||
ctx: {
|
||||
accessService: this.ctx.accessService,
|
||||
logger: this.ctx.logger,
|
||||
utils: this.ctx.utils,
|
||||
},
|
||||
});
|
||||
|
||||
await client.listDir("/");
|
||||
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
|
||||
new S3Access();
|
||||
|
||||
@@ -3,6 +3,35 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/ui-client
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复重试次数设置无效的bug ([e2099ac](https://github.com/certd/certd/commit/e2099ac9ca344bc70bfa4219002e9138708973ae))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 授权列表类型颜色优化 ([1e86338](https://github.com/certd/certd/commit/1e863382d3d1a8cc95a1abf51e75bf6eaea3244f))
|
||||
* 支持雨云dns解析以及雨云证书更新 ([43c7a19](https://github.com/certd/certd/commit/43c7a1984926f5d4647760cc134bb0aede3a7b7a))
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 子域名托管帮助链接优化为打开新窗口 ([7c0cdd1](https://github.com/certd/certd/commit/7c0cdd169e2f943e703e433677f2f437d4aa02ee))
|
||||
* history增加触发类型显示 ([7f6070c](https://github.com/certd/certd/commit/7f6070c960ed7bf02add5ab36436de6573f2f1fa))
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化流水线页面,增加下次执行时间、查看证书显示 ([c820315](https://github.com/certd/certd/commit/c8203154094fae3d17198747f49f5f41ddf29a4e))
|
||||
* 站点证书监控支持定时设置,重试次数设置 ([d3c2f8e](https://github.com/certd/certd/commit/d3c2f8eb436e670772d14a54acd6b541c5aa3978))
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/ui-client
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -30,10 +30,10 @@
|
||||
"@aws-sdk/client-s3": "^3.535.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.535.0",
|
||||
"@ctrl/tinycolor": "^4.1.0",
|
||||
"@fast-crud/fast-crud": "^1.25.8",
|
||||
"@fast-crud/fast-extends": "^1.25.8",
|
||||
"@fast-crud/ui-antdv4": "^1.25.8",
|
||||
"@fast-crud/ui-interface": "^1.25.8",
|
||||
"@fast-crud/fast-crud": "^1.25.13",
|
||||
"@fast-crud/fast-extends": "^1.25.13",
|
||||
"@fast-crud/ui-antdv4": "^1.25.13",
|
||||
"@fast-crud/ui-interface": "^1.25.13",
|
||||
"@iconify/tailwind": "^1.2.0",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@manypkg/get-packages": "^2.2.2",
|
||||
@@ -102,8 +102,8 @@
|
||||
"zod-defaults": "^0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.35.0",
|
||||
"@certd/pipeline": "^1.35.0",
|
||||
"@certd/lib-iframe": "^1.35.4",
|
||||
"@certd/pipeline": "^1.35.4",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
|
||||
@@ -1,17 +1,7 @@
|
||||
<template>
|
||||
<div class="cron-editor">
|
||||
<div class="flex-o">
|
||||
<cron-light
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
:period="period"
|
||||
class="flex-o cron-ant"
|
||||
locale="zh-CN"
|
||||
format="quartz"
|
||||
:model-value="modelValue"
|
||||
@update:model-value="onUpdate"
|
||||
@error="onError"
|
||||
/>
|
||||
<cron-light :disabled="disabled" :readonly="readonly" :period="period" class="flex-o cron-ant" locale="zh-CN" format="quartz" :model-value="modelValue" @update:model-value="onUpdate" @error="onError" />
|
||||
</div>
|
||||
<div class="mt-5 flex">
|
||||
<a-input :disabled="true" :readonly="readonly" :value="modelValue" @change="onChange"></a-input>
|
||||
@@ -26,13 +16,15 @@
|
||||
import parser from "cron-parser";
|
||||
import { computed, ref } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import { getCronNextTimes } from "/@/components/cron-editor/utils";
|
||||
defineOptions({
|
||||
name: "CronEditor"
|
||||
name: "CronEditor",
|
||||
});
|
||||
const props = defineProps<{
|
||||
modelValue?: string;
|
||||
disabled?: boolean;
|
||||
readonly?: boolean;
|
||||
allowEveryMin?: boolean;
|
||||
}>();
|
||||
|
||||
const period = ref<string>("");
|
||||
@@ -58,9 +50,12 @@ const onUpdate = (value: string) => {
|
||||
if (arr[0] === "*") {
|
||||
arr[0] = "0";
|
||||
}
|
||||
if (arr[1] === "*") {
|
||||
arr[1] = "0";
|
||||
if (!props.allowEveryMin) {
|
||||
if (arr[1] === "*") {
|
||||
arr[1] = "0";
|
||||
}
|
||||
}
|
||||
|
||||
value = arr.join(" ");
|
||||
|
||||
emit("update:modelValue", value);
|
||||
@@ -90,10 +85,10 @@ const nextTime = computed(() => {
|
||||
if (props.modelValue == null) {
|
||||
return "请先设置正确的cron表达式";
|
||||
}
|
||||
|
||||
try {
|
||||
const interval = parser.parseExpression(props.modelValue);
|
||||
const next = interval.next().getTime();
|
||||
return dayjs(next).format("YYYY-MM-DD HH:mm:ss");
|
||||
const nextTimes = getCronNextTimes(props.modelValue, 2);
|
||||
return nextTimes.join(",");
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return "请先设置正确的cron表达式";
|
||||
|
||||
15
packages/ui/certd-client/src/components/cron-editor/utils.ts
Normal file
15
packages/ui/certd-client/src/components/cron-editor/utils.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import parser from "cron-parser";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export function getCronNextTimes(cron: string, count: number = 1) {
|
||||
if (cron == null) {
|
||||
return [];
|
||||
}
|
||||
const nextTimes = [];
|
||||
const interval = parser.parseExpression(cron);
|
||||
for (let i = 0; i < count; i++) {
|
||||
const next = interval.next().getTime();
|
||||
nextTimes.push(dayjs(next).format("YYYY-MM-DD HH:mm:ss"));
|
||||
}
|
||||
return nextTimes;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ export default {
|
||||
.text-editable {
|
||||
flex: 1;
|
||||
line-height: 34px;
|
||||
|
||||
overflow: hidden;
|
||||
span.fs-iconify {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
|
||||
@@ -334,6 +334,22 @@ function install(app: App, options: any = {}) {
|
||||
return columnProps;
|
||||
},
|
||||
});
|
||||
|
||||
registerMergeColumnPlugin({
|
||||
name: "reset-values-format-colors",
|
||||
order: 10,
|
||||
handle: (columnProps: ColumnCompositionProps) => {
|
||||
// 你可以在此处做你自己的处理
|
||||
// 比如你可以定义一个readonly的公共属性,处理该字段只读,不能编辑
|
||||
if (columnProps.column?.component?.name === "fs-values-format") {
|
||||
// 合并column配置
|
||||
if (!columnProps.column.component.autoColors) {
|
||||
columnProps.column.component.autoColors = ["green", "cyan", "blue", "purple", "geekblue"];
|
||||
}
|
||||
}
|
||||
return columnProps;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -49,38 +49,38 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
pageRequest,
|
||||
addRequest,
|
||||
editRequest,
|
||||
delRequest
|
||||
delRequest,
|
||||
},
|
||||
toolbar: {
|
||||
show: false
|
||||
show: false,
|
||||
},
|
||||
search: {
|
||||
show: false
|
||||
show: false,
|
||||
},
|
||||
form: {
|
||||
wrapper: {
|
||||
width: "1050px"
|
||||
}
|
||||
width: "1050px",
|
||||
},
|
||||
},
|
||||
rowHandle: {
|
||||
width: 200
|
||||
width: 200,
|
||||
},
|
||||
table: {
|
||||
scroll: {
|
||||
x: 800
|
||||
x: 800,
|
||||
},
|
||||
rowSelection: {
|
||||
type: "radio",
|
||||
selectedRowKeys: selectedRowKey,
|
||||
onChange: onSelectChange
|
||||
onChange: onSelectChange,
|
||||
},
|
||||
customRow: (record: any) => {
|
||||
return {
|
||||
onClick: () => {
|
||||
onSelectChange([record.id]);
|
||||
} // 点击行
|
||||
}, // 点击行
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
@@ -88,25 +88,25 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
key: "id",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 50
|
||||
width: 50,
|
||||
},
|
||||
form: {
|
||||
show: false
|
||||
}
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
name: {
|
||||
title: "名称",
|
||||
search: {
|
||||
show: true
|
||||
show: true,
|
||||
},
|
||||
type: ["text"],
|
||||
form: {
|
||||
rules: [{ required: true, message: "请填写名称" }],
|
||||
helper: "随便填,当多个相同类型的授权时,便于区分"
|
||||
helper: "随便填,当多个相同类型的授权时,便于区分",
|
||||
},
|
||||
column: {
|
||||
width: 200
|
||||
}
|
||||
width: 200,
|
||||
},
|
||||
},
|
||||
from: {
|
||||
title: "级别",
|
||||
@@ -114,29 +114,29 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "系统", value: "sys" },
|
||||
{ label: "用户", value: "user" }
|
||||
]
|
||||
{ label: "用户", value: "user" },
|
||||
],
|
||||
}),
|
||||
search: {
|
||||
show: false
|
||||
show: false,
|
||||
},
|
||||
form: {
|
||||
show: false
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
width: 100,
|
||||
align: "center",
|
||||
component: {
|
||||
color: "auto"
|
||||
color: "auto",
|
||||
},
|
||||
order: 10
|
||||
order: 10,
|
||||
},
|
||||
valueBuilder: ({ row, key, value }) => {
|
||||
row[key] = row.userId > 0 ? "user" : "sys";
|
||||
}
|
||||
},
|
||||
},
|
||||
...commonColumnsDefine
|
||||
}
|
||||
}
|
||||
...commonColumnsDefine,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@ import * as api from "./api";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { computed, Ref, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
|
||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const router = useRouter();
|
||||
@@ -143,6 +144,50 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
},
|
||||
},
|
||||
},
|
||||
triggerType: {
|
||||
title: "触发类型",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
dict: dict({
|
||||
data: [
|
||||
{ value: "user", label: "手动执行" },
|
||||
{ value: "timer", label: "定时执行" },
|
||||
],
|
||||
}),
|
||||
form: {
|
||||
show: false,
|
||||
value: "custom",
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 90,
|
||||
align: "center",
|
||||
show: true,
|
||||
component: {
|
||||
color: "auto",
|
||||
},
|
||||
},
|
||||
},
|
||||
status: {
|
||||
title: "状态",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
dict: dict({
|
||||
data: statusUtil.getOptions(),
|
||||
}),
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 120,
|
||||
align: "center",
|
||||
},
|
||||
},
|
||||
createTime: {
|
||||
title: "创建时间",
|
||||
type: "datetime",
|
||||
|
||||
@@ -130,7 +130,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
await api.DoCheck(row.id);
|
||||
await crudExpose.doRefresh();
|
||||
notification.success({
|
||||
message: "检查完成",
|
||||
message: "检查任务已提交,请稍后刷新查看结果",
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -137,7 +137,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
await api.DoCheck(row.id);
|
||||
await crudExpose.doRefresh();
|
||||
notification.success({
|
||||
message: "检查任务已提交",
|
||||
message: "检查任务已提交,请稍后刷新查看结果",
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -3,6 +3,8 @@ import { request } from "/src/api/service";
|
||||
const apiPrefix = "/monitor/site/setting";
|
||||
export type UserSiteMonitorSetting = {
|
||||
notificationId?: number;
|
||||
retryTimes?: number;
|
||||
cron?: string;
|
||||
};
|
||||
|
||||
export async function SiteMonitorSettingsGet() {
|
||||
|
||||
@@ -11,6 +11,19 @@
|
||||
</div>
|
||||
<div class="helper">设置通知渠道</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="重试次数" :name="['retryTimes']">
|
||||
<div class="flex">
|
||||
<a-input-number v-model:value="formState.retryTimes" />
|
||||
</div>
|
||||
<div class="helper">监控请求重试次数</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="监控定时设置" :name="['cron']">
|
||||
<div class="flex flex-baseline">
|
||||
<cron-editor v-model="formState.cron" :disabled="!settingsStore.isPlus" :allow-every-min="userStore.isAdmin" />
|
||||
<vip-button class="ml-5" mode="button"></vip-button>
|
||||
</div>
|
||||
<div class="helper">定时触发监控</div>
|
||||
</a-form-item>
|
||||
<a-form-item label=" " :colon="false" :wrapper-col="{ span: 16 }">
|
||||
<loading-button type="primary" html-type="button" :click="doSave">保存</loading-button>
|
||||
</a-form-item>
|
||||
@@ -27,8 +40,10 @@ import { notification } from "ant-design-vue";
|
||||
import { merge } from "lodash-es";
|
||||
import { useSettingStore } from "/src/store/settings";
|
||||
import NotificationSelector from "/@/views/certd/notification/notification-selector/index.vue";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
|
||||
const settingsStore = useSettingStore();
|
||||
const userStore = useUserStore();
|
||||
defineOptions({
|
||||
name: "UserSecurity",
|
||||
});
|
||||
@@ -56,7 +71,7 @@ const doSave = async (form: any) => {
|
||||
<style lang="less">
|
||||
.page-user-settings {
|
||||
.user-settings-form {
|
||||
width: 600px;
|
||||
width: 700px;
|
||||
margin: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,17 +5,15 @@ import { useRouter } from "vue-router";
|
||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, useUi } from "@fast-crud/fast-crud";
|
||||
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
|
||||
import { Modal, notification } from "ant-design-vue";
|
||||
import { env } from "/@/utils/util.env";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
import dayjs from "dayjs";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { useModal } from "/@/use/use-modal";
|
||||
import CertView from "./cert-view.vue";
|
||||
import { eachStages } from "./utils";
|
||||
import { setRunnableIds, useCertPipelineCreator } from "/@/views/certd/pipeline/certd-form/use";
|
||||
import { useCertUpload } from "/@/views/certd/pipeline/cert-upload/use";
|
||||
import GroupSelector from "/@/views/certd/pipeline/group/group-selector.vue";
|
||||
import { useCertViewer } from "/@/views/certd/pipeline/use";
|
||||
|
||||
export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const router = useRouter();
|
||||
@@ -61,59 +59,7 @@ export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys
|
||||
return res;
|
||||
};
|
||||
|
||||
const model = useModal();
|
||||
const viewCert = async (row: any) => {
|
||||
const cert = await api.GetCert(row.id);
|
||||
if (!cert) {
|
||||
notification.error({ message: "请先运行一次流水线" });
|
||||
return;
|
||||
}
|
||||
|
||||
model.success({
|
||||
title: "查看证书",
|
||||
maskClosable: true,
|
||||
okText: "关闭",
|
||||
width: 800,
|
||||
content: () => {
|
||||
return <CertView cert={cert}></CertView>;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const downloadCert = async (row: any) => {
|
||||
const files = await api.GetFiles(row.id);
|
||||
model.success({
|
||||
title: "点击链接下载",
|
||||
maskClosable: true,
|
||||
okText: "关闭",
|
||||
content: () => {
|
||||
const children = [];
|
||||
for (const file of files) {
|
||||
const downloadUrl = `${env.API}/pi/history/download?pipelineId=${row.id}&fileId=${file.id}`;
|
||||
children.push(
|
||||
<div>
|
||||
<div class={"flex-o m-5"}>
|
||||
<fs-icon icon={"ant-design:cloud-download-outlined"} class={"mr-5 fs-16"}></fs-icon>
|
||||
<a href={downloadUrl} target={"_blank"}>
|
||||
{file.filename}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (children.length === 0) {
|
||||
return <div>暂无文件下载</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={"mt-3"}>
|
||||
<div> {children}</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
const { viewCert, downloadCert } = useCertViewer();
|
||||
const userStore = useUserStore();
|
||||
const settingStore = useSettingStore();
|
||||
|
||||
@@ -208,6 +154,10 @@ export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys
|
||||
},
|
||||
table: {
|
||||
scroll: { x: 1500 },
|
||||
remove: {
|
||||
confirmTitle: "确定要删除吗?",
|
||||
confirmMessage: "将删除该流水线相关的所有数据,包括执行历史、证书文件、证书仓库记录等",
|
||||
},
|
||||
},
|
||||
tabs: {
|
||||
name: "groupId",
|
||||
@@ -281,7 +231,7 @@ export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys
|
||||
type: "link",
|
||||
icon: "ph:certificate",
|
||||
async click({ row }) {
|
||||
await viewCert(row);
|
||||
await viewCert(row.id);
|
||||
},
|
||||
},
|
||||
download: {
|
||||
@@ -291,7 +241,7 @@ export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys
|
||||
tooltip: { title: "下载证书" },
|
||||
icon: "ant-design:download-outlined",
|
||||
async click({ row }) {
|
||||
await downloadCert(row);
|
||||
await downloadCert(row.id);
|
||||
},
|
||||
},
|
||||
remove: {
|
||||
|
||||
@@ -34,6 +34,8 @@ const pipelineOptions: PipelineOptions = {
|
||||
stages: [],
|
||||
triggers: [],
|
||||
...JSON.parse(detail.pipeline.content || "{}"),
|
||||
type: detail.pipeline.type,
|
||||
from: detail.pipeline.from,
|
||||
},
|
||||
} as PipelineDetail;
|
||||
},
|
||||
|
||||
@@ -1,18 +1,43 @@
|
||||
<template>
|
||||
<fs-page v-if="pipeline" class="page-pipeline-edit">
|
||||
<template #header>
|
||||
<div class="title">
|
||||
<div class="title flex-1">
|
||||
<fs-button class="back" icon="ion:chevron-back-outline" @click="goBack"></fs-button>
|
||||
<text-editable v-model="pipeline.title" :hover-show="false" :disabled="!editMode"></text-editable>
|
||||
</div>
|
||||
<div class="more">
|
||||
<template v-if="editMode">
|
||||
<a-button type="primary" :loading="saveLoading" @click="save">保存</a-button>
|
||||
<a-button class="ml-5" @click="cancel">取消</a-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-button type="primary" @click="edit">编辑</a-button>
|
||||
</template>
|
||||
<div class="more flex items-center flex-1 justify-end">
|
||||
<div v-if="isCert" class="flex items-center hidden md:block">
|
||||
<a-tag class="mr-5 pointer" color="green" type="primary" text="查看证书" @click="viewCert(pipeline.id)">
|
||||
<span class="flex"><fs-icon icon="ant-design:eye-outlined"></fs-icon> 查看证书</span>
|
||||
</a-tag>
|
||||
<a-tag class="mr-5 pointer" color="green" type="primary" text="下载证书" @click="downloadCert(pipeline.id)">
|
||||
<span class="flex"> <fs-icon icon="ant-design:download-outlined"></fs-icon> 下载证书 </span>
|
||||
</a-tag>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center hidden md:block">
|
||||
<a-tag v-if="nextTriggerTimes" color="blue">
|
||||
<span class="flex">
|
||||
<fs-icon icon="ion:time-outline"></fs-icon>
|
||||
下次执行时间:{{ nextTriggerTimes }}
|
||||
</span>
|
||||
</a-tag>
|
||||
<a-tag v-else-if="nextTriggerTimes === false" color="red">
|
||||
<span class="flex">
|
||||
<fs-icon icon="ion:caret-forward-circle-outline"></fs-icon>
|
||||
未设置触发源,不会自动执行
|
||||
</span>
|
||||
</a-tag>
|
||||
</div>
|
||||
<div class="basis-40 flex justify-end mr-10">
|
||||
<template v-if="editMode">
|
||||
<fs-button type="primary" :loading="saveLoading" @click="save">保存</fs-button>
|
||||
<fs-button class="ml-5" @click="cancel">取消</fs-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<fs-button icon="ant-design:edit-outlined" type="primary" @click="edit">编辑</fs-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -241,7 +266,7 @@
|
||||
@cancel="historyCancel()"
|
||||
></pi-history-timeline-item>
|
||||
</template>
|
||||
<a-empty v-if="histories.length === 0"> </a-empty>
|
||||
<a-empty v-if="histories.length === 0"></a-empty>
|
||||
</a-timeline>
|
||||
</a-page-header>
|
||||
</div>
|
||||
@@ -255,7 +280,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, onUnmounted, provide, Ref, ref, watch } from "vue";
|
||||
import { defineComponent, onMounted, onUnmounted, provide, Ref, ref, watch, computed } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import PiTaskForm from "./component/task-form/index.vue";
|
||||
import PiTriggerForm from "./component/trigger-form/index.vue";
|
||||
@@ -275,11 +300,23 @@ import { useUserStore } from "/@/store/user";
|
||||
import TaskShortcuts from "./component/shortcut/task-shortcuts.vue";
|
||||
import { eachSteps, findStep } from "../utils";
|
||||
import { PluginGroups } from "/@/store/plugin";
|
||||
import { getCronNextTimes } from "/@/components/cron-editor/utils";
|
||||
import { useCertViewer } from "/@/views/certd/pipeline/use";
|
||||
|
||||
export default defineComponent({
|
||||
name: "PipelineEdit",
|
||||
// eslint-disable-next-line vue/no-unused-components
|
||||
components: { FsIcon, PiHistoryTimelineItem, PiTaskForm, PiTriggerForm, PiTaskView, PiStatusShow, PiNotificationForm, VDraggable, TaskShortcuts },
|
||||
components: {
|
||||
FsIcon,
|
||||
PiHistoryTimelineItem,
|
||||
PiTaskForm,
|
||||
PiTriggerForm,
|
||||
PiTaskView,
|
||||
PiStatusShow,
|
||||
PiNotificationForm,
|
||||
VDraggable,
|
||||
TaskShortcuts,
|
||||
},
|
||||
props: {
|
||||
pipelineId: {
|
||||
type: [Number, String],
|
||||
@@ -309,7 +346,24 @@ export default defineComponent({
|
||||
|
||||
const currentHistory: Ref<any> = ref({});
|
||||
|
||||
const nextTriggerTimes = computed(() => {
|
||||
const triggers = pipeline.value.triggers;
|
||||
if (!triggers || triggers.length === 0) {
|
||||
return false;
|
||||
}
|
||||
let nextTimes: any = [];
|
||||
for (const item of triggers) {
|
||||
if (!item.props?.cron) {
|
||||
continue;
|
||||
}
|
||||
const ret = getCronNextTimes(item.props?.cron, 1);
|
||||
nextTimes.push(...ret);
|
||||
}
|
||||
return nextTimes.join(",");
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
function goBack() {
|
||||
router.back();
|
||||
}
|
||||
@@ -365,8 +419,10 @@ export default defineComponent({
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const intervalLoadHistoryRef = ref();
|
||||
const isLoadingHistory = ref(false);
|
||||
|
||||
function watchNewHistoryList() {
|
||||
intervalLoadHistoryRef.value = setInterval(async () => {
|
||||
if (isLoadingHistory.value) {
|
||||
@@ -390,6 +446,7 @@ export default defineComponent({
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
watchNewHistoryList();
|
||||
});
|
||||
@@ -420,7 +477,15 @@ export default defineComponent({
|
||||
return;
|
||||
}
|
||||
const detail: PipelineDetail = await props.options.getPipelineDetail({ pipelineId: value });
|
||||
currentPipeline.value = _.merge({ title: "新管道流程", stages: [], triggers: [], notifications: [] }, detail.pipeline);
|
||||
currentPipeline.value = _.merge(
|
||||
{
|
||||
title: "新管道流程",
|
||||
stages: [],
|
||||
triggers: [],
|
||||
notifications: [],
|
||||
},
|
||||
detail.pipeline
|
||||
);
|
||||
pipeline.value = currentPipeline.value;
|
||||
await loadHistoryList(true);
|
||||
},
|
||||
@@ -535,6 +600,7 @@ export default defineComponent({
|
||||
function isLastStage(index: number) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
stageAdd,
|
||||
isLastStage,
|
||||
@@ -654,6 +720,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const validateErrors: Ref = ref({});
|
||||
|
||||
function addValidateError(taskId: string, error: any) {
|
||||
const errors = validateErrors.value[taskId] || [];
|
||||
validateErrors.value[taskId] = errors;
|
||||
@@ -708,6 +775,7 @@ export default defineComponent({
|
||||
function hasValidateError(taskId: string) {
|
||||
return validateErrors.value[taskId] != null;
|
||||
}
|
||||
|
||||
const save = async (offEdit = true) => {
|
||||
doValidate();
|
||||
|
||||
@@ -771,9 +839,11 @@ export default defineComponent({
|
||||
};
|
||||
|
||||
const logsCollapse = ref(false);
|
||||
|
||||
function toggleLogsCollapse() {
|
||||
logsCollapse.value = !logsCollapse.value;
|
||||
}
|
||||
|
||||
return {
|
||||
historyView,
|
||||
historyCancel,
|
||||
@@ -838,7 +908,12 @@ export default defineComponent({
|
||||
};
|
||||
});
|
||||
|
||||
const { viewCert, downloadCert } = useCertViewer();
|
||||
const isCert = computed(() => {
|
||||
return currentPipeline.value?.type?.startsWith("cert");
|
||||
});
|
||||
return {
|
||||
isCert,
|
||||
pipeline,
|
||||
currentHistory,
|
||||
histories,
|
||||
@@ -852,6 +927,9 @@ export default defineComponent({
|
||||
...useHistory(),
|
||||
...useNotification(),
|
||||
...useScroll(),
|
||||
nextTriggerTimes,
|
||||
viewCert,
|
||||
downloadCert,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -864,9 +942,11 @@ export default defineComponent({
|
||||
text-overflow: ellipsis;
|
||||
text-wrap: nowrap;
|
||||
display: flex;
|
||||
|
||||
.back {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.text-editable {
|
||||
width: 300px;
|
||||
}
|
||||
@@ -876,47 +956,57 @@ export default defineComponent({
|
||||
.pi-status-show {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.fs-page-content {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.layout {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow-x: hidden;
|
||||
|
||||
.layout-left {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.layout-right {
|
||||
width: 350px;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.pipeline-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.pipeline {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
|
||||
.stages {
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
min-width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.stage {
|
||||
width: 300px;
|
||||
border-right: 1px solid #c7c7c7;
|
||||
|
||||
.is-add {
|
||||
visibility: hidden;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
&:hover .is-add {
|
||||
visibility: visible;
|
||||
}
|
||||
@@ -925,11 +1015,13 @@ export default defineComponent({
|
||||
padding: 20px;
|
||||
color: gray;
|
||||
display: flex;
|
||||
|
||||
.stage-move-handle {
|
||||
cursor: move;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
//.sortable-ghost {
|
||||
// .line {
|
||||
// visibility: hidden;
|
||||
@@ -943,6 +1035,7 @@ export default defineComponent({
|
||||
|
||||
&.line-left {
|
||||
left: 25px;
|
||||
|
||||
.flow-line {
|
||||
border-right: 0;
|
||||
}
|
||||
@@ -950,6 +1043,7 @@ export default defineComponent({
|
||||
|
||||
&.line-right {
|
||||
right: 25px;
|
||||
|
||||
.flow-line {
|
||||
border-left: 0;
|
||||
}
|
||||
@@ -960,6 +1054,7 @@ export default defineComponent({
|
||||
border: 1px solid #c7c7c7;
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.add-stage-btn {
|
||||
display: inline-flex;
|
||||
visibility: hidden;
|
||||
@@ -969,6 +1064,7 @@ export default defineComponent({
|
||||
bottom: -12px;
|
||||
left: -12px;
|
||||
z-index: 100;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
@@ -981,6 +1077,7 @@ export default defineComponent({
|
||||
|
||||
&.line-left {
|
||||
left: 0;
|
||||
|
||||
.flow-line {
|
||||
border-right: 0;
|
||||
border-left: 0;
|
||||
@@ -989,6 +1086,7 @@ export default defineComponent({
|
||||
|
||||
&.line-right {
|
||||
right: 0;
|
||||
|
||||
.flow-line {
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
@@ -1008,13 +1106,16 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.last-stage {
|
||||
.line {
|
||||
width: 50% !important;
|
||||
right: auto;
|
||||
|
||||
.flow-line {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.add-stage-btn {
|
||||
visibility: hidden;
|
||||
}
|
||||
@@ -1038,6 +1139,7 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.task {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -1050,6 +1152,7 @@ export default defineComponent({
|
||||
&.in-edit {
|
||||
margin-right: 28px;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
}
|
||||
}
|
||||
@@ -1061,12 +1164,15 @@ export default defineComponent({
|
||||
//font-size: 18px;
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
&.copy {
|
||||
right: 30px;
|
||||
}
|
||||
|
||||
&.drag {
|
||||
right: 10px;
|
||||
cursor: move;
|
||||
@@ -1078,6 +1184,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
position: relative;
|
||||
|
||||
.shortcut {
|
||||
position: absolute;
|
||||
bottom: -10px;
|
||||
@@ -1092,6 +1199,7 @@ export default defineComponent({
|
||||
|
||||
.layout-right {
|
||||
position: relative;
|
||||
|
||||
&.collapsed {
|
||||
margin-right: -350px;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
return (
|
||||
<div>
|
||||
如果您不理解什么是子域托管,可以参考文档
|
||||
<a href={"https://help.aliyun.com/zh/dns/subdomain-management"}>子域管理</a>
|
||||
<a href={"https://help.aliyun.com/zh/dns/subdomain-management"} target={"_blank"}>
|
||||
子域管理
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
65
packages/ui/certd-client/src/views/certd/pipeline/use.tsx
Normal file
65
packages/ui/certd-client/src/views/certd/pipeline/use.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import * as api from "/@/views/certd/pipeline/api";
|
||||
import { notification } from "ant-design-vue";
|
||||
import CertView from "/@/views/certd/pipeline/cert-view.vue";
|
||||
import { env } from "/@/utils/util.env";
|
||||
import { useModal } from "/@/use/use-modal";
|
||||
|
||||
export function useCertViewer() {
|
||||
const model = useModal();
|
||||
const viewCert = async (id: number) => {
|
||||
const cert = await api.GetCert(id);
|
||||
if (!cert) {
|
||||
notification.error({ message: "请先运行一次流水线" });
|
||||
return;
|
||||
}
|
||||
|
||||
model.success({
|
||||
title: "查看证书",
|
||||
maskClosable: true,
|
||||
okText: "关闭",
|
||||
width: 800,
|
||||
content: () => {
|
||||
return <CertView cert={cert}></CertView>;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const downloadCert = async (id: any) => {
|
||||
const files = await api.GetFiles(id);
|
||||
model.success({
|
||||
title: "点击链接下载",
|
||||
maskClosable: true,
|
||||
okText: "关闭",
|
||||
content: () => {
|
||||
const children = [];
|
||||
for (const file of files) {
|
||||
const downloadUrl = `${env.API}/pi/history/download?pipelineId=${id}&fileId=${file.id}`;
|
||||
children.push(
|
||||
<div>
|
||||
<div class={"flex-o m-5"}>
|
||||
<fs-icon icon={"ant-design:cloud-download-outlined"} class={"mr-5 fs-16"}></fs-icon>
|
||||
<a href={downloadUrl} target={"_blank"}>
|
||||
{file.filename}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (children.length === 0) {
|
||||
return <div>暂无文件下载</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={"mt-3"}>
|
||||
<div> {children}</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
return {
|
||||
viewCert,
|
||||
downloadCert,
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,52 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.35.4](https://github.com/certd/certd/compare/v1.35.3...v1.35.4) (2025-06-13)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持s3 access做测试 ([f00aeac](https://github.com/certd/certd/commit/f00aeacb8b5c81f0bafa4c1b76723dec2b6b7784))
|
||||
|
||||
## [1.35.3](https://github.com/certd/certd/compare/v1.35.2...v1.35.3) (2025-06-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复重试次数设置无效的bug ([e2099ac](https://github.com/certd/certd/commit/e2099ac9ca344bc70bfa4219002e9138708973ae))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持雨云dns解析 ([8354348](https://github.com/certd/certd/commit/83543487e7418683bd79cfe3b9e0d792bdb977f7))
|
||||
* 支持雨云dns解析以及雨云证书更新 ([43c7a19](https://github.com/certd/certd/commit/43c7a1984926f5d4647760cc134bb0aede3a7b7a))
|
||||
* github 版本检查支持执行脚本 ([bad3504](https://github.com/certd/certd/commit/bad3504d4a15e6989b967b66aa9da8c6981f25bf))
|
||||
|
||||
## [1.35.2](https://github.com/certd/certd/compare/v1.35.1...v1.35.2) (2025-06-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云新加坡clb无法部署证书的bug ([c1fbc8c](https://github.com/certd/certd/commit/c1fbc8cd68ae020ef342e4e92f4d9b4869ca1ead))
|
||||
* 修复阿里云新加坡clb无法部署证书的bug ([3e84e11](https://github.com/certd/certd/commit/3e84e116e863b54c6b4d7db160af372dacc5857f))
|
||||
* 修复检查github release 插件无法保存最后版本的bug ([a92107c](https://github.com/certd/certd/commit/a92107cc47133883b099d5228b06373e84c8bb50))
|
||||
* 修复站点监控定时器多次添加的bug ([9361679](https://github.com/certd/certd/commit/936167972fe83e519bc01a0dd961d9c0635d24ab))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 阿里云dns操作增加重试机制 ([424fd96](https://github.com/certd/certd/commit/424fd96615c05e949af8c837c261c1400bdffba2))
|
||||
* 优化阿里云nlb支持部署扩展证书 ([9cbdfda](https://github.com/certd/certd/commit/9cbdfda829b231733d54c66c5024d46e6fc11af3))
|
||||
* history增加触发类型显示 ([7f6070c](https://github.com/certd/certd/commit/7f6070c960ed7bf02add5ab36436de6573f2f1fa))
|
||||
|
||||
## [1.35.1](https://github.com/certd/certd/compare/v1.35.0...v1.35.1) (2025-06-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复站点监控通知渠道设置无效的bug ([a00453c](https://github.com/certd/certd/commit/a00453c83a58114ce2873dd6e6aaf313f1ce0f87))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修改 HTTPS 服务器监听地址 ([e1cf64a](https://github.com/certd/certd/commit/e1cf64ae16d4abfe4299ff16d5088c30cf3c6365))
|
||||
* 优化流水线页面,增加下次执行时间、查看证书显示 ([c820315](https://github.com/certd/certd/commit/c8203154094fae3d17198747f49f5f41ddf29a4e))
|
||||
* 站点证书监控支持定时设置,重试次数设置 ([d3c2f8e](https://github.com/certd/certd/commit/d3c2f8eb436e670772d14a54acd6b541c5aa3978))
|
||||
* aliyun alb支持部署扩展证书 ([2a19b61](https://github.com/certd/certd/commit/2a19b61b7a78620c06396c2cc37cc77d738b6d12))
|
||||
|
||||
# [1.35.0](https://github.com/certd/certd/compare/v1.34.11...v1.35.0) (2025-06-05)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
ALTER TABLE pi_history ADD COLUMN `trigger_type` varchar(100);
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
ALTER TABLE pi_history ADD COLUMN "trigger_type" varchar(100);
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
ALTER TABLE pi_history ADD COLUMN "trigger_type" varchar(100);
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-server",
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.4",
|
||||
"description": "fast-server base midway",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -42,20 +42,20 @@
|
||||
"@aws-sdk/client-cloudfront": "^3.699.0",
|
||||
"@aws-sdk/client-iam": "^3.699.0",
|
||||
"@aws-sdk/client-s3": "^3.705.0",
|
||||
"@certd/acme-client": "^1.35.0",
|
||||
"@certd/basic": "^1.35.0",
|
||||
"@certd/commercial-core": "^1.35.0",
|
||||
"@certd/acme-client": "^1.35.4",
|
||||
"@certd/basic": "^1.35.4",
|
||||
"@certd/commercial-core": "^1.35.4",
|
||||
"@certd/cv4pve-api-javascript": "^8.4.1",
|
||||
"@certd/jdcloud": "^1.35.0",
|
||||
"@certd/lib-huawei": "^1.35.0",
|
||||
"@certd/lib-k8s": "^1.35.0",
|
||||
"@certd/lib-server": "^1.35.0",
|
||||
"@certd/midway-flyway-js": "^1.35.0",
|
||||
"@certd/pipeline": "^1.35.0",
|
||||
"@certd/plugin-cert": "^1.35.0",
|
||||
"@certd/plugin-lib": "^1.35.0",
|
||||
"@certd/plugin-plus": "^1.35.0",
|
||||
"@certd/plus-core": "^1.35.0",
|
||||
"@certd/jdcloud": "^1.35.4",
|
||||
"@certd/lib-huawei": "^1.35.4",
|
||||
"@certd/lib-k8s": "^1.35.4",
|
||||
"@certd/lib-server": "^1.35.4",
|
||||
"@certd/midway-flyway-js": "^1.35.4",
|
||||
"@certd/pipeline": "^1.35.4",
|
||||
"@certd/plugin-cert": "^1.35.4",
|
||||
"@certd/plugin-lib": "^1.35.4",
|
||||
"@certd/plugin-plus": "^1.35.4",
|
||||
"@certd/plus-core": "^1.35.4",
|
||||
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120",
|
||||
"@huaweicloud/huaweicloud-sdk-core": "^3.1.120",
|
||||
"@koa/cors": "^5.0.0",
|
||||
|
||||
@@ -154,4 +154,5 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
await this.service.saveSetting(userId, setting);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {ALL, Body, Controller, Inject, Post, Provide} from '@midwayjs/core';
|
||||
import {AccessService, BaseController, Constants} from '@certd/lib-server';
|
||||
import {AccessGetter, AccessService, BaseController, Constants} from '@certd/lib-server';
|
||||
import {
|
||||
AccessRequestHandleReq,
|
||||
IAccessService,
|
||||
@@ -33,6 +33,7 @@ export class HandleController extends BaseController {
|
||||
|
||||
@Post('/access', { summary: Constants.per.authOnly })
|
||||
async accessRequest(@Body(ALL) body: AccessRequestHandleReq) {
|
||||
const userId = this.getUserId();
|
||||
let inputAccess = body.input.access;
|
||||
if (body.input.id > 0) {
|
||||
const oldEntity = await this.accessService.info(body.input.id);
|
||||
@@ -48,8 +49,8 @@ export class HandleController extends BaseController {
|
||||
inputAccess = this.accessService.decryptAccessEntity(param);
|
||||
}
|
||||
}
|
||||
|
||||
const access = await newAccess(body.typeName, inputAccess);
|
||||
const accessGetter = new AccessGetter(userId, this.accessService.getById.bind(this.accessService));
|
||||
const access = await newAccess(body.typeName, inputAccess,accessGetter);
|
||||
|
||||
const res = await access.onRequest(body);
|
||||
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { PipelineService } from '../pipeline/service/pipeline-service.js';
|
||||
import { logger } from '@certd/basic';
|
||||
import { SysSettingsService } from '@certd/lib-server';
|
||||
import {SysSettingsService, SysSiteInfo} from '@certd/lib-server';
|
||||
import { SiteInfoService } from '../monitor/index.js';
|
||||
import { Cron } from '../cron/cron.js';
|
||||
import {UserSettingsService} from "../mine/service/user-settings-service.js";
|
||||
import {UserSiteMonitorSetting} from "../mine/service/models.js";
|
||||
import {getPlusInfo} from "@certd/plus-core";
|
||||
import dayjs from "dayjs";
|
||||
import {NotificationService} from "../pipeline/service/notification-service.js";
|
||||
import {UserService} from "../sys/authority/service/user-service.js";
|
||||
|
||||
@Autoload()
|
||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||
@@ -22,6 +28,8 @@ export class AutoCRegisterCron {
|
||||
|
||||
@Inject()
|
||||
sysSettingsService: SysSettingsService;
|
||||
@Inject()
|
||||
userSettingsService: UserSettingsService;
|
||||
|
||||
@Inject()
|
||||
siteInfoService: SiteInfoService;
|
||||
@@ -29,6 +37,13 @@ export class AutoCRegisterCron {
|
||||
@Inject()
|
||||
cron: Cron;
|
||||
|
||||
@Inject()
|
||||
notificationService: NotificationService;
|
||||
|
||||
@Inject()
|
||||
userService: UserService;
|
||||
|
||||
|
||||
@Init()
|
||||
async init() {
|
||||
logger.info('加载定时trigger开始');
|
||||
@@ -39,39 +54,87 @@ export class AutoCRegisterCron {
|
||||
// console.log('meta', meta);
|
||||
// const metas = listPropertyDataFromClass(CLASS_KEY, this.echoPlugin);
|
||||
// console.log('metas', metas);
|
||||
this.registerSiteMonitorCron();
|
||||
await this.registerSiteMonitorCron();
|
||||
|
||||
|
||||
await this.registerPlusExpireCheckCron();
|
||||
}
|
||||
|
||||
registerSiteMonitorCron() {
|
||||
const job = async () => {
|
||||
logger.info('站点证书检查开始执行');
|
||||
async registerSiteMonitorCron() {
|
||||
//先注册公共job
|
||||
await this.siteInfoService.registerSiteMonitorJob()
|
||||
|
||||
let offset = 0;
|
||||
const limit = 50;
|
||||
while (true) {
|
||||
const res = await this.siteInfoService.page({
|
||||
query: { disabled: false },
|
||||
page: { offset, limit },
|
||||
});
|
||||
const { records } = res;
|
||||
|
||||
if (records.length === 0) {
|
||||
break;
|
||||
}
|
||||
offset += records.length;
|
||||
await this.siteInfoService.checkList(records);
|
||||
//注册用户独立的检查时间
|
||||
const monitorSettingList = await this.userSettingsService.list({
|
||||
query:{
|
||||
key: UserSiteMonitorSetting.__key__,
|
||||
}
|
||||
})
|
||||
for (const item of monitorSettingList) {
|
||||
const setting = item.setting ?? JSON.parse(item.setting)
|
||||
if(!setting?.cron){
|
||||
continue
|
||||
}
|
||||
await this.siteInfoService.registerSiteMonitorJob(item.userId)
|
||||
}
|
||||
|
||||
logger.info('站点证书检查完成');
|
||||
};
|
||||
|
||||
this.cron.register({
|
||||
name: 'siteMonitor',
|
||||
cron: '0 0 0 * * *',
|
||||
job,
|
||||
});
|
||||
if (this.immediateTriggerSiteMonitor) {
|
||||
job();
|
||||
logger.info(`立即触发一次站点证书检查任务`)
|
||||
await this.siteInfoService.triggerJobOnce()
|
||||
}
|
||||
}
|
||||
|
||||
registerPlusExpireCheckCron(){
|
||||
// 添加plus即将到期检查任务
|
||||
this.cron.register({
|
||||
name: 'plus-expire-check',
|
||||
cron: `0 10 9 * * *`, // 一天只能检查一次,否则会重复发送通知
|
||||
job: async () => {
|
||||
const plusInfo = getPlusInfo()
|
||||
if (!plusInfo.originVipType || plusInfo.originVipType==="free" ) {
|
||||
return
|
||||
}
|
||||
let label ="专业版"
|
||||
if( plusInfo.originVipType === 'comm'){
|
||||
label = "商业版"
|
||||
}
|
||||
const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo)
|
||||
|
||||
const appTitle = siteInfo.title || "certd"
|
||||
const expiresDate = dayjs(plusInfo.expireTime).format("YYYY-MM-DD")
|
||||
// plusInfo.expireTime= dayjs("2025-06-10").valueOf()
|
||||
let expiresDays =Math.floor((plusInfo.expireTime - new Date().getTime())/ 1000 / 60 / 60 / 24)
|
||||
let title = ""
|
||||
let content =""
|
||||
if(expiresDays === 20 ||expiresDays === 10 || expiresDays === 3 || expiresDays === 1 || expiresDays === 0){
|
||||
title = `vip(${label})即将到期`
|
||||
content = `您的${appTitle} vip (${label})剩余${expiresDays}天(${expiresDate})到期,请及时续期,以免影响业务`
|
||||
}else if (expiresDays === -1 || expiresDays === -3 || expiresDays === -7) {
|
||||
title = `vip(${label})已过期`
|
||||
content = `您的${appTitle} vip (${label})已过期${Math.abs(expiresDays)}天(${expiresDate}),请尽快续期,以免影响业务`
|
||||
}
|
||||
if(title){
|
||||
logger.warn(title)
|
||||
logger.warn(content)
|
||||
const url = await this.notificationService.getBindUrl("");
|
||||
const adminUsers = await this.userService.getAdmins()
|
||||
for (const adminUser of adminUsers) {
|
||||
logger.info(`发送vip到期通知给管理员:${adminUser.username}`)
|
||||
await this.notificationService.send({
|
||||
useDefault: true,
|
||||
logger: logger,
|
||||
body:{
|
||||
title,
|
||||
content,
|
||||
errorMessage:title,
|
||||
url
|
||||
}
|
||||
},adminUser.id)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ export class HttpsServer {
|
||||
opts.app.callback()
|
||||
);
|
||||
this.server = httpServer;
|
||||
const hostname = '0.0.0.0';
|
||||
const hostname = '::';
|
||||
// A function that runs in the context of the http server
|
||||
// and reports what type of server listens on which port
|
||||
function listeningReporter() {
|
||||
|
||||
@@ -85,6 +85,8 @@ export class Cron {
|
||||
}
|
||||
this.logger.info(`[cron] register cron : [${req.name}] ,${req.cron}`);
|
||||
|
||||
this.remove(req.name)
|
||||
|
||||
const task = new CronTask(req, this.logger);
|
||||
this.queue.push(task);
|
||||
this.logger.info('当前定时任务数量:', this.getTaskSize());
|
||||
|
||||
@@ -25,6 +25,8 @@ export class UserSiteMonitorSetting extends BaseSettings {
|
||||
static __key__ = "user.site.monitor";
|
||||
|
||||
notificationId?:number= 0;
|
||||
cron?:string = undefined;
|
||||
retryTimes?:number = 3;
|
||||
}
|
||||
|
||||
export class UserEmailSetting extends BaseSettings {
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||
import { BaseService, NeedSuiteException, NeedVIPException, SysSettingsService } from "@certd/lib-server";
|
||||
import { InjectEntityModel } from "@midwayjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { SiteInfoEntity } from "../entity/site-info.js";
|
||||
import { siteTester } from "./site-tester.js";
|
||||
import {Inject, Provide, Scope, ScopeEnum} from "@midwayjs/core";
|
||||
import {BaseService, NeedSuiteException, NeedVIPException, SysSettingsService} from "@certd/lib-server";
|
||||
import {InjectEntityModel} from "@midwayjs/typeorm";
|
||||
import {Repository} from "typeorm";
|
||||
import {SiteInfoEntity} from "../entity/site-info.js";
|
||||
import {siteTester} from "./site-tester.js";
|
||||
import dayjs from "dayjs";
|
||||
import { logger, utils } from "@certd/basic";
|
||||
import { PeerCertificate } from "tls";
|
||||
import { NotificationService } from "../../pipeline/service/notification-service.js";
|
||||
import { isComm, isPlus } from "@certd/plus-core";
|
||||
import { UserSuiteService } from "@certd/commercial-core";
|
||||
import { UserSettingsService } from "../../mine/service/user-settings-service.js";
|
||||
import { UserSiteMonitorSetting } from "../../mine/service/models.js";
|
||||
import { SiteIpService } from "./site-ip-service.js";
|
||||
import { SiteIpEntity } from "../entity/site-ip.js";
|
||||
import {logger, utils} from "@certd/basic";
|
||||
import {PeerCertificate} from "tls";
|
||||
import {NotificationService} from "../../pipeline/service/notification-service.js";
|
||||
import {isComm, isPlus} from "@certd/plus-core";
|
||||
import {UserSuiteService} from "@certd/commercial-core";
|
||||
import {UserSettingsService} from "../../mine/service/user-settings-service.js";
|
||||
import {UserSiteMonitorSetting} from "../../mine/service/models.js";
|
||||
import {SiteIpService} from "./site-ip-service.js";
|
||||
import {SiteIpEntity} from "../entity/site-ip.js";
|
||||
import {Cron} from "../../cron/cron.js";
|
||||
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||
@Scope(ScopeEnum.Request, {allowDowngrade: true})
|
||||
export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
@InjectEntityModel(SiteInfoEntity)
|
||||
repository: Repository<SiteInfoEntity>;
|
||||
@@ -36,6 +37,10 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
@Inject()
|
||||
siteIpService: SiteIpService;
|
||||
|
||||
|
||||
@Inject()
|
||||
cron: Cron;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
@@ -70,7 +75,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
}
|
||||
});
|
||||
if (found) {
|
||||
return { id: found.id };
|
||||
return {id: found.id};
|
||||
}
|
||||
|
||||
return await super.add(data);
|
||||
@@ -89,7 +94,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
throw new Error("userId is required");
|
||||
}
|
||||
return await this.repository.count({
|
||||
where: { userId }
|
||||
where: {userId}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -99,7 +104,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
* @param notify
|
||||
* @param retryTimes
|
||||
*/
|
||||
async doCheck(site: SiteInfoEntity, notify = true, retryTimes = 3) {
|
||||
async doCheck(site: SiteInfoEntity, notify = true, retryTimes = null) {
|
||||
if (!site?.domain) {
|
||||
throw new Error("站点域名不能为空");
|
||||
}
|
||||
@@ -141,13 +146,13 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
};
|
||||
|
||||
if (site.ipCheck) {
|
||||
delete updateData.checkStatus
|
||||
delete updateData.checkStatus
|
||||
}
|
||||
await this.update(updateData);
|
||||
|
||||
|
||||
//检查ip
|
||||
await this.checkAllIp(site);
|
||||
await this.checkAllIp(site,retryTimes);
|
||||
|
||||
if (!notify) {
|
||||
return;
|
||||
@@ -176,7 +181,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
async checkAllIp(site: SiteInfoEntity) {
|
||||
async checkAllIp(site: SiteInfoEntity,retryTimes = null) {
|
||||
if (!site.ipCheck) {
|
||||
return;
|
||||
}
|
||||
@@ -220,7 +225,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
logger.error("send notify error", e);
|
||||
}
|
||||
};
|
||||
await this.siteIpService.checkAll(site, onFinished);
|
||||
await this.siteIpService.checkAll(site, retryTimes,onFinished);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -229,7 +234,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
* @param notify
|
||||
* @param retryTimes
|
||||
*/
|
||||
async check(id: number, notify = false, retryTimes = 3) {
|
||||
async check(id: number, notify = false, retryTimes = null) {
|
||||
const site = await this.info(id);
|
||||
if (!site) {
|
||||
throw new Error("站点不存在");
|
||||
@@ -239,9 +244,11 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
|
||||
async sendCheckErrorNotify(site: SiteInfoEntity, fromIpCheck = false) {
|
||||
const url = await this.notificationService.getBindUrl("#/certd/monitor/site");
|
||||
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(site.userId, UserSiteMonitorSetting)
|
||||
// 发邮件
|
||||
await this.notificationService.send(
|
||||
{
|
||||
id: setting?.notificationId,
|
||||
useDefault: true,
|
||||
logger: logger,
|
||||
body: {
|
||||
@@ -262,11 +269,13 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
const expires = site.certExpiresTime;
|
||||
const validDays = dayjs(expires).diff(dayjs(), "day");
|
||||
const url = await this.notificationService.getBindUrl("#/certd/monitor/site");
|
||||
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(site.userId, UserSiteMonitorSetting)
|
||||
const content = `站点名称: ${site.name} \n站点域名: ${site.domain} \n证书域名: ${site.certDomains} \n颁发机构: ${site.certProvider} \n过期时间: ${dayjs(site.certExpiresTime).format("YYYY-MM-DD")} \n`;
|
||||
if (validDays >= 0 && validDays < tipDays) {
|
||||
// 发通知
|
||||
await this.notificationService.send(
|
||||
{
|
||||
id: setting?.notificationId,
|
||||
useDefault: true,
|
||||
logger: logger,
|
||||
body: {
|
||||
@@ -281,6 +290,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
//发过期通知
|
||||
await this.notificationService.send(
|
||||
{
|
||||
id: setting?.notificationId,
|
||||
useDefault: true,
|
||||
logger: logger,
|
||||
body: {
|
||||
@@ -300,17 +310,35 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
throw new Error("userId is required");
|
||||
}
|
||||
const sites = await this.repository.find({
|
||||
where: { userId }
|
||||
where: {userId}
|
||||
});
|
||||
this.checkList(sites);
|
||||
this.checkList(sites,false);
|
||||
}
|
||||
|
||||
async checkList(sites: SiteInfoEntity[]) {
|
||||
async checkList(sites: SiteInfoEntity[],isCommon: boolean) {
|
||||
const cache = {}
|
||||
const getFromCache = async (userId: number) =>{
|
||||
if (cache[userId]) {
|
||||
return cache[userId];
|
||||
}
|
||||
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId, UserSiteMonitorSetting)
|
||||
cache[userId] = setting
|
||||
return setting;
|
||||
}
|
||||
for (const site of sites) {
|
||||
this.doCheck(site).catch(e => {
|
||||
const setting = await getFromCache(site.userId)
|
||||
if (isCommon) {
|
||||
//公共的检查,排除有设置cron的用户
|
||||
if (setting?.cron) {
|
||||
//设置了cron,跳过公共检查
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let retryTimes = setting?.retryTimes
|
||||
this.doCheck(site,true,retryTimes).catch(e => {
|
||||
logger.error(`检查站点证书失败,${site.domain}`, e.message);
|
||||
});
|
||||
await utils.sleep(200);
|
||||
await utils.sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,6 +348,12 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
|
||||
async saveSetting(userId: number, bean: UserSiteMonitorSetting) {
|
||||
await this.userSettingsService.saveSetting(userId, bean);
|
||||
if(bean.cron){
|
||||
//注册job
|
||||
await this.registerSiteMonitorJob(userId);
|
||||
}else{
|
||||
this.clearSiteMonitorJob(userId);
|
||||
}
|
||||
}
|
||||
|
||||
async ipCheckChange(req: { id: any; ipCheck: any }) {
|
||||
@@ -396,4 +430,67 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
};
|
||||
await batchAdd(list);
|
||||
}
|
||||
|
||||
clearSiteMonitorJob(userId: number) {
|
||||
this.cron.remove(`siteMonitor-${userId}`);
|
||||
}
|
||||
|
||||
async registerSiteMonitorJob(userId?: number) {
|
||||
|
||||
if(!userId){
|
||||
//注册公共job
|
||||
logger.info(`注册站点证书检查定时任务`)
|
||||
this.cron.register({
|
||||
name: 'siteMonitor',
|
||||
cron: '0 0 0 * * *',
|
||||
job:async ()=>{
|
||||
await this.triggerJobOnce()
|
||||
},
|
||||
});
|
||||
logger.info(`注册站点证书检查定时任务完成`)
|
||||
}else{
|
||||
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId, UserSiteMonitorSetting);
|
||||
if (!setting.cron) {
|
||||
return;
|
||||
}
|
||||
//注册个人的
|
||||
this.cron.register({
|
||||
name: `siteMonitor-${userId}`,
|
||||
cron: setting.cron,
|
||||
job: () => this.triggerJobOnce(userId),
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async triggerJobOnce(userId?:number) {
|
||||
logger.info(`站点证书检查开始执行[${userId??'所有用户'}]`);
|
||||
const query:any = { disabled: false };
|
||||
if(userId){
|
||||
query.userId = userId;
|
||||
//判断是否已关闭
|
||||
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId, UserSiteMonitorSetting);
|
||||
if (!setting.cron) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let offset = 0;
|
||||
const limit = 50;
|
||||
while (true) {
|
||||
const res = await this.page({
|
||||
query: query,
|
||||
page: { offset, limit },
|
||||
});
|
||||
const { records } = res;
|
||||
|
||||
if (records.length === 0) {
|
||||
break;
|
||||
}
|
||||
offset += records.length;
|
||||
const isCommon = !userId;
|
||||
await this.checkList(records,isCommon);
|
||||
}
|
||||
|
||||
logger.info(`站点证书检查完成[${userId??'所有用户'}]`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
await this.updateIpCount(entity.id)
|
||||
}
|
||||
|
||||
async check(ipId: number, domain: string, port: number) {
|
||||
async check(ipId: number, domain: string, port: number,retryTimes = null) {
|
||||
if(!ipId){
|
||||
return
|
||||
}
|
||||
@@ -105,7 +105,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
const res = await siteTester.test({
|
||||
host: domain,
|
||||
port: port,
|
||||
retryTimes: 3,
|
||||
retryTimes : retryTimes??3,
|
||||
ipAddress: entity.ipAddress
|
||||
});
|
||||
|
||||
@@ -154,7 +154,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
async checkAll(siteInfo: SiteInfoEntity,onFinish?: (e: any) => void) {
|
||||
async checkAll(siteInfo: SiteInfoEntity,retryTimes = null,onFinish?: (e: any) => void) {
|
||||
const siteId = siteInfo.id;
|
||||
const ips = await this.repository.find({
|
||||
where: {
|
||||
@@ -167,7 +167,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
for (const item of ips) {
|
||||
const func = async () => {
|
||||
try {
|
||||
return await this.check(item.id, domain, port);
|
||||
return await this.check(item.id, domain, port,retryTimes);
|
||||
} catch (e) {
|
||||
logger.error("check site item error", e);
|
||||
return {
|
||||
|
||||
@@ -18,7 +18,7 @@ export type SiteTestRes = {
|
||||
export class SiteTester {
|
||||
async test(req: SiteTestReq): Promise<SiteTestRes> {
|
||||
logger.info("测试站点:", JSON.stringify(req));
|
||||
const maxRetryTimes = req.retryTimes ?? 3;
|
||||
const maxRetryTimes = req.retryTimes==null ? 3 : req.retryTimes;
|
||||
let tryCount = 0;
|
||||
let result: SiteTestRes = {};
|
||||
while (true) {
|
||||
@@ -28,12 +28,12 @@ export class SiteTester {
|
||||
} catch (e) {
|
||||
tryCount++;
|
||||
if (tryCount > maxRetryTimes) {
|
||||
logger.error(`测试站点出错,重试${maxRetryTimes}次。`, e.message);
|
||||
logger.error(`测试站点出错,已超过最大重试次数(${maxRetryTimes})`, e.message);
|
||||
throw e;
|
||||
}
|
||||
//指数退避
|
||||
const time = 2 ** tryCount;
|
||||
logger.error(`测试站点出错,${time}s后重试`, e);
|
||||
logger.error(`测试站点出错,${time}s后重试(${tryCount}/${maxRetryTimes})`, e);
|
||||
await utils.sleep(time * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ export class HistoryEntity {
|
||||
@Column({ comment: '结果状态', length: 20, nullable: true })
|
||||
status: string;
|
||||
|
||||
@Column({ name: 'trigger_type',comment: '触发类型', length: 20, nullable: true })
|
||||
triggerType: string;
|
||||
|
||||
@Column({
|
||||
name: 'end_time',
|
||||
comment: '结束时间',
|
||||
|
||||
@@ -60,12 +60,13 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
||||
return new HistoryDetail(entity, log);
|
||||
}
|
||||
|
||||
async start(pipeline: PipelineEntity) {
|
||||
async start(pipeline: PipelineEntity,triggerType:string) {
|
||||
const bean = {
|
||||
userId: pipeline.userId,
|
||||
pipelineId: pipeline.id,
|
||||
title: pipeline.title,
|
||||
status: 'start',
|
||||
triggerType
|
||||
};
|
||||
const { id } = await this.add(bean);
|
||||
//清除大于pipeline.keepHistoryCount的历史记录
|
||||
|
||||
@@ -110,6 +110,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
}
|
||||
|
||||
async add(bean: PipelineEntity) {
|
||||
bean.status = ResultType.none
|
||||
await this.save(bean);
|
||||
return bean;
|
||||
}
|
||||
@@ -191,6 +192,9 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
await this.checkMaxPipelineCount(bean, pipeline, domains);
|
||||
}
|
||||
|
||||
if (!bean.status ){
|
||||
bean.status = ResultType.none;
|
||||
}
|
||||
if (!isUpdate) {
|
||||
//如果是添加,先保存一下,获取到id,更新pipeline.id
|
||||
await this.addOrUpdate(bean);
|
||||
@@ -493,7 +497,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
};
|
||||
|
||||
const userId = entity.userId;
|
||||
const historyId = await this.historyService.start(entity);
|
||||
const historyId = await this.historyService.start(entity,triggerType);
|
||||
const userIsAdmin = await this.userService.isAdmin(userId);
|
||||
const user: UserInfo = {
|
||||
id: userId,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { MoreThan, Not, Repository } from 'typeorm';
|
||||
import {In, MoreThan, Not, Repository} from 'typeorm';
|
||||
import { UserEntity } from '../entity/user.js';
|
||||
import * as _ from 'lodash-es';
|
||||
import { BaseService, CommonException, Constants, FileService, SysInstallInfo, SysSettingsService } from '@certd/lib-server';
|
||||
@@ -15,6 +15,8 @@ import { DbAdapter } from '../../../db/index.js';
|
||||
import { simpleNanoId, utils } from '@certd/basic';
|
||||
|
||||
export type RegisterType = 'username' | 'mobile' | 'email';
|
||||
|
||||
export const AdminRoleId = 1
|
||||
/**
|
||||
* 系统用户
|
||||
*/
|
||||
@@ -275,7 +277,7 @@ export class UserService extends BaseService<UserEntity> {
|
||||
},
|
||||
});
|
||||
const roleIds = userRoles.map(item => item.roleId);
|
||||
if (roleIds.includes(1)) {
|
||||
if (roleIds.includes(AdminRoleId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -313,4 +315,23 @@ export class UserService extends BaseService<UserEntity> {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async getAdmins() {
|
||||
const admins = await this.userRoleService.find({
|
||||
where: {
|
||||
roleId: AdminRoleId,
|
||||
},
|
||||
});
|
||||
|
||||
const userIds = admins.map(item => item.userId);
|
||||
return await this.repository.find({
|
||||
where: {
|
||||
id: In(userIds),
|
||||
status: 1,
|
||||
},
|
||||
order: {
|
||||
updateTime: 'DESC',
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,3 +24,4 @@ export * from './plugin-notification/index.js'
|
||||
export * from './plugin-flex/index.js'
|
||||
export * from './plugin-farcdn/index.js'
|
||||
export * from './plugin-fnos/index.js'
|
||||
export * from './plugin-rainyun/index.js'
|
||||
|
||||
@@ -101,7 +101,6 @@ export class AliyunDnsProvider extends AbstractDnsProvider {
|
||||
const requestOption = {
|
||||
method: 'POST',
|
||||
};
|
||||
|
||||
try {
|
||||
const ret = await this.client.request('AddDomainRecord', params, requestOption);
|
||||
this.logger.info('添加域名解析成功:', JSON.stringify(options), ret.RecordId);
|
||||
@@ -110,6 +109,11 @@ export class AliyunDnsProvider extends AbstractDnsProvider {
|
||||
if (e.code === 'DomainRecordDuplicate') {
|
||||
return;
|
||||
}
|
||||
if(e.code === "LastOperationNotFinished"){
|
||||
this.logger.info('上一个操作还未完成,5s后重试')
|
||||
await this.ctx.utils.sleep(5000)
|
||||
return this.createRecord(options)
|
||||
}
|
||||
this.logger.info('添加域名解析出错', e);
|
||||
this.resolveError(e, options);
|
||||
}
|
||||
@@ -132,10 +136,18 @@ export class AliyunDnsProvider extends AbstractDnsProvider {
|
||||
const requestOption = {
|
||||
method: 'POST',
|
||||
};
|
||||
|
||||
const ret = await this.client.request('DeleteDomainRecord', params, requestOption);
|
||||
this.logger.info('删除域名解析成功:', fullRecord, value, ret.RecordId);
|
||||
return ret.RecordId;
|
||||
try{
|
||||
const ret = await this.client.request('DeleteDomainRecord', params, requestOption);
|
||||
this.logger.info('删除域名解析成功:', fullRecord, value, ret.RecordId);
|
||||
return ret.RecordId;
|
||||
}catch (e) {
|
||||
if(e.code === "LastOperationNotFinished"){
|
||||
this.logger.info('上一个操作还未完成,5s后重试')
|
||||
await this.ctx.utils.sleep(5000)
|
||||
return this.removeRecord(options)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,36 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { CertInfo ,CertApplyPluginNames, CertReader} from '@certd/plugin-cert';
|
||||
import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { CertApplyPluginNames, CertInfo, CertReader } from "@certd/plugin-cert";
|
||||
import {
|
||||
AliyunAccess,
|
||||
AliyunClient,
|
||||
AliyunClientV2,
|
||||
AliyunSslClient,
|
||||
createCertDomainGetterInputDefine,
|
||||
createRemoteSelectInputDefine
|
||||
} from "@certd/plugin-lib";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'AliyunDeployCertToALB',
|
||||
title: '阿里云-部署至ALB(应用负载均衡)',
|
||||
icon: 'svg:icon-aliyun',
|
||||
name: "AliyunDeployCertToALB",
|
||||
title: "阿里云-部署至ALB(应用负载均衡)",
|
||||
icon: "svg:icon-aliyun",
|
||||
group: pluginGroups.aliyun.key,
|
||||
desc: 'ALB,更新监听器的默认证书',
|
||||
desc: "ALB,更新监听器的默认证书",
|
||||
needPlus: false,
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
runStrategy: RunStrategy.SkipWhenSucceed
|
||||
}
|
||||
}
|
||||
})
|
||||
export class AliyunDeployCertToALB extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID,可以减少上传到阿里云的证书数量',
|
||||
title: "域名证书",
|
||||
helper: "请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID,可以减少上传到阿里云的证书数量",
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: [...CertApplyPluginNames, 'uploadCertToAliyun'],
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames, "uploadCertToAliyun"]
|
||||
},
|
||||
required: true,
|
||||
required: true
|
||||
})
|
||||
cert!: CertInfo | number;
|
||||
|
||||
@@ -31,122 +38,257 @@ export class AliyunDeployCertToALB extends AbstractTaskPlugin {
|
||||
certDomains!: string[];
|
||||
|
||||
@TaskInput({
|
||||
title: 'Access授权',
|
||||
helper: '阿里云授权AccessKeyId、AccessKeySecret',
|
||||
title: "证书接入点",
|
||||
helper: "不会选就保持默认即可",
|
||||
value: "cas.aliyuncs.com",
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'aliyun',
|
||||
name: "a-select",
|
||||
options: [
|
||||
{ value: "cas.aliyuncs.com", label: "中国大陆" },
|
||||
{ value: "cas.ap-southeast-1.aliyuncs.com", label: "新加坡" },
|
||||
{ value: "cas.eu-central-1.aliyuncs.com", label: "德国(法兰克福)" }
|
||||
]
|
||||
},
|
||||
required: true,
|
||||
required: true
|
||||
})
|
||||
casEndpoint!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "Access授权",
|
||||
helper: "阿里云授权AccessKeyId、AccessKeySecret",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "aliyun"
|
||||
},
|
||||
required: true
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: 'ALB所在地区',
|
||||
typeName: 'AliyunDeployCertToALB',
|
||||
title: "ALB所在地区",
|
||||
typeName: "AliyunDeployCertToALB",
|
||||
multi: false,
|
||||
action: AliyunDeployCertToALB.prototype.onGetRegionList.name,
|
||||
watches: ['accessId'],
|
||||
watches: ["accessId"]
|
||||
})
|
||||
)
|
||||
regionId: string;
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: '负载均衡列表',
|
||||
helper: '要部署证书的负载均衡ID',
|
||||
typeName: 'AliyunDeployCertToALB',
|
||||
title: "负载均衡列表",
|
||||
helper: "要部署证书的负载均衡ID",
|
||||
typeName: "AliyunDeployCertToALB",
|
||||
action: AliyunDeployCertToALB.prototype.onGetLoadBalanceList.name,
|
||||
watches: ['regionId'],
|
||||
watches: ["regionId"]
|
||||
})
|
||||
)
|
||||
loadBalancers!: string[];
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: '监听器列表',
|
||||
helper: '要部署证书的监听器列表',
|
||||
typeName: 'AliyunDeployCertToALB',
|
||||
title: "监听器列表",
|
||||
helper: "要部署证书的监听器列表",
|
||||
typeName: "AliyunDeployCertToALB",
|
||||
action: AliyunDeployCertToALB.prototype.onGetListenerList.name,
|
||||
watches: ['loadBalancers'],
|
||||
watches: ["loadBalancers"]
|
||||
})
|
||||
)
|
||||
listeners!: string[];
|
||||
|
||||
@TaskInput({
|
||||
title: '证书接入点',
|
||||
helper: '不会选就保持默认即可',
|
||||
value: 'cas.aliyuncs.com',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
options: [
|
||||
{ value: 'cas.aliyuncs.com', label: '中国大陆' },
|
||||
{ value: 'cas.ap-southeast-1.aliyuncs.com', label: '新加坡' },
|
||||
{ value: 'cas.eu-central-1.aliyuncs.com', label: '德国(法兰克福)' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
casEndpoint!: string;
|
||||
|
||||
async onInstance() {}
|
||||
@TaskInput({
|
||||
title: "部署证书类型",
|
||||
value: "default",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{
|
||||
label: "默认证书",
|
||||
value: "default"
|
||||
},
|
||||
{
|
||||
label: "扩展证书",
|
||||
value: "extension"
|
||||
}
|
||||
]
|
||||
},
|
||||
required: true
|
||||
}
|
||||
)
|
||||
deployType: string = "default";
|
||||
|
||||
|
||||
async onInstance() {
|
||||
}
|
||||
|
||||
async getLBClient(access: AliyunAccess, region: string) {
|
||||
const client = new AliyunClient({ logger: this.logger });
|
||||
|
||||
const version = '2020-06-16';
|
||||
const version = "2020-06-16";
|
||||
await client.init({
|
||||
accessKeyId: access.accessKeyId,
|
||||
accessKeySecret: access.accessKeySecret,
|
||||
//https://wafopenapi.cn-hangzhou.aliyuncs.com
|
||||
endpoint: `https://alb.${region}.aliyuncs.com`,
|
||||
apiVersion: version,
|
||||
apiVersion: version
|
||||
});
|
||||
return client;
|
||||
}
|
||||
|
||||
getALBClientV2(access: AliyunAccess) {
|
||||
return access.getClient(`alb.${this.regionId}.aliyuncs.com`);
|
||||
}
|
||||
|
||||
async execute(): Promise<void> {
|
||||
this.logger.info(`开始部署证书到阿里云(alb)`);
|
||||
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||||
const certId = await this.getAliyunCertId(access);
|
||||
|
||||
const client = await this.getLBClient(access, this.regionId);
|
||||
//部署扩展证书
|
||||
const albClientV2 = this.getALBClientV2(access);
|
||||
if (this.deployType === "extension") {
|
||||
await this.deployExtensionCert(albClientV2, certId);
|
||||
} else {
|
||||
const client = await this.getLBClient(access, this.regionId);
|
||||
await this.deployDefaultCert(certId, client);
|
||||
}
|
||||
|
||||
await this.ctx.utils.sleep(10000)
|
||||
for (const listener of this.listeners) {
|
||||
await this.clearInvalidCert(albClientV2, listener);
|
||||
}
|
||||
|
||||
|
||||
this.logger.info("执行完成");
|
||||
}
|
||||
|
||||
private async deployDefaultCert(certId: any, client: AliyunClient) {
|
||||
for (const listener of this.listeners) {
|
||||
//查询原来的证书
|
||||
let params: any = {};
|
||||
params = {
|
||||
ListenerId: listener,
|
||||
Certificates: [
|
||||
{
|
||||
CertificateId: certId,
|
||||
},
|
||||
],
|
||||
CertificateId: certId
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const res = await client.request('UpdateListenerAttribute', params);
|
||||
const res = await client.request("UpdateListenerAttribute", params);
|
||||
this.checkRet(res);
|
||||
this.logger.info(`部署${listener}监听器证书成功`, JSON.stringify(res));
|
||||
|
||||
//删除旧证书关联
|
||||
}
|
||||
this.logger.info('执行完成');
|
||||
}
|
||||
|
||||
async deployExtensionCert(client: AliyunClientV2, certId: any) {
|
||||
for (const listenerId of this.listeners) {
|
||||
this.logger.info(`开始部署监听器${listenerId}的扩展证书`);
|
||||
await client.doRequest({
|
||||
// 接口名称
|
||||
action: "AssociateAdditionalCertificatesWithListener",
|
||||
// 接口版本
|
||||
version: "2020-06-16",
|
||||
data: {
|
||||
query: {
|
||||
ListenerId: listenerId,
|
||||
Certificates: [
|
||||
{
|
||||
CertificateId: certId
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.logger.info(`部署监听器${listenerId}的扩展证书成功`);
|
||||
}
|
||||
}
|
||||
|
||||
async clearInvalidCert(client: AliyunClientV2, listener: string) {
|
||||
this.logger.info(`开始清理监听器${listener}的过期证书`);
|
||||
const req = {
|
||||
// 接口名称
|
||||
action: "ListListenerCertificates",
|
||||
// 接口版本
|
||||
version: "2020-06-16",
|
||||
data: {
|
||||
query: {
|
||||
ListenerId: listener
|
||||
}
|
||||
}
|
||||
};
|
||||
const res = await client.doRequest(req);
|
||||
const list = res.Certificates;
|
||||
if (list.length === 0) {
|
||||
this.logger.info(`监听器${listener}没有绑定证书`);
|
||||
return
|
||||
}
|
||||
|
||||
const sslClient = new AliyunSslClient({
|
||||
access: client.access,
|
||||
logger: this.logger,
|
||||
endpoint: this.casEndpoint
|
||||
});
|
||||
|
||||
|
||||
const certIds = [];
|
||||
for (const item of list) {
|
||||
if (item.Status !== "Associated") {
|
||||
continue;
|
||||
}
|
||||
if (item.IsDefault) {
|
||||
continue;
|
||||
}
|
||||
certIds.push( parseInt(item.CertificateId));
|
||||
}
|
||||
//检查是否过期,过期则删除
|
||||
const invalidCertIds = [];
|
||||
for (const certId of certIds) {
|
||||
const res = await sslClient.getCertInfo(certId);
|
||||
if (res.notAfter < new Date().getTime()) {
|
||||
invalidCertIds.push(certId);
|
||||
}
|
||||
}
|
||||
if (invalidCertIds.length === 0) {
|
||||
this.logger.info(`监听器${listener}没有过期的证书`);
|
||||
return
|
||||
}
|
||||
this.logger.info(`开始解绑过期的证书:${invalidCertIds}`);
|
||||
await client.doRequest({
|
||||
// 接口名称
|
||||
action: "DissociateAdditionalCertificatesFromListener",
|
||||
// 接口版本
|
||||
version: "2020-06-16",
|
||||
data: {
|
||||
query: {
|
||||
ListenerId: listener,
|
||||
Certificates: invalidCertIds.map((item) => {
|
||||
return {
|
||||
CertificateId: item
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
this.logger.info(`解绑过期证书成功`);
|
||||
}
|
||||
|
||||
async getAliyunCertId(access: AliyunAccess) {
|
||||
let certId: any = this.cert;
|
||||
if (typeof this.cert === 'object') {
|
||||
if (typeof this.cert === "object") {
|
||||
const sslClient = new AliyunSslClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
endpoint: this.casEndpoint,
|
||||
endpoint: this.casEndpoint
|
||||
});
|
||||
|
||||
const certName = this.buildCertName(CertReader.getMainDomain(this.cert.crt))
|
||||
const certName = this.buildCertName(CertReader.getMainDomain(this.cert.crt));
|
||||
certId = await sslClient.uploadCert({
|
||||
name: certName,
|
||||
cert: this.cert,
|
||||
cert: this.cert
|
||||
});
|
||||
}
|
||||
return certId;
|
||||
@@ -154,74 +296,74 @@ export class AliyunDeployCertToALB extends AbstractTaskPlugin {
|
||||
|
||||
async onGetRegionList(data: any) {
|
||||
if (!this.accessId) {
|
||||
throw new Error('请选择Access授权');
|
||||
throw new Error("请选择Access授权");
|
||||
}
|
||||
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||||
const client = await this.getLBClient(access, 'cn-shanghai');
|
||||
const client = await this.getLBClient(access, "cn-shanghai");
|
||||
|
||||
const res = await client.request('DescribeRegions', {});
|
||||
const res = await client.request("DescribeRegions", {});
|
||||
this.checkRet(res);
|
||||
if (!res?.Regions || res?.Regions.length === 0) {
|
||||
throw new Error('没有找到Regions列表');
|
||||
throw new Error("没有找到Regions列表");
|
||||
}
|
||||
|
||||
return res.Regions.map((item: any) => {
|
||||
return {
|
||||
label: item.LocalName,
|
||||
value: item.RegionId,
|
||||
endpoint: item.RegionEndpoint,
|
||||
endpoint: item.RegionEndpoint
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async onGetLoadBalanceList(data: any) {
|
||||
if (!this.accessId) {
|
||||
throw new Error('请先选择Access授权');
|
||||
throw new Error("请先选择Access授权");
|
||||
}
|
||||
if (!this.regionId) {
|
||||
throw new Error('请先选择地区');
|
||||
throw new Error("请先选择地区");
|
||||
}
|
||||
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||||
const client = await this.getLBClient(access, this.regionId);
|
||||
|
||||
const params = {
|
||||
MaxResults: 100,
|
||||
MaxResults: 100
|
||||
};
|
||||
const res = await client.request('ListLoadBalancers', params);
|
||||
const res = await client.request("ListLoadBalancers", params);
|
||||
this.checkRet(res);
|
||||
if (!res?.LoadBalancers || res?.LoadBalancers.length === 0) {
|
||||
throw new Error('没有找到LoadBalancers');
|
||||
throw new Error("没有找到LoadBalancers");
|
||||
}
|
||||
|
||||
return res.LoadBalancers.map((item: any) => {
|
||||
const label = `${item.LoadBalancerId}<${item.LoadBalancerName}}>`;
|
||||
return {
|
||||
label: label,
|
||||
value: item.LoadBalancerId,
|
||||
value: item.LoadBalancerId
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async onGetListenerList(data: any) {
|
||||
if (!this.accessId) {
|
||||
throw new Error('请先选择Access授权');
|
||||
throw new Error("请先选择Access授权");
|
||||
}
|
||||
if (!this.regionId) {
|
||||
throw new Error('请先选择地区');
|
||||
throw new Error("请先选择地区");
|
||||
}
|
||||
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||||
const client = await this.getLBClient(access, this.regionId);
|
||||
|
||||
const params: any = {
|
||||
MaxResults: 100,
|
||||
MaxResults: 100
|
||||
};
|
||||
if (this.loadBalancers && this.loadBalancers.length > 0) {
|
||||
params.LoadBalancerIds = this.loadBalancers;
|
||||
}
|
||||
const res = await client.request('ListListeners', params);
|
||||
const res = await client.request("ListListeners", params);
|
||||
this.checkRet(res);
|
||||
if (!res?.Listeners || res?.Listeners.length === 0) {
|
||||
throw new Error('没有找到HTTPS监听器');
|
||||
throw new Error("没有找到HTTPS监听器");
|
||||
}
|
||||
|
||||
return res.Listeners.map((item: any) => {
|
||||
@@ -229,16 +371,19 @@ export class AliyunDeployCertToALB extends AbstractTaskPlugin {
|
||||
return {
|
||||
label: label,
|
||||
value: item.ListenerId,
|
||||
lbid: item.LoadBalancerId,
|
||||
lbid: item.LoadBalancerId
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
checkRet(ret: any) {
|
||||
if (ret.Code != null) {
|
||||
throw new Error(ret.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
new AliyunDeployCertToALB();
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { CertInfo, CertReader } from "@certd/plugin-cert";
|
||||
import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
|
||||
import {
|
||||
AliyunAccess,
|
||||
AliyunClient,
|
||||
AliyunClientV2,
|
||||
AliyunSslClient,
|
||||
createCertDomainGetterInputDefine,
|
||||
createRemoteSelectInputDefine
|
||||
} from "@certd/plugin-lib";
|
||||
import { CertApplyPluginNames} from '@certd/plugin-cert';
|
||||
@IsTaskPlugin({
|
||||
name: 'AliyunDeployCertToNLB',
|
||||
@@ -30,6 +37,23 @@ export class AliyunDeployCertToNLB extends AbstractTaskPlugin {
|
||||
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||
certDomains!: string[];
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: '证书接入点',
|
||||
helper: '不会选就保持默认即可',
|
||||
value: 'cas.aliyuncs.com',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
options: [
|
||||
{ value: 'cas.aliyuncs.com', label: '中国大陆' },
|
||||
{ value: 'cas.ap-southeast-1.aliyuncs.com', label: '新加坡' },
|
||||
{ value: 'cas.eu-central-1.aliyuncs.com', label: '德国(法兰克福)' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
casEndpoint!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: 'Access授权',
|
||||
helper: '阿里云授权AccessKeyId、AccessKeySecret',
|
||||
@@ -74,21 +98,30 @@ export class AliyunDeployCertToNLB extends AbstractTaskPlugin {
|
||||
)
|
||||
listeners!: string[];
|
||||
|
||||
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: '证书接入点',
|
||||
helper: '不会选就保持默认即可',
|
||||
value: 'cas.aliyuncs.com',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
options: [
|
||||
{ value: 'cas.aliyuncs.com', label: '中国大陆' },
|
||||
{ value: 'cas.ap-southeast-1.aliyuncs.com', label: '新加坡' },
|
||||
{ value: 'cas.eu-central-1.aliyuncs.com', label: '德国(法兰克福)' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
casEndpoint!: string;
|
||||
title: "部署证书类型",
|
||||
value: "default",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{
|
||||
label: "默认证书",
|
||||
value: "default"
|
||||
},
|
||||
{
|
||||
label: "扩展证书",
|
||||
value: "extension"
|
||||
}
|
||||
]
|
||||
},
|
||||
required: true
|
||||
}
|
||||
)
|
||||
deployType: string = "default";
|
||||
|
||||
async onInstance() {}
|
||||
|
||||
@@ -110,24 +143,137 @@ export class AliyunDeployCertToNLB extends AbstractTaskPlugin {
|
||||
this.logger.info(`开始部署证书到阿里云(nlb)`);
|
||||
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||||
const certId = await this.getAliyunCertId(access);
|
||||
const nlbClientV2 = this.getNLBClientV2(access);
|
||||
if (this.deployType === "extension") {
|
||||
//部署扩展证书
|
||||
await this.deployExtensionCert(nlbClientV2, certId);
|
||||
} else {
|
||||
const client = await this.getLBClient(access, this.regionId);
|
||||
await this.deployDefaultCert(certId, client);
|
||||
}
|
||||
|
||||
const client = await this.getLBClient(access, this.regionId);
|
||||
await this.ctx.utils.sleep(10000)
|
||||
for (const listener of this.listeners) {
|
||||
await this.clearInvalidCert(nlbClientV2, listener);
|
||||
}
|
||||
|
||||
this.logger.info('执行完成');
|
||||
}
|
||||
|
||||
async deployExtensionCert(client: AliyunClientV2, certId: any) {
|
||||
for (const listenerId of this.listeners) {
|
||||
this.logger.info(`开始部署监听器${listenerId}的扩展证书`);
|
||||
await client.doRequest({
|
||||
// 接口名称
|
||||
action: "AssociateAdditionalCertificatesWithListener",
|
||||
// 接口版本
|
||||
version: "2022-04-30",
|
||||
data: {
|
||||
body: {
|
||||
ListenerId: listenerId,
|
||||
RegionId: this.regionId,
|
||||
"AdditionalCertificateIds.1": certId
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.logger.info(`部署监听器${listenerId}的扩展证书成功`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async deployDefaultCert(certId: any, client: AliyunClient) {
|
||||
for (const listener of this.listeners) {
|
||||
//查询原来的证书
|
||||
const params: any = {
|
||||
RegionId: this.regionId,
|
||||
ListenerId: listener,
|
||||
CertificateIds: [certId],
|
||||
CertificateIds:[certId], //旧sdk
|
||||
};
|
||||
|
||||
const res = await client.request('UpdateListenerAttribute', params);
|
||||
this.checkRet(res);
|
||||
this.logger.info(`部署${listener}监听器证书成功`, JSON.stringify(res));
|
||||
|
||||
//删除旧证书关联
|
||||
}
|
||||
this.logger.info('执行完成');
|
||||
}
|
||||
|
||||
|
||||
getNLBClientV2(access: AliyunAccess) {
|
||||
return access.getClient(`nlb.${this.regionId}.aliyuncs.com`);
|
||||
}
|
||||
|
||||
async clearInvalidCert(client: AliyunClientV2, listener: string) {
|
||||
this.logger.info(`开始清理监听器${listener}的过期证书`);
|
||||
const req = {
|
||||
// 接口名称
|
||||
action: "ListListenerCertificates",
|
||||
// 接口版本
|
||||
version: "2022-04-30",
|
||||
data: {
|
||||
body: {
|
||||
ListenerId: listener,
|
||||
RegionId: this.regionId
|
||||
}
|
||||
}
|
||||
};
|
||||
const res = await client.doRequest(req);
|
||||
const list = res.Certificates;
|
||||
if (list.length === 0) {
|
||||
this.logger.info(`监听器${listener}没有绑定证书`);
|
||||
return
|
||||
}
|
||||
|
||||
const sslClient = new AliyunSslClient({
|
||||
access: client.access,
|
||||
logger: this.logger,
|
||||
endpoint: this.casEndpoint
|
||||
});
|
||||
|
||||
|
||||
const certIds = [];
|
||||
for (const item of list) {
|
||||
if (item.Status !== "Associated") {
|
||||
continue;
|
||||
}
|
||||
if (item.IsDefault) {
|
||||
continue;
|
||||
}
|
||||
certIds.push( parseInt(item.CertificateId));
|
||||
}
|
||||
//检查是否过期,过期则删除
|
||||
const invalidCertIds = [];
|
||||
for (const certId of certIds) {
|
||||
const res = await sslClient.getCertInfo(certId);
|
||||
if (res.notAfter < new Date().getTime()) {
|
||||
invalidCertIds.push(certId);
|
||||
}
|
||||
}
|
||||
if (invalidCertIds.length === 0) {
|
||||
this.logger.info(`监听器${listener}没有过期的证书`);
|
||||
return
|
||||
}
|
||||
this.logger.info(`开始解绑过期的证书:${invalidCertIds}`);
|
||||
|
||||
const ids:any = {}
|
||||
let i = 0
|
||||
for (const certId of invalidCertIds) {
|
||||
i++
|
||||
ids[`AdditionalCertificateIds.${i}`] = certId;
|
||||
}
|
||||
await client.doRequest({
|
||||
// 接口名称
|
||||
action: "DissociateAdditionalCertificatesFromListener",
|
||||
// 接口版本
|
||||
version: "2022-04-30",
|
||||
data: {
|
||||
body: {
|
||||
ListenerId: listener,
|
||||
RegionId: this.regionId,
|
||||
...ids
|
||||
}
|
||||
}
|
||||
});
|
||||
this.logger.info(`解绑过期证书成功`);
|
||||
}
|
||||
|
||||
async getAliyunCertId(access: AliyunAccess) {
|
||||
|
||||
@@ -233,6 +233,7 @@ export class AliyunDeployCertToSLB extends AbstractTaskPlugin {
|
||||
RegionId: this.regionId,
|
||||
AliCloudCertificateId: aliyunCert.certId,
|
||||
AliCloudCertificateName: aliyunCert.certName,
|
||||
AliCloudCertificateRegionId: aliyunCert.casRegion
|
||||
};
|
||||
|
||||
const res = await client.request('UploadServerCertificate', params);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import { GithubAccess } from "../access.js";
|
||||
import {SshClient} from "@certd/plugin-lib";
|
||||
|
||||
@IsTaskPlugin({
|
||||
//命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名
|
||||
@@ -56,6 +57,31 @@ export class GithubCheckRelease extends AbstractTaskPlugin {
|
||||
lastVersion?: string;
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: '主机登录配置',
|
||||
helper: '登录',
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'ssh',
|
||||
},
|
||||
required: false,
|
||||
})
|
||||
sshAccessId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: 'shell脚本命令',
|
||||
component: {
|
||||
name: 'a-textarea',
|
||||
vModel: 'value',
|
||||
rows: 6,
|
||||
placeholder: `#拉取最新版镜像\ndocker pull greper/certd:latest \n#重建容器 \nnohup sh -c 'sleep 10; cd ~/deploy/certd/ ; docker compose down; docker compose up -d' >/dev/null & `,
|
||||
},
|
||||
helper: '有新版本后执行命令,比如:拉取最新版镜像,然后重建容器\n注意:自己升级自己需要使用nobup配合sleep',
|
||||
required: false,
|
||||
})
|
||||
script!: string;
|
||||
|
||||
|
||||
//插件实例化时执行的方法
|
||||
async onInstance() {
|
||||
}
|
||||
@@ -71,6 +97,7 @@ export class GithubCheckRelease extends AbstractTaskPlugin {
|
||||
|
||||
if(res.tag_name == null || res.tag_name ==lastVersion){
|
||||
this.logger.info(`暂无更新,${res.tag_name}`);
|
||||
this.lastVersion = res.tag_name || lastVersion;
|
||||
return "skip"
|
||||
}
|
||||
//有更新
|
||||
@@ -99,6 +126,19 @@ export class GithubCheckRelease extends AbstractTaskPlugin {
|
||||
})
|
||||
}
|
||||
|
||||
if (this.script != null && this.script.trim() != "") {
|
||||
const connectConf = await this.getAccess(this.sshAccessId);
|
||||
const sshClient = new SshClient(this.logger);
|
||||
const scripts = this.script.split('\n');
|
||||
await sshClient.exec({
|
||||
connectConf,
|
||||
script: scripts,
|
||||
env: {
|
||||
REPO: this.repoName,
|
||||
LAST_VERSION: this.lastVersion,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ export class TelegramNotification extends BaseNotification {
|
||||
skipSslVerify: boolean;
|
||||
|
||||
replaceText(text: string) {
|
||||
return text.replaceAll('.', '\\.').replaceAll('*', '\\*');
|
||||
// .*()<> 等都需要用\\进行替换
|
||||
return text.replace(/[\\.*()<>]/g, '\\$&');
|
||||
}
|
||||
async send(body: NotificationBody) {
|
||||
if (!this.botToken || !this.chatId) {
|
||||
|
||||
152
packages/ui/certd-server/src/plugins/plugin-rainyun/access.ts
Normal file
152
packages/ui/certd-server/src/plugins/plugin-rainyun/access.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import {AccessInput, BaseAccess, IsAccess} from "@certd/pipeline";
|
||||
import {HttpRequestConfig} from "@certd/basic";
|
||||
import { CertInfo } from "@certd/plugin-cert";
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
@IsAccess({
|
||||
name: "rainyun",
|
||||
title: "雨云授权",
|
||||
desc: "https://app.rainyun.com/",
|
||||
icon: "svg:icon-lucky"
|
||||
})
|
||||
export class RainyunAccess extends BaseAccess {
|
||||
|
||||
|
||||
@AccessInput({
|
||||
title: "ApiKey",
|
||||
component: {
|
||||
placeholder: "api-key",
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
}
|
||||
},
|
||||
helper:"https://app.rainyun.com/account/settings/api-key",
|
||||
encrypt: true,
|
||||
required: true
|
||||
})
|
||||
apiKey!: string;
|
||||
|
||||
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest"
|
||||
},
|
||||
helper: "点击测试接口是否正常"
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.getDomainList({limit:1});
|
||||
return "ok"
|
||||
}
|
||||
|
||||
// {"columnFilters":{"domains.Domain":"domain"},"sort":[],"page":1,"perPage":20}
|
||||
async getDomainList(req:{offset?:number,limit?:number,query?:string}){
|
||||
const size = req.limit ?? 20;
|
||||
const offset = req.offset ?? 0;
|
||||
let page = Math.floor(offset / size);
|
||||
if(offset % size === 0 ){
|
||||
page++
|
||||
}
|
||||
const options ={
|
||||
page: page,
|
||||
perPage: size,
|
||||
columnFilters: {
|
||||
"domains.Domain": req.query??""
|
||||
},
|
||||
}
|
||||
const res = await this.doRequest({
|
||||
url: `/product/domain/?options=${encodeURIComponent(JSON.stringify(options))}`,
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
return {
|
||||
total: res.TotalRecords,
|
||||
list: res.Records || [],
|
||||
limit: size,
|
||||
offset: offset
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async getCertList(req:{offset?:number,limit?:number,query?:string}){
|
||||
const size = req.limit ?? 20;
|
||||
const offset = req.offset ?? 0;
|
||||
let page = Math.floor(offset / size);
|
||||
if(offset % size === 0 ){
|
||||
page++
|
||||
}
|
||||
const options ={
|
||||
columnFilters: {
|
||||
Domain: req.query??""
|
||||
},
|
||||
sort:[],
|
||||
page: page,
|
||||
perPage: size,
|
||||
|
||||
}
|
||||
const res = await this.doRequest({
|
||||
url: `product/sslcenter/?options=${encodeURIComponent(JSON.stringify(options))}`,
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
return {
|
||||
total: res.TotalRecords,
|
||||
list: res.Records || [],
|
||||
limit: size,
|
||||
offset: offset
|
||||
}
|
||||
}
|
||||
|
||||
async doCertReplace(req:{certId:number,cert:CertInfo}){
|
||||
|
||||
// /product/sslcenter/{id}
|
||||
return await this.doRequest({
|
||||
url: `product/sslcenter/${req.certId}`,
|
||||
method: "PUT",
|
||||
data: {
|
||||
cert: req.cert.crt,
|
||||
key: req.cert.key,
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
async getDomainId(domain:string){
|
||||
const res = await this.getDomainList({query: domain,limit:1});
|
||||
if (res.list.length === 0) {
|
||||
throw new Error(`域名${domain}不存在` );
|
||||
}
|
||||
return res.list[0].id;
|
||||
}
|
||||
|
||||
async doRequest(req:HttpRequestConfig){
|
||||
const res = await this.ctx.http.request({
|
||||
url: req.url,
|
||||
baseURL:"https://api.v2.rainyun.com",
|
||||
method: req.method|| "POST",
|
||||
data: req.data,
|
||||
params: req.params,
|
||||
headers:{
|
||||
"X-Api-Key": this.apiKey
|
||||
},
|
||||
// httpProxy: this.httpProxy||undefined,
|
||||
});
|
||||
|
||||
if (res.code === 200) {
|
||||
return res.data;
|
||||
}
|
||||
throw new Error(res.message || res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
new RainyunAccess();
|
||||
@@ -0,0 +1,66 @@
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
|
||||
import { RainyunAccess } from "./access.js";
|
||||
|
||||
@IsDnsProvider({
|
||||
name: "rainyun",
|
||||
title: "雨云",
|
||||
desc: "雨云DNS解析提供商",
|
||||
accessType: "rainyun",
|
||||
icon: "svg:icon-lucky",
|
||||
order: 0
|
||||
})
|
||||
export class RainyunDnsProvider extends AbstractDnsProvider {
|
||||
|
||||
client: any;
|
||||
|
||||
async onInstance() {
|
||||
|
||||
}
|
||||
|
||||
async createRecord(options: CreateRecordOptions): Promise<any> {
|
||||
|
||||
const access: RainyunAccess = this.ctx.access as RainyunAccess;
|
||||
|
||||
const domainId = await access.getDomainId(options.domain);
|
||||
if (!domainId) {
|
||||
throw new Error(`域名${options.domain}未找到`);
|
||||
}
|
||||
|
||||
const { fullRecord, hostRecord, value, type, domain } = options;
|
||||
this.logger.info("添加域名解析:", fullRecord, value, domain);
|
||||
|
||||
const ret = await access.doRequest({
|
||||
url: `/product/domain/${domainId}/dns`,
|
||||
method: "POST",
|
||||
data: {
|
||||
host: hostRecord,
|
||||
value: value,
|
||||
level: 1,
|
||||
type: type,
|
||||
line: "DEFAULT",
|
||||
ttl: 60
|
||||
}
|
||||
});
|
||||
this.logger.info("添加域名解析成功:", JSON.stringify(options), ret);
|
||||
return {
|
||||
recordId: ret,
|
||||
domainId: domainId
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
async removeRecord(options: RemoveRecordOptions<any>): Promise<any> {
|
||||
const { fullRecord, value } = options.recordReq;
|
||||
const access: RainyunAccess = this.ctx.access as RainyunAccess;
|
||||
const record = options.recordRes;
|
||||
const ret = await access.doRequest({
|
||||
url: `/product/domain/${record.domainId}/dns?record_id=${record.recordId}`,
|
||||
method: "DELETE",
|
||||
});
|
||||
this.logger.info("删除域名解析成功:", fullRecord, value, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
new RainyunDnsProvider();
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./plugins/index.js";
|
||||
export * from "./access.js";
|
||||
@@ -0,0 +1,113 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, PageReq, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
|
||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
|
||||
import { RainyunAccess } from "../access.js";
|
||||
|
||||
@IsTaskPlugin({
|
||||
//命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名
|
||||
name: "RainyunRefreshCert",
|
||||
title: "雨云-更新证书",
|
||||
desc: "app.rainyun.com",
|
||||
icon: "svg:icon-lucky",
|
||||
//插件分组
|
||||
group: pluginGroups.cdn.key,
|
||||
needPlus: false,
|
||||
default: {
|
||||
//默认值配置照抄即可
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed
|
||||
}
|
||||
}
|
||||
})
|
||||
//类名规范,跟上面插件名称(name)一致
|
||||
export class RainyunRefreshCert extends AbstractTaskPlugin {
|
||||
//证书选择,此项必须要有
|
||||
@TaskInput({
|
||||
title: "域名证书",
|
||||
helper: "请选择前置任务输出的域名证书",
|
||||
component: {
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames]
|
||||
}
|
||||
// required: true, // 必填
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||
certDomains!: string[];
|
||||
|
||||
//授权选择框
|
||||
@TaskInput({
|
||||
title: "雨云授权",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "rainyun" //固定授权类型
|
||||
},
|
||||
required: true //必填
|
||||
})
|
||||
accessId!: string;
|
||||
//
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: "证书Id",
|
||||
helper: "要更新的rainyun证书id",
|
||||
|
||||
action: RainyunRefreshCert.prototype.onGetCertList.name
|
||||
})
|
||||
)
|
||||
certList!: number[];
|
||||
|
||||
//插件实例化时执行的方法
|
||||
async onInstance() {
|
||||
}
|
||||
|
||||
//插件执行方法
|
||||
async execute(): Promise<void> {
|
||||
const access = await this.getAccess<RainyunAccess>(this.accessId);
|
||||
|
||||
for (const item of this.certList) {
|
||||
this.logger.info(`----------- 开始更新证书:${item}`);
|
||||
await access.doCertReplace({
|
||||
certId: item,
|
||||
cert: this.cert
|
||||
});
|
||||
this.logger.info(`----------- 更新证书${item}成功`);
|
||||
}
|
||||
|
||||
this.logger.info("部署完成");
|
||||
}
|
||||
|
||||
async onGetCertList(req: PageReq = {}) {
|
||||
const access = await this.getAccess<RainyunAccess>(this.accessId);
|
||||
|
||||
const offset = req.offset ?? 0;
|
||||
const limit = req.limit ?? 100;
|
||||
const res = await access.getCertList({
|
||||
offset,
|
||||
limit
|
||||
});
|
||||
const total = res.total;
|
||||
const list = res.list;
|
||||
if (!list || list.length === 0) {
|
||||
throw new Error("没有找到证书,请先在控制台上传一次证书且关联站点");
|
||||
}
|
||||
|
||||
const options = list.map((item: any) => {
|
||||
return {
|
||||
label: `${item.Domain}<${item.ID}>`,
|
||||
value: item.ID,
|
||||
domain: item.Domain.split(",").map(item => item.trim())
|
||||
};
|
||||
});
|
||||
return {
|
||||
list: this.ctx.utils.options.buildGroupOptions(options, this.certDomains),
|
||||
total: total,
|
||||
offset: offset,
|
||||
limit: limit
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//实例化一下,注册插件
|
||||
new RainyunRefreshCert();
|
||||
133
pnpm-lock.yaml
generated
133
pnpm-lock.yaml
generated
@@ -46,7 +46,7 @@ importers:
|
||||
packages/core/acme-client:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../basic
|
||||
'@peculiar/x509':
|
||||
specifier: ^1.11.0
|
||||
@@ -207,10 +207,10 @@ importers:
|
||||
packages/core/pipeline:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../basic
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../pro/plus-core
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
@@ -415,7 +415,7 @@ importers:
|
||||
packages/libs/lib-k8s:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/basic
|
||||
'@kubernetes/client-node':
|
||||
specifier: 0.21.0
|
||||
@@ -455,16 +455,16 @@ importers:
|
||||
packages/libs/lib-server:
|
||||
dependencies:
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../pro/plus-core
|
||||
'@midwayjs/cache':
|
||||
specifier: ~3.14.0
|
||||
@@ -607,16 +607,16 @@ importers:
|
||||
packages/plugins/plugin-cert:
|
||||
dependencies:
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../plugin-lib
|
||||
'@google-cloud/publicca':
|
||||
specifier: ^1.3.0
|
||||
@@ -685,6 +685,9 @@ importers:
|
||||
'@alicloud/openapi-client':
|
||||
specifier: ^0.4.14
|
||||
version: 0.4.14
|
||||
'@alicloud/openapi-util':
|
||||
specifier: ^0.3.2
|
||||
version: 0.3.2
|
||||
'@alicloud/pop-core':
|
||||
specifier: ^1.7.10
|
||||
version: 1.8.0
|
||||
@@ -695,10 +698,10 @@ importers:
|
||||
specifier: ^3.787.0
|
||||
version: 3.810.0(aws-crt@1.26.2)
|
||||
'@certd/basic':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/pipeline
|
||||
'@kubernetes/client-node':
|
||||
specifier: 0.21.0
|
||||
@@ -786,19 +789,19 @@ importers:
|
||||
packages/pro/commercial-core:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/basic
|
||||
'@certd/lib-server':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../libs/lib-server
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-plus':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../plugin-plus
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../plus-core
|
||||
'@midwayjs/core':
|
||||
specifier: ~3.20.3
|
||||
@@ -883,22 +886,22 @@ importers:
|
||||
specifier: ^1.0.2
|
||||
version: 1.0.3
|
||||
'@certd/basic':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/basic
|
||||
'@certd/lib-k8s':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../libs/lib-k8s
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-cert':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../plugins/plugin-cert
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../plus-core
|
||||
ali-oss:
|
||||
specifier: ^6.21.0
|
||||
@@ -1001,7 +1004,7 @@ importers:
|
||||
packages/pro/plus-core:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/basic
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
@@ -1080,17 +1083,17 @@ importers:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
'@fast-crud/fast-crud':
|
||||
specifier: ^1.25.8
|
||||
version: 1.25.11(vue@3.5.14(typescript@5.8.3))
|
||||
specifier: ^1.25.13
|
||||
version: 1.25.13(vue@3.5.14(typescript@5.8.3))
|
||||
'@fast-crud/fast-extends':
|
||||
specifier: ^1.25.8
|
||||
version: 1.25.11(aws-crt@1.26.2)(vue@3.5.14(typescript@5.8.3))
|
||||
specifier: ^1.25.13
|
||||
version: 1.25.13(aws-crt@1.26.2)(vue@3.5.14(typescript@5.8.3))
|
||||
'@fast-crud/ui-antdv4':
|
||||
specifier: ^1.25.8
|
||||
version: 1.25.11
|
||||
specifier: ^1.25.13
|
||||
version: 1.25.13
|
||||
'@fast-crud/ui-interface':
|
||||
specifier: ^1.25.8
|
||||
version: 1.25.11
|
||||
specifier: ^1.25.13
|
||||
version: 1.25.13
|
||||
'@iconify/tailwind':
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
@@ -1291,10 +1294,10 @@ importers:
|
||||
version: 0.1.3(zod@3.24.4)
|
||||
devDependencies:
|
||||
'@certd/lib-iframe':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../libs/lib-iframe
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/pipeline
|
||||
'@rollup/plugin-commonjs':
|
||||
specifier: ^25.0.7
|
||||
@@ -1477,46 +1480,46 @@ importers:
|
||||
specifier: ^3.705.0
|
||||
version: 3.810.0(aws-crt@1.26.2)
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/basic
|
||||
'@certd/commercial-core':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../pro/commercial-core
|
||||
'@certd/cv4pve-api-javascript':
|
||||
specifier: ^8.4.1
|
||||
version: 8.4.1
|
||||
'@certd/jdcloud':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../libs/lib-jdcloud
|
||||
'@certd/lib-huawei':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../libs/lib-huawei
|
||||
'@certd/lib-k8s':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../libs/lib-k8s
|
||||
'@certd/lib-server':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../libs/lib-server
|
||||
'@certd/midway-flyway-js':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../libs/midway-flyway-js
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-cert':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../plugins/plugin-cert
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plugin-plus':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../pro/plugin-plus
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.34.11
|
||||
specifier: ^1.35.2
|
||||
version: link:../../pro/plus-core
|
||||
'@huaweicloud/huaweicloud-sdk-cdn':
|
||||
specifier: ^3.1.120
|
||||
@@ -3390,17 +3393,17 @@ packages:
|
||||
resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
||||
'@fast-crud/fast-crud@1.25.11':
|
||||
resolution: {integrity: sha512-goqkB2ve05TSZ1pEXZZpyK2XuTn2jAM/0CYwYIUlZaQzY0xaKkh+7/8/wX/ZRsAV+Ppee6FEnnbEZaIA3YUb8w==}
|
||||
'@fast-crud/fast-crud@1.25.13':
|
||||
resolution: {integrity: sha512-2UDp0Wzsf9CXA9qJnyYjHYOR2usBRPij/8/15ksyFhBPLC8JJgXHFUae0lXqhib6QCV0CYrF8t7REEtxKmkUfw==}
|
||||
|
||||
'@fast-crud/fast-extends@1.25.11':
|
||||
resolution: {integrity: sha512-TmH/SpDeHmKkcKmXlBj93R/ibhmtf7yki1z2wEIX1bEpAi0Nb5O5YwZXZO4sbze3LfTDAJhP1H74eerp009qWQ==}
|
||||
'@fast-crud/fast-extends@1.25.13':
|
||||
resolution: {integrity: sha512-Hn4p/sdO96KB/+umfrZhgPM3ZbaU78uMamjl+UKhyEB5U42jN45XSEsP4ax1IHFCpvxLvTMnmTzRHqkbgTS18g==}
|
||||
|
||||
'@fast-crud/ui-antdv4@1.25.11':
|
||||
resolution: {integrity: sha512-0MceuaHdMizkRkTbRTNAqeWbJd6CkVsRPXYsOYBtM6L7HrtOJ/a/xqVlZaZyHlNqp2ZgwUV4eU4b0xWtPgksLA==}
|
||||
'@fast-crud/ui-antdv4@1.25.13':
|
||||
resolution: {integrity: sha512-3BDfZRGH9rBEYKw6hUyXD1kI9XtUFl9U/dX4PDH98i1tMg3GhUJ51gDZjZ8as9HsMrCE88m8ZUPjjQU/HLVY1w==}
|
||||
|
||||
'@fast-crud/ui-interface@1.25.11':
|
||||
resolution: {integrity: sha512-/mu0fGNfugsl3NgoP7sEPDm8UGWXf4o8s6JxuhUIspS10YKwRs+1HgrI59YxRYq34/L2oGkCBVyPC0traT7kZA==}
|
||||
'@fast-crud/ui-interface@1.25.13':
|
||||
resolution: {integrity: sha512-hWjN6j6H2e9YxtqKL+fpls4/TTLZX6TuazjuxE+VoH0EdJF9QRk/D8GLxORGvnRgPABClbQvVPyofb6rPHjbAw==}
|
||||
|
||||
'@fidm/asn1@1.0.4':
|
||||
resolution: {integrity: sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==}
|
||||
@@ -14543,10 +14546,10 @@ snapshots:
|
||||
'@aws-sdk/crt-loader': 3.810.0
|
||||
'@aws-sdk/signature-v4-multi-region': 3.810.0
|
||||
'@aws-sdk/types': 3.804.0
|
||||
'@smithy/querystring-parser': 4.0.2
|
||||
'@smithy/signature-v4': 5.1.0
|
||||
'@smithy/types': 4.2.0
|
||||
'@smithy/util-middleware': 4.0.2
|
||||
'@smithy/querystring-parser': 4.0.4
|
||||
'@smithy/signature-v4': 5.1.2
|
||||
'@smithy/types': 4.3.1
|
||||
'@smithy/util-middleware': 4.0.4
|
||||
tslib: 2.8.1
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -15932,7 +15935,7 @@ snapshots:
|
||||
|
||||
'@eslint/js@8.57.0': {}
|
||||
|
||||
'@fast-crud/fast-crud@1.25.11(vue@3.5.14(typescript@5.8.3))':
|
||||
'@fast-crud/fast-crud@1.25.13(vue@3.5.14(typescript@5.8.3))':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
file-saver: 2.0.5
|
||||
@@ -15942,7 +15945,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- vue
|
||||
|
||||
'@fast-crud/fast-extends@1.25.11(aws-crt@1.26.2)(vue@3.5.14(typescript@5.8.3))':
|
||||
'@fast-crud/fast-extends@1.25.13(aws-crt@1.26.2)(vue@3.5.14(typescript@5.8.3))':
|
||||
dependencies:
|
||||
'@aws-sdk/client-s3': 3.810.0(aws-crt@1.26.2)
|
||||
'@aws-sdk/s3-request-presigner': 3.810.0
|
||||
@@ -15974,9 +15977,9 @@ snapshots:
|
||||
- utf-8-validate
|
||||
- vue
|
||||
|
||||
'@fast-crud/ui-antdv4@1.25.11': {}
|
||||
'@fast-crud/ui-antdv4@1.25.13': {}
|
||||
|
||||
'@fast-crud/ui-interface@1.25.11':
|
||||
'@fast-crud/ui-interface@1.25.13':
|
||||
dependencies:
|
||||
lodash-es: 4.17.21
|
||||
|
||||
|
||||
Reference in New Issue
Block a user