Compare commits

...

75 Commits

Author SHA1 Message Date
xiaojunnuo
f3a90a63b6 v1.36.14 2025-07-28 23:42:30 +08:00
xiaojunnuo
2494173aec build: prepare to build 2025-07-28 23:38:49 +08:00
xiaojunnuo
866eb6241b perf: 授权管理支持模糊查询 2025-07-28 23:36:10 +08:00
xiaojunnuo
86b3df1941 perf: 运行主机脚本插件支持选择运行策略 2025-07-28 23:22:38 +08:00
xiaojunnuo
e87f6d56f5 perf: cdnfly 支持 账号密码登陆授权 2025-07-28 23:20:44 +08:00
xiaojunnuo
acc890730f perf: 1panel支持 currenNode 2025-07-28 22:41:45 +08:00
xiaojunnuo
b0707739fd fix: 修复复制流水线为空的bug 2025-07-28 18:29:28 +08:00
xiaojunnuo
251dd1fe45 fix: 修复商用证书上传第二次运行无法使用pfx格式证书的bug 2025-07-28 16:18:49 +08:00
xiaojunnuo
b9f3dc65e0 chore: 雨云ref 2025-07-25 17:29:37 +08:00
xiaojunnuo
238ad7ce51 perf: 优化start脚本 2025-07-25 16:57:21 +08:00
xiaojunnuo
99fd5fca4d chore: 2025-07-25 12:05:42 +08:00
xiaojunnuo
8eda77b76d Merge branch 'v2' into v2-dev 2025-07-25 10:18:35 +08:00
ahe
81ac240ac8 perf: 新增找回密码功能 @nicheng-he
* feat 找回密码

* 1.发送邮件时修改模版
2.重置成功时清除登陆错误次数

* 增加自助找回密码控制

* 补充接口自助找回判断
2025-07-24 16:56:22 +08:00
xiaojunnuo
6109798fab chore: 2025-07-24 16:23:13 +08:00
xiaojunnuo
95715a007d perf: k8s ack、tke 支持重启ingress 2025-07-24 16:22:07 +08:00
xiaojunnuo
b33ec201ac build: publish 2025-07-23 23:41:46 +08:00
xiaojunnuo
b53fbaf5b3 build: trigger build image 2025-07-23 23:41:31 +08:00
xiaojunnuo
1e03a2e553 v1.36.13 2025-07-23 23:40:09 +08:00
xiaojunnuo
fda7c6f67a build: prepare to build 2025-07-23 23:37:57 +08:00
xiaojunnuo
fabb7982ff chore: 2025-07-23 17:55:08 +08:00
xiaojunnuo
cbf206be60 chore: 2025-07-23 17:41:16 +08:00
xiaojunnuo
aa0c282205 Merge branch 'v2' into v2-dev 2025-07-23 15:59:14 +08:00
xiaojunnuo
9759365329 Merge remote-tracking branch 'origin/v2' into v2 2025-07-23 15:56:09 +08:00
ahe
e3738f6422 perf: 阿里云部分插件优化 @nicheng-he
1.新增RemoteAutoComplete插件
2.阿里云OSS部署插件支持自动获取BucketList
3.阿里云ESA支持选择上传到阿里云CAS产物
4.解决阿里云OSS默认接入点配置错误问题
2025-07-23 15:55:52 +08:00
ahe
9746d169f9 阿里云部分插件优化 @nicheng-he
1.新增RemoteAutoComplete插件
2.阿里云OSS部署插件支持自动获取BucketList
3.阿里云ESA支持选择上传到阿里云CAS产物
4.解决阿里云OSS默认接入点配置错误问题
2025-07-23 15:45:40 +08:00
xiaojunnuo
2e6d03ff00 fix: 修复阿里云发送短信验证码失败的bug 2025-07-23 11:33:02 +08:00
xiaojunnuo
f7b7d3d65e build: publish 2025-07-23 00:18:48 +08:00
xiaojunnuo
4037cf11aa build: trigger build image 2025-07-23 00:18:32 +08:00
xiaojunnuo
02aeb321ce v1.36.12 2025-07-23 00:17:02 +08:00
xiaojunnuo
0012619257 build: prepare to build 2025-07-23 00:14:43 +08:00
xiaojunnuo
6f3ade0d94 Merge branch 'v2' into v2-dev 2025-07-23 00:13:58 +08:00
xiaojunnuo
cf572f328a Merge branch 'v2' into v2-dev 2025-07-23 00:13:29 +08:00
xiaojunnuo
d1ce36038c perf: 增加版本过低提示 2025-07-23 00:10:15 +08:00
xiaojunnuo
b382351c7b fix: 上传到阿里云cas,证书前缀无效的bug 2025-07-22 23:53:33 +08:00
xiaojunnuo
4e5e862f58 fix: 修复自定义插件onlyAdmin报错的bug 2025-07-22 23:31:42 +08:00
xiaojunnuo
ab84835362 perf: 部署到k8s,tke,ack忽悠证书校验 2025-07-22 17:03:52 +08:00
xiaojunnuo
41ce8489dc perf: 首页增加更新日志按钮 2025-07-22 16:42:17 +08:00
xiaojunnuo
ef3faf5832 Merge branch 'v2-dev' into v2 2025-07-22 12:27:51 +08:00
xiaojunnuo
edf089ec9e build: publish 2025-07-22 12:27:21 +08:00
xiaojunnuo
0ae9a3605c build: trigger build image 2025-07-22 12:27:10 +08:00
xiaojunnuo
7f9c4e52ac v1.36.11 2025-07-22 12:25:40 +08:00
xiaojunnuo
35947f96a8 build: prepare to build 2025-07-22 12:23:42 +08:00
xiaojunnuo
b0f91f1eea chore: 2025-07-22 12:22:54 +08:00
xiaojunnuo
13dfca1749 fix: 安全更新,备份数据库插件仅限管理员运行 2025-07-22 11:51:27 +08:00
xiaojunnuo
9d9cd8a362 build: 2025-07-19 12:02:08 +08:00
xiaojunnuo
5e5c41fda5 build: 2025-07-19 12:01:47 +08:00
xiaojunnuo
3ebdc52b3e build: 2025-07-19 08:58:02 +08:00
xiaojunnuo
af54f48cec Merge branch 'v2-dev' into v2 2025-07-18 23:14:52 +08:00
xiaojunnuo
8656059151 build: publish 2025-07-18 23:09:44 +08:00
xiaojunnuo
a6d38f2458 build: trigger build image 2025-07-18 23:09:27 +08:00
xiaojunnuo
085bdf5cfa v1.36.10 2025-07-18 23:08:03 +08:00
xiaojunnuo
6883bcacee build: prepare to build 2025-07-18 23:02:57 +08:00
xiaojunnuo
2ecc6e0368 build: prepare to build 2025-07-18 23:00:39 +08:00
xiaojunnuo
8fb5ca2fe1 chore: ip检查新旧ip变化对比逻辑修复 2025-07-18 18:24:01 +08:00
xiaojunnuo
e40345095f perf: 账号即将过期通知 2025-07-18 18:18:01 +08:00
xiaojunnuo
ffc0c7bb7b perf: 子域名托管重复域名不允许添加 2025-07-18 16:36:56 +08:00
xiaojunnuo
58fadc8928 chore: 2025-07-18 16:32:19 +08:00
xiaojunnuo
d96a607c04 chore: 2025-07-18 16:00:34 +08:00
xiaojunnuo
2ea2c8c05f perf: 部署到阿里云oss插件支持选择上传到阿里云cas中的证书 2025-07-18 15:35:35 +08:00
xiaojunnuo
b15f514018 perf: 优化子域名托管的说明 2025-07-18 14:47:15 +08:00
xiaojunnuo
05a33a0ec9 fix: api接口获取不到证书的bug 2025-07-18 14:46:58 +08:00
xiaojunnuo
747d266742 fix: 企业微信通知改成text类型,因为markdown类型不支持@用户 2025-07-15 17:15:43 +08:00
xiaojunnuo
522d30545b Merge branch 'v2-dev' into v2 2025-07-15 16:56:31 +08:00
xiaojunnuo
6135a44a8d build: publish 2025-07-15 16:54:52 +08:00
xiaojunnuo
7c7d646792 build: trigger build image 2025-07-15 16:54:35 +08:00
xiaojunnuo
4a36fd2ec3 v1.36.9 2025-07-15 16:53:06 +08:00
xiaojunnuo
b1bcc287cb build: prepare to build 2025-07-15 16:46:42 +08:00
xiaojunnuo
6f5868a9d7 build: prepare to build 2025-07-15 16:43:58 +08:00
xiaojunnuo
75863441f4 build: prepare to build 2025-07-15 16:41:37 +08:00
xiaojunnuo
9763cb00e5 fix: 修复ssh无法执行命令的bug 2025-07-15 16:41:15 +08:00
xiaojunnuo
521599ef39 Merge branch 'v2-dev' into v2 2025-07-15 15:47:46 +08:00
xiaojunnuo
1921a64f4b build: publish 2025-07-15 15:36:31 +08:00
xiaojunnuo
6b73f5d555 build: trigger build image 2025-07-15 15:36:14 +08:00
xiaojunnuo
1ff6daaa27 Merge branch 'v2-dev' into v2 2025-07-14 23:55:04 +08:00
xiaojunnuo
dbf69bcd98 chore: 2025-07-11 11:11:22 +08:00
100 changed files with 2028 additions and 648 deletions

View File

@@ -3,6 +3,72 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
### Bug Fixes
* 修复复制流水线为空的bug ([b070773](https://github.com/certd/certd/commit/b0707739fdfbae3d78db4efd3f180db05c4e4164))
* 修复商用证书上传第二次运行无法使用pfx格式证书的bug ([251dd1f](https://github.com/certd/certd/commit/251dd1fe457a7b152f43eb6de18f7beb9f0b194e))
### Performance Improvements
* 1panel支持 currenNode ([acc8907](https://github.com/certd/certd/commit/acc890730f43d492c9b1bd3668814cf10efdf7b8))
* 授权管理支持模糊查询 ([866eb62](https://github.com/certd/certd/commit/866eb6241baa7b21f6eddc649966324c188236c6))
* 新增找回密码功能 [@nicheng-he](https://github.com/nicheng-he) ([81ac240](https://github.com/certd/certd/commit/81ac240ac84db0af2f56b6352e227ecb49f38377))
* 优化start脚本 ([238ad7c](https://github.com/certd/certd/commit/238ad7ce51f17e1098c624e7f61ee2d98de1e02d))
* 运行主机脚本插件支持选择运行策略 ([86b3df1](https://github.com/certd/certd/commit/86b3df194126476e1f58e0952a77e986f62eecce))
* cdnfly 支持 账号密码登陆授权 ([e87f6d5](https://github.com/certd/certd/commit/e87f6d56f524dbbb9e3243e382b348b6e49f0d2c))
* k8s ack、tke 支持重启ingress ([95715a0](https://github.com/certd/certd/commit/95715a007d931c64fa7dd953d94957398e00a443))
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
### Bug Fixes
* 修复阿里云发送短信验证码失败的bug ([2e6d03f](https://github.com/certd/certd/commit/2e6d03ff001f521f57368e7a62b97ed7b122e8d0))
### Performance Improvements
* 阿里云部分插件优化 [@nicheng-he](https://github.com/nicheng-he) ([e3738f6](https://github.com/certd/certd/commit/e3738f6422270d75ec414c15a343248cc4cad6e1))
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
### Bug Fixes
* 上传到阿里云cas证书前缀无效的bug ([b382351](https://github.com/certd/certd/commit/b382351c7b91ec10e1f61d94bec5aad075207ec8))
* 修复自定义插件onlyAdmin报错的bug ([4e5e862](https://github.com/certd/certd/commit/4e5e862f5834ad180e4428959c272d444a6f78ab))
### Performance Improvements
* 部署到k8stkeack忽悠证书校验 ([ab84835](https://github.com/certd/certd/commit/ab848353621869464a2c9a45fdb5e28d998b8a58))
* 首页增加更新日志按钮 ([41ce848](https://github.com/certd/certd/commit/41ce8489dc2f03a705dfa3fbb357769defb56c60))
* 增加版本过低提示 ([d1ce360](https://github.com/certd/certd/commit/d1ce36038cab72b5dc1b320d0a708c261ffbdacb))
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
### Bug Fixes
* 安全更新,备份数据库插件仅限管理员运行 ([13dfca1](https://github.com/certd/certd/commit/13dfca1749275526c82465a17c482b607c820fdd))
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
### Bug Fixes
* 企业微信通知改成text类型因为markdown类型不支持@用户 ([747d266](https://github.com/certd/certd/commit/747d26674248082e678a3fd5ecc94712641a2716))
* api接口获取不到证书的bug ([05a33a0](https://github.com/certd/certd/commit/05a33a0ec9999e2802f6c7b23cc1c61a2b9e963d))
### Performance Improvements
* 部署到阿里云oss插件支持选择上传到阿里云cas中的证书 ([2ea2c8c](https://github.com/certd/certd/commit/2ea2c8c05fc40f79595f1bbde67c1413558bf684))
* 优化子域名托管的说明 ([b15f514](https://github.com/certd/certd/commit/b15f514018b728acb0922ee3f93c1f302eb5d471))
* 账号即将过期通知 ([e403450](https://github.com/certd/certd/commit/e40345095f31e2fb8e2333a6647466659133fa0c))
* 子域名托管重复域名不允许添加 ([ffc0c7b](https://github.com/certd/certd/commit/ffc0c7bb7b16d9904fd2d905d1c4e1d4854e92a9))
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
### Bug Fixes
* 修复ssh无法执行命令的bug ([9763cb0](https://github.com/certd/certd/commit/9763cb00e5d95b2fa5d1c2d3d4a8eecac71600e6))
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
### Bug Fixes

View File

@@ -16,7 +16,6 @@ Certd® 是一个免费的全自动证书管理系统,让你的网站证书永
> 流水线数量现已调整为无限制,欢迎大家使用
## 一、特性
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
@@ -87,8 +86,8 @@ https://certd.handfree.work/
1. 【推荐】[Docker方式部署 ](https://certd.docmirror.cn/guide/install/docker/)
2. 【推荐】[宝塔面板方式部署 ](https://certd.docmirror.cn/guide/install/docker/)
3. 【推荐】[1Panel面板方式部署](https://certd.docmirror.cn/guide/install/1panel/)
4. 【推荐】[雨云一键部署](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2_) 首充翻倍每月仅需2.2元
[<img src="https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-cn.svg">](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2_)
4. 【推荐】[雨云一键部署](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2) 首充翻倍每月仅需2.2元
[<img src="https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-cn.svg">](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2)
5. 【不推荐】[源码方式部署 ](https://certd.docmirror.cn/guide/install/source/)
#### Docker镜像说明

View File

@@ -1 +1 @@
23:53
23:41

View File

@@ -3,6 +3,68 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
### Bug Fixes
* 修复阿里云发送短信验证码失败的bug ([2e6d03f](https://github.com/certd/certd/commit/2e6d03ff001f521f57368e7a62b97ed7b122e8d0))
### Performance Improvements
* 阿里云部分插件优化 [@nicheng-he](https://github.com/nicheng-he) ([e3738f6](https://github.com/certd/certd/commit/e3738f6422270d75ec414c15a343248cc4cad6e1))
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
### Bug Fixes
* 上传到阿里云cas证书前缀无效的bug ([b382351](https://github.com/certd/certd/commit/b382351c7b91ec10e1f61d94bec5aad075207ec8))
* 修复自定义插件onlyAdmin报错的bug ([4e5e862](https://github.com/certd/certd/commit/4e5e862f5834ad180e4428959c272d444a6f78ab))
### Performance Improvements
* 部署到k8stkeack忽悠证书校验 ([ab84835](https://github.com/certd/certd/commit/ab848353621869464a2c9a45fdb5e28d998b8a58))
* 首页增加更新日志按钮 ([41ce848](https://github.com/certd/certd/commit/41ce8489dc2f03a705dfa3fbb357769defb56c60))
* 增加版本过低提示 ([d1ce360](https://github.com/certd/certd/commit/d1ce36038cab72b5dc1b320d0a708c261ffbdacb))
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
### Bug Fixes
* 安全更新,备份数据库插件仅限管理员运行 ([13dfca1](https://github.com/certd/certd/commit/13dfca1749275526c82465a17c482b607c820fdd))
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
### Bug Fixes
* 企业微信通知改成text类型因为markdown类型不支持@用户 ([747d266](https://github.com/certd/certd/commit/747d26674248082e678a3fd5ecc94712641a2716))
* api接口获取不到证书的bug ([05a33a0](https://github.com/certd/certd/commit/05a33a0ec9999e2802f6c7b23cc1c61a2b9e963d))
### Performance Improvements
* 部署到阿里云oss插件支持选择上传到阿里云cas中的证书 ([2ea2c8c](https://github.com/certd/certd/commit/2ea2c8c05fc40f79595f1bbde67c1413558bf684))
* 优化子域名托管的说明 ([b15f514](https://github.com/certd/certd/commit/b15f514018b728acb0922ee3f93c1f302eb5d471))
* 账号即将过期通知 ([e403450](https://github.com/certd/certd/commit/e40345095f31e2fb8e2333a6647466659133fa0c))
* 子域名托管重复域名不允许添加 ([ffc0c7b](https://github.com/certd/certd/commit/ffc0c7bb7b16d9904fd2d905d1c4e1d4854e92a9))
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
### Bug Fixes
* 修复ssh无法执行命令的bug ([9763cb0](https://github.com/certd/certd/commit/9763cb00e5d95b2fa5d1c2d3d4a8eecac71600e6))
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
### Bug Fixes
* 修复流水线列表页报length错误的bug ([9864792](https://github.com/certd/certd/commit/9864792bbfd149e770d6e1ffa809573694f99dd3))
* 修复流水线页面状态没有刷新的bug ([93e9498](https://github.com/certd/certd/commit/93e9498b410353f504e11e264db62468895d7290))
* 修复自定义证书检查时间重启之后不生效的bug ([38e867c](https://github.com/certd/certd/commit/38e867c917bbc68bd228bdd8064f3e7358d6413d))
### Performance Improvements
* 支持上传证书到各种对象存储oss、cos、七牛、s3、minio等 ([1da8617](https://github.com/certd/certd/commit/1da8617a53a675776635bbc3bcb3c6d7dff83e27))
* 支持邮箱发送证书 ([95332d5](https://github.com/certd/certd/commit/95332d5db96cd54ddab6ab737332417a09169b39))
## [1.36.6](https://github.com/certd/certd/compare/v1.36.5...v1.36.6) (2025-07-14)
### Bug Fixes

View File

@@ -4,7 +4,7 @@
## 一、源码安装
### 环境要求
- nodejs 20 及以上
- nodejs 22 及以上
### 源码启动
```shell
# 克隆代码

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -8,8 +8,11 @@
![](./tencent-access.png)
## 如何避免收到腾讯云证书过期邮件
> 新版本已经自动将证书设置为免提醒certd上传的证书后续都不会再提醒了。
腾讯云在证书有效期还剩28天时会发送过期通知邮件
您可以通过配置“腾讯云过期证书删除”任务来避免收到此类邮件。
@@ -18,4 +21,17 @@
注意点:
> 1. 选择腾讯云授权,需授权`服务角色SSL_QCSLinkedRoleInReplaceLoadCertificate`权限
> 2. `1.26.14`版本之前Certd创建的证书流水线默认是到期前20天才更新证书需要将之前创建的证书申请任务的更新天数修改为35天保证删除之前就已经替换掉即将过期证书
![](./images/delete2.png)
![](./images/delete2.png)
## TKE service 的 TCP_SSL Opaque类型证书授权
部署证书到腾讯云TKE如果报以下错误
`is forbidden: User "xxxxxx-xxxxx" cannot get resource "secrets" in API group "" in the namespace "default"'`
则需要单独从授权管理侧再授权子用户的权限
![](./images/tcpssl.png)
![](./images/opaque.png)

View File

@@ -9,5 +9,5 @@
}
},
"npmClient": "pnpm",
"version": "1.36.7"
"version": "1.36.14"
}

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/publishlab/node-acme-client/compare/v1.36.13...v1.36.14) (2025-07-28)
**Note:** Version bump only for package @certd/acme-client
## [1.36.13](https://github.com/publishlab/node-acme-client/compare/v1.36.12...v1.36.13) (2025-07-23)
**Note:** Version bump only for package @certd/acme-client
## [1.36.12](https://github.com/publishlab/node-acme-client/compare/v1.36.11...v1.36.12) (2025-07-22)
**Note:** Version bump only for package @certd/acme-client
## [1.36.11](https://github.com/publishlab/node-acme-client/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/acme-client
## [1.36.10](https://github.com/publishlab/node-acme-client/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/acme-client
## [1.36.9](https://github.com/publishlab/node-acme-client/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/acme-client
## [1.36.7](https://github.com/publishlab/node-acme-client/compare/v1.36.6...v1.36.7) (2025-07-15)
**Note:** Version bump only for package @certd/acme-client

View File

@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client",
"private": false,
"author": "nmorsman",
"version": "1.36.7",
"version": "1.36.14",
"type": "module",
"module": "scr/index.js",
"main": "src/index.js",
@@ -18,7 +18,7 @@
"types"
],
"dependencies": {
"@certd/basic": "^1.36.7",
"@certd/basic": "^1.36.14",
"@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": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
**Note:** Version bump only for package @certd/basic
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
**Note:** Version bump only for package @certd/basic
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
**Note:** Version bump only for package @certd/basic
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/basic
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/basic
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/basic
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
**Note:** Version bump only for package @certd/basic

View File

@@ -1 +1 @@
15:21
23:38

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/basic",
"private": false,
"version": "1.36.7",
"version": "1.36.14",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -45,5 +45,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
**Note:** Version bump only for package @certd/pipeline
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
**Note:** Version bump only for package @certd/pipeline
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
### Bug Fixes
* 修复自定义插件onlyAdmin报错的bug ([4e5e862](https://github.com/certd/certd/commit/4e5e862f5834ad180e4428959c272d444a6f78ab))
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
### Bug Fixes
* 安全更新,备份数据库插件仅限管理员运行 ([13dfca1](https://github.com/certd/certd/commit/13dfca1749275526c82465a17c482b607c820fdd))
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/pipeline
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/pipeline
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
### Performance Improvements

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/pipeline",
"private": false,
"version": "1.36.7",
"version": "1.36.14",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -17,8 +17,8 @@
"pub": "npm publish"
},
"dependencies": {
"@certd/basic": "^1.36.7",
"@certd/plus-core": "^1.36.7",
"@certd/basic": "^1.36.14",
"@certd/plus-core": "^1.36.14",
"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": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -352,6 +352,7 @@ export class Executor {
pipeline: this.pipeline,
runtime: this.runtime,
step,
define: cloneDeep(define),
lastStatus,
http,
download,

View File

@@ -59,6 +59,7 @@ export type PluginDefine = Registrable & {
form: any;
};
};
onlyAdmin?: boolean;
needPlus?: boolean;
showRunStrategy?: boolean;
pluginType?: string; //类型
@@ -85,6 +86,7 @@ export type TaskInstanceContext = {
runtime: RunHistory;
//步骤定义
step: Step;
define: PluginDefine;
//日志
logger: ILogger;
//当前步骤输入参数跟上一次执行比较是否有变化
@@ -162,6 +164,12 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
this.registerSecret(cert.key);
this.registerSecret(cert.one);
}
if (this.ctx?.define?.onlyAdmin) {
if (!this.isAdmin()) {
throw new Error("只有管理员才能运行此任务");
}
}
}
async getAccess<T = any>(accessId: string | number, isCommon = false) {

View File

@@ -30,4 +30,5 @@ export const pluginGroups = {
qiniu: new PluginGroup("qiniu", "七牛云", 5, "svg:icon-qiniuyun"),
aws: new PluginGroup("aws", "亚马逊云", 6, "svg:icon-aws"),
other: new PluginGroup("other", "其他", 10, "clarity:plugin-line"),
admin: new PluginGroup("admin", "管理", 11, "ion:settings-outline"),
};

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
**Note:** Version bump only for package @certd/lib-huawei
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
**Note:** Version bump only for package @certd/lib-huawei
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
**Note:** Version bump only for package @certd/lib-huawei
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/lib-huawei
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/lib-huawei
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/lib-huawei
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
**Note:** Version bump only for package @certd/lib-huawei

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/lib-huawei",
"private": false,
"version": "1.36.7",
"version": "1.36.14",
"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": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
**Note:** Version bump only for package @certd/lib-iframe
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
**Note:** Version bump only for package @certd/lib-iframe
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
**Note:** Version bump only for package @certd/lib-iframe
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/lib-iframe
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/lib-iframe
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/lib-iframe
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
**Note:** Version bump only for package @certd/lib-iframe

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/lib-iframe",
"private": false,
"version": "1.36.7",
"version": "1.36.14",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -31,5 +31,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
**Note:** Version bump only for package @certd/jdcloud
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
**Note:** Version bump only for package @certd/jdcloud
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
**Note:** Version bump only for package @certd/jdcloud
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/jdcloud
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/jdcloud
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/jdcloud
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
**Note:** Version bump only for package @certd/jdcloud

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/jdcloud",
"version": "1.36.7",
"version": "1.36.14",
"description": "jdcloud openApi sdk",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
@@ -61,5 +61,5 @@
"fetch"
]
},
"gitHead": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
### Performance Improvements
* k8s ack、tke 支持重启ingress ([95715a0](https://github.com/certd/certd/commit/95715a007d931c64fa7dd953d94957398e00a443))
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
**Note:** Version bump only for package @certd/lib-k8s
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
### Performance Improvements
* 部署到k8stkeack忽悠证书校验 ([ab84835](https://github.com/certd/certd/commit/ab848353621869464a2c9a45fdb5e28d998b8a58))
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/lib-k8s
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/lib-k8s
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/lib-k8s
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
**Note:** Version bump only for package @certd/lib-k8s

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/lib-k8s",
"private": false,
"version": "1.36.7",
"version": "1.36.14",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -17,7 +17,7 @@
"pub": "npm publish"
},
"dependencies": {
"@certd/basic": "^1.36.7",
"@certd/basic": "^1.36.14",
"@kubernetes/client-node": "0.21.0"
},
"devDependencies": {
@@ -32,5 +32,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -1 +1 @@
export * from './lib/k8s.client.js';
export * from "./lib/k8s.client.js";

View File

@@ -1,7 +1,7 @@
import { CoreV1Api, KubeConfig, NetworkingV1Api, V1Ingress, V1Secret } from '@kubernetes/client-node';
import dns from 'dns';
import { ILogger } from '@certd/basic';
import _ from 'lodash-es';
import { CoreV1Api, KubeConfig, NetworkingV1Api, V1Ingress, V1Secret } from "@kubernetes/client-node";
import dns from "dns";
import { ILogger } from "@certd/basic";
import _ from "lodash-es";
export type K8sClientOpts = {
kubeConfigStr: string;
@@ -9,6 +9,7 @@ export type K8sClientOpts = {
//{ [domain]:{ip:'xxx.xx.xxx'} }
//暂时没用
lookup?: any;
skipTLSVerify?: boolean;
};
export class K8sClient {
kubeconfig!: KubeConfig;
@@ -16,10 +17,12 @@ export class K8sClient {
lookup!: (hostnameReq: any, options: any, callback: any) => void;
client!: CoreV1Api;
logger: ILogger;
skipTLSVerify?: boolean;
constructor(opts: K8sClientOpts) {
this.kubeConfigStr = opts.kubeConfigStr;
this.logger = opts.logger;
this.setLookup(opts.lookup);
this.skipTLSVerify = opts.skipTLSVerify;
this.init();
}
@@ -27,6 +30,18 @@ export class K8sClient {
const kubeconfig = new KubeConfig();
kubeconfig.loadFromString(this.kubeConfigStr);
this.kubeconfig = kubeconfig;
try {
if (this.skipTLSVerify == true) {
for (const cluster of kubeconfig.getClusters()) {
// @ts-ignore
cluster["skipTLSVerify"] = this.skipTLSVerify;
}
}
} catch (e) {
this.logger.warn("skipTLSVerify error", e);
}
this.client = kubeconfig.makeApiClient(CoreV1Api);
// const reqOpts = { kubeconfig, request: {} } as any;
@@ -47,9 +62,9 @@ export class K8sClient {
return;
}
this.lookup = (hostnameReq: any, options: any, callback: any) => {
this.logger.info('custom lookup', hostnameReq, localRecords);
this.logger.info("custom lookup", hostnameReq, localRecords);
if (localRecords[hostnameReq]) {
this.logger.info('local record', hostnameReq, localRecords[hostnameReq]);
this.logger.info("local record", hostnameReq, localRecords[hostnameReq]);
callback(null, localRecords[hostnameReq].ip, 4);
} else {
dns.lookup(hostnameReq, options, callback);
@@ -63,7 +78,7 @@ export class K8sClient {
* @returns secretsList
*/
async getSecrets(opts: { namespace: string }) {
const namespace = opts.namespace || 'default';
const namespace = opts.namespace || "default";
return await this.client.listNamespacedSecret(namespace);
}
@@ -73,9 +88,9 @@ export class K8sClient {
* @returns {Promise<*>}
*/
async createSecret(opts: { namespace: string; body: V1Secret }) {
const namespace = opts.namespace || 'default';
const namespace = opts.namespace || "default";
const created = await this.client.createNamespacedSecret(namespace, opts.body);
this.logger.info('new secrets:', opts.body);
this.logger.info("new secrets:", opts.body);
return created.body;
}
@@ -89,24 +104,24 @@ export class K8sClient {
// }
async patchSecret(opts: { namespace: string; secretName: string; body: V1Secret }) {
const namespace = opts.namespace || 'default';
const namespace = opts.namespace || "default";
const secretName = opts.secretName;
if (secretName == null) {
throw new Error('secretName 不能为空');
throw new Error("secretName 不能为空");
}
this.logger.info('patch secret:', secretName, namespace);
this.logger.info("patch secret:", secretName, namespace);
const oldSecret = await this.client.readNamespacedSecret(secretName, namespace);
const newSecret = _.merge(oldSecret.body, opts.body);
const res = await this.client.replaceNamespacedSecret(secretName, namespace, newSecret);
this.logger.info('secret updated');
this.logger.info("secret updated");
return res.body;
}
async getIngressList(opts: { namespace: string }) {
const namespace = opts.namespace || 'default';
const namespace = opts.namespace || "default";
const client = this.kubeconfig.makeApiClient(NetworkingV1Api);
const res = await client.listNamespacedIngress(namespace);
this.logger.info('ingress list get:', res.body);
this.logger.info("ingress list get:", res.body);
return res.body;
}
@@ -122,17 +137,31 @@ export class K8sClient {
// }
async patchIngress(opts: { namespace: string; ingressName: string; body: V1Ingress }) {
const namespace = opts.namespace || 'default';
const namespace = opts.namespace || "default";
const ingressName = opts.ingressName;
if (!ingressName) {
throw new Error('ingressName 不能为空');
throw new Error("ingressName 不能为空");
}
this.logger.info('patch ingress:', ingressName, namespace);
this.logger.info("patch ingress:", ingressName, namespace);
const client = this.kubeconfig.makeApiClient(NetworkingV1Api);
const oldIngress = await client.readNamespacedIngress(ingressName, namespace);
const newIngress = _.merge(oldIngress.body, opts.body);
const res = await client.replaceNamespacedIngress(ingressName, namespace, newIngress);
this.logger.info('ingress patched', opts.body);
this.logger.info("ingress patched", opts.body);
return res;
}
async restartIngress(namespace: string, ingressNames: string[], labels: any) {
const body = {
metadata: {
labels: {
...labels,
},
},
};
for (const ingress of ingressNames) {
await this.patchIngress({ namespace, ingressName: ingress, body });
this.logger.info(`ingress已重启:${ingress}`);
}
}
}

View File

@@ -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.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
### Performance Improvements
* 新增找回密码功能 [@nicheng-he](https://github.com/nicheng-he) ([81ac240](https://github.com/certd/certd/commit/81ac240ac84db0af2f56b6352e227ecb49f38377))
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
**Note:** Version bump only for package @certd/lib-server
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
**Note:** Version bump only for package @certd/lib-server
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/lib-server
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/lib-server
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/lib-server
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
**Note:** Version bump only for package @certd/lib-server

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/lib-server",
"version": "1.36.7",
"version": "1.36.14",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -27,10 +27,10 @@
],
"license": "AGPL",
"dependencies": {
"@certd/acme-client": "^1.36.7",
"@certd/basic": "^1.36.7",
"@certd/pipeline": "^1.36.7",
"@certd/plus-core": "^1.36.7",
"@certd/acme-client": "^1.36.14",
"@certd/basic": "^1.36.14",
"@certd/pipeline": "^1.36.14",
"@certd/plus-core": "^1.36.14",
"@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": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -22,6 +22,7 @@ export class SysPublicSettings extends BaseSettings {
mobileRegisterEnabled = false;
smsLoginEnabled = false;
emailRegisterEnabled = false;
selfServicePasswordRetrievalEnabled = false;
limitUserPipelineCount = 0;
managerOtherUserPipeline = false;

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
**Note:** Version bump only for package @certd/midway-flyway-js

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/midway-flyway-js",
"version": "1.36.7",
"version": "1.36.14",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -46,5 +46,5 @@
"typeorm": "^0.3.11",
"typescript": "^5.4.2"
},
"gitHead": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -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.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
### Bug Fixes
* 修复商用证书上传第二次运行无法使用pfx格式证书的bug ([251dd1f](https://github.com/certd/certd/commit/251dd1fe457a7b152f43eb6de18f7beb9f0b194e))
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
**Note:** Version bump only for package @certd/plugin-cert
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
**Note:** Version bump only for package @certd/plugin-cert
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/plugin-cert
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/plugin-cert
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/plugin-cert
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
### Performance Improvements

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-cert",
"private": false,
"version": "1.36.7",
"version": "1.36.14",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -16,10 +16,10 @@
"pub": "npm publish"
},
"dependencies": {
"@certd/acme-client": "^1.36.7",
"@certd/basic": "^1.36.7",
"@certd/pipeline": "^1.36.7",
"@certd/plugin-lib": "^1.36.7",
"@certd/acme-client": "^1.36.14",
"@certd/basic": "^1.36.14",
"@certd/pipeline": "^1.36.14",
"@certd/plugin-lib": "^1.36.14",
"@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": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -194,4 +194,13 @@ cert.jksjks格式证书文件java服务器使用
};
return newCert;
}
async readLastCert(): Promise<CertReader | undefined> {
const cert = this.lastStatus?.status?.output?.cert;
if (cert == null) {
this.logger.info("没有找到上次的证书");
return undefined;
}
return new CertReader(cert);
}
}

View File

@@ -130,15 +130,6 @@ export abstract class CertApplyBasePlugin extends CertApplyBaseConvertPlugin {
return null;
}
async readLastCert(): Promise<CertReader | undefined> {
const cert = this.lastStatus?.status?.output?.cert;
if (cert == null) {
this.logger.info("没有找到上次的证书");
return undefined;
}
return new CertReader(cert);
}
/**
* 检查是否过期默认提前35天
* @param expires

View File

@@ -100,8 +100,17 @@ export class CertApplyUploadPlugin extends CertApplyBaseConvertPlugin {
async onInit(): Promise<void> {}
async getCertFromStore() {
const certReader = new CertReader(this.uploadCert);
if (!certReader.expires && certReader.expires < new Date().getTime()) {
let certReader = null;
try {
this.logger.info("读取上次证书");
certReader = await this.readLastCert();
} catch (e) {
this.logger.warn("读取cert失败", e);
}
if (certReader == null) {
certReader = new CertReader(this.uploadCert);
}
if (!certReader.expires || certReader.expires < new Date().getTime()) {
throw new Error("证书已过期,停止部署,请重新上传证书");
}

View File

@@ -3,6 +3,36 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
### Performance Improvements
* 1panel支持 currenNode ([acc8907](https://github.com/certd/certd/commit/acc890730f43d492c9b1bd3668814cf10efdf7b8))
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
### Bug Fixes
* 修复阿里云发送短信验证码失败的bug ([2e6d03f](https://github.com/certd/certd/commit/2e6d03ff001f521f57368e7a62b97ed7b122e8d0))
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
**Note:** Version bump only for package @certd/plugin-lib
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/plugin-lib
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
**Note:** Version bump only for package @certd/plugin-lib
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
### Bug Fixes
* 修复ssh无法执行命令的bug ([9763cb0](https://github.com/certd/certd/commit/9763cb00e5d95b2fa5d1c2d3d4a8eecac71600e6))
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
### Bug Fixes

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-lib",
"private": false,
"version": "1.36.7",
"version": "1.36.14",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -21,8 +21,8 @@
"@alicloud/pop-core": "^1.7.10",
"@alicloud/tea-util": "^1.4.10",
"@aws-sdk/client-s3": "^3.787.0",
"@certd/basic": "^1.36.7",
"@certd/pipeline": "^1.36.7",
"@certd/basic": "^1.36.14",
"@certd/pipeline": "^1.36.14",
"@kubernetes/client-node": "0.21.0",
"ali-oss": "^6.22.0",
"basic-ftp": "^5.0.5",
@@ -53,5 +53,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "29d49d72f95aa101729965710375104240a2c038"
"gitHead": "1e03a2e553aa94982453a477d2a0d35a565b6270"
}

View File

@@ -35,7 +35,7 @@ export class AliyunClient {
}
checkRet(ret: any) {
if (ret.Code != null) {
if (ret.Code != null && ret.Code !== "OK" && ret.Message !== "OK") {
throw new Error("执行失败:" + ret.Message);
}
}

View File

@@ -17,7 +17,7 @@ export function createCertDomainGetterInputDefine(opts?: { certInputKey?: string
}
}
`,
template:false,
template: false,
required: true,
},
opts?.props
@@ -42,6 +42,7 @@ export function createRemoteSelectInputDefine(opts?: {
search?: boolean;
pager?: boolean;
component?: any;
value?: any;
}) {
const title = opts?.title || "请选择";
const certDomainsInputKey = opts?.certDomainsInputKey || "certDomains";
@@ -74,6 +75,7 @@ export function createRemoteSelectInputDefine(opts?: {
watches: [certDomainsInputKey, accessIdInputKey, ...watches],
...opts.component,
},
value: opts.value,
rules: opts?.rules,
required: opts.required ?? true,
mergeScript:

View File

@@ -506,10 +506,6 @@ export class SshClient {
isWinCmd = await this.isCmd(conn);
}
if (isLinux && options.stopOnError !== false) {
script = "set -e\n" + script;
}
if (options.env) {
for (const key in options.env) {
if (isLinux) {
@@ -525,10 +521,10 @@ export class SshClient {
}
if (isWinCmd) {
//组合成&&的形式
if (typeof script === "string") {
script = script.split("\n");
}
//组合成&&的形式
script = envScripts.concat(script);
script = script as Array<string>;
script = script.join(" && ");
@@ -543,6 +539,10 @@ export class SshClient {
}
}
if (isLinux && options.stopOnError !== false) {
script = "set -e\n" + script;
}
return await conn.exec(script as string, { throwOnStdErr });
},
});

View File

@@ -9,3 +9,4 @@ yarn.lock
/.idea/
yarn-error.log
vite-profile.cpuprofile
!build

View File

@@ -3,6 +3,50 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
### Bug Fixes
* 修复复制流水线为空的bug ([b070773](https://github.com/certd/certd/commit/b0707739fdfbae3d78db4efd3f180db05c4e4164))
### Performance Improvements
* 授权管理支持模糊查询 ([866eb62](https://github.com/certd/certd/commit/866eb6241baa7b21f6eddc649966324c188236c6))
* 新增找回密码功能 [@nicheng-he](https://github.com/nicheng-he) ([81ac240](https://github.com/certd/certd/commit/81ac240ac84db0af2f56b6352e227ecb49f38377))
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
### Performance Improvements
* 阿里云部分插件优化 [@nicheng-he](https://github.com/nicheng-he) ([e3738f6](https://github.com/certd/certd/commit/e3738f6422270d75ec414c15a343248cc4cad6e1))
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
### Bug Fixes
* 上传到阿里云cas证书前缀无效的bug ([b382351](https://github.com/certd/certd/commit/b382351c7b91ec10e1f61d94bec5aad075207ec8))
### Performance Improvements
* 首页增加更新日志按钮 ([41ce848](https://github.com/certd/certd/commit/41ce8489dc2f03a705dfa3fbb357769defb56c60))
* 增加版本过低提示 ([d1ce360](https://github.com/certd/certd/commit/d1ce36038cab72b5dc1b320d0a708c261ffbdacb))
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
**Note:** Version bump only for package @certd/ui-client
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
### Performance Improvements
* 优化子域名托管的说明 ([b15f514](https://github.com/certd/certd/commit/b15f514018b728acb0922ee3f93c1f302eb5d471))
* 账号即将过期通知 ([e403450](https://github.com/certd/certd/commit/e40345095f31e2fb8e2333a6647466659133fa0c))
* 子域名托管重复域名不允许添加 ([ffc0c7b](https://github.com/certd/certd/commit/ffc0c7bb7b16d9904fd2d905d1c4e1d4854e92a9))
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/ui-client
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/ui-client",
"version": "1.36.7",
"version": "1.36.14",
"private": true,
"scripts": {
"dev": "vite --open",
@@ -103,8 +103,8 @@
"zod-defaults": "^0.1.3"
},
"devDependencies": {
"@certd/lib-iframe": "^1.36.7",
"@certd/pipeline": "^1.36.7",
"@certd/lib-iframe": "^1.36.14",
"@certd/pipeline": "^1.36.14",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.12",

View File

@@ -0,0 +1,162 @@
<template>
<div class="remote-auto-complete">
<div class="flex flex-row">
<a-auto-complete class="remote-auto-complete-input" :filter-option="filterOption" :options="optionsRef" :value="value" v-bind="attrs" @click="onClick" @update:value="emit('update:value', $event)">
</a-auto-complete>
<div class="ml-5">
<fs-button :loading="loading" title="刷新选项" icon="ion:refresh-outline" @click="refreshOptions"></fs-button>
</div>
</div>
<div class="helper" :class="{ error: hasError }">
{{ message }}
</div>
</div>
</template>
<script setup lang="ts">
import { ComponentPropsType, doRequest } from "/@/components/plugins/lib";
import { defineComponent, inject, ref, useAttrs, watch, Ref } from "vue";
import { PluginDefine } from "@certd/pipeline";
defineOptions({
name: "RemoteAutoComplete",
});
const props = defineProps<
{
watches: string[];
} & ComponentPropsType
>();
const emit = defineEmits<{
"update:value": any;
}>();
const attrs = useAttrs();
const getCurrentPluginDefine: any = inject("getCurrentPluginDefine", () => {
return {};
});
const getScope: any = inject("get:scope", () => {
return {};
});
const getPluginType: any = inject("get:plugin:type", () => {
return "plugin";
});
const optionsRef = ref([]);
const message = ref("");
const hasError = ref(false);
const loading = ref(false);
const getOptions = async () => {
if (loading.value) {
return;
}
if (!getCurrentPluginDefine) {
return;
}
const define: PluginDefine = getCurrentPluginDefine()?.value;
if (!define) {
return;
}
const pluginType = getPluginType();
const { form } = getScope();
const input = (pluginType === "plugin" ? form?.input : form) || {};
for (let key in define.input) {
const inWatches = props.watches.includes(key);
const inputDefine = define.input[key];
if (inWatches && inputDefine.required) {
const value = input[key];
if (value == null || value === "") {
console.log("remote-select required", key);
return;
}
}
}
message.value = "";
hasError.value = false;
loading.value = true;
try {
const res = await doRequest(
{
type: pluginType,
typeName: form.type,
action: props.action,
input,
data: {},
},
{
onError(err: any) {
hasError.value = true;
message.value = `获取选项出错:${err.message}`;
},
showErrorNotify: false,
}
);
const list = res?.list || res || [];
if (list.length > 0) {
message.value = "获取数据成功,请从下拉框中选择";
}
optionsRef.value = list;
return res;
} finally {
loading.value = false;
}
};
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 || String(option.value).toLowerCase().indexOf(input.toLowerCase());
};
async function onClick() {
if (optionsRef.value?.length === 0) {
await refreshOptions();
}
}
async function refreshOptions() {
await getOptions();
}
watch(
() => {
const pluginType = getPluginType();
const { form, key } = getScope();
const input = (pluginType === "plugin" ? form?.input : form) || {};
const watches = {};
for (const key of props.watches) {
//@ts-ignore
watches[key] = input[key];
}
return {
form: watches,
key,
};
},
async (value, oldValue) => {
const { form } = value;
const oldForm: any = oldValue?.form;
let changed = oldForm == null || optionsRef.value.length == 0;
for (const key of props.watches) {
//@ts-ignore
if (oldForm && form[key] != oldForm[key]) {
changed = true;
break;
}
}
if (changed) {
await getOptions();
}
},
{
immediate: true,
}
);
</script>
<style lang="less"></style>

View File

@@ -1,4 +1,5 @@
import SynologyIdDeviceGetter from "./synology/device-id-getter.vue";
import RemoteAutoComplete from "./common/remote-auto-complete.vue";
import RemoteSelect from "./common/remote-select.vue";
import RemoteInput from "./common/remote-input.vue";
import CertDomainsGetter from "./common/cert-domains-getter.vue";
@@ -21,6 +22,7 @@ export default {
app.component("ApiTest", ApiTest);
app.component("SynologyDeviceIdGetter", SynologyIdDeviceGetter);
app.component("RemoteAutoComplete", RemoteAutoComplete);
app.component("RemoteSelect", RemoteSelect);
app.component("RemoteInput", RemoteInput);
app.component("CertDomainsGetter", CertDomainsGetter);

View File

@@ -57,6 +57,7 @@ export default {
passwordPlaceholder: "Please enter your password",
mobilePlaceholder: "Please enter your mobile number",
loginButton: "Log In",
forgotPassword: "Forgot password?",
forgotAdminPassword: "Forgot admin password?",
registerLink: "Register",

View File

@@ -78,6 +78,7 @@ export default {
runCount: "Run Count",
expiringCerts: "Soon-to-Expire Certificates",
supportedTasks: "Overview of Supported Deployment Tasks",
changeLog: "Change Log",
},
steps: {
createPipeline: "Create Certificate Pipeline",
@@ -449,7 +450,7 @@ export default {
batchDeleteConfirm: "Are you sure to batch delete these {count} records?",
selectRecordFirst: "Please select records first",
subdomainHosted: "Hosted Subdomain",
subdomainHelpText: "If you don't understand what subdomain hosting is, please refer to the documentation ",
subdomainHelpText: "If you don't understand what subdomain hosting is,Do not set it randomly, as it may result in the inability to apply for the certificate. please refer to the documentation ",
subdomainManagement: "Subdomain Management",
isDisabled: "Is Disabled",
enabled: "Enabled",
@@ -564,6 +565,7 @@ export default {
dualStackNetworkHelper: "If IPv6 priority is selected, enable IPv6 in docker-compose.yaml",
enableCommonCnameService: "Enable Public CNAME Service",
commonCnameHelper: "Allow use of public CNAME service. If disabled and no <router-link to='/sys/cname/provider'>custom CNAME service</router-link> is set, CNAME proxy certificate application will not work.",
enableCommonSelfServicePasswordRetrieval: "Enable self-service password recovery",
saveButton: "Save",
stopSuccess: "Stopped successfully",
google: "Google",

View File

@@ -57,6 +57,7 @@ export default {
passwordPlaceholder: "请输入密码",
mobilePlaceholder: "请输入手机号",
loginButton: "登录",
forgotPassword: "忘记密码?",
forgotAdminPassword: "忘记管理员密码?",
registerLink: "注册",

View File

@@ -84,6 +84,7 @@ export default {
runCount: "运行次数",
expiringCerts: "最快到期证书",
supportedTasks: "已支持的部署任务总览",
changeLog: "更新日志",
},
steps: {
createPipeline: "创建证书流水线",
@@ -415,7 +416,7 @@ export default {
is_present_no: "否",
basicInfo: "基础信息",
titlea: "名称",
disabled: "是否禁用",
disabled: "禁用",
ordera: "排序",
supportBuy: "支持购买",
intro: "介绍",
@@ -455,7 +456,7 @@ export default {
batchDeleteConfirm: "确定要批量删除这{count}条记录吗",
selectRecordFirst: "请先勾选记录",
subdomainHosted: "托管的子域名",
subdomainHelpText: "如果您不理解什么是子域托管,可以参考文档",
subdomainHelpText: "如果您不理解什么是子域托管,请不要随意设置,可能导致证书无法申请,可以参考文档",
subdomainManagement: "子域管理",
isDisabled: "是否禁用",
enabled: "启用",
@@ -570,6 +571,7 @@ export default {
dualStackNetworkHelper: "如果选择IPv6优先需要在docker-compose.yaml中启用ipv6",
enableCommonCnameService: "启用公共CNAME服务",
commonCnameHelper: "是否可以使用公共CNAME服务如果禁用且没有设置<router-link to='/sys/cname/provider'>自定义CNAME服务</router-link>则无法使用CNAME代理方式申请证书",
enableCommonSelfServicePasswordRetrieval: "启用自助找回密码",
saveButton: "保存",
stopSuccess: "停止成功",
google: "Google",

View File

@@ -24,6 +24,14 @@ export const outsideResource = [
path: "/register",
component: "/framework/register/index.vue",
},
{
meta: {
title: "找回密码",
},
name: "forgotPassword",
path: "/forgotPassword",
component: "/framework/forgot-password/index.vue",
},
],
},
...errorPage,

View File

@@ -36,6 +36,7 @@ export type SysPublicSetting = {
emailRegisterEnabled?: boolean;
passwordLoginEnabled?: boolean;
smsLoginEnabled?: boolean;
selfServicePasswordRetrievalEnabled?: boolean;
limitUserPipelineCount?: number;
managerOtherUserPipeline?: boolean;

View File

@@ -46,6 +46,10 @@ export interface SettingState {
price3: number;
tooltip?: string;
};
app?: {
minVersion?: string;
minVersionTip?: string;
};
};
}
@@ -107,6 +111,10 @@ export const useSettingStore = defineStore({
price: 399,
price3: 899,
},
app: {
minVersion: "",
minVersionTip: "",
},
},
}),
getters: {

View File

@@ -20,6 +20,17 @@ export interface SmsLoginReq {
randomStr: string;
}
export interface ForgotPasswordReq {
forgotPasswordType: string;
input: string;
randomStr: string;
imgCode: string;
validateCode: string;
password: string;
confirmPassword: string;
}
export interface UserInfoRes {
id: string | number;
username: string;
@@ -43,6 +54,13 @@ export async function register(user: RegisterReq): Promise<UserInfoRes> {
data: user,
});
}
export async function forgotPassword(data: ForgotPasswordReq): Promise<any> {
return await request({
url: "/forgotPassword",
method: "post",
data: data,
});
}
export async function logout() {
return await request({
url: "/logout",

View File

@@ -4,7 +4,7 @@ import router from "../../router";
import { LocalStorage } from "/src/utils/util.storage";
// @ts-ignore
import * as UserApi from "./api.user";
import { RegisterReq, SmsLoginReq } from "./api.user";
import { ForgotPasswordReq, RegisterReq, SmsLoginReq } from "./api.user";
// @ts-ignore
import { LoginReq, UserInfoRes } from "/@/store/user/api.user";
import { message, Modal, notification } from "ant-design-vue";
@@ -67,6 +67,13 @@ export const useUserStore = defineStore({
});
await router.replace("/login");
},
async forgotPassword(params: ForgotPasswordReq): Promise<any> {
await UserApi.forgotPassword(params);
notification.success({
message: "密码已重置,请登录",
});
await router.replace("/login");
},
/**
* @description: login
*/

View File

@@ -488,7 +488,7 @@ const idMainContent = ELEMENT_ID_MAIN_CONTENT;
</template>
</LayoutContent>
<LayoutFooter v-if="footerEnable" class="hidden md:block" :fixed="footerFixed" :height="footerHeight" :show="!isFullContent" :width="footerWidth" :z-index="zIndex + 2">
<LayoutFooter v-if="footerEnable" class="hidden md:block" :fixed="footerFixed" :height="footerHeight" :show="!isFullContent" :width="footerWidth" :z-index="zIndex">
<slot name="footer"></slot>
</LayoutFooter>
</div>

View File

@@ -112,7 +112,8 @@ function menuIcon(menu: MenuRecordRaw) {
.vben-normal-menu__name,
.vben-normal-menu__icon {
@apply text-primary-foreground font-semibold;
//@apply text-primary-foreground font-semibold;
@apply font-semibold;
}
}

View File

@@ -57,7 +57,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
show: false,
},
search: {
show: false,
show: true,
},
form: {
wrapper: {

View File

@@ -14,6 +14,7 @@ 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";
import { useI18n } from "/src/locales";
import { GetDetail, GetObj } from "./api";
export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter();
@@ -200,7 +201,9 @@ export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys
const { ui } = useUi();
// @ts-ignore
let row = context[ui.tableColumn.row];
row = cloneDeep(row);
const info = await GetDetail(row.id);
row = info.pipeline;
row.content = JSON.parse(row.content);
row.title = row.title + "_copy";
await crudExpose.openCopy({
row: row,

View File

@@ -26,43 +26,45 @@
</template>
<div class="flex-col h-100 w-100 overflow-hidden">
<a-tabs v-model:active-key="pluginGroupActive" tab-position="left" class="flex-1 overflow-hidden">
<a-tab-pane v-for="group of computedPluginGroups" :key="group.key" class="scroll-y">
<template #tab>
<div class="cd-step-form-tab-label">
<fs-icon :icon="group.icon" class="mr-2" />
<div>{{ group.title }}</div>
</div>
</template>
<a-row v-if="!group.plugins || group.plugins.length === 0" :gutter="10">
<a-col class="flex-o">
<div class="flex-o m-10">没有找到插件</div>
</a-col>
</a-row>
<a-row v-else :gutter="10">
<a-col v-for="item of group.plugins" :key="item.key" class="step-plugin w-full md:w-[50%]">
<a-card
hoverable
:class="{ current: item.name === currentStep.type }"
@click="stepTypeSelected(item)"
@dblclick="
stepTypeSelected(item);
stepTypeSave();
"
>
<a-card-meta>
<template #title>
<fs-icon class="plugin-icon" :icon="item.icon || 'clarity:plugin-line'"></fs-icon>
<span class="title" :title="item.title">{{ item.title }}</span>
<vip-button v-if="item.needPlus" mode="icon" />
</template>
<template #description>
<span :title="item.desc" v-html="transformDesc(item.desc)"></span>
</template>
</a-card-meta>
</a-card>
</a-col>
</a-row>
</a-tab-pane>
<template v-for="group of computedPluginGroups" :key="group.key">
<a-tab-pane v-if="(group.key === 'admin' && userStore.isAdmin) || group.key !== 'admin'" :key="group.key" class="scroll-y">
<template #tab>
<div class="cd-step-form-tab-label">
<fs-icon :icon="group.icon" class="mr-2" />
<div>{{ group.title }}</div>
</div>
</template>
<a-row v-if="!group.plugins || group.plugins.length === 0" :gutter="10">
<a-col class="flex-o">
<div class="flex-o m-10">没有找到插件</div>
</a-col>
</a-row>
<a-row v-else :gutter="10">
<a-col v-for="item of group.plugins" :key="item.key" class="step-plugin w-full md:w-[50%]">
<a-card
hoverable
:class="{ current: item.name === currentStep.type }"
@click="stepTypeSelected(item)"
@dblclick="
stepTypeSelected(item);
stepTypeSave();
"
>
<a-card-meta>
<template #title>
<fs-icon class="plugin-icon" :icon="item.icon || 'clarity:plugin-line'"></fs-icon>
<span class="title" :title="item.title">{{ item.title }}</span>
<vip-button v-if="item.needPlus" mode="icon" />
</template>
<template #description>
<span :title="item.desc" v-html="transformDesc(item.desc)"></span>
</template>
</a-card-meta>
</a-card>
</a-col>
</a-row>
</a-tab-pane>
</template>
</a-tabs>
</div>
<template #footer>
@@ -124,6 +126,7 @@ import { useReference } from "/@/use/use-refrence";
import { useSettingStore } from "/@/store/settings";
import { mitter } from "/@/utils/util.mitt";
import { utils } from "/@/utils";
import { useUserStore } from "/@/store/user";
defineOptions({
name: "PiStepForm",
@@ -138,7 +141,7 @@ const props = defineProps({
const emit = defineEmits(["update"]);
const pluginStore = usePluginStore();
const userStore = useUserStore();
function transformDesc(desc: string = "") {
return utils.transformLink(desc);
}

View File

@@ -298,7 +298,7 @@ import { FsIcon } from "@fast-crud/fast-crud";
import { useSettingStore } from "/@/store/settings";
import { useUserStore } from "/@/store/user";
import TaskShortcuts from "./component/shortcut/task-shortcuts.vue";
import { eachSteps, findStep } from "../utils";
import { eachSteps, findStep, eachStages } from "../utils";
import { usePluginStore } from "/@/store/plugin";
import { getCronNextTimes } from "/@/components/cron-editor/utils";
import { useCertViewer } from "/@/views/certd/pipeline/use";
@@ -381,6 +381,9 @@ export default defineComponent({
//取消历史记录查看模式
currentHistory.value = null;
pipeline.value = cloneDeep(currentPipeline.value);
eachStages(pipeline.value.stages, item => {
item.status = null;
});
return;
}
currentHistory.value = history;

View File

@@ -3,7 +3,12 @@
<template #header>
<div class="title">
{{ t("certd.subdomainHosting") }}
<span class="sub">{{ t("certd.subdomainHostingHint") }}</span>
<span class="sub">
{{ t("certd.subdomainHostingHint") }} {{ t("certd.subdomainHelpText") }}
<a href="https://help.aliyun.com/zh/dns/subdomain-management" target="_blank">
{{ t("certd.subdomainManagement") }}
</a>
</span>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding">

View File

@@ -0,0 +1,179 @@
<template>
<div class="main forgot-password-page">
<a-form
ref="formRef"
class="user-layout-forgot-password"
name="custom-validation"
:model="formState"
:rules="rules"
v-bind="layout"
:label-col="{ span: 6 }"
@finish="handleFinish"
@finish-failed="handleFinishFailed"
>
<a-tabs v-model:active-key="forgotPasswordType" :destroyInactiveTabPane="true">
<a-tab-pane key="email" tab="邮箱找回">
<a-form-item has-feedback name="input" label="邮箱">
<a-input v-model:value="formState.input" placeholder="邮箱" size="large" autocomplete="off">
<template #prefix>
<fs-icon icon="ion:mail-outline"></fs-icon>
</template>
</a-input>
</a-form-item>
<a-form-item has-feedback name="validateCode" label="邮件验证码">
<email-code
v-model:value="formState.validateCode"
:img-code="formState.imgCode"
:email="formState.input"
:random-str="formState.randomStr"
verification-type="forgotPassword"
/>
</a-form-item>
</a-tab-pane>
<a-tab-pane key="mobile" tab="手机号找回">
<a-form-item required has-feedback name="input" label="手机号">
<a-input v-model:value="formState.input" placeholder="手机号" autocomplete="off">
<template #prefix>
<fs-icon icon="ion:phone-portrait-outline"></fs-icon>
</template>
</a-input>
</a-form-item>
<a-form-item name="validateCode" label="手机验证码">
<sms-code
v-model:value="formState.validateCode"
:img-code="formState.imgCode"
:mobile="formState.input"
:phone-code="formState.phoneCode"
:random-str="formState.randomStr"
verification-type="forgotPassword"
/>
</a-form-item>
</a-tab-pane>
</a-tabs>
<a-form-item has-feedback name="imgCode" label="图片验证码">
<image-code ref="imageCodeRef" v-model:value="formState.imgCode" v-model:random-str="formState.randomStr"></image-code>
</a-form-item>
<a-form-item has-feedback name="password" label="新密码">
<a-input-password v-model:value="formState.password" placeholder="新密码" size="large" autocomplete="off">
<template #prefix>
<fs-icon icon="ion:lock-closed-outline"></fs-icon>
</template>
</a-input-password>
</a-form-item>
<a-form-item has-feedback name="confirmPassword" label="确认密码">
<a-input-password v-model:value="formState.confirmPassword" placeholder="确认密码" size="large" autocomplete="off">
<template #prefix>
<fs-icon icon="ion:lock-closed-outline"></fs-icon>
</template>
</a-input-password>
</a-form-item>
<a-form-item>
<a-button type="primary" size="large" html-type="submit" class="submit-button"> 找回密码</a-button>
<div class="mt-2">
<a href="https://certd.docmirror.cn/guide/use/forgotpasswd/" target="_blank"> 管理员无绑定通信方式或MFA丢失找回 </a>
</div>
</a-form-item>
</a-form>
</div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref, toRaw, watch } from "vue";
import ImageCode from "/@/views/framework/login/image-code.vue";
import EmailCode from "/@/views/framework/register/email-code.vue";
import SmsCode from "/@/views/framework/login/sms-code.vue";
import { utils } from "@fast-crud/fast-crud";
import { useUserStore } from "/@/store/user";
defineOptions({
name: "ForgotPasswordPage",
});
const rules = {
input: [{ required: true }],
validateCode: [{ required: true }],
imgCode: [{ required: true }, { min: 4, max: 4, message: "请输入4位图片验证码" }],
password: [
{ required: true, trigger: "change", message: "请输入密码" },
{ min: 6, message: "至少输入6位密码" },
],
confirmPassword: [
{ required: true, trigger: "change", message: "请确认密码" },
{
validator: async (rule: any, value: any) => {
if (value && value !== formState.password) {
throw new Error("两次输入密码不一致");
}
return true;
},
},
],
};
const layout = {
labelCol: {
span: 0,
},
wrapperCol: {
span: 24,
},
};
const forgotPasswordType = ref();
const userStore = useUserStore();
const formRef = ref();
const imageCodeRef = ref();
const formState: any = reactive({
input: "",
randomStr: "",
imgCode: "",
phoneCode: "86",
validateCode: "",
password: "",
confirmPassword: "",
});
// TODO 这里配置不同的找回方式
onMounted(() => {
forgotPasswordType.value = "email";
});
// 监控找回类型变化
watch(forgotPasswordType, () => {
formState.input = "";
formState.validateCode = "";
imageCodeRef.value.resetImageCode();
formRef.value.clearValidate(Object.keys(formState).filter(key => !["password", "confirmPassword"].includes(key)));
});
const handleFinish = async (values: any) => {
await userStore.forgotPassword(
toRaw({
type: forgotPasswordType.value,
input: formState.input,
randomStr: formState.randomStr,
imgCode: formState.imgCode,
validateCode: formState.validateCode,
password: formState.password,
confirmPassword: formState.confirmPassword,
}) as any
);
};
const handleFinishFailed = (errors: any) => {
utils.logger.log(errors);
};
</script>
<style scoped lang="less">
.forgot-password-page {
.user-layout-forgot-password {
.submit-button {
width: 100%;
}
}
}
</style>

View File

@@ -29,6 +29,10 @@
</a-tag>
</a-badge>
<a-divider type="vertical" />
<a-tag color="blue" class="flex-inline pointer mr-0" @click="openChangeLogUrl()">
{{ t("certd.dashboard.changeLog") }}
</a-tag>
<a-divider type="vertical" />
<vip-button mode="nav" style="font-size: 12px"></vip-button>
</template>
<template v-if="settingsStore.isComm">
@@ -152,32 +156,48 @@ import * as api from "./api";
import { useI18n } from "/src/locales";
const { t } = useI18n();
import { usePluginStore } from "/@/store/plugin";
import { notification } from "ant-design-vue";
defineOptions({
name: "DashboardUser",
});
const version = ref(import.meta.env.VITE_APP_VERSION);
const latestVersion = ref("");
const hasNewVersion = computed(() => {
if (!latestVersion.value) {
function isNewVersion(version: string, latestVersion: string) {
if (!latestVersion) {
return false;
}
if (latestVersion.value === version.value) {
if (latestVersion === version) {
return false;
}
//分段比较
const current = version.value.split(".");
const latest = latestVersion.value.split(".");
const current = version.split(".");
const latest = latestVersion.split(".");
for (let i = 0; i < current.length; i++) {
if (parseInt(latest[i]) < parseInt(current[i])) {
return false;
if (parseInt(latest[i]) > parseInt(current[i])) {
return true;
}
}
return true;
return false;
}
const hasNewVersion = computed(() => {
return isNewVersion(version.value, latestVersion.value);
});
async function loadLatestVersion() {
latestVersion.value = await api.GetLatestVersion();
console.log("latestVersion", latestVersion.value);
const minVersion = settingsStore.productInfo?.app?.minVersion;
if (minVersion) {
//
if (isNewVersion(version.value, minVersion)) {
notification.error({
message: settingsStore.productInfo?.app?.minVersionTip ?? "版本过低,为了您的数据安全,请尽快升级",
});
}
}
}
const settingStore = useSettingStore();
const siteInfo: Ref<SiteInfo> = computed(() => {
@@ -255,6 +275,9 @@ onMounted(async () => {
function openUpgradeUrl() {
window.open("https://certd.docmirror.cn/guide/install/upgrade.html");
}
function openChangeLogUrl() {
window.open("https://certd.docmirror.cn/guide/changelogs/CHANGELOG.html");
}
</script>
<style lang="less">

View File

@@ -11,7 +11,7 @@
</div>
</template>
<script setup lang="ts">
import { ref, useAttrs } from "vue";
import { ref, useAttrs, defineExpose } from "vue";
import { nanoid } from "nanoid";
const props = defineProps<{
@@ -32,5 +32,10 @@ function resetImageCode() {
imageCodeUrl.value = url + "?randomStr=" + randomStr;
emit("update:randomStr", randomStr);
}
defineExpose({
resetImageCode,
})
resetImageCode();
</script>

View File

@@ -47,10 +47,10 @@
{{ t("authentication.loginButton") }}
</a-button>
<div v-if="!settingStore.isComm" class="mt-2">
<a href="https://certd.docmirror.cn/guide/use/forgotpasswd/" target="_blank">
{{ t("authentication.forgotAdminPassword") }}
</a>
<div v-if="!!settingStore.sysPublic.selfServicePasswordRetrievalEnabled" class="mt-2">
<router-link :to="{ name: 'forgotPassword' }">
{{ t("authentication.forgotPassword") }}
</router-link>
</div>
</a-form-item>

View File

@@ -23,6 +23,7 @@ const props = defineProps<{
phoneCode?: string;
imgCode?: string;
randomStr?: string;
verificationType?: string;
}>();
const emit = defineEmits(["update:value", "change"]);
@@ -58,6 +59,7 @@ async function sendSmsCode() {
mobile: props.mobile,
imgCode: props.imgCode,
randomStr: props.randomStr,
verificationType: props.verificationType,
});
} finally {
loading.value = false;

View File

@@ -22,6 +22,7 @@ const props = defineProps<{
email?: string;
imgCode?: string;
randomStr?: string;
verificationType?: string;
}>();
const emit = defineEmits(["update:value", "change"]);
@@ -53,6 +54,7 @@ async function sendSmsCode() {
email: props.email,
imgCode: props.imgCode,
randomStr: props.randomStr,
verificationType: props.verificationType,
});
} finally {
loading.value = false;

View File

@@ -1,10 +1,11 @@
import * as api from "./api";
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { useUserStore } from "/@/store/user";
import { Modal, notification } from "ant-design-vue";
import dayjs from "dayjs";
import { useSettingStore } from "/@/store/settings";
import { useI18n } from "/src/locales";
import { computed } from "vue";
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
@@ -26,7 +27,7 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
const userStore = useUserStore();
const settingStore = useSettingStore();
const userValidTimeEnabled = compute(() => {
const userValidTimeEnabled = computed(() => {
return settingStore.sysPublic.userValidTimeEnabled === true;
});
return {
@@ -226,7 +227,7 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
column: {
align: "center",
sorter: true,
width: 100,
width: 160,
show: userValidTimeEnabled,
cellRender({ value }) {
if (value == null || value === 0) {

View File

@@ -47,6 +47,10 @@
<div class="helper" v-html="t('certd.commonCnameHelper')"></div>
</a-form-item>
<a-form-item :label="t('certd.enableCommonSelfServicePasswordRetrieval')" :name="['public', 'selfServicePasswordRetrievalEnabled']">
<a-switch v-model:checked="formState.public.selfServicePasswordRetrievalEnabled" />
</a-form-item>
<a-form-item label=" " :colon="false" :wrapper-col="{ span: 8 }">
<a-button :loading="saveLoading" type="primary" html-type="submit">{{ t("certd.saveButton") }}</a-button>
</a-form-item>

View File

@@ -3,6 +3,53 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
### Performance Improvements
* 授权管理支持模糊查询 ([866eb62](https://github.com/certd/certd/commit/866eb6241baa7b21f6eddc649966324c188236c6))
* 新增找回密码功能 [@nicheng-he](https://github.com/nicheng-he) ([81ac240](https://github.com/certd/certd/commit/81ac240ac84db0af2f56b6352e227ecb49f38377))
* 运行主机脚本插件支持选择运行策略 ([86b3df1](https://github.com/certd/certd/commit/86b3df194126476e1f58e0952a77e986f62eecce))
## [1.36.13](https://github.com/certd/certd/compare/v1.36.12...v1.36.13) (2025-07-23)
### Performance Improvements
* 阿里云部分插件优化 [@nicheng-he](https://github.com/nicheng-he) ([e3738f6](https://github.com/certd/certd/commit/e3738f6422270d75ec414c15a343248cc4cad6e1))
## [1.36.12](https://github.com/certd/certd/compare/v1.36.11...v1.36.12) (2025-07-22)
### Bug Fixes
* 上传到阿里云cas证书前缀无效的bug ([b382351](https://github.com/certd/certd/commit/b382351c7b91ec10e1f61d94bec5aad075207ec8))
### Performance Improvements
* 部署到k8stkeack忽悠证书校验 ([ab84835](https://github.com/certd/certd/commit/ab848353621869464a2c9a45fdb5e28d998b8a58))
## [1.36.11](https://github.com/certd/certd/compare/v1.36.10...v1.36.11) (2025-07-22)
### Bug Fixes
* 安全更新,备份数据库插件仅限管理员运行 ([13dfca1](https://github.com/certd/certd/commit/13dfca1749275526c82465a17c482b607c820fdd))
## [1.36.10](https://github.com/certd/certd/compare/v1.36.9...v1.36.10) (2025-07-18)
### Bug Fixes
* 企业微信通知改成text类型因为markdown类型不支持@用户 ([747d266](https://github.com/certd/certd/commit/747d26674248082e678a3fd5ecc94712641a2716))
* api接口获取不到证书的bug ([05a33a0](https://github.com/certd/certd/commit/05a33a0ec9999e2802f6c7b23cc1c61a2b9e963d))
### Performance Improvements
* 部署到阿里云oss插件支持选择上传到阿里云cas中的证书 ([2ea2c8c](https://github.com/certd/certd/commit/2ea2c8c05fc40f79595f1bbde67c1413558bf684))
* 账号即将过期通知 ([e403450](https://github.com/certd/certd/commit/e40345095f31e2fb8e2333a6647466659133fa0c))
* 子域名托管重复域名不允许添加 ([ffc0c7b](https://github.com/certd/certd/commit/ffc0c7bb7b16d9904fd2d905d1c4e1d4854e92a9))
## [1.36.9](https://github.com/certd/certd/compare/v1.36.7...v1.36.9) (2025-07-15)
**Note:** Version bump only for package @certd/ui-server
## [1.36.7](https://github.com/certd/certd/compare/v1.36.6...v1.36.7) (2025-07-15)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/ui-server",
"version": "1.36.7",
"version": "1.36.14",
"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.36.7",
"@certd/basic": "^1.36.7",
"@certd/commercial-core": "^1.36.7",
"@certd/acme-client": "^1.36.14",
"@certd/basic": "^1.36.14",
"@certd/commercial-core": "^1.36.14",
"@certd/cv4pve-api-javascript": "^8.4.1",
"@certd/jdcloud": "^1.36.7",
"@certd/lib-huawei": "^1.36.7",
"@certd/lib-k8s": "^1.36.7",
"@certd/lib-server": "^1.36.7",
"@certd/midway-flyway-js": "^1.36.7",
"@certd/pipeline": "^1.36.7",
"@certd/plugin-cert": "^1.36.7",
"@certd/plugin-lib": "^1.36.7",
"@certd/plugin-plus": "^1.36.7",
"@certd/plus-core": "^1.36.7",
"@certd/jdcloud": "^1.36.14",
"@certd/lib-huawei": "^1.36.14",
"@certd/lib-k8s": "^1.36.14",
"@certd/lib-server": "^1.36.14",
"@certd/midway-flyway-js": "^1.36.14",
"@certd/pipeline": "^1.36.14",
"@certd/plugin-cert": "^1.36.14",
"@certd/plugin-lib": "^1.36.14",
"@certd/plugin-plus": "^1.36.14",
"@certd/plus-core": "^1.36.14",
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120",
"@huaweicloud/huaweicloud-sdk-core": "^3.1.120",
"@koa/cors": "^5.0.0",

View File

@@ -27,6 +27,9 @@ export class EmailCodeReq {
@Rule(RuleType.string().required().max(4))
imgCode: string;
@Rule(RuleType.string())
verificationType: string;
}
/**
@@ -55,8 +58,20 @@ export class BasicController extends BaseController {
@Body(ALL)
body: EmailCodeReq
) {
const opts = {
verificationType: body.verificationType,
title: undefined,
content: undefined,
duration: undefined,
};
if(body?.verificationType === 'forgotPassword') {
opts.title = '找回密码';
opts.content = '验证码:${code}。您正在找回密码,请输入验证码并完成操作。如非本人操作请忽略';
opts.duration = 3;
}
await this.codeService.checkCaptcha(body.randomStr, body.imgCode);
await this.codeService.sendEmailCode(body.email, body.randomStr);
await this.codeService.sendEmailCode(body.email, body.randomStr, opts);
// 设置缓存内容
return this.ok(null);
}

View File

@@ -0,0 +1,56 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { BaseController, CommonException, Constants, SysSettingsService } from "@certd/lib-server";
import { CodeService } from '../../../modules/basic/service/code-service.js';
import { UserService } from '../../../modules/sys/authority/service/user-service.js';
import { LoginService } from "../../../modules/login/service/login-service.js";
/**
*/
@Provide()
@Controller('/api')
export class LoginController extends BaseController {
@Inject()
loginService: LoginService;
@Inject()
userService: UserService;
@Inject()
codeService: CodeService;
@Inject()
sysSettingsService: SysSettingsService;
@Post('/forgotPassword', { summary: Constants.per.guest })
public async forgotPassword(
@Body(ALL)
body: any,
) {
const sysSettings = await this.sysSettingsService.getPublicSettings();
if(!sysSettings.selfServicePasswordRetrievalEnabled) {
throw new CommonException('暂未开启自助找回');
}
if(body.type === 'email') {
this.codeService.checkEmailCode({
verificationType: 'forgotPassword',
email: body.input,
randomStr: body.randomStr,
validateCode: body.validateCode,
throwError: true,
});
} else if(body.type === 'mobile') {
await this.codeService.checkSmsCode({
verificationType: 'forgotPassword',
mobile: body.input,
randomStr: body.randomStr,
phoneCode: body.phoneCode,
smsCode: body.validateCode,
throwError: true,
});
} else {
throw new CommonException('暂不支持的找回类型,请联系管理员找回');
}
const username = await this.userService.forgotPassword(body);
username && this.loginService.clearCacheOnSuccess(username)
return this.ok();
}
}

View File

@@ -23,8 +23,13 @@ export class AccessController extends CrudController<AccessService> {
async page(@Body(ALL) body) {
body.query = body.query ?? {};
delete body.query.userId;
body.query.userId = this.getUserId()
let name = body.query?.name;
delete body.query.name;
const buildQuery = qb => {
qb.andWhere('user_id = :userId', { userId: this.getUserId() });
if (name) {
qb.andWhere('name like :name', { name: `%${name.trim()}%` });
}
};
const res = await this.service.page({
query: body.query,

View File

@@ -15,6 +15,7 @@ import {EmailService} from '../../../modules/basic/service/email-service.js';
import {http, HttpRequestConfig, logger, mergeUtils, utils} from '@certd/basic';
import {NotificationService} from '../../../modules/pipeline/service/notification-service.js';
import {TaskServiceBuilder} from "../../../modules/pipeline/service/getter/task-service-getter.js";
import { cloneDeep } from 'lodash-es';
@Provide()
@Controller('/api/pi/handle')
@@ -103,6 +104,7 @@ export class HandleController extends BaseController {
const taskCtx: TaskInstanceContext = {
pipeline: undefined,
step: undefined,
define: cloneDeep( pluginDefine.define),
lastStatus: undefined,
http,
download,

View File

@@ -1,15 +1,16 @@
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
import { PipelineService } from '../pipeline/service/pipeline-service.js';
import { logger } from '@certd/basic';
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, SysSiteInfo} from '@certd/lib-server';
import { SiteInfoService } from '../monitor/index.js';
import { Cron } from '../cron/cron.js';
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";
import {Between} from "typeorm";
@Autoload()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
@@ -58,6 +59,8 @@ export class AutoCRegisterCron {
await this.registerPlusExpireCheckCron();
await this.registerUserExpireCheckCron()
}
async registerSiteMonitorCron() {
@@ -137,4 +140,61 @@ export class AutoCRegisterCron {
}
})
}
registerUserExpireCheckCron() {
// 添加plus即将到期检查任务
this.cron.register({
name: 'user-expire-check',
cron: `0 20 9 * * *`, // 一天只能检查一次,否则会重复发送通知
job: async () => {
const getExpiresDaysUsers = async (days: number) => {
const targetDate = dayjs().add(days, 'day')
const startTime = targetDate.startOf('day').valueOf()
const endTime = targetDate.endOf('day').valueOf()
return await this.userService.find({
where: {
validTime: Between(startTime, endTime),
status: 1
}
})
}
const notifyExpiresDaysUsers = async (days: number) => {
const list = await getExpiresDaysUsers(days)
if (list.length === 0) {
return
}
let title = `账号即将到期`
let content = `您的账号剩余${days}天到期,请及时续期,以免影响业务`
if (days <= 0) {
title = `账号已过期`
content = `您的账号已过期${Math.abs(days)}天,请尽快续期,以免影响业务`
}
const url = await this.notificationService.getBindUrl("");
for (const user of list) {
logger.info(`发送到期通知给用户:${user.username}`)
await this.notificationService.send({
useDefault: true,
logger: logger,
body: {
title,
content,
errorMessage: title,
url
}
}, user.id)
}
}
await notifyExpiresDaysUsers(7)
await notifyExpiresDaysUsers(3)
await notifyExpiresDaysUsers(1)
await notifyExpiresDaysUsers(0)
await notifyExpiresDaysUsers(-1)
await notifyExpiresDaysUsers(-3)
}
})
}
}

View File

@@ -57,7 +57,15 @@ export class CodeService {
}
/**
*/
async sendSmsCode(phoneCode = '86', mobile: string, randomStr: string) {
async sendSmsCode(
phoneCode = '86',
mobile: string,
randomStr: string,
opts?: {
duration?: number,
verificationType?: string
},
) {
if (!mobile) {
throw new Error('手机号不能为空');
}
@@ -65,6 +73,8 @@ export class CodeService {
throw new Error('randomStr不能为空');
}
const duration = Math.max(Math.floor(Math.min(opts?.duration || 5, 15)), 1);
const sysSettings = await this.sysSettingsService.getPrivateSettings();
if (!sysSettings.sms?.config?.accessId) {
throw new Error('当前站点还未配置短信');
@@ -84,16 +94,29 @@ export class CodeService {
phoneCode,
});
const key = this.buildSmsCodeKey(phoneCode, mobile, randomStr);
const key = this.buildSmsCodeKey(phoneCode, mobile, randomStr, opts?.verificationType);
cache.set(key, smsCode, {
ttl: 5 * 60 * 1000, //5分钟
ttl: duration * 60 * 1000, //5分钟
});
return smsCode;
}
/**
*
* @param email 收件邮箱
* @param randomStr
* @param opts title标题 content内容模版 duration有效时间单位分钟 verificationType验证类型
*/
async sendEmailCode(email: string, randomStr: string) {
async sendEmailCode(
email: string,
randomStr: string,
opts?: {
title?: string,
content?: string,
duration?: number,
verificationType?: string
},
) {
if (!email) {
throw new Error('Email不能为空');
}
@@ -110,15 +133,20 @@ export class CodeService {
}
const code = randomNumber(4);
const duration = Math.max(Math.floor(Math.min(opts?.duration || 5, 15)), 1);
const title = `${siteTitle}${!!opts?.title ? opts.title : '验证码'}`;
const content = !!opts.content ? this.compile(opts.content)({code, duration}) : `您的验证码是${code},请勿泄露`;
await this.emailService.send({
subject: `${siteTitle}】验证码`,
content: `您的验证码是${code},请勿泄露`,
subject: title,
content: content,
receivers: [email],
});
const key = this.buildEmailCodeKey(email, randomStr);
const key = this.buildEmailCodeKey(email, randomStr, opts?.verificationType);
cache.set(key, code, {
ttl: 5 * 60 * 1000, //5分钟
ttl: duration * 60 * 1000, //5分钟
});
return code;
}
@@ -126,20 +154,20 @@ export class CodeService {
/**
* checkSms
*/
async checkSmsCode(opts: { mobile: string; phoneCode: string; smsCode: string; randomStr: string; throwError: boolean }) {
const key = this.buildSmsCodeKey(opts.phoneCode, opts.mobile, opts.randomStr);
async checkSmsCode(opts: { mobile: string; phoneCode: string; smsCode: string; randomStr: string; verificationType?: string; throwError: boolean }) {
const key = this.buildSmsCodeKey(opts.phoneCode, opts.mobile, opts.randomStr, opts.verificationType);
if (isDev()) {
return true;
}
return this.checkValidateCode(key, opts.smsCode, opts.throwError);
}
buildSmsCodeKey(phoneCode: string, mobile: string, randomStr: string) {
return `sms:${phoneCode}${mobile}:${randomStr}`;
buildSmsCodeKey(phoneCode: string, mobile: string, randomStr: string, verificationType?: string) {
return ['sms', verificationType, phoneCode, mobile, randomStr].filter(item => !!item).join(':');
}
buildEmailCodeKey(email: string, randomStr: string) {
return `email:${email}:${randomStr}`;
buildEmailCodeKey(email: string, randomStr: string, verificationType?: string) {
return ['email', verificationType, email, randomStr].filter(item => !!item).join(':');
}
checkValidateCode(key: string, userCode: string, throwError = true) {
//验证图片验证码
@@ -154,8 +182,18 @@ export class CodeService {
return true;
}
checkEmailCode(opts: { randomStr: string; validateCode: string; email: string; throwError: boolean }) {
const key = this.buildEmailCodeKey(opts.email, opts.randomStr);
checkEmailCode(opts: { randomStr: string; validateCode: string; email: string; verificationType?: string; throwError: boolean }) {
const key = this.buildEmailCodeKey(opts.email, opts.randomStr, opts.verificationType);
return this.checkValidateCode(key, opts.validateCode, opts.throwError);
}
compile(templateString: string) {
return new Function(
"data",
` with(data || {}) {
return \`${templateString}\`;
}
`
);
}
}

View File

@@ -32,6 +32,12 @@ export class CertInfoFacade {
if (certId) {
return await this.certInfoService.getCertInfoById({ id: certId, userId });
}
if (!domains) {
throw new CodeException({
...Constants.res.openParamError,
message: "参数错误certId和domains必须传一个",
});
}
const domainArr = domains.split(',');
const matchedList = await this.certInfoService.getMatchCertList({domains:domainArr,userId})
@@ -42,12 +48,15 @@ export class CertInfoFacade {
const pipeline:PipelineEntity = await this.createAutoPipeline({domains:domainArr,userId})
await this.triggerApplyPipeline({pipelineId:pipeline.id})
}else{
throw new CodeException(Constants.res.openCertNotFound);
throw new CodeException({
...Constants.res.openCertNotFound,
message:"在证书仓库中没有找到匹配域名的证书请先创建证书流水线或传入autoApply参数自动创建"
});
}
}
matched = null;
for (const item of matchedList) {
if (item.expiresTime>0 && item.expiresTime < new Date().getTime()) {
if (item.expiresTime>0 && item.expiresTime > new Date().getTime()) {
matched = item;
break
}
@@ -59,7 +68,10 @@ export class CertInfoFacade {
await this.triggerApplyPipeline({pipelineId:first.pipelineId})
return
}else{
throw new CodeException(Constants.res.openCertNotFound);
throw new CodeException({
...Constants.res.openCertNotFound,
message:"证书已过期请触发流水线申请或者传入autoApply参数自动触发"
});
}
}
@@ -109,10 +121,12 @@ export class CertInfoFacade {
await this.pipelineService.trigger(req.pipelineId)
await utils.sleep(1000)
}
const certInfo = await this.certInfoService.getByPipelineId(req.pipelineId)
throw new CodeException({
...Constants.res.openCertApplying,
data:{
pipelineId:req.pipelineId
pipelineId:req.pipelineId,
certId:certInfo?.id
}
});
}

View File

@@ -86,7 +86,10 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
async getMatchCertList(params: { domains: string[]; userId: number }) {
const { domains, userId } = params;
if (!domains) {
throw new CodeException(Constants.res.openCertNotFound);
throw new CodeException({
...Constants.res.openCertNotFound,
message:"域名不能为空"
});
}
const list = await this.find({
@@ -99,6 +102,9 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
where: {
userId,
},
order: {
id: 'DESC',
},
});
//遍历查找
return list.filter(item => {
@@ -161,4 +167,12 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
return bean;
}
async getByPipelineId(pipelineId: number) {
return await this.repository.findOne({
where: {
pipelineId,
},
});
}
}

View File

@@ -93,7 +93,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
if (oldIps.length === ips.length ){
//检查是否有变化
const oldIpList = oldIps.map(ip=>ip.ipAddress).sort().join(",")
const newIpList = ips.filter(ip=>!oldIpList.includes(ip)).sort().join(",")
const newIpList = ips.sort().join(",")
if(oldIpList === newIpList){
//无变化
hasChanged = false

View File

@@ -36,4 +36,25 @@ export class SubDomainService extends BaseService<SubDomainEntity> {
return list.map(item=>item.domain);
}
async add(bean: SubDomainEntity) {
const {domain, userId} = bean;
if (!domain) {
throw new Error('域名不能为空');
}
if (!userId) {
throw new Error('用户ID不能为空');
}
const exist = await this.repository.findOne({
where: {
domain,
userId,
},
});
if (exist) {
throw new Error('域名已存在');
}
return await super.add(bean)
}
}

View File

@@ -15,6 +15,7 @@ import { DbAdapter } from '../../../db/index.js';
import { simpleNanoId, utils } from '@certd/basic';
export type RegisterType = 'username' | 'mobile' | 'email';
export type ForgotPasswordType = 'mobile' | 'email';
export const AdminRoleId = 1
/**
@@ -23,7 +24,7 @@ export const AdminRoleId = 1
@Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class UserService extends BaseService<UserEntity> {
@InjectEntityModel(UserEntity)
repository: Repository<UserEntity>;
@Inject()
@@ -229,6 +230,29 @@ export class UserService extends BaseService<UserEntity> {
return newUser;
}
async forgotPassword(
data: {
type: ForgotPasswordType; input?: string, phoneCode?: string,
randomStr: string, imgCode:string, validateCode: string,
password: string, confirmPassword: string,
}
) {
if(!data.type) {
throw new CommonException('找回类型不能为空');
}
if(data.password !== data.confirmPassword) {
throw new CommonException('两次输入的密码不一致');
}
const user = await this.findOne([{ [data.type]: data.input }]);
console.log('user', user)
if(!user) {
throw new CommonException('用户不存在');
// return;
}
await this.resetPassword(user.id, data.password)
return user.username;
}
async changePassword(userId: any, form: any) {
const user = await this.info(userId);
const passwordChecked = await this.checkPassword(form.password, user.password, user.passwordVersion);

View File

@@ -30,3 +30,4 @@ export * from './plugin-github/index.js'
export * from './plugin-namesilo/index.js'
export * from './plugin-proxmox/index.js'
export * from './plugin-wangsu/index.js'
export * from './plugin-admin/index.js'

View File

@@ -0,0 +1,3 @@
export * from './plugin-restart.js';
export * from './plugin-script.js';
export * from './plugin-db-backup.js';

View File

@@ -14,14 +14,15 @@ const defaultFilePrefix = 'db_backup';
name: 'DBBackupPlugin',
title: '数据库备份',
icon: 'lucide:database-backup',
desc: '仅支持备份SQLite数据库',
group: pluginGroups.other.key,
desc: '【仅管理员可用】仅支持备份SQLite数据库',
group: pluginGroups.admin.key,
showRunStrategy: true,
default: {
strategy: {
runStrategy: RunStrategy.AlwaysRun,
},
},
onlyAdmin:true,
needPlus: true,
})
export class DBBackupPlugin extends AbstractPlusTaskPlugin {
@@ -157,6 +158,11 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
}
async execute(): Promise<void> {
if (!this.isAdmin()) {
throw new Error('只有管理员才能运行此任务');
}
this.logger.info('开始备份数据库');
let dbPath = process.env.certd_typeorm_dataSource_default_database;

View File

@@ -1,12 +1,13 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy } from '@certd/pipeline';
import { httpsServer } from '../../../modules/auto/https/server.js';
import { httpsServer } from '../../modules/auto/https/server.js';
@IsTaskPlugin({
name: 'RestartCertd',
title: '重启 Certd',
icon: 'mdi:restart',
desc: '【仅管理员可用】 重启 certd的https服务用于更新 Certd 的 ssl 证书',
group: pluginGroups.other.key,
group: pluginGroups.admin.key,
onlyAdmin:true,
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed,

View File

@@ -11,8 +11,9 @@ export type CustomScriptContext = {
title: '自定义js脚本',
icon: 'ri:javascript-line',
desc: '【仅管理员】运行自定义js脚本执行',
group: pluginGroups.other.key,
group: pluginGroups.admin.key,
showRunStrategy: true,
onlyAdmin: true,
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed,

View File

@@ -26,7 +26,7 @@ export class AliyunDeployCertToESA extends AbstractTaskPlugin {
helper: "请选择证书申请任务输出的域名证书",
component: {
name: "output-selector",
from: [...CertApplyPluginNames]
from: [...CertApplyPluginNames, 'uploadCertToAliyun']
},
required: true
})
@@ -58,8 +58,8 @@ export class AliyunDeployCertToESA extends AbstractTaskPlugin {
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: "德国(法兰克福)" }
{ value: "cas.ap-southeast-1.aliyuncs.com", label: "新加坡" }
// { value: "cas.eu-central-1.aliyuncs.com", label: "德国(法兰克福)" }
]
},
required: true

View File

@@ -1,6 +1,6 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { AliyunAccess } from '@certd/plugin-lib';
import { CertInfo } from '@certd/plugin-cert';
import {AliyunAccess, AliyunSslClient} from '@certd/plugin-lib';
import {CertInfo, CertReader} from '@certd/plugin-cert';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({
name: 'DeployCertToAliyunOSS',
@@ -59,6 +59,15 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
@TaskInput({
title: 'Bucket',
helper: '存储桶名称',
component: {
name: 'remote-auto-complete',
vModel: 'value',
type: 'plugin',
action: 'onGetBucketList',
search: false,
pager: false,
watches: ['accessId', 'region']
},
required: true,
})
bucket!: string;
@@ -82,11 +91,28 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书',
component: {
name: 'output-selector',
from: [...CertApplyPluginNames],
from: [...CertApplyPluginNames,"uploadCertToAliyun"],
},
required: true,
})
cert!: CertInfo;
cert!: CertInfo | string;
@TaskInput({
title: '证书服务接入点',
helper: '不会选就按默认',
value: 'cn-hangzhou',
component: {
name: 'a-select',
options: [
{ value: 'cn-hangzhou', label: '中国大陆' },
{ value: 'southeast-1', label: '新加坡' },
{ value: 'eu-central-1', label: '德国(法兰克福)' },
],
},
required: true,
order: -99,
})
casRegion!: string;
@TaskInput({
title: 'Access授权',
@@ -96,6 +122,7 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
type: 'aliyun',
},
required: true,
order: -98,
})
accessId!: string;
@@ -103,12 +130,42 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
async execute(): Promise<void> {
this.logger.info('开始部署证书到阿里云OSS');
const access = (await this.getAccess(this.accessId)) as AliyunAccess;
await this.getAliyunCertId(access)
this.logger.info(`bucket: ${this.bucket}, region: ${this.region}, domainName: ${this.domainName}`);
const client = await this.getClient(access);
await this.doRequest(client, {});
this.logger.info('部署完成');
}
async getAliyunCertId(access: AliyunAccess) {
let certId: any = this.cert;
let certName: any = this.appendTimeSuffix("certd");
if (typeof this.cert === "object") {
let endpoint = `cas.${this.casRegion}.aliyuncs.com`;
if (this.casRegion === "cn-hangzhou"){
endpoint = "cas.aliyuncs.com";
}
const sslClient = new AliyunSslClient({
access,
logger: this.logger,
endpoint: endpoint
});
certName = this.buildCertName(CertReader.getMainDomain(this.cert.crt));
certId = await sslClient.uploadCert({
name: certName,
cert: this.cert
});
this.logger.info("上传证书成功", certId, certName);
}
return {
certId,
certName
};
}
async getClient(access: AliyunAccess) {
// @ts-ignore
const OSS = await import('ali-oss');
@@ -124,18 +181,47 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
});
}
async onGetBucketList(data: any) {
console.log('data', data)
const access = (await this.getAccess(this.accessId)) as AliyunAccess;
const client = await this.getClient(access);
let res;
const buckets = []
do{
const requestData = {'marker': res?.nextMarker || null, 'max-keys': 1000};
res = await client.listBuckets(requestData)
buckets.push(...(res?.buckets || []))
} while (!!res?.nextMarker)
return buckets
.filter(bucket => bucket?.region === this.region)
.map(bucket => ({label: `${bucket.name}<${bucket.region}>`, value: bucket.name}));
}
async doRequest(client: any, params: any) {
params = client._bucketRequestParams('POST', this.bucket, {
cname: '',
comp: 'add',
});
let certStr = ""
if (typeof this.cert === "object" ){
certStr = `
<PrivateKey>${this.cert.key}</PrivateKey>
<Certificate>${this.cert.crt}</Certificate>
`
}else{
certStr = `<CertId>${this.cert}-${this.casRegion}</CertId>`
}
const xml = `
<BucketCnameConfiguration>
<Cname>
<Domain>${this.domainName}</Domain>
<CertificateConfiguration>
<PrivateKey>${this.cert.key}</PrivateKey>
<Certificate>${this.cert.crt}</Certificate>
${certStr}
<Force>true</Force>
</CertificateConfiguration>
</Cname>
</BucketCnameConfiguration>`;

View File

@@ -15,7 +15,7 @@ import { CertApplyPluginNames, CertReader } from "@certd/plugin-cert";
const regionDict = [
{ value: 'cn-hangzhou', endpoint: 'cas.aliyuncs.com', label: 'cn-hangzhou-中国大陆' },
{ value: 'eu-central-1', endpoint: 'cas.eu-central-1.aliyuncs.com', label: 'eu-central-1-德国(法兰克福)' },
{ value: 'ap-southeast-1', endpoint: 'cas.ap-southeast-1.aliyuncs.com', label: 'ap-southeast-1-新加坡' },
{ value: 'ap-southeast-1', endpoint: 'cas.ap-southeast-1.aliyuncs.com', label: 'ap-southeast-1-新加坡(国际版选这个)' },
{ value: 'ap-southeast-3', endpoint: 'cas.ap-southeast-3.aliyuncs.com', label: 'ap-southeast-3-马来西亚(吉隆坡)' },
{ value: 'ap-southeast-5', endpoint: 'cas.ap-southeast-5.aliyuncs.com', label: 'ap-southeast-5-印度尼西亚(雅加达)' },
{ value: 'cn-hongkong', endpoint: 'cas.cn-hongkong.aliyuncs.com', label: 'cn-hongkong-中国香港' },
@@ -23,7 +23,7 @@ const regionDict = [
@IsTaskPlugin({
name: 'uploadCertToAliyun',
title: '阿里云-上传证书到阿里云',
title: '阿里云-上传证书到阿里云CAS',
icon: 'svg:icon-aliyun',
group: pluginGroups.aliyun.key,
desc: '上传证书到阿里云数字证书管理服务CAS注意不会部署到任何应用上如果不想在阿里云上同一份证书上传多次可以把此任务作为前置任务其他阿里云任务证书那一项选择此任务的输出',
@@ -82,7 +82,7 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
async onInstance() {}
async execute(): Promise<void> {
this.logger.info('开始部署证书到阿里云cdn');
this.logger.info('开始上传证书到阿里云证书管理CAS');
const access: AliyunAccess = await this.getAccess(this.accessId);
let endpoint = '';
@@ -97,7 +97,12 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
logger: this.logger,
endpoint,
});
const certName = this.buildCertName(CertReader.getMainDomain(this.cert.crt))
let certName = ""
if (this.name){
certName = this.appendTimeSuffix(this.name)
}else{
certName = this.buildCertName(CertReader.getMainDomain(this.cert.crt))
}
this.aliyunCertId = await client.uploadCert({
name: certName,
cert: this.cert,

View File

@@ -7,6 +7,7 @@ import { SshClient } from '@certd/plugin-lib';
group: pluginGroups.host.key,
desc: '可以执行重启nginx等操作让证书生效',
input: {},
showRunStrategy: true,
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed,

View File

@@ -47,26 +47,35 @@ export class QywxNotification extends BaseNotification {
if (!this.webhook) {
throw new Error('webhook地址不能为空');
}
/**
*
* "msgtype": "text",
* "text": {
* "content": "hello world"
* }
* }
*/
const color = body.errorMessage?'red':'green';
await this.http.request({
url: this.webhook,
method: 'POST',
data: {
msgtype: 'markdown',
markdown: {
content: `<font color='${color}'>${body.title}</font>\n\n\n${body.content}\n\n[查看详情](${body.url})`,
msgtype: 'text',
text: {
content: `${body.title}\n${body.content}\n查看详情: ${body.url}`,
mentioned_list: this.mentionedList,
mentioned_mobile_list: this.mentionedMobileList,
},
},
});
//Markdown 模式不支持@
// const color = body.errorMessage?'red':'green';
// await this.http.request({
// url: this.webhook,
// method: 'POST',
// data: {
// msgtype: 'markdown',
// markdown: {
// content: `<font color='${color}'>${body.title}</font>\n\n\n${body.content}\n\n[查看详情](${body.url})`,
// mentioned_list: this.mentionedList,
// mentioned_mobile_list: this.mentionedMobileList,
// },
// },
// });
}
}

View File

@@ -1,5 +1,2 @@
export * from './plugin-restart.js';
export * from './plugin-script.js';
export * from './plugin-wait.js';
export * from './plugin-db-backup.js';
export * from './plugin-deploy-to-mail.js';

View File

@@ -24,10 +24,10 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
component: {
name: "a-select",
vModel: "value",
options: [{ value: "nginx", label: "TLS证书格式Nginx可用" }, {
value: "qcloud",
label: "Opaque格式CLB可用原qcloud"
}]
options: [
{ value: "nginx", label: "TLS证书格式Nginx可用" },
{ value: "qcloud",label: "Opaque格式CLB可用原qcloud"}
]
},
helper: "clb将部署Opaque类型的证书nginx类型将部署TLS证书格式",
required: true
@@ -136,6 +136,18 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
ingressName!: string | string[];
@TaskInput({
title: "忽略证书校验",
required: false,
helper: "是否忽略证书校验",
component: {
name: "a-switch",
vModel: "checked",
}
})
skipTLSVerify!:boolean
// @TaskInput({ title: "集群内网ip", helper: "如果开启了外网的话,无需设置" })
// clusterIp!: string;
@@ -163,7 +175,8 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
this.logger.info("kubeconfig已成功获取");
const k8sClient = new this.K8sClient({
kubeConfigStr,
logger: this.logger
logger: this.logger,
skipTLSVerify: this.skipTLSVerify,
});
// if (this.clusterIp != null) {
// if (!this.clusterDomain) {

823
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -33,22 +33,22 @@ echo "开始构建"
echo "构建certd-client"
export NODE_OPTIONS=--max-old-space-size=32768
cd packages/ui/certd-client
npm run build
pnpm run build
cp -r dist/* ../certd-server/public
echo "构建certd-server"
cd ../certd-server
npm run build
pnpm run build
echo "构建完成"
echo "启动服务"
# 前台运行
if [ $confirmNohup != "y" ]; then
echo "当前运行模式为前台运行ctrl+c或者关闭ssh将会停止运行"
npm run start
pnpm run start
else
echo "当前运行模式为后台运行可以通过tail -f ./certd.log 命令查看日志"
nohup npm run start > certd.log &
nohup pnpm run start > certd.log &
fi