mirror of
https://github.com/certd/certd.git
synced 2026-04-08 17:12:22 +08:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ff700849f | ||
|
|
5c695dea20 | ||
|
|
c7ee4ca4db | ||
|
|
c3da026b33 | ||
|
|
98da4e1791 | ||
|
|
8626b6d9f2 | ||
|
|
80c5331a5d | ||
|
|
b37cffd704 | ||
|
|
2af91dbf2a | ||
|
|
f2551318fc | ||
|
|
22eb84f944 | ||
|
|
1ece0915f1 | ||
|
|
87853a2015 | ||
|
|
46a1b74799 | ||
|
|
0f6e7e5eab | ||
|
|
5dfa9615d2 | ||
|
|
1bde777bee | ||
|
|
fa4f5df3e7 | ||
|
|
8a3c3810e0 | ||
|
|
144532530a | ||
|
|
0f1129e19b | ||
|
|
1f74580f15 | ||
|
|
f93ba9970c | ||
|
|
f87a3d0892 | ||
|
|
c661ad67d0 | ||
|
|
ce4dc9e3fa | ||
|
|
3d2c6e6032 | ||
|
|
6000a0cfe3 | ||
|
|
b80c60997a | ||
|
|
35e45f0df1 | ||
|
|
e65f5b9f78 | ||
|
|
5969f71e67 | ||
|
|
b1307863eb | ||
|
|
9d0abe993b | ||
|
|
c53bb7cf67 | ||
|
|
0cea26c628 | ||
|
|
610c919c72 | ||
|
|
2c35f94f7c | ||
|
|
cd9a3870b3 | ||
|
|
e11373f23a | ||
|
|
f591635fc1 | ||
|
|
474b57ca61 |
38
CHANGELOG.md
38
CHANGELOG.md
@@ -3,6 +3,44 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复查看证书对话框翻译错误的bug ([8626b6d](https://github.com/certd/certd/commit/8626b6d9f235c511766f2ae98e0a37f6cebb621c))
|
||||
* 修复translation后分组编辑打不开的bug ([46a1b74](https://github.com/certd/certd/commit/46a1b7479923d2feb2dece202a5932b99981b2cd))
|
||||
* 执行windows nginx命令时,改为return code判断是否执行成功 ([b37cffd](https://github.com/certd/certd/commit/b37cffd704cd08b8bdd68a6e284706eabe59e78d))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化证书进度条颜色 ([2af91db](https://github.com/certd/certd/commit/2af91dbf2ae36a4ed17c6788bc2a2a79a3bb29f8))
|
||||
* 站点证书即将过期通知标题颜色优化为红色 ([80c5331](https://github.com/certd/certd/commit/80c5331a5d4c320323d9b9b800e4ea3b72577b33))
|
||||
* 支持部署到阿里云vod ([98da4e1](https://github.com/certd/certd/commit/98da4e1791ed8bb21daf2a9914fda875d14633c9))
|
||||
* 支持部署证书到网宿CDN ([c3da026](https://github.com/certd/certd/commit/c3da026b33106f5195959825a68cadbe49efef00))
|
||||
* 重置管理员密码同时可以清除管理员的2FA设置 ([1ece091](https://github.com/certd/certd/commit/1ece0915f172d5f8b8adb866434e7efcc5c8c46d))
|
||||
* output-selector from参数支持更丰富的过滤规则 ([87853a2](https://github.com/certd/certd/commit/87853a201535f3bfe8505c40f8f5229d82ffcc73))
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复开放接口添加按钮文本显示问题 ([f93ba99](https://github.com/certd/certd/commit/f93ba9970c12680f38eba2a7abd4b72cf3f5b6a6))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化部署到腾讯TKE插件,支持Opaque类型选择,优化填写说明 ([1445325](https://github.com/certd/certd/commit/144532530a865b634e68539e4888e26f52f73492))
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复notification编辑按钮无法打开对话框的bug ([0cea26c](https://github.com/certd/certd/commit/0cea26c6287f52adf273b4a525c37bea8555c68c))
|
||||
* 优化更新飞牛os证书有效期,修复某些情况下部署证书后飞牛无法访问https的bug ([610c919](https://github.com/certd/certd/commit/610c919c72037becc0ed326f5d5b18c963dfcb3a))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书检查支持自定义dns服务器 ([c53bb7c](https://github.com/certd/certd/commit/c53bb7cf677faa32729709ae0c10359db5194d7a))
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Certd
|
||||
|
||||
[English](./README_en.md) | [中文](./README.md)
|
||||
|
||||
Certd® 是一个免费的全自动证书管理系统,让你的网站证书永不过期。
|
||||
后缀d取自linux守护进程的命名风格,意为证书守护进程
|
||||
|
||||
@@ -195,8 +197,7 @@ https://afdian.com/a/greper
|
||||
|
||||
## 十一、我的其他项目(求Star)
|
||||
|
||||
| 项目名称 | stars | 项目描述 |
|
||||
|---------------------------------------------------------|-------------------------------------------------------------------------------------------------------|-----------------------------------|
|
||||
| [袖手AI](https://ai.handsfree.work/) | | 袖手GPT,国内可用,无需FQ,每日免费额度 |
|
||||
| 项目名称 | stars | 项目描述 |
|
||||
| --------- |--------- |----------- |
|
||||
| [fast-crud](https://gitee.com/fast-crud/fast-crud/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/fast-crud/fast-crud?logo=github"/> | 基于vue3的crud快速开发框架 |
|
||||
| [dev-sidecar](https://github.com/docmirror/dev-sidecar/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"/> | 直连访问github工具,无需FQ,解决github无法访问的问题 |
|
||||
| [dev-sidecar](https://github.com/docmirror/dev-sidecar/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"/> | 直连访问github工具,无需FQ,解决github无法访问的问题 |
|
||||
|
||||
183
README_en.md
Normal file
183
README_en.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Certd
|
||||
|
||||
[English](./README_en.md) | [中文](./README.md)
|
||||
|
||||
Certd® is a free, fully automated certificate management system that ensures your website certificates never expire. The suffix 'd' is inspired by the naming convention of Linux daemons, representing a certificate daemon.
|
||||
|
||||
> We pioneered the pipeline-based certificate application and deployment model, which has been "referenced" by multiple projects. Being copied is also a form of success.
|
||||
|
||||
> Regarding certificate renewal:
|
||||
>* In fact, it's impossible to renew or reissue a certificate without modifying the certificate file itself.
|
||||
>* What we refer to as renewal is essentially applying for a new certificate following the full process and redeploying it.
|
||||
>* Free certificates expire in 90 days, which may be shortened in the future. Therefore, automated deployment is essential.
|
||||
|
||||
> The number of pipelines is now unlimited. Welcome to use it.
|
||||
|
||||
## 1. Features
|
||||
This project not only supports automated certificate application but also automated certificate deployment and updates, ensuring your certificates never expire.
|
||||
|
||||
* Fully automated certificate application (supports domains registered with all registrars and multiple domain verification methods such as DNS-01, HTTP-01, and CNAME proxy).
|
||||
* Fully automated certificate deployment and updates (currently supports deployment to over 70 plugins, including hosts, Alibaba Cloud, Tencent Cloud, etc.).
|
||||
* Supports wildcard domains/pan-domains, allows multiple domains in a single certificate, and supports various certificate formats such as pem, pfx, der, and jks.
|
||||
* Multiple notification methods, including email, webhook, WeChat Work, DingTalk, Lark, and anpush.
|
||||
* On-premises deployment, local data storage, simple and quick installation. Images are built by Github Actions, with a transparent process.
|
||||
* Multiple security measures, including authorization encryption, site hiding, 2FA, and password brute-force protection.
|
||||
* Supports multiple databases such as SQLite, PostgreSQL, and MySQL.
|
||||
* Open API support.
|
||||
* Site certificate monitoring.
|
||||
* Multi-user management.
|
||||
* Multi-language support (Chinese and English switching).
|
||||
* Downward compatibility across all versions, with one-click worry-free upgrades.
|
||||
|
||||

|
||||
|
||||
## 2. Online Experience
|
||||
Visit the official demo site and register to experience it.
|
||||
|
||||
https://certd.handfree.work/
|
||||
|
||||
> Note: Data will be cleaned up irregularly, and scheduled tasks may be stopped. For production use, please deploy it yourself.
|
||||
> The content contains sensitive information. Make sure to deploy it locally for production use.
|
||||
|
||||

|
||||
|
||||
## 3. Usage Tutorial
|
||||
Just 3 steps to ensure your certificates never expire.
|
||||
|
||||
### 1. Create a Certificate Pipeline
|
||||

|
||||
|
||||
> After successful addition, you can directly run the pipeline to apply for a certificate.
|
||||
|
||||
### 2. Add a Deployment Task
|
||||
Normally, we need to deploy certificates to applications. Certd supports a wide range of deployment plugins. You can choose based on your needs, such as deploying to Nginx, Alibaba Cloud, Tencent Cloud, K8S, CDN, Baota, 1Panel, etc.
|
||||
|
||||
Here's a demonstration of deploying certificates to a host's Nginx:
|
||||

|
||||
|
||||
If the current deployment plugins don't meet your needs, you can also download them manually and deploy them yourself.
|
||||

|
||||
|
||||
### 3. Run Scheduled Tasks
|
||||

|
||||
|
||||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
||||
-------> [Click here to view detailed usage steps](./step.md) <--------
|
||||
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
|
||||
|
||||
For more tutorials, please visit the official documentation [certd.docmirror.cn](https://certd.docmirror.cn/guide/).
|
||||
|
||||
## 4. On-Premises Deployment
|
||||
Since certificates, authorization information, and other data are highly sensitive, please make sure to deploy them on-premises to ensure data security.
|
||||
|
||||
You can choose one of the following deployment methods based on your needs:
|
||||
|
||||
1. 【Recommended】[Docker Deployment](https://certd.docmirror.cn/guide/install/docker/)
|
||||
2. 【Recommended】[BT Panel Deployment](https://certd.docmirror.cn/guide/install/docker/)
|
||||
3. 【Recommended】[1Panel Deployment](https://certd.docmirror.cn/guide/install/1panel/)
|
||||
4. 【Recommended】[Rainyun One-Click Deployment](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2_): Double your first recharge, only $2.2 per month.
|
||||
[<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. 【Not Recommended】[Source Code Deployment](https://certd.docmirror.cn/guide/install/source/)
|
||||
|
||||
#### Docker Image Information:
|
||||
* Domestic Image Addresses:
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest`
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:armv7`, `[version]-armv7`
|
||||
* DockerHub Addresses:
|
||||
* `https://hub.docker.com/r/greper/certd`
|
||||
* `greper/certd:latest`
|
||||
* `greper/certd:armv7`, `greper/certd:[version]-armv7`
|
||||
* GitHub Packages Addresses:
|
||||
* `ghcr.io/certd/certd:latest`
|
||||
* `ghcr.io/certd/certd:armv7`, `ghcr.io/certd/certd:[version]-armv7`
|
||||
|
||||
* Images are built automatically by `Actions`, with a transparent process. Please use them with confidence.
|
||||
* [Click here to view image build logs](https://github.com/certd/certd/actions/workflows/build-image.yml)
|
||||
|
||||

|
||||
|
||||
> Note:
|
||||
> * The certificates, authorization information, and other data stored in this application are highly sensitive. Please take appropriate security measures.
|
||||
> * Make sure to use the HTTPS protocol to access this application to avoid man-in-the-middle attacks.
|
||||
> * Make sure to use a web application firewall to protect this application from attacks such as XSS and SQL injection.
|
||||
> * Make sure to secure the server itself to prevent database leakage.
|
||||
> * Make sure to back up your data to avoid data loss.
|
||||
> * [Click here for more production safety suggestions](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
|
||||
## 5. Ecosystem
|
||||
|
||||
### 1. Client Tool: SSL-Assistant
|
||||
`SSL Assistant` is a certificate deployment and management assistant client that runs on hosts. It supports automatic scanning of the host's `Nginx` configuration and pulling certificates from `Certd` for deployment. This tool is very useful when you don't want to expose your SSH host password.
|
||||
|
||||
Open-source Address: https://github.com/Youngxj/SSL-Assistant
|
||||
|
||||
## 6. More Help
|
||||
Please visit the official documentation: [https://certd.docmirror.cn/](https://certd.docmirror.cn/guide/).
|
||||
|
||||
* Upgrade Method: [Upgrade Guide](https://certd.docmirror.cn/guide/install/upgrade/)
|
||||
* Common Issues: [Forgot Password](https://certd.docmirror.cn/guide/use/forgotpasswd/)
|
||||
* Multi-Database: [Multi-Database Configuration](https://certd.docmirror.cn/guide/install/database/)
|
||||
* Site Security: [Site Security Features](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
* Changelog: [CHANGELOG](./CHANGELOG.md)
|
||||
|
||||
## 7. Contact the Author
|
||||
If you have any questions, feel free to join the group chat (please mention 'certd' in your message).
|
||||
|
||||
| Join Group | WeChat Group | QQ Group |
|
||||
|---------|-------|-------|
|
||||
| QR Code | <img height="230" src="./docs/guide/contact/images/wx.png"> | <img height="230" src="./docs/guide/contact/images/qq.png"> |
|
||||
|
||||
You can also add the author as a friend.
|
||||
|
||||
| Add Author as Friend | WeChat QQ |
|
||||
|---------|-------|-------|
|
||||
| QR Code | <img height="230" src="./docs/guide/contact/images/me.png"> |
|
||||
|
||||
## 8. Donation
|
||||
************************
|
||||
Support open-source projects and contribute with love. I've joined Afdian.
|
||||
https://afdian.com/a/greper
|
||||
|
||||
Benefits of Contribution:
|
||||
1. Join the exclusive contributor group and get one-on-one technical support from the author.
|
||||
2. Your requests will be prioritized and implemented as professional edition features.
|
||||
3. Receive a one-year professional edition activation code.
|
||||
|
||||
Comparison of Professional Edition Privileges:
|
||||
|
||||
| Feature | Free Edition | Professional Edition |
|
||||
|---------|---------------------------------------|--------------------------------|
|
||||
| Free Certificate Application | Unlimited for free | Unlimited for free |
|
||||
| Number of Domains | Unlimited | Unlimited |
|
||||
| Number of Certificate Pipelines | Unlimited | Unlimited |
|
||||
| Site Certificate Monitoring | Limited to 1 | Unlimited |
|
||||
| Automatic Deployment Plugins | Most plugins such as Alibaba Cloud CDN, Tencent Cloud, QiNiu CDN, Host Deployment, Baota, 1Panel | Synology |
|
||||
| Notifications | Email, Custom Webhook | Email without configuration, WeChat Work, DingTalk, Lark, anpush, ServerChan, etc. |
|
||||
|
||||
************************
|
||||
|
||||
## 9. Contribute Code
|
||||
|
||||
1. For local development, please refer to the [Plugin Contribution Guide](https://certd.docmirror.cn/guide/development/).
|
||||
2. As a contributor, you agree that your contributed code is subject to the following license:
|
||||
1. The open-source license can be adjusted to be more or less restrictive.
|
||||
2. It can be used for commercial purposes.
|
||||
|
||||
Thank you to the following contributors.
|
||||
|
||||
<a href="https://github.com/certd/certd/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=certd/certd" />
|
||||
</a>
|
||||
|
||||
## 10. Open-Source License
|
||||
* This project follows the GNU Affero General Public License (AGPL).
|
||||
* Individuals and companies are allowed to use, copy, modify, and distribute this project freely for internal use. Any form of commercial use is prohibited without obtaining commercial authorization.
|
||||
* Without commercial authorization, any modification of the logo, copyright information, and license-related code is prohibited.
|
||||
* For commercial authorization, please contact the author.
|
||||
|
||||
## 11. My Other Projects (Please Star)
|
||||
|
||||
| Project Name | Stars | Project Description |
|
||||
|----------------|---------------|--------------|
|
||||
| [fast-crud](https://gitee.com/fast-crud/fast-crud/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/fast-crud/fast-crud?logo=github"/> | A fast CRUD development framework based on Vue3. |
|
||||
| [dev-sidecar](https://github.com/docmirror/dev-sidecar/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"/> | A tool to access GitHub directly without a VPN, solving the problem of inaccessible GitHub. |
|
||||
@@ -1 +1 @@
|
||||
23:26
|
||||
22:21
|
||||
|
||||
@@ -3,6 +3,37 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复开放接口添加按钮文本显示问题 ([f93ba99](https://github.com/certd/certd/commit/f93ba9970c12680f38eba2a7abd4b72cf3f5b6a6))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化部署到腾讯TKE插件,支持Opaque类型选择,优化填写说明 ([1445325](https://github.com/certd/certd/commit/144532530a865b634e68539e4888e26f52f73492))
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复notification编辑按钮无法打开对话框的bug ([0cea26c](https://github.com/certd/certd/commit/0cea26c6287f52adf273b4a525c37bea8555c68c))
|
||||
* 优化更新飞牛os证书有效期,修复某些情况下部署证书后飞牛无法访问https的bug ([610c919](https://github.com/certd/certd/commit/610c919c72037becc0ed326f5d5b18c963dfcb3a))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书检查支持自定义dns服务器 ([c53bb7c](https://github.com/certd/certd/commit/c53bb7cf677faa32729709ae0c10359db5194d7a))
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复通知和触发器无法编辑的bug ([a2e0951](https://github.com/certd/certd/commit/a2e09510426680eb425c0d7ad337f39d3f052054))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持部署到七牛云DCDN ([bde601b](https://github.com/certd/certd/commit/bde601bfffb4f7345d97e1e3b064520816d31555))
|
||||
|
||||
# [1.36.0](https://github.com/certd/certd/compare/v1.35.5...v1.36.0) (2025-07-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.36.1"
|
||||
"version": "1.36.4"
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"deploy1": "node --experimental-json-modules deploy.js ",
|
||||
"check": "node --experimental-json-modules publish-check.js",
|
||||
"init": "lerna run build",
|
||||
"init:dev": "lerna run build",
|
||||
"docs:dev": "vitepress dev docs",
|
||||
"docs:build": "vitepress build docs",
|
||||
"docs:preview": "vitepress preview docs",
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/publishlab/node-acme-client/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.36.3](https://github.com/publishlab/node-acme-client/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.36.2](https://github.com/publishlab/node-acme-client/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.36.1](https://github.com/publishlab/node-acme-client/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"type": "module",
|
||||
"module": "scr/index.js",
|
||||
"main": "src/index.js",
|
||||
@@ -18,7 +18,7 @@
|
||||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.36.1",
|
||||
"@certd/basic": "^1.36.4",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
@@ -69,5 +69,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ export default async (client, userOpts) => {
|
||||
log(`开始第${j}个任务`);
|
||||
results.push(task());
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
log(`wait ${waitTime}s`)
|
||||
log(`wait ${Math.floor(waitTime/1000)}s`)
|
||||
await wait(waitTime);
|
||||
}
|
||||
return Promise.all(results);
|
||||
|
||||
@@ -3,6 +3,20 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书检查支持自定义dns服务器 ([c53bb7c](https://github.com/certd/certd/commit/c53bb7cf677faa32729709ae0c10359db5194d7a))
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
@@ -1 +1 @@
|
||||
22:53
|
||||
23:36
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -45,5 +45,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import { locker } from "./util.lock.js";
|
||||
import { mitter } from "./util.mitter.js";
|
||||
|
||||
import * as request from "./util.request.js";
|
||||
export * from "./util.cache.js";
|
||||
export const utils = {
|
||||
sleep,
|
||||
http,
|
||||
|
||||
@@ -1,8 +1,53 @@
|
||||
// LRUCache
|
||||
|
||||
import { LRUCache } from 'lru-cache';
|
||||
import { LRUCache } from "lru-cache";
|
||||
|
||||
export const cache = new LRUCache<string, any>({
|
||||
max: 1000,
|
||||
ttl: 1000 * 60 * 10,
|
||||
});
|
||||
|
||||
export class LocalCache<V = any> {
|
||||
cache: Map<string, { value: V; expiresAt: number }>;
|
||||
constructor(opts: { clearInterval?: number } = {}) {
|
||||
this.cache = new Map();
|
||||
setInterval(() => {
|
||||
this.clearExpires();
|
||||
}, opts.clearInterval ?? 5 * 60 * 1000);
|
||||
}
|
||||
|
||||
get(key: string): V | undefined {
|
||||
const entry = this.cache.get(key);
|
||||
if (!entry) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
if (Date.now() > entry.expiresAt) {
|
||||
this.cache.delete(key);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return entry.value;
|
||||
}
|
||||
|
||||
set(key: string, value: V, ttl = 300000) {
|
||||
// 默认5分钟 (300000毫秒)
|
||||
this.cache.set(key, {
|
||||
value,
|
||||
expiresAt: Date.now() + ttl,
|
||||
});
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
clearExpires() {
|
||||
for (const [key, entry] of this.cache) {
|
||||
if (entry.expiresAt < Date.now()) {
|
||||
this.cache.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export default function (timeout: number) {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve({});
|
||||
}, timeout);
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -17,8 +17,8 @@
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.36.1",
|
||||
"@certd/plus-core": "^1.36.1",
|
||||
"@certd/basic": "^1.36.4",
|
||||
"@certd/plus-core": "^1.36.4",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
@@ -44,5 +44,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { FormItemProps, HistoryResult, Pipeline } from "../dt/index.js";
|
||||
import { HttpClient, ILogger, utils } from "@certd/basic";
|
||||
import * as _ from "lodash-es";
|
||||
import { IEmailService } from "../service/index.js";
|
||||
import { isPlus } from "@certd/plus-core";
|
||||
|
||||
export type NotificationBody = {
|
||||
userId?: number;
|
||||
@@ -81,9 +80,6 @@ export abstract class BaseNotification implements INotification {
|
||||
logger!: ILogger;
|
||||
|
||||
async doSend(body: NotificationBody) {
|
||||
if (this.define.needPlus && !isPlus()) {
|
||||
body.content = `${body.content}\n\n注意:此通知渠道已调整为专业版功能,后续版本将不再支持发送,请尽快修改或升级为专业版`;
|
||||
}
|
||||
return await this.send(body);
|
||||
}
|
||||
abstract send(body: NotificationBody): Promise<void>;
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -24,5 +24,5 @@
|
||||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -31,5 +31,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/jdcloud",
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"description": "jdcloud openApi sdk",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
@@ -61,5 +61,5 @@
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
"gitHead": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -17,7 +17,7 @@
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.36.1",
|
||||
"@certd/basic": "^1.36.4",
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -32,5 +32,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -27,10 +27,10 @@
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.36.1",
|
||||
"@certd/basic": "^1.36.1",
|
||||
"@certd/pipeline": "^1.36.1",
|
||||
"@certd/plus-core": "^1.36.1",
|
||||
"@certd/acme-client": "^1.36.4",
|
||||
"@certd/basic": "^1.36.4",
|
||||
"@certd/pipeline": "^1.36.4",
|
||||
"@certd/plus-core": "^1.36.4",
|
||||
"@midwayjs/cache": "~3.14.0",
|
||||
"@midwayjs/core": "~3.20.3",
|
||||
"@midwayjs/i18n": "~3.20.3",
|
||||
@@ -61,5 +61,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -46,5 +46,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化证书进度条颜色 ([2af91db](https://github.com/certd/certd/commit/2af91dbf2ae36a4ed17c6788bc2a2a79a3bb29f8))
|
||||
* 支持部署到阿里云vod ([98da4e1](https://github.com/certd/certd/commit/98da4e1791ed8bb21daf2a9914fda875d14633c9))
|
||||
* output-selector from参数支持更丰富的过滤规则 ([87853a2](https://github.com/certd/certd/commit/87853a201535f3bfe8505c40f8f5229d82ffcc73))
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -16,10 +16,10 @@
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.36.1",
|
||||
"@certd/basic": "^1.36.1",
|
||||
"@certd/pipeline": "^1.36.1",
|
||||
"@certd/plugin-lib": "^1.36.1",
|
||||
"@certd/acme-client": "^1.36.4",
|
||||
"@certd/basic": "^1.36.4",
|
||||
"@certd/pipeline": "^1.36.4",
|
||||
"@certd/plugin-lib": "^1.36.4",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jszip": "^3.10.1",
|
||||
@@ -43,5 +43,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
|
||||
|
||||
@TaskOutput({
|
||||
title: "域名证书",
|
||||
type: "cert",
|
||||
})
|
||||
cert?: CertInfo;
|
||||
|
||||
|
||||
@@ -204,4 +204,11 @@ export class CertReader {
|
||||
domain = domain.replaceAll(".", "_").replaceAll("*", "_");
|
||||
return `${domain}_${dayjs().format("YYYYMMDDHHmmssSSS")}`;
|
||||
}
|
||||
|
||||
static appendTimeSuffix(name?: string) {
|
||||
if (name == null) {
|
||||
name = "certd";
|
||||
}
|
||||
return name + "_" + dayjs().format("YYYYMMDDHHmmssSSS");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ export class CertApplyUploadPlugin extends CertApplyBaseConvertPlugin {
|
||||
|
||||
@TaskOutput({
|
||||
title: "证书MD5",
|
||||
type: "certMd5",
|
||||
})
|
||||
certMd5?: string;
|
||||
|
||||
|
||||
@@ -65,12 +65,15 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
{ value: "dns", label: "DNS直接验证" },
|
||||
{ value: "cname", label: "CNAME代理验证" },
|
||||
{ value: "http", label: "HTTP文件验证" },
|
||||
{ value: "dnses", label: "多DNS提供商" },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
helper: `1. <b>DNS直接验证</b>:域名dns解析是在阿里云/腾讯云/华为云/CF/NameSilo/西数/火山/dns.la/京东云/51dns的,选它
|
||||
2. <b>CNAME代理验证</b>:支持任何注册商的域名,第一次需要手动添加CNAME记录(建议将DNS服务器修改为阿里云/腾讯云的,然后使用DNS直接验证)
|
||||
3. <b>HTTP文件验证</b>:不支持泛域名,需要配置网站文件上传`,
|
||||
3. <b>HTTP文件验证</b>:不支持泛域名,需要配置网站文件上传
|
||||
4. <b>多DNS提供商</b>:每个域名可以选择独立的DNS提供商
|
||||
`,
|
||||
})
|
||||
challengeType!: string;
|
||||
|
||||
@@ -159,13 +162,15 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
})
|
||||
},
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.challengeType === 'cname' || form.challengeType === 'http'
|
||||
return form.challengeType === 'cname' || form.challengeType === 'http' || form.challengeType === 'dnses'
|
||||
}),
|
||||
helper: ctx.compute(({form})=>{
|
||||
if(form.challengeType === 'cname' ){
|
||||
return '请按照上面的提示,给要申请证书的域名添加CNAME记录,添加后,点击验证,验证成功后不要删除记录,申请和续期证书会一直用它'
|
||||
}else if (form.challengeType === 'http'){
|
||||
return '请按照上面的提示,给每个域名设置文件上传配置,证书申请过程中会上传校验文件到网站根目录下'
|
||||
}else if (form.challengeType === 'http'){
|
||||
return '给每个域名单独配置dns提供商'
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -321,7 +326,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
name: "a-input-number",
|
||||
vModel: "value",
|
||||
},
|
||||
helper: "等待解析生效时长(秒)",
|
||||
helper: "等待解析生效时长(秒),如果使用CNAME方式校验,本地验证失败,可以尝试延长此时间(比如5-10分钟)",
|
||||
})
|
||||
waitDnsDiffuseTime = 30;
|
||||
|
||||
@@ -402,7 +407,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
|
||||
let dnsProvider: IDnsProvider = null;
|
||||
let domainsVerifyPlan: DomainsVerifyPlan = null;
|
||||
if (this.challengeType === "cname" || this.challengeType === "http") {
|
||||
if (this.challengeType === "cname" || this.challengeType === "http" || this.challengeType === "dnses") {
|
||||
domainsVerifyPlan = await this.createDomainsVerifyPlan();
|
||||
} else {
|
||||
const dnsProviderType = this.dnsProviderType;
|
||||
|
||||
@@ -3,4 +3,4 @@ export { EVENT_CERT_APPLY_SUCCESS } from "./cert-plugin/base-convert.js";
|
||||
export * from "./cert-plugin/index.js";
|
||||
export * from "./cert-plugin/lego/index.js";
|
||||
export * from "./cert-plugin/custom/index.js";
|
||||
export const CertApplyPluginNames = ["CertApply", "CertApplyLego", "CertApplyUpload"];
|
||||
export const CertApplyPluginNames = [":cert:"];
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 执行windows nginx命令时,改为return code判断是否执行成功 ([b37cffd](https://github.com/certd/certd/commit/b37cffd704cd08b8bdd68a6e284706eabe59e78d))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持部署到阿里云vod ([98da4e1](https://github.com/certd/certd/commit/98da4e1791ed8bb21daf2a9914fda875d14633c9))
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-lib",
|
||||
"private": false,
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"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.1",
|
||||
"@certd/pipeline": "^1.36.1",
|
||||
"@certd/basic": "^1.36.4",
|
||||
"@certd/pipeline": "^1.36.4",
|
||||
"@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": "5c251ee77460440a204b1514ab30c512ce6be2c1"
|
||||
"gitHead": "1bde777beead9dd23b8d3d98479d616170b8bb69"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
||||
import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline";
|
||||
import { ILogger } from "@certd/basic";
|
||||
|
||||
export type AliyunClientV2Req = {
|
||||
action: string;
|
||||
version: string;
|
||||
|
||||
@@ -33,8 +33,10 @@ export type CasCertInfo = { certId: number; certName: string; certIdentifier: st
|
||||
|
||||
export class AliyunSslClient {
|
||||
opts: AliyunSslClientOpts;
|
||||
logger: ILogger;
|
||||
constructor(opts: AliyunSslClientOpts) {
|
||||
this.opts = opts;
|
||||
this.logger = opts.logger;
|
||||
}
|
||||
|
||||
checkRet(ret: any) {
|
||||
|
||||
@@ -204,9 +204,18 @@ export class AsyncSsh2Client {
|
||||
stream
|
||||
.on("close", (code: any, signal: any) => {
|
||||
this.logger.info(`[${this.connConf.host}][close]:code:${code}`);
|
||||
if (opts.throwOnStdErr == null && this.windows) {
|
||||
opts.throwOnStdErr = true;
|
||||
}
|
||||
/**
|
||||
* ]pipeline 执行命令:[10.123.0.2][exec]:cd /d D:\nginx-1.27.5 && D:\nginx-1.27.5\nginx.exe -t && D:\nginx-1.27.5\nginx.exe -s reload
|
||||
* [2025-07-09T10:24:11.219] [ERROR]pipeline - [10. 123.0. 2][error]: nginx: the configuration file D: \nginx-1.27. 5/conf/nginx. conf syntax is ok
|
||||
* [2025-07-09T10:24:11.231] [ERROR][10. 123. 0. 2] [error]: nginx: configuration file D: \nginx-1.27.5/conf/nginx.conf test is successful
|
||||
* pipeline-
|
||||
* [2025-07-09T10:24:11.473] [INFO]pipeline -[10.123.0.2][close]:code:0
|
||||
* [2025-07-09T10:24:11.473][ERRoR] pipeline- [step][主机一执行远程主机脚本命令]<id:53hyarN3yvmbijNuMiNAt>: [Eror: nginx: the configuration fileD:\nginx-1.27.5/conf/nginx.conf syntax is ok
|
||||
//需要忽略windows的错误
|
||||
*/
|
||||
// if (opts.throwOnStdErr == null && this.windows) {
|
||||
// opts.throwOnStdErr = true;
|
||||
// }
|
||||
if (opts.throwOnStdErr && hasErrorLog) {
|
||||
reject(new Error(data));
|
||||
}
|
||||
@@ -482,9 +491,9 @@ export class SshClient {
|
||||
* Set-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\cmd.exe"
|
||||
* @param options
|
||||
*/
|
||||
async exec(options: { connectConf: SshAccess; script: string | Array<string>; env?: any }): Promise<string> {
|
||||
async exec(options: { connectConf: SshAccess; script: string | Array<string>; env?: any; throwOnStdErr?: boolean }): Promise<string> {
|
||||
let { script } = options;
|
||||
const { connectConf } = options;
|
||||
const { connectConf, throwOnStdErr } = options;
|
||||
|
||||
// this.logger.info('命令:', script);
|
||||
return await this._call({
|
||||
@@ -529,7 +538,7 @@ export class SshClient {
|
||||
script = envScripts.join(newLine) + newLine + script;
|
||||
}
|
||||
}
|
||||
return await conn.exec(script as string, {});
|
||||
return await conn.exec(script as string, { throwOnStdErr });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复查看证书对话框翻译错误的bug ([8626b6d](https://github.com/certd/certd/commit/8626b6d9f235c511766f2ae98e0a37f6cebb621c))
|
||||
* 修复translation后分组编辑打不开的bug ([46a1b74](https://github.com/certd/certd/commit/46a1b7479923d2feb2dece202a5932b99981b2cd))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化证书进度条颜色 ([2af91db](https://github.com/certd/certd/commit/2af91dbf2ae36a4ed17c6788bc2a2a79a3bb29f8))
|
||||
* output-selector from参数支持更丰富的过滤规则 ([87853a2](https://github.com/certd/certd/commit/87853a201535f3bfe8505c40f8f5229d82ffcc73))
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复开放接口添加按钮文本显示问题 ([f93ba99](https://github.com/certd/certd/commit/f93ba9970c12680f38eba2a7abd4b72cf3f5b6a6))
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复notification编辑按钮无法打开对话框的bug ([0cea26c](https://github.com/certd/certd/commit/0cea26c6287f52adf273b4a525c37bea8555c68c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书检查支持自定义dns服务器 ([c53bb7c](https://github.com/certd/certd/commit/c53bb7cf677faa32729709ae0c10359db5194d7a))
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -103,8 +103,8 @@
|
||||
"zod-defaults": "^0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.36.1",
|
||||
"@certd/pipeline": "^1.36.1",
|
||||
"@certd/lib-iframe": "^1.36.4",
|
||||
"@certd/pipeline": "^1.36.4",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
|
||||
@@ -167,10 +167,14 @@ async function onDomainsChanged(domains: string[]) {
|
||||
let planItem = planRef.value[domain];
|
||||
const domainGroupItem = domainGroups[domain];
|
||||
if (!planItem) {
|
||||
let type = props.defaultType || "cname";
|
||||
if (type === "dnses") {
|
||||
type = "dns";
|
||||
}
|
||||
planItem = {
|
||||
domain,
|
||||
//@ts-ignore
|
||||
type: props.defaultType || "cname",
|
||||
type: type,
|
||||
//@ts-ignore
|
||||
cnameVerifyPlan: {},
|
||||
//@ts-ignore
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { inject, ref, watch } from "vue";
|
||||
import { CertApplyPluginNames } from "/@/constants";
|
||||
|
||||
defineOptions({
|
||||
name: "CertDomainsGetter",
|
||||
@@ -54,8 +53,9 @@ function getDomainFromPipeline(inputKey: string) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CertApplyPluginNames.includes(certStep.type)) {
|
||||
targetStepId = getStepIdFromInputKey(certStep.input?.cert);
|
||||
const firstLevelValue = certStep.input.cert;
|
||||
if (firstLevelValue && typeof firstLevelValue === "string" && firstLevelValue.indexOf(".") > 0) {
|
||||
targetStepId = getStepIdFromInputKey(firstLevelValue);
|
||||
certStep = findStepFromPipeline(targetStepId);
|
||||
if (!certStep) {
|
||||
errorRef.value = "找不到目标步骤,请先选择域名证书";
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { inject, onMounted, Ref, ref, watch } from "vue";
|
||||
import { usePluginStore } from "/@/store/plugin";
|
||||
|
||||
export default {
|
||||
name: "OutputSelector",
|
||||
@@ -27,10 +28,11 @@ export default {
|
||||
const currentStepIndex = inject("currentStepIndex") as Ref<number>;
|
||||
const currentTask = inject("currentTask") as Ref<any>;
|
||||
|
||||
const getPluginGroups = inject("getPluginGroups") as any;
|
||||
const pluginGroups = getPluginGroups();
|
||||
function onCreate() {
|
||||
options.value = pluginGroups.getPreStepOutputOptions({
|
||||
const pluginStore = usePluginStore();
|
||||
|
||||
async function onCreate() {
|
||||
await pluginStore.init();
|
||||
options.value = pluginStore.group.getPreStepOutputOptions({
|
||||
pipeline: pipeline.value,
|
||||
currentStageIndex: currentStageIndex.value,
|
||||
currentTaskIndex: currentTaskIndex.value,
|
||||
@@ -38,11 +40,38 @@ export default {
|
||||
currentTask: currentTask.value,
|
||||
});
|
||||
if (props.from) {
|
||||
let froms = [];
|
||||
if (typeof props.from === "string") {
|
||||
options.value = options.value.filter((item: any) => item.type === props.from);
|
||||
froms = [props.from];
|
||||
} else {
|
||||
options.value = options.value.filter((item: any) => props.from.includes(item.type));
|
||||
froms = props.from;
|
||||
}
|
||||
function match(from: string, item: any) {
|
||||
// pluginType:valueType:keyName
|
||||
if (from.includes(":")) {
|
||||
const [pluginType, valueType, keyName] = from.split(":");
|
||||
if (pluginType && item.type !== pluginType) {
|
||||
return false;
|
||||
}
|
||||
if (valueType && item.valueType !== valueType) {
|
||||
return false;
|
||||
}
|
||||
if (keyName && item.key !== keyName) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return item.type === from;
|
||||
}
|
||||
}
|
||||
options.value = options.value.filter((item: any) => {
|
||||
for (const from of froms) {
|
||||
if (match(from, item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (props.modelValue != null) {
|
||||
@@ -55,19 +84,10 @@ export default {
|
||||
ctx.emit("update:modelValue", value);
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
onCreate();
|
||||
onMounted(async () => {
|
||||
await onCreate();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => {
|
||||
return pluginGroups.value?.map;
|
||||
},
|
||||
() => {
|
||||
onCreate();
|
||||
}
|
||||
);
|
||||
|
||||
function onChanged(value: any) {
|
||||
ctx.emit("update:modelValue", value);
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const CertApplyPluginNames = ["CertApply", "CertApplyLego", "CertApplyUpload"];
|
||||
export const CertApplyPluginNames = [":cert:"];
|
||||
|
||||
@@ -273,8 +273,7 @@ export default {
|
||||
monitorCronSetting: "Monitoring Schedule",
|
||||
cronTrigger: "Scheduled trigger for monitoring",
|
||||
dnsServer: "DNS Server",
|
||||
// dnsServerHelper: "使用自定义的域名解析服务器,如:1.1.1.1,8.8.8.8",
|
||||
dnsServerHelper: "Use a custom domain name resolution server, such as: 1.1.1.1,8.8.8.8",
|
||||
dnsServerHelper: "Use a custom domain name resolution server, such as: 1.1.1.1 , support multiple",
|
||||
},
|
||||
},
|
||||
checkStatus: {
|
||||
@@ -472,7 +471,7 @@ export default {
|
||||
statusError: "Error",
|
||||
actionImportBatch: "Batch Import",
|
||||
actionSyncIp: "Sync IP",
|
||||
modalTitleSyncIp: "Sync IP",
|
||||
TitleSyncIp: "Sync IP",
|
||||
modalContentSyncIp: "Are you sure to sync IP?",
|
||||
notificationSyncComplete: "Sync Complete",
|
||||
actionCheckAll: "Check All",
|
||||
@@ -709,4 +708,8 @@ export default {
|
||||
showRunStrategyHelper: "Allow modify the run strategy of the task",
|
||||
},
|
||||
},
|
||||
modal: {
|
||||
close: "Close",
|
||||
viewCertificateTitle: "View Certificate",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -278,7 +278,7 @@ export default {
|
||||
monitorCronSetting: "监控定时设置",
|
||||
cronTrigger: "定时触发监控",
|
||||
dnsServer: "DNS服务器",
|
||||
dnsServerHelper: "使用自定义的域名解析服务器,如:1.1.1.1,8.8.8.8",
|
||||
dnsServerHelper: "使用自定义的域名解析服务器,如:1.1.1.1 , 支持多个",
|
||||
},
|
||||
},
|
||||
checkStatus: {
|
||||
@@ -711,4 +711,8 @@ export default {
|
||||
showRunStrategyHelper: "任务设置中是否允许选择运行策略",
|
||||
},
|
||||
},
|
||||
modal: {
|
||||
close: "关闭",
|
||||
viewCertificateTitle: "查看证书",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -87,10 +87,13 @@ export class PluginGroups {
|
||||
for (const step of steps) {
|
||||
const stepDefine = this.get(step.type);
|
||||
for (const key in stepDefine?.output) {
|
||||
const inputDefine = stepDefine.output[key];
|
||||
options.push({
|
||||
value: `step.${step.id}.${key}`,
|
||||
label: `${stepDefine.output[key].title}【from:${step.title}】`,
|
||||
label: `${inputDefine.title}【from:${step.title}】`,
|
||||
type: step.type,
|
||||
valueType: inputDefine.type,
|
||||
key: key,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,3 +67,8 @@ footer {
|
||||
margin-inline-end: calc(-3em - 8px);
|
||||
padding-inline-end: calc(3em + 8px);
|
||||
}
|
||||
|
||||
|
||||
.ant-progress .ant-progress-text{
|
||||
width:3em;
|
||||
}
|
||||
@@ -228,7 +228,11 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
const leftDays = dayjs(value).diff(dayjs(), "day");
|
||||
const color = leftDays < 20 ? "red" : "#389e0d";
|
||||
const percent = (leftDays / 90) * 100;
|
||||
return <a-progress title={expireDate + t("certd.expires")} percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}${t("certd.days")}`} />;
|
||||
const textColor = leftDays < 20 ? "red" : leftDays > 60 ? "#389e0d" : "";
|
||||
const format = () => {
|
||||
return <span style={{ color: textColor }}>{`${leftDays}${t("certd.days")}`}</span>;
|
||||
};
|
||||
return <a-progress title={expireDate + t("certd.expires")} percent={percent} strokeColor={color} format={format} />;
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -47,6 +47,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
const { openSiteIpMonitorDialog } = useSiteIpMonitor();
|
||||
const { openSiteImportDialog } = useSiteImport();
|
||||
return {
|
||||
id: "siteMonitorCrud",
|
||||
crudOptions: {
|
||||
request: {
|
||||
pageRequest,
|
||||
@@ -117,7 +118,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
},
|
||||
rowHandle: {
|
||||
fixed: "right",
|
||||
width: 240,
|
||||
width: 280,
|
||||
buttons: {
|
||||
check: {
|
||||
order: 0,
|
||||
|
||||
@@ -45,6 +45,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
const { openSiteIpImportDialog } = useSiteIpMonitor();
|
||||
return {
|
||||
crudOptions: {
|
||||
id: "siteIpCrud",
|
||||
request: {
|
||||
pageRequest,
|
||||
addRequest,
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
</div>
|
||||
<div class="helper">{{ t("certd.monitor.setting.monitorRetryTimes") }}</div>
|
||||
</a-form-item>
|
||||
<!-- <a-form-item :label="t('certd.monitor.setting.dnsServer')" :name="['dnsServer']">
|
||||
<a-form-item :label="t('certd.monitor.setting.dnsServer')" :name="['dnsServer']">
|
||||
<div class="flex">
|
||||
<a-select v-model:value="formState.dnsServer" mode="tags" :open="false" />
|
||||
</div>
|
||||
<div class="helper">{{ t("certd.monitor.setting.dnsServerHelper") }}</div>
|
||||
</a-form-item> -->
|
||||
</a-form-item>
|
||||
<a-form-item :label="t('certd.monitor.setting.monitorCronSetting')" :name="['cron']">
|
||||
<div class="flex flex-baseline">
|
||||
<cron-editor v-model="formState.cron" :disabled="!settingsStore.isPlus" :allow-every-min="userStore.isAdmin" />
|
||||
|
||||
@@ -3,9 +3,8 @@ import { computed, provide, ref, toRef } from "vue";
|
||||
import { useReference } from "/@/use/use-refrence";
|
||||
import { forEach, get, merge, set } from "lodash-es";
|
||||
import { Modal } from "ant-design-vue";
|
||||
import * as api from "/@/views/sys/cname/provider/api";
|
||||
import { mitter } from "/@/utils/util.mitt";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useI18n } from "/src/locales";
|
||||
|
||||
export function notificationProvide(api: any) {
|
||||
provide("notificationApi", api);
|
||||
|
||||
@@ -53,13 +53,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
width: 600,
|
||||
},
|
||||
},
|
||||
actionbar: {
|
||||
buttons: {
|
||||
add: {
|
||||
text: t("certd.actionbar.add"),
|
||||
},
|
||||
},
|
||||
},
|
||||
actionbar: {},
|
||||
rowHandle: {
|
||||
width: 300,
|
||||
fixed: "right",
|
||||
|
||||
@@ -363,13 +363,19 @@ export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys
|
||||
},
|
||||
column: {
|
||||
cellRender({ row }) {
|
||||
if (!row.lastVars?.certExpiresTime) {
|
||||
const value = row.lastVars?.certExpiresTime;
|
||||
if (!value) {
|
||||
return "-";
|
||||
}
|
||||
const leftDays = dayjs(row.lastVars.certExpiresTime).diff(dayjs(), "day");
|
||||
const expireDate = dayjs(value).format("YYYY-MM-DD");
|
||||
const leftDays = dayjs(value).diff(dayjs(), "day");
|
||||
const color = leftDays < 20 ? "red" : "#389e0d";
|
||||
const percent = (leftDays / 90) * 100;
|
||||
return <a-progress percent={percent} strokeColor={color} format={percent => `${leftDays} 天`} />;
|
||||
const textColor = leftDays < 20 ? "red" : leftDays > 60 ? "#389e0d" : "";
|
||||
const format = () => {
|
||||
return <span style={{ color: textColor }}>{`${leftDays}${t("certd.days")}`}</span>;
|
||||
};
|
||||
return <a-progress title={expireDate + t("certd.expires")} percent={percent} strokeColor={color} format={format} />;
|
||||
},
|
||||
width: 150,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// @ts-ignore
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "/src/locales";
|
||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
import { pipelineGroupApi } from "./api";
|
||||
|
||||
|
||||
@@ -299,7 +299,7 @@ import { useSettingStore } from "/@/store/settings";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
import TaskShortcuts from "./component/shortcut/task-shortcuts.vue";
|
||||
import { eachSteps, findStep } from "../utils";
|
||||
import { PluginGroups } from "/@/store/plugin";
|
||||
import { PluginGroups, usePluginStore } from "/@/store/plugin";
|
||||
import { getCronNextTimes } from "/@/components/cron-editor/utils";
|
||||
import { useCertViewer } from "/@/views/certd/pipeline/use";
|
||||
|
||||
@@ -494,16 +494,15 @@ export default defineComponent({
|
||||
}
|
||||
);
|
||||
|
||||
const pluginGroupsRef: Ref<PluginGroups> = ref();
|
||||
|
||||
const pluginStore = usePluginStore();
|
||||
const fetchPlugins = async () => {
|
||||
pluginGroupsRef.value = await props.options.getPluginGroups();
|
||||
await pluginStore.init();
|
||||
};
|
||||
fetchPlugins();
|
||||
|
||||
provide("pipeline", pipeline);
|
||||
provide("getPluginGroups", () => {
|
||||
return pluginGroupsRef.value;
|
||||
return pluginStore.group;
|
||||
});
|
||||
provide("currentHistory", currentHistory);
|
||||
|
||||
|
||||
@@ -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.4](https://github.com/certd/certd/compare/v1.36.3...v1.36.4) (2025-07-10)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 站点证书即将过期通知标题颜色优化为红色 ([80c5331](https://github.com/certd/certd/commit/80c5331a5d4c320323d9b9b800e4ea3b72577b33))
|
||||
* 支持部署到阿里云vod ([98da4e1](https://github.com/certd/certd/commit/98da4e1791ed8bb21daf2a9914fda875d14633c9))
|
||||
* 支持部署证书到网宿CDN ([c3da026](https://github.com/certd/certd/commit/c3da026b33106f5195959825a68cadbe49efef00))
|
||||
* 重置管理员密码同时可以清除管理员的2FA设置 ([1ece091](https://github.com/certd/certd/commit/1ece0915f172d5f8b8adb866434e7efcc5c8c46d))
|
||||
* output-selector from参数支持更丰富的过滤规则 ([87853a2](https://github.com/certd/certd/commit/87853a201535f3bfe8505c40f8f5229d82ffcc73))
|
||||
|
||||
## [1.36.3](https://github.com/certd/certd/compare/v1.36.2...v1.36.3) (2025-07-07)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化部署到腾讯TKE插件,支持Opaque类型选择,优化填写说明 ([1445325](https://github.com/certd/certd/commit/144532530a865b634e68539e4888e26f52f73492))
|
||||
|
||||
## [1.36.2](https://github.com/certd/certd/compare/v1.36.1...v1.36.2) (2025-07-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 优化更新飞牛os证书有效期,修复某些情况下部署证书后飞牛无法访问https的bug ([610c919](https://github.com/certd/certd/commit/610c919c72037becc0ed326f5d5b18c963dfcb3a))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书检查支持自定义dns服务器 ([c53bb7c](https://github.com/certd/certd/commit/c53bb7cf677faa32729709ae0c10359db5194d7a))
|
||||
|
||||
## [1.36.1](https://github.com/certd/certd/compare/v1.36.0...v1.36.1) (2025-07-02)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-server",
|
||||
"version": "1.36.1",
|
||||
"version": "1.36.4",
|
||||
"description": "fast-server base midway",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -42,20 +42,20 @@
|
||||
"@aws-sdk/client-cloudfront": "^3.699.0",
|
||||
"@aws-sdk/client-iam": "^3.699.0",
|
||||
"@aws-sdk/client-s3": "^3.705.0",
|
||||
"@certd/acme-client": "^1.36.1",
|
||||
"@certd/basic": "^1.36.1",
|
||||
"@certd/commercial-core": "^1.36.1",
|
||||
"@certd/acme-client": "^1.36.4",
|
||||
"@certd/basic": "^1.36.4",
|
||||
"@certd/commercial-core": "^1.36.4",
|
||||
"@certd/cv4pve-api-javascript": "^8.4.1",
|
||||
"@certd/jdcloud": "^1.36.1",
|
||||
"@certd/lib-huawei": "^1.36.1",
|
||||
"@certd/lib-k8s": "^1.36.1",
|
||||
"@certd/lib-server": "^1.36.1",
|
||||
"@certd/midway-flyway-js": "^1.36.1",
|
||||
"@certd/pipeline": "^1.36.1",
|
||||
"@certd/plugin-cert": "^1.36.1",
|
||||
"@certd/plugin-lib": "^1.36.1",
|
||||
"@certd/plugin-plus": "^1.36.1",
|
||||
"@certd/plus-core": "^1.36.1",
|
||||
"@certd/jdcloud": "^1.36.4",
|
||||
"@certd/lib-huawei": "^1.36.4",
|
||||
"@certd/lib-k8s": "^1.36.4",
|
||||
"@certd/lib-server": "^1.36.4",
|
||||
"@certd/midway-flyway-js": "^1.36.4",
|
||||
"@certd/pipeline": "^1.36.4",
|
||||
"@certd/plugin-cert": "^1.36.4",
|
||||
"@certd/plugin-lib": "^1.36.4",
|
||||
"@certd/plugin-plus": "^1.36.4",
|
||||
"@certd/plus-core": "^1.36.4",
|
||||
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120",
|
||||
"@huaweicloud/huaweicloud-sdk-core": "^3.1.120",
|
||||
"@koa/cors": "^5.0.0",
|
||||
@@ -82,7 +82,6 @@
|
||||
"cross-env": "^7.0.3",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"dns2": "^2.1.0",
|
||||
"form-data": "^4.0.0",
|
||||
"glob": "^11.0.0",
|
||||
"https-proxy-agent": "^7.0.5",
|
||||
|
||||
@@ -26,11 +26,11 @@ process.on('uncaughtException', error => {
|
||||
});
|
||||
|
||||
@Configuration({
|
||||
// detectorOptions: {
|
||||
// ignore: [
|
||||
// '**/plugins/**'
|
||||
// ]
|
||||
// },
|
||||
detectorOptions: {
|
||||
ignore: [
|
||||
'**/plugins/**'
|
||||
]
|
||||
},
|
||||
imports: [
|
||||
koa,
|
||||
orm,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa';
|
||||
import { CommonException } from '@certd/lib-server';
|
||||
import { UserService } from '../../modules/sys/authority/service/user-service.js';
|
||||
import { logger } from '@certd/basic';
|
||||
import {UserSettingsService} from "../../modules/mine/service/user-settings-service.js";
|
||||
|
||||
/**
|
||||
* 重置密码模式
|
||||
@@ -13,6 +14,10 @@ import { logger } from '@certd/basic';
|
||||
export class ResetPasswdMiddleware implements IWebMiddleware {
|
||||
@Inject()
|
||||
userService: UserService;
|
||||
|
||||
@Inject()
|
||||
userSettingsService: UserSettingsService;
|
||||
|
||||
@Config('system.resetAdminPasswd')
|
||||
private resetAdminPasswd: boolean;
|
||||
resolve() {
|
||||
@@ -31,8 +36,12 @@ export class ResetPasswdMiddleware implements IWebMiddleware {
|
||||
const newPasswd = '123456';
|
||||
await this.userService.resetPassword(1, newPasswd);
|
||||
await this.userService.updateStatus(1, 1);
|
||||
await this.userSettingsService.deleteWhere({
|
||||
userId: 1,
|
||||
key:"user.two.factor"
|
||||
})
|
||||
const user = await this.userService.info(1);
|
||||
logger.info(`重置1号管理员用户的密码完成,用户名:${user.username},新密码:${newPasswd}`);
|
||||
logger.info(`重置1号管理员用户的密码完成,2FA设置已删除,用户名:${user.username},新密码:${newPasswd},请在登录进去之后尽快修改密码`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
}
|
||||
param.hostRecord = hostRecord;
|
||||
|
||||
const cnameKey = utils.id.simpleNanoId();
|
||||
const cnameKey = utils.id.simpleNanoId().toLowerCase();
|
||||
const safeDomain = param.domain.replaceAll('.', '-');
|
||||
param.recordValue = `${safeDomain}.${cnameKey}.${cnameProvider.domain}`;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ export class UserSiteMonitorSetting extends BaseSettings {
|
||||
notificationId?:number= 0;
|
||||
cron?:string = undefined;
|
||||
retryTimes?:number = 3;
|
||||
dnsServer?:string[] = undefined;
|
||||
}
|
||||
|
||||
export class UserEmailSetting extends BaseSettings {
|
||||
|
||||
@@ -3,8 +3,13 @@ import { InjectEntityModel } from "@midwayjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { BaseService, BaseSettings } from "@certd/lib-server";
|
||||
import { UserSettingsEntity } from "../entity/user-settings.js";
|
||||
import { mergeUtils } from "@certd/basic";
|
||||
import { LocalCache, mergeUtils } from "@certd/basic";
|
||||
const {merge} = mergeUtils
|
||||
|
||||
const UserSettingCache = new LocalCache({
|
||||
clearInterval: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
/**
|
||||
* 授权
|
||||
*/
|
||||
@@ -75,14 +80,26 @@ export class UserSettingsService extends BaseService<UserSettingsEntity> {
|
||||
}
|
||||
|
||||
|
||||
async getSetting<T>( userId: number,type: any): Promise<T> {
|
||||
async getSetting<T>( userId: number,type: any, cache:boolean = false): Promise<T> {
|
||||
if(!userId){
|
||||
throw new Error('userId is required');
|
||||
}
|
||||
const key = type.__key__;
|
||||
const cacheKey = key + '_' + userId;
|
||||
if (cache) {
|
||||
const settings: T = UserSettingCache.get(cacheKey);
|
||||
if (settings) {
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
||||
let newSetting: T = new type();
|
||||
const savedSettings = await this.getSettingByKey(key, userId);
|
||||
newSetting = merge(newSetting, savedSettings);
|
||||
|
||||
if (cache) {
|
||||
UserSettingCache.set(cacheKey, newSetting);
|
||||
}
|
||||
return newSetting;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||
import { BaseService, CodeException, Constants, PageReq } from "@certd/lib-server";
|
||||
import { InjectEntityModel } from "@midwayjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { CertInfoEntity } from "../entity/cert-info.js";
|
||||
import { utils } from "@certd/basic";
|
||||
import { CertInfo, CertReader } from "@certd/plugin-cert";
|
||||
import {Provide, Scope, ScopeEnum} from "@midwayjs/core";
|
||||
import {BaseService, CodeException, Constants, PageReq} from "@certd/lib-server";
|
||||
import {InjectEntityModel} from "@midwayjs/typeorm";
|
||||
import {MoreThan, Repository} from "typeorm";
|
||||
import {CertInfoEntity} from "../entity/cert-info.js";
|
||||
import {utils} from "@certd/basic";
|
||||
import {CertInfo, CertReader} from "@certd/plugin-cert";
|
||||
|
||||
export type UploadCertReq = {
|
||||
id?: number;
|
||||
@@ -107,6 +107,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||
},
|
||||
where: {
|
||||
userId,
|
||||
expiresTime: MoreThan(new Date().getTime())
|
||||
},
|
||||
});
|
||||
//遍历查找
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { LocalCache } from '@certd/basic';
|
||||
import dnsSdk from 'dns'
|
||||
const dns = dnsSdk.promises
|
||||
|
||||
export class DnsCustom{
|
||||
resolver: any;
|
||||
|
||||
constructor(dnsServers:string[]) {
|
||||
const resolver = new dns.Resolver();
|
||||
resolver.setServers(dnsServers);
|
||||
this.resolver = resolver;
|
||||
}
|
||||
async resolve(hostname:string,options:any):Promise<string[]>{
|
||||
// { family: undefined, hints: 0, all: true }
|
||||
|
||||
const cnames = await this.resolver.resolveCname(hostname)
|
||||
let cnameIps = []
|
||||
// deep
|
||||
if (cnames && cnames.length > 0) {
|
||||
for (let cname of cnames) {
|
||||
const cnameIp = await this.resolve(cname,options)
|
||||
if (cnameIp && cnameIp.length > 0) {
|
||||
cnameIps.push(...cnameIp)
|
||||
}
|
||||
}
|
||||
}
|
||||
let v4 = []
|
||||
let v6 = []
|
||||
|
||||
const {family, all} = options
|
||||
if(family === 6 && !all){
|
||||
v6= await this.resolver.resolve6(hostname)
|
||||
}
|
||||
if(family === 4 && !all){
|
||||
v4 = await this.resolver.resolve4(hostname)
|
||||
}
|
||||
|
||||
if(all){
|
||||
v4 = await this.resolver.resolve4(hostname)
|
||||
v6 = await this.resolver.resolve6(hostname)
|
||||
}
|
||||
|
||||
return [...v4,...v6,...cnameIps]
|
||||
}
|
||||
|
||||
async resolve4(hostname:string,options:any):Promise<string[]>{
|
||||
return await this.resolver.resolve4(hostname,options)
|
||||
}
|
||||
async resolve6(hostname:string,options:any):Promise<string[]>{
|
||||
return await this.resolver.resolve6(hostname,options)
|
||||
}
|
||||
async resolveAny(hostname:string,options:any):Promise<string[]>{
|
||||
return await this.resolver.resolveAny(hostname,options)
|
||||
}
|
||||
|
||||
async resolveCname(hostname:string,options:any):Promise<string[]>{
|
||||
return await this.resolver.resolveCname(hostname,options)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export class DnsContainer{
|
||||
bucket: LocalCache<DnsCustom> = new LocalCache()
|
||||
|
||||
constructor() {}
|
||||
getDns(server:string[]){
|
||||
const key = server.join(',')
|
||||
let dns = this.bucket.get(key)
|
||||
if (dns){
|
||||
return dns
|
||||
}
|
||||
dns = new DnsCustom(server)
|
||||
this.bucket.set(key,dns)
|
||||
return dns
|
||||
}
|
||||
}
|
||||
|
||||
export const dnsContainer = new DnsContainer()
|
||||
@@ -15,6 +15,7 @@ import {UserSiteMonitorSetting} from "../../mine/service/models.js";
|
||||
import {SiteIpService} from "./site-ip-service.js";
|
||||
import {SiteIpEntity} from "../entity/site-ip.js";
|
||||
import {Cron} from "../../cron/cron.js";
|
||||
import { dnsContainer } from "./dns-custom.js";
|
||||
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Request, {allowDowngrade: true})
|
||||
@@ -108,6 +109,14 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
if (!site?.domain) {
|
||||
throw new Error("站点域名不能为空");
|
||||
}
|
||||
|
||||
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(site.userId, UserSiteMonitorSetting);
|
||||
const dnsServer = setting.dnsServer
|
||||
let resolver = null
|
||||
if (dnsServer && dnsServer.length > 0) {
|
||||
resolver = dnsContainer.getDns(dnsServer) as any
|
||||
}
|
||||
|
||||
try {
|
||||
await this.update({
|
||||
id: site.id,
|
||||
@@ -117,7 +126,8 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
const res = await siteTester.test({
|
||||
host: site.domain,
|
||||
port: site.httpsPort,
|
||||
retryTimes
|
||||
retryTimes,
|
||||
resolver
|
||||
});
|
||||
|
||||
const certi: PeerCertificate = res.certificate;
|
||||
@@ -281,7 +291,8 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
body: {
|
||||
title: `站点证书即将过期,剩余${validDays}天,<${site.name}>`,
|
||||
content,
|
||||
url
|
||||
url,
|
||||
errorMessage: "站点证书即将过期"
|
||||
}
|
||||
},
|
||||
site.userId
|
||||
|
||||
@@ -7,11 +7,15 @@ import {NotificationService} from "../../pipeline/service/notification-service.j
|
||||
import {UserSuiteService} from "@certd/commercial-core";
|
||||
import {UserSettingsService} from "../../mine/service/user-settings-service.js";
|
||||
import {SiteIpEntity} from "../entity/site-ip.js";
|
||||
import dns from "dns";
|
||||
import {logger, safePromise} from "@certd/basic";
|
||||
import dnsSdk from "dns";
|
||||
import {logger} from "@certd/basic";
|
||||
import dayjs from "dayjs";
|
||||
import {siteTester} from "./site-tester.js";
|
||||
import {PeerCertificate} from "tls";
|
||||
import { UserSiteMonitorSetting } from "../../mine/service/models.js";
|
||||
import { dnsContainer } from "./dns-custom.js";
|
||||
|
||||
const dns = dnsSdk.promises;
|
||||
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||
@@ -62,11 +66,20 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
async sync(entity: SiteInfoEntity,check:boolean = true) {
|
||||
|
||||
const domain = entity.domain;
|
||||
|
||||
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(entity.userId, UserSiteMonitorSetting);
|
||||
|
||||
const dnsServer = setting.dnsServer
|
||||
let resolver = dns
|
||||
if (dnsServer && dnsServer.length > 0) {
|
||||
resolver = dnsContainer.getDns(dnsServer) as any
|
||||
}
|
||||
|
||||
//从域名解析中获取所有ip
|
||||
const ips = await this.getAllIpsFromDomain(domain);
|
||||
const ips = await this.getAllIpsFromDomain(domain,resolver);
|
||||
if (ips.length === 0 ) {
|
||||
logger.warn(`没有发现${domain}的IP`)
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
const oldIps = await this.repository.find({
|
||||
@@ -86,7 +99,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
hasChanged = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(hasChanged){
|
||||
logger.info(`发现${domain}的IP变化,需要更新,旧IP:${oldIps.map(ip=>ip.ipAddress).join(",")},新IP:${ips.join(",")}`)
|
||||
//有变化需要更新
|
||||
@@ -213,30 +226,26 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
})
|
||||
}
|
||||
|
||||
async getAllIpsFromDomain(domain: string) {
|
||||
const getFromV4 = safePromise<string[]>((resolve, reject) => {
|
||||
dns.resolve4(domain, (err, addresses) => {
|
||||
if (err) {
|
||||
logger.error(`[${domain}] resolve4 error`, err)
|
||||
resolve([])
|
||||
return;
|
||||
}
|
||||
resolve(addresses);
|
||||
});
|
||||
});
|
||||
async getAllIpsFromDomain(domain: string,resolver:any = dns):Promise<string[]> {
|
||||
const getFromV4 = async ():Promise<string[]> => {
|
||||
try{
|
||||
return await resolver.resolve4(domain);
|
||||
}catch (err) {
|
||||
logger.error(`[${domain}] resolve4 error`, err)
|
||||
return []
|
||||
}
|
||||
}
|
||||
const getFromV6 = async ():Promise<string[]> => {
|
||||
try{
|
||||
return await resolver.resolve6(domain);
|
||||
}catch (err) {
|
||||
logger.error(`[${domain}] resolve6 error`, err)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
const getFromV6 = safePromise<string[]>((resolve, reject) => {
|
||||
dns.resolve6(domain, (err, addresses) => {
|
||||
if (err) {
|
||||
logger.error("[${domain}] resolve6 error", err)
|
||||
resolve([])
|
||||
return;
|
||||
}
|
||||
resolve(addresses);
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all([getFromV4, getFromV6]).then(res => {
|
||||
return Promise.all([getFromV4(), getFromV6()]).then(res => {
|
||||
return [...res[0], ...res[1]];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { logger, safePromise, utils } from "@certd/basic";
|
||||
import { merge } from "lodash-es";
|
||||
import https from "https";
|
||||
import { PeerCertificate } from "tls";
|
||||
// import { TCPClient } from "dns2";
|
||||
|
||||
export type SiteTestReq = {
|
||||
host: string; // 只用域名部分
|
||||
@@ -11,7 +10,7 @@ export type SiteTestReq = {
|
||||
retryTimes?: number;
|
||||
ipAddress?: string;
|
||||
|
||||
dnsServer?: string[];
|
||||
resolver?: any;
|
||||
};
|
||||
|
||||
export type SiteTestRes = {
|
||||
@@ -52,6 +51,7 @@ export class SiteTester {
|
||||
req
|
||||
);
|
||||
|
||||
let customLookup = null
|
||||
if (req.ipAddress) {
|
||||
//使用固定的ip
|
||||
const ipAddress = req.ipAddress;
|
||||
@@ -61,37 +61,20 @@ export class SiteTester {
|
||||
servername: options.host
|
||||
};
|
||||
options.host = ipAddress;
|
||||
}else if (req.resolver ) {
|
||||
// 非ip address 请求时
|
||||
const resolver = req.resolver
|
||||
customLookup = async (hostname:string, options:any, callback)=> {
|
||||
console.log(hostname, options);
|
||||
|
||||
// { family: undefined, hints: 0, all: true }
|
||||
const res = await resolver.resolve(hostname, options)
|
||||
console.log("custom lookup res:",res)
|
||||
callback(null, res);
|
||||
}
|
||||
}
|
||||
|
||||
// let dnsClients = [];
|
||||
// if (req.dnsServer && req.dnsServer.length > 0) {
|
||||
// for (let dns of req.dnsServer) {
|
||||
// const dnsClient = TCPClient({ dns });
|
||||
// dnsClients.push(dnsClient);
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function customLookup(hostname, options, callback) {
|
||||
// for (let client of dnsClients) {
|
||||
// try {
|
||||
// const result = await client.resolve(hostname, options);
|
||||
// return callback(null, result);
|
||||
// } catch (e) {
|
||||
// this.logger.error(e);
|
||||
// }
|
||||
// }
|
||||
// try {
|
||||
// // 使用自定义DNS解析
|
||||
// const response = await dnsClients
|
||||
// const address = response.answers[0].address;
|
||||
// callback(null, address, 4);
|
||||
// } catch (err) {
|
||||
// // 解析失败时回退到系统DNS
|
||||
// require('dns').lookup(hostname, options, callback);
|
||||
// }
|
||||
// }
|
||||
|
||||
options.agent = new https.Agent({ keepAlive: false });
|
||||
options.agent = new https.Agent({ keepAlive: false, lookup: customLookup });
|
||||
|
||||
// 创建 HTTPS 请求
|
||||
const requestPromise = safePromise((resolve, reject) => {
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { BaseService, SysInstallInfo, SysSettingsService, SysSiteInfo, ValidateException } from '@certd/lib-server';
|
||||
import {
|
||||
BaseService,
|
||||
NeedVIPException,
|
||||
SysInstallInfo,
|
||||
SysSettingsService,
|
||||
SysSiteInfo,
|
||||
ValidateException
|
||||
} from "@certd/lib-server";
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { NotificationEntity } from '../entity/notification.js';
|
||||
import { NotificationInstanceConfig, notificationRegistry, NotificationSendReq, sendNotification } from '@certd/pipeline';
|
||||
import { http, utils } from '@certd/basic';
|
||||
import { EmailService } from '../../basic/service/email-service.js';
|
||||
import { isComm } from '@certd/plus-core';
|
||||
import { isComm, isPlus } from '@certd/plus-core';
|
||||
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||
@@ -46,6 +53,7 @@ export class NotificationService extends BaseService<NotificationEntity> {
|
||||
}
|
||||
|
||||
async add(bean: NotificationEntity) {
|
||||
this.checkNeedPlus(bean.type);
|
||||
const res = await super.add(bean);
|
||||
if(bean.isDefault){
|
||||
await this.setDefault(res.id, bean.userId);
|
||||
@@ -54,14 +62,28 @@ export class NotificationService extends BaseService<NotificationEntity> {
|
||||
}
|
||||
|
||||
async update(bean: NotificationEntity) {
|
||||
|
||||
const old = await this.info(bean.id);
|
||||
this.checkNeedPlus(old.type);
|
||||
|
||||
delete bean.userId;
|
||||
delete bean.type
|
||||
const res = await super.update(bean);
|
||||
if(bean.isDefault){
|
||||
const old = await this.info(bean.id);
|
||||
await this.setDefault(bean.id, old.userId);
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
checkNeedPlus(type: string){
|
||||
const define = this.getDefineByType(type)
|
||||
//@ts-ignore
|
||||
if (define.needPlus && !isPlus()) {
|
||||
throw new NeedVIPException("此通知类型为专业版功能,请升级到专业版或以上级别");
|
||||
}
|
||||
}
|
||||
|
||||
async getById(id: number, userId: number): Promise<NotificationInstanceConfig> {
|
||||
if (!id) {
|
||||
throw new ValidateException('id不能为空');
|
||||
|
||||
@@ -41,7 +41,7 @@ export function getDefaultDeployPlugin() {
|
||||
let certApplyNames = ''
|
||||
for (const name of CertApplyPluginNames) {
|
||||
certApplyNames += `
|
||||
- ${name}`
|
||||
- "${name}"`
|
||||
}
|
||||
const metadata =`
|
||||
input: # 插件的输入参数
|
||||
|
||||
@@ -25,3 +25,4 @@ export * from './plugin-flex/index.js'
|
||||
export * from './plugin-farcdn/index.js'
|
||||
export * from './plugin-fnos/index.js'
|
||||
export * from './plugin-rainyun/index.js'
|
||||
export * from './plugin-wangsu/index.js'
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
|
||||
import { AliyunAccess, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: "AliyunDeployCertToVod",
|
||||
title: "阿里云-部署至VOD",
|
||||
icon: "svg:icon-aliyun",
|
||||
group: pluginGroups.aliyun.key,
|
||||
desc: "部署证书到阿里云视频点播(vod)",
|
||||
needPlus: false,
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed
|
||||
}
|
||||
}
|
||||
})
|
||||
export class AliyunDeployCertToVod extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: "域名证书",
|
||||
helper: "请选择证书申请任务输出的域名证书",
|
||||
component: {
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames]
|
||||
},
|
||||
required: true
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||
certDomains!: string[];
|
||||
|
||||
// @TaskInput({
|
||||
// title: "大区",
|
||||
// value: "cn-hangzhou",
|
||||
// component: {
|
||||
// name: "a-auto-complete",
|
||||
// vModel: "value",
|
||||
// options: [
|
||||
// { value: "cn-hangzhou", label: "华东1(杭州)" },
|
||||
// { value: "ap-southeast-1", label: "新加坡" }
|
||||
// ]
|
||||
// },
|
||||
// required: true
|
||||
// })
|
||||
// regionId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "证书接入点",
|
||||
helper: "不会选就保持默认即可",
|
||||
value: "cas.aliyuncs.com",
|
||||
component: {
|
||||
name: "a-select",
|
||||
options: [
|
||||
{ value: "cas.aliyuncs.com", label: "中国大陆" },
|
||||
{ value: "cas.ap-southeast-1.aliyuncs.com", label: "新加坡" },
|
||||
{ value: "cas.eu-central-1.aliyuncs.com", label: "德国(法兰克福)" }
|
||||
]
|
||||
},
|
||||
required: true
|
||||
})
|
||||
casEndpoint!: string;
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: "Access授权",
|
||||
helper: "阿里云授权AccessKeyId、AccessKeySecret",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "aliyun"
|
||||
},
|
||||
required: true
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: "加速域名",
|
||||
helper: "请选择要部署证书的域名",
|
||||
action: AliyunDeployCertToVod.prototype.onGetDomainList.name,
|
||||
watches: ["accessId"],
|
||||
pager: true,
|
||||
search: true
|
||||
})
|
||||
)
|
||||
domainList!: string[];
|
||||
|
||||
|
||||
async onInstance() {
|
||||
}
|
||||
|
||||
|
||||
async execute(): Promise<void> {
|
||||
this.logger.info("开始部署证书到阿里云VOD");
|
||||
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||||
|
||||
const client = await this.getClient(access);
|
||||
|
||||
|
||||
for (const siteId of this.domainList) {
|
||||
/**
|
||||
* let queries : {[key: string ]: any} = { };
|
||||
* queries["DomainName"] = "324234234";
|
||||
* queries["CertName"] = "ccccccc";
|
||||
* queries["SSLProtocol"] = "on";
|
||||
* queries["SSLPub"] = "cert";
|
||||
* queries["SSLPri"] = "key";
|
||||
* // runtime options
|
||||
* let runtime = new $Util.RuntimeOptions({ });
|
||||
* let request = new $OpenApi.OpenApiRequest({
|
||||
* query: OpenApiUtil.query(queries),
|
||||
* });
|
||||
*/
|
||||
const res = await client.doRequest({
|
||||
action: "SetVodDomainCertificate",
|
||||
version: "2017-03-21",
|
||||
protocol: "HTTPS",
|
||||
data: {
|
||||
query: {
|
||||
DomainName: siteId,
|
||||
CertName: this.appendTimeSuffix("certd"),
|
||||
SSLProtocol: "on",
|
||||
SSLPub: this.cert.crt,
|
||||
SSLPri: this.cert.key
|
||||
}
|
||||
}
|
||||
});
|
||||
this.logger.info(`部署站点[${siteId}]证书成功:${JSON.stringify(res)}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getClient(access: AliyunAccess) {
|
||||
const endpoint = `vod.cn-shanghai.aliyuncs.com`;
|
||||
return access.getClient(endpoint);
|
||||
}
|
||||
|
||||
async onGetDomainList(data: PageSearch) {
|
||||
if (!this.accessId) {
|
||||
throw new Error("请选择Access授权");
|
||||
}
|
||||
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||||
|
||||
/**
|
||||
* let queries : {[key: string ]: any} = { };
|
||||
* queries["PageSize"] = 50;
|
||||
* queries["PageNumber"] = 1;
|
||||
* queries["DomainName"] = "5555";
|
||||
* // runtime options
|
||||
* let runtime = new $Util.RuntimeOptions({ });
|
||||
* let request = new $OpenApi.OpenApiRequest({
|
||||
* query: OpenApiUtil.query(queries),
|
||||
* });
|
||||
*/
|
||||
const client = await this.getClient(access);
|
||||
const res = await client.doRequest({
|
||||
action: "DescribeVodUserDomains",
|
||||
version: "2017-03-21",
|
||||
protocol: "HTTPS",
|
||||
data: {
|
||||
query: {
|
||||
DomainName: data.searchKey,
|
||||
PageNumber: data.pageNo,
|
||||
PageSize: data.pageSize
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const list = res?.Domains.PageData;
|
||||
if (!list || list.length === 0) {
|
||||
throw new Error("没有找到加速域名,请先在阿里云添加点播加速域名");
|
||||
}
|
||||
|
||||
const options = list.map((item: any) => {
|
||||
return {
|
||||
label: item.DomainName,
|
||||
value: item.DomainName,
|
||||
domain: item.DomainName
|
||||
};
|
||||
});
|
||||
return this.ctx.utils.options.buildGroupOptions(options, this.certDomains);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new AliyunDeployCertToVod();
|
||||
@@ -7,3 +7,4 @@ export * from './deploy-to-alb/index.js';
|
||||
export * from './deploy-to-nlb/index.js';
|
||||
export * from './deploy-to-slb/index.js';
|
||||
export * from './deploy-to-fc/index.js';
|
||||
export * from './deploy-to-vod/index.js';
|
||||
|
||||
@@ -26,7 +26,7 @@ const regionDict = [
|
||||
title: '阿里云-上传证书到阿里云',
|
||||
icon: 'svg:icon-aliyun',
|
||||
group: pluginGroups.aliyun.key,
|
||||
desc: '如果不想在阿里云上同一份证书上传多次,可以把此任务作为前置任务,其他阿里云任务证书那一项选择此任务的输出',
|
||||
desc: '上传证书到阿里云数字证书管理服务(CAS),注意:不会部署到任何应用上;如果不想在阿里云上同一份证书上传多次,可以把此任务作为前置任务,其他阿里云任务证书那一项选择此任务的输出',
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import dayjs from 'dayjs';
|
||||
import dayjs from "dayjs";
|
||||
import { AliyunSslClient } from "@certd/plugin-lib";
|
||||
import { CertInfo, CertReader } from "@certd/plugin-cert";
|
||||
|
||||
export const ZoneOptions = [{ value: 'cn-hangzhou' }];
|
||||
export function appendTimeSuffix(name: string) {
|
||||
@@ -13,3 +15,27 @@ export function checkRet(ret: any) {
|
||||
throw new Error('执行失败:' + ret.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function getAliyunCertId(opts:{
|
||||
cert: string | CertInfo,
|
||||
sslClient: AliyunSslClient,
|
||||
}) {
|
||||
const { cert, sslClient } = opts;
|
||||
let certId: any = cert;
|
||||
let certName: any = CertReader.appendTimeSuffix("certd");
|
||||
if (typeof cert === "object") {
|
||||
const certReader = new CertReader(cert)
|
||||
certName = certReader.buildCertName()
|
||||
|
||||
certId = await sslClient.uploadCert({
|
||||
name: certName,
|
||||
cert: cert,
|
||||
});
|
||||
sslClient.logger.info("上传证书成功", certId, certName);
|
||||
}
|
||||
return {
|
||||
certId,
|
||||
certName,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
|
||||
import { CertApplyPluginNames, CertInfo, CertReader } from "@certd/plugin-cert";
|
||||
import {
|
||||
createCertDomainGetterInputDefine,
|
||||
createRemoteSelectInputDefine,
|
||||
SshAccess,
|
||||
SshClient
|
||||
} from "@certd/plugin-lib";
|
||||
import path from "node:path";
|
||||
|
||||
@IsTaskPlugin({
|
||||
//命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名
|
||||
@@ -75,6 +76,9 @@ export class FnOSDeployToNAS extends AbstractTaskPlugin {
|
||||
//复制证书
|
||||
const list = await this.doGetCertList()
|
||||
|
||||
const certReader = new CertReader(this.cert);
|
||||
const expiresAt = certReader.expires;
|
||||
const validFrom = certReader.detail.notBefore.getTime()
|
||||
for (const target of this.certList) {
|
||||
this.logger.info(`----------- 准备部署:${target}`);
|
||||
let found = false
|
||||
@@ -83,6 +87,7 @@ export class FnOSDeployToNAS extends AbstractTaskPlugin {
|
||||
this.logger.info(`----------- 找到证书,开始部署:${item.sum},${item.domain}`)
|
||||
const certPath = item.certificate;
|
||||
const keyPath = item.privateKey;
|
||||
const certDir = path.dirname(keyPath)
|
||||
const cmd = `
|
||||
sudo tee ${certPath} > /dev/null <<'EOF'
|
||||
${this.cert.crt}
|
||||
@@ -90,6 +95,11 @@ EOF
|
||||
sudo tee ${keyPath} > /dev/null <<'EOF'
|
||||
${this.cert.key}
|
||||
EOF
|
||||
|
||||
sudo chmod 0755 "${certDir}/" -R
|
||||
|
||||
sudo -u postgres psql -d trim_connect -c "UPDATE cert SET valid_to=${expiresAt},valid_from=${validFrom} WHERE private_key='${item.privateKey}'"
|
||||
|
||||
`
|
||||
const res = await client.exec({
|
||||
connectConf: access,
|
||||
@@ -113,9 +123,9 @@ EOF
|
||||
|
||||
const restartCmd= `
|
||||
echo "正在重启相关服务..."
|
||||
systemctl restart webdav.service
|
||||
systemctl restart smbftpd.service
|
||||
systemctl restart trim_nginx.service
|
||||
sudo systemctl restart webdav.service
|
||||
sudo systemctl restart smbftpd.service
|
||||
sudo systemctl restart trim_nginx.service
|
||||
echo "服务重启完成!"
|
||||
`
|
||||
await client.exec({
|
||||
|
||||
@@ -1,101 +1,77 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { utils } from "@certd/basic";
|
||||
|
||||
import dayjs from "dayjs";
|
||||
import { CertApplyPluginNames } from "@certd/plugin-cert";
|
||||
import yaml from "js-yaml";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'DeployCertToTencentTKEIngress',
|
||||
title: '腾讯云-部署到TKE-ingress',
|
||||
name: "DeployCertToTencentTKEIngress",
|
||||
title: "腾讯云-部署到TKE",
|
||||
needPlus: false,
|
||||
icon: 'svg:icon-tencentcloud',
|
||||
icon: "svg:icon-tencentcloud",
|
||||
group: pluginGroups.tencent.key,
|
||||
desc: 'serverless集群请使用K8S部署插件;Qcloud类型需要【上传到腾讯云】作为前置任务;ApiServer未开启外网访问则需要做域名的内网IP映射',
|
||||
desc: "修改TKE集群密钥配置,支持Opaque和TLS证书类型。注意:\n1. serverless集群请使用K8S部署插件;\n2. Opaque类型需要【上传到腾讯云】作为前置任务;\n3. ApiServer需要开通公网访问(或者certd可访问),实际上底层仍然是通过KubeClient进行部署",
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
runStrategy: RunStrategy.SkipWhenSucceed
|
||||
}
|
||||
}
|
||||
})
|
||||
export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({ title: '大区', value: 'ap-guangzhou', required: true })
|
||||
region!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '集群ID',
|
||||
required: true,
|
||||
desc: '例如:cls-6lbj1vee',
|
||||
request: true,
|
||||
})
|
||||
clusterId!: string;
|
||||
|
||||
@TaskInput({ title: '集群namespace', value: 'default', required: true })
|
||||
namespace!: string;
|
||||
|
||||
@TaskInput({ title: '证书的secret名称', required: true })
|
||||
secretName!: string | string[];
|
||||
|
||||
@TaskInput({ title: 'ingress名称', required: true })
|
||||
ingressName!: string | string[];
|
||||
|
||||
@TaskInput({
|
||||
title: 'ingress类型',
|
||||
title: "ingress证书类型",
|
||||
component: {
|
||||
name: 'a-auto-complete',
|
||||
vModel: 'value',
|
||||
options: [{ value: 'qcloud' }, { value: 'nginx' }],
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
options: [{ value: "nginx", label: "TLS证书格式(Nginx可用)" }, {
|
||||
value: "qcloud",
|
||||
label: "Opaque格式(CLB可用,原qcloud)"
|
||||
}]
|
||||
},
|
||||
helper: '可选 qcloud / nginx',
|
||||
helper: "clb将部署Opaque类型的证书,nginx类型将部署TLS证书格式",
|
||||
required: true
|
||||
})
|
||||
ingressClass!: string;
|
||||
|
||||
// @TaskInput({ title: "集群内网ip", helper: "如果开启了外网的话,无需设置" })
|
||||
// clusterIp!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '集群域名',
|
||||
helper: '可不填,默认为:[clusterId].ccs.tencent-cloud.com',
|
||||
})
|
||||
clusterDomain!: string;
|
||||
|
||||
/**
|
||||
* AccessProvider的key,或者一个包含access的具体的对象
|
||||
*/
|
||||
@TaskInput({
|
||||
title: 'Access授权',
|
||||
helper: 'access授权',
|
||||
title: "Access授权",
|
||||
helper: "access授权",
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'tencent',
|
||||
name: "access-selector",
|
||||
type: "tencent"
|
||||
},
|
||||
required: true,
|
||||
required: true
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '腾讯云证书id',
|
||||
helper: '请选择“上传证书到腾讯云”前置任务的输出',
|
||||
title: "腾讯云证书id",
|
||||
helper: "请选择“上传证书到腾讯云”前置任务的输出",
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: 'UploadCertToTencent',
|
||||
name: "output-selector",
|
||||
from: "UploadCertToTencent"
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.ingressClass === "qcloud"
|
||||
return form.ingressClass === "qcloud"|| form.ingressClass === "clb"
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
required: true
|
||||
})
|
||||
tencentCertId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
title: "域名证书",
|
||||
helper: "请选择前置任务输出的域名证书",
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: [...CertApplyPluginNames],
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames]
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
@@ -104,26 +80,90 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
required: true
|
||||
})
|
||||
cert!: any;
|
||||
|
||||
|
||||
@TaskInput({ title: "大区", value: "ap-guangzhou", required: true })
|
||||
region!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "集群ID",
|
||||
required: true,
|
||||
desc: "例如:cls-6lbj1vee",
|
||||
request: true
|
||||
})
|
||||
clusterId!: string;
|
||||
|
||||
@TaskInput({ title: "集群namespace", value: "default", required: true })
|
||||
namespace!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "证书的secret名称",
|
||||
helper: "集群->配置管理->Secret,复制名称",
|
||||
required: true,
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
open: false
|
||||
}
|
||||
})
|
||||
secretName!: string | string[];
|
||||
|
||||
@TaskInput({
|
||||
title: "集群域名",
|
||||
helper: "ApiServer需要开通公网访问,填写`ApiServer公网IP:443`\n默认为:[clusterId].ccs.tencent-cloud.com,可能访问不通",
|
||||
component: {
|
||||
placeholder: "xx.xxx.xx.xx:443"
|
||||
}
|
||||
})
|
||||
clusterDomain!: string;
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: "ingress名称",
|
||||
required: false,
|
||||
helper: "填写之后会自动重启ingress",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
open: false
|
||||
}
|
||||
})
|
||||
ingressName!: string | string[];
|
||||
|
||||
|
||||
// @TaskInput({ title: "集群内网ip", helper: "如果开启了外网的话,无需设置" })
|
||||
// clusterIp!: string;
|
||||
|
||||
|
||||
K8sClient: any;
|
||||
|
||||
async onInstance() {
|
||||
// const TkeClient = this.tencentcloud.tke.v20180525.Client;
|
||||
const k8sSdk = await import('@certd/lib-k8s');
|
||||
const k8sSdk = await import("@certd/lib-k8s");
|
||||
this.K8sClient = k8sSdk.K8sClient;
|
||||
}
|
||||
|
||||
async execute(): Promise<void> {
|
||||
const accessProvider = await this.getAccess(this.accessId);
|
||||
const tkeClient = await this.getTkeClient(accessProvider, this.region);
|
||||
const kubeConfigStr = await this.getTkeKubeConfig(tkeClient, this.clusterId);
|
||||
let kubeConfigStr = await this.getTkeKubeConfig(tkeClient, this.clusterId);
|
||||
|
||||
this.logger.info('kubeconfig已成功获取');
|
||||
|
||||
if (this.clusterDomain) {
|
||||
const kubeConfig = yaml.load(kubeConfigStr);
|
||||
kubeConfig.clusters[0].cluster.server = `https://${this.clusterDomain}`;
|
||||
kubeConfigStr = yaml.dump(kubeConfig);
|
||||
}
|
||||
|
||||
this.logger.info("kubeconfig已成功获取");
|
||||
const k8sClient = new this.K8sClient({
|
||||
kubeConfigStr,
|
||||
logger: this.logger,
|
||||
logger: this.logger
|
||||
});
|
||||
// if (this.clusterIp != null) {
|
||||
// if (!this.clusterDomain) {
|
||||
@@ -132,31 +172,34 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
|
||||
// // 修改内网解析ip地址
|
||||
// k8sClient.setLookup({ [this.clusterDomain]: { ip: this.clusterIp } });
|
||||
// }
|
||||
const ingressType = this.ingressClass || 'qcloud';
|
||||
if (ingressType === 'qcloud') {
|
||||
const ingressType = this.ingressClass || "qcloud";
|
||||
if (ingressType === "qcloud" || ingressType === "clb") {
|
||||
await this.patchQcloudCertSecret({ k8sClient });
|
||||
} else {
|
||||
await this.patchNginxCertSecret({ k8sClient });
|
||||
}
|
||||
|
||||
await utils.sleep(5000); // 停留2秒,等待secret部署完成
|
||||
await this.restartIngress({ k8sClient });
|
||||
if (this.ingressName) {
|
||||
this.logger.info("正在重启ingress:", this.ingressName);
|
||||
await this.restartIngress({ k8sClient });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async getTkeClient(accessProvider: any, region = 'ap-guangzhou') {
|
||||
const sdk = await import('tencentcloud-sdk-nodejs/tencentcloud/services/tke/v20180525/index.js');
|
||||
async getTkeClient(accessProvider: any, region = "ap-guangzhou") {
|
||||
const sdk = await import("tencentcloud-sdk-nodejs/tencentcloud/services/tke/v20180525/index.js");
|
||||
const TkeClient = sdk.v20180525.Client;
|
||||
const clientConfig = {
|
||||
credential: {
|
||||
secretId: accessProvider.secretId,
|
||||
secretKey: accessProvider.secretKey,
|
||||
secretKey: accessProvider.secretKey
|
||||
},
|
||||
region,
|
||||
profile: {
|
||||
httpProfile: {
|
||||
endpoint: 'tke.tencentcloudapi.com',
|
||||
},
|
||||
},
|
||||
endpoint: "tke.tencentcloudapi.com"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return new TkeClient(clientConfig);
|
||||
@@ -165,49 +208,42 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
|
||||
async getTkeKubeConfig(client: any, clusterId: string) {
|
||||
// Depends on tencentcloud-sdk-nodejs version 4.0.3 or higher
|
||||
const params = {
|
||||
ClusterId: clusterId,
|
||||
ClusterId: clusterId
|
||||
};
|
||||
const ret = await client.DescribeClusterKubeconfig(params);
|
||||
this.checkRet(ret);
|
||||
this.logger.info('注意:后续操作需要在【集群->基本信息】中开启外网或内网访问,https://console.cloud.tencent.com/tke2/cluster');
|
||||
this.logger.info("注意:后续操作需要在【集群->基本信息】中开启外网或内网访问,https://console.cloud.tencent.com/tke2/cluster");
|
||||
return ret.Kubeconfig;
|
||||
}
|
||||
|
||||
appendTimeSuffix(name: string) {
|
||||
if (name == null) {
|
||||
name = 'certd';
|
||||
}
|
||||
return name + '-' + dayjs().format('YYYYMMDD-HHmmss');
|
||||
}
|
||||
|
||||
async patchQcloudCertSecret(options: { k8sClient: any }) {
|
||||
if (this.tencentCertId == null) {
|
||||
throw new Error('请先将【上传证书到腾讯云】作为前置任务');
|
||||
throw new Error("请先将【上传证书到腾讯云】作为前置任务");
|
||||
}
|
||||
this.logger.info('腾讯云证书ID:', this.tencentCertId);
|
||||
const certIdBase64 = Buffer.from(this.tencentCertId).toString('base64');
|
||||
this.logger.info("腾讯云证书ID:", this.tencentCertId);
|
||||
const certIdBase64 = Buffer.from(this.tencentCertId).toString("base64");
|
||||
|
||||
const { namespace, secretName } = this;
|
||||
|
||||
const body = {
|
||||
data: {
|
||||
qcloud_cert_id: certIdBase64,
|
||||
qcloud_cert_id: certIdBase64
|
||||
},
|
||||
metadata: {
|
||||
labels: {
|
||||
certd: this.appendTimeSuffix('certd'),
|
||||
},
|
||||
},
|
||||
certd: this.appendTimeSuffix("certd")
|
||||
}
|
||||
}
|
||||
};
|
||||
let secretNames: any = secretName;
|
||||
if (typeof secretName === 'string') {
|
||||
if (typeof secretName === "string") {
|
||||
secretNames = [secretName];
|
||||
}
|
||||
for (const secret of secretNames) {
|
||||
await options.k8sClient.patchSecret({
|
||||
namespace,
|
||||
secretName: secret,
|
||||
body,
|
||||
body
|
||||
});
|
||||
this.logger.info(`CertSecret已更新:${secret}`);
|
||||
}
|
||||
@@ -218,24 +254,24 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
|
||||
const { cert } = this;
|
||||
const crt = cert.crt;
|
||||
const key = cert.key;
|
||||
const crtBase64 = Buffer.from(crt).toString('base64');
|
||||
const keyBase64 = Buffer.from(key).toString('base64');
|
||||
const crtBase64 = Buffer.from(crt).toString("base64");
|
||||
const keyBase64 = Buffer.from(key).toString("base64");
|
||||
|
||||
const { namespace, secretName } = this;
|
||||
|
||||
const body = {
|
||||
data: {
|
||||
'tls.crt': crtBase64,
|
||||
'tls.key': keyBase64,
|
||||
"tls.crt": crtBase64,
|
||||
"tls.key": keyBase64
|
||||
},
|
||||
metadata: {
|
||||
labels: {
|
||||
certd: this.appendTimeSuffix('certd'),
|
||||
},
|
||||
},
|
||||
certd: this.appendTimeSuffix("certd")
|
||||
}
|
||||
}
|
||||
};
|
||||
let secretNames = secretName;
|
||||
if (typeof secretName === 'string') {
|
||||
if (typeof secretName === "string") {
|
||||
secretNames = [secretName];
|
||||
}
|
||||
for (const secret of secretNames) {
|
||||
@@ -251,12 +287,12 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
|
||||
const body = {
|
||||
metadata: {
|
||||
labels: {
|
||||
certd: this.appendTimeSuffix('certd'),
|
||||
},
|
||||
},
|
||||
certd: this.appendTimeSuffix("certd")
|
||||
}
|
||||
}
|
||||
};
|
||||
let ingressNames = this.ingressName;
|
||||
if (typeof ingressName === 'string') {
|
||||
let ingressNames = this.ingressName || [];
|
||||
if (typeof ingressName === "string") {
|
||||
ingressNames = [ingressName];
|
||||
}
|
||||
for (const ingress of ingressNames) {
|
||||
@@ -264,9 +300,11 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
|
||||
this.logger.info(`ingress已重启:${ingress}`);
|
||||
}
|
||||
}
|
||||
|
||||
checkRet(ret: any) {
|
||||
if (!ret || ret.Error) {
|
||||
throw new Error('执行失败:' + ret.Error.Code + ',' + ret.Error.Message);
|
||||
throw new Error("执行失败:" + ret.Error.Code + "," + ret.Error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
161
packages/ui/certd-server/src/plugins/plugin-wangsu/access.ts
Normal file
161
packages/ui/certd-server/src/plugins/plugin-wangsu/access.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline";
|
||||
import { HttpRequestConfig } from "@certd/basic";
|
||||
import { CertInfo } from "@certd/plugin-cert";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
@IsAccess({
|
||||
name: "wangsu",
|
||||
title: "网宿授权",
|
||||
desc: "",
|
||||
icon: "svg:icon-lucky"
|
||||
})
|
||||
export class WangsuAccess extends BaseAccess {
|
||||
|
||||
@AccessInput({
|
||||
title: "accessKeyId",
|
||||
component: {
|
||||
placeholder: "accessKeyId",
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
}
|
||||
},
|
||||
helper: "[点击前往获取AccessKey](https://console.wangsu.com/account/accessKey?rsr=ws)",
|
||||
encrypt: false,
|
||||
required: true
|
||||
})
|
||||
accessKeyId!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "accessKeySecret",
|
||||
component: {
|
||||
placeholder: "accessKeySecret",
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
}
|
||||
},
|
||||
encrypt: true,
|
||||
required: true
|
||||
})
|
||||
accessKeySecret!: string;
|
||||
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest"
|
||||
},
|
||||
helper: "点击测试接口是否正常"
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.getCertList({ });
|
||||
return "ok";
|
||||
}
|
||||
|
||||
async getCertList(req: { }) {
|
||||
/**
|
||||
* certificate-id
|
||||
* name
|
||||
* dns-names
|
||||
*/
|
||||
const res = await this.doRequest({
|
||||
url: "/api/ssl/certificate",
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
return res["ssl-certificate"]
|
||||
}
|
||||
|
||||
async getCertInfo(req:{certId:string}){
|
||||
return await this.doRequest({
|
||||
url: `/api/certificate/${req.certId}`,
|
||||
method:"GET",
|
||||
});
|
||||
}
|
||||
|
||||
async updateCert(req: {
|
||||
certId: string,
|
||||
cert: CertInfo,
|
||||
}) {
|
||||
|
||||
const certInfo= await this.getCertInfo({certId:req.certId});
|
||||
|
||||
const name = certInfo.name;
|
||||
const {cert,certId} = req;
|
||||
return await this.doRequest({
|
||||
url: `/api/certificate/${certId}`,
|
||||
method:"PUT",
|
||||
data: {
|
||||
/**
|
||||
* name: string;
|
||||
* certificate?: string;
|
||||
* privateKey?: string;
|
||||
* autoRenew?: string;
|
||||
* isNeedAlarm?: string;
|
||||
* csrId?: number;
|
||||
* comment?: string;
|
||||
*/
|
||||
name:name,
|
||||
certificate: cert.crt,
|
||||
privateKey: cert.key,
|
||||
autoRenew:"false",
|
||||
isNeedAlarm:"false",
|
||||
comment: "certd"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
async doRequest(req: HttpRequestConfig) {
|
||||
|
||||
const data: any = req.data;
|
||||
|
||||
const {AkSkConfig,AkSkAuth} = await import("./lib/index.js");
|
||||
|
||||
const akskConfig = new AkSkConfig();
|
||||
akskConfig.accessKey = this.accessKeyId;
|
||||
akskConfig.secretKey = this.accessKeySecret;
|
||||
akskConfig.endPoint = "open.chinanetcenter.com";
|
||||
akskConfig.uri = req.url;
|
||||
akskConfig.method = req.method;
|
||||
|
||||
const requestMsg = AkSkAuth.transferHttpRequestMsg(akskConfig,data?JSON.stringify(data):"");
|
||||
AkSkAuth.getAuthAndSetHeaders(requestMsg, akskConfig.accessKey, akskConfig.secretKey);
|
||||
|
||||
let response = undefined
|
||||
try{
|
||||
response = await this.ctx.http.request({
|
||||
method: requestMsg.method,
|
||||
url: requestMsg.url,
|
||||
headers: requestMsg.headers,
|
||||
data: requestMsg.body
|
||||
});
|
||||
}catch (e) {
|
||||
if (e.response?.data?.result) {
|
||||
throw new Error(e.response?.data?.result);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (response.code != null && response.code != 0){
|
||||
throw new Error(response.message);
|
||||
}
|
||||
if (response.data != null && response.code!==null){
|
||||
return response.data;
|
||||
}
|
||||
return response;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
new WangsuAccess();
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./plugins/index.js";
|
||||
export * from "./access.js";
|
||||
@@ -0,0 +1,87 @@
|
||||
import { HttpRequestMsg } from "../model/HttpRequestMsg.js";
|
||||
import { AkSkConfig } from "../model/AkSkConfig.js";
|
||||
import { CryptoUtils } from "../util/CryptoUtils.js";
|
||||
import { HttpUtils } from "../util/HttpUtils.js";
|
||||
import { Constant } from "../common/Constant.js";
|
||||
|
||||
export class AkSkAuth {
|
||||
|
||||
public static invoke(akSkConfig: AkSkConfig, jsonBody: string): Promise<string | null> {
|
||||
const requestMsg = AkSkAuth.transferHttpRequestMsg(akSkConfig, jsonBody);
|
||||
AkSkAuth.getAuthAndSetHeaders(requestMsg, akSkConfig.accessKey, akSkConfig.secretKey);
|
||||
return HttpUtils.call(requestMsg);
|
||||
}
|
||||
|
||||
static transferHttpRequestMsg(akSkConfig: AkSkConfig, jsonBody: string): HttpRequestMsg {
|
||||
const requestMsg = new HttpRequestMsg();
|
||||
requestMsg.uri = akSkConfig.uri;
|
||||
if (akSkConfig.endPoint && akSkConfig.endPoint !== Constant.END_POINT) {
|
||||
requestMsg.host = akSkConfig.endPoint;
|
||||
requestMsg.url = `${Constant.HTTPS_REQUEST_PREFIX}${akSkConfig.endPoint}${requestMsg.uri}`;
|
||||
} else {
|
||||
requestMsg.host = Constant.HTTP_DOMAIN;
|
||||
requestMsg.url = `${Constant.HTTP_REQUEST_PREFIX}${requestMsg.uri}`;
|
||||
}
|
||||
requestMsg.method = akSkConfig.method;
|
||||
requestMsg.signedHeaders = AkSkAuth.getSignedHeaders(akSkConfig.signedHeaders);
|
||||
if (['POST', 'PUT', 'PATCH', 'DELETE'].indexOf(akSkConfig.method) !== -1) {
|
||||
requestMsg.body = jsonBody;
|
||||
}
|
||||
return requestMsg;
|
||||
}
|
||||
|
||||
static getAuthAndSetHeaders(requestMsg: HttpRequestMsg, accessKey: string, secretKey: string): void {
|
||||
const timeStamp = (Date.now() / 1000 | 0).toString();
|
||||
requestMsg.headers['Host'] = requestMsg.host;
|
||||
requestMsg.headers[Constant.HEAD_SIGN_ACCESS_KEY] = accessKey;
|
||||
requestMsg.headers[Constant.HEAD_SIGN_TIMESTAMP] = timeStamp;
|
||||
requestMsg.headers["Accept"] = Constant.APPLICATION_JSON;
|
||||
const signature = AkSkAuth.getSignature(requestMsg, secretKey, timeStamp);
|
||||
requestMsg.headers['Authorization'] = AkSkAuth.genAuthorization(accessKey, AkSkAuth.getSignedHeaders(requestMsg.signedHeaders), signature);
|
||||
}
|
||||
|
||||
private static genAuthorization(accessKey: string, signedHeaders: string, signature: string): string {
|
||||
return `${Constant.HEAD_SIGN_ALGORITHM} Credential=${accessKey}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
||||
}
|
||||
|
||||
private static getSignature(requestMsg: HttpRequestMsg, secretKey: string, timestamp: string): string {
|
||||
let bodyStr = requestMsg.body || "";
|
||||
const hashedRequestPayload = CryptoUtils.sha256Hex(bodyStr);
|
||||
const canonicalRequest = `${requestMsg.method}\n${requestMsg.uri.split("?")[0]}\n${decodeURIComponent(requestMsg.getQueryString())}\n${AkSkAuth.getCanonicalHeaders(requestMsg.headers, AkSkAuth.getSignedHeaders(requestMsg.signedHeaders))}\n${AkSkAuth.getSignedHeaders(requestMsg.signedHeaders)}\n${hashedRequestPayload}`;
|
||||
const stringToSign = `${Constant.HEAD_SIGN_ALGORITHM}\n${timestamp}\n${CryptoUtils.sha256Hex(canonicalRequest)}`;
|
||||
return CryptoUtils.hmac256(secretKey, stringToSign).toLowerCase();
|
||||
}
|
||||
|
||||
private static getCanonicalHeaders(headers: Record<string, string>, signedHeaders: string): string {
|
||||
const headerNames = signedHeaders.split(";");
|
||||
let canonicalHeaders = "";
|
||||
for (const headerName of headerNames) {
|
||||
const headerValue = AkSkAuth.getValueByHeader(headerName, headers);
|
||||
if (headerValue !== null) {
|
||||
canonicalHeaders += `${headerName}:${headerValue.toLowerCase()}\n`;
|
||||
} else {
|
||||
// Handle missing headers if necessary, e.g., log a warning or skip
|
||||
console.warn(`Header ${headerName} not found in provided headers.`);
|
||||
}
|
||||
}
|
||||
return canonicalHeaders;
|
||||
}
|
||||
|
||||
|
||||
private static getSignedHeaders(signedHeaders: string): string {
|
||||
if (!signedHeaders) {
|
||||
return "content-type;host";
|
||||
}
|
||||
const headers = signedHeaders.split(";");
|
||||
return headers.map(header => header.toLowerCase()).sort().join(";");
|
||||
}
|
||||
|
||||
private static getValueByHeader(name: string, customHeaderMap: { [key: string]: string }): string | null {
|
||||
for (const key in customHeaderMap) {
|
||||
if (key.toLowerCase() === name.toLowerCase()) {
|
||||
return customHeaderMap[key];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export class Constant {
|
||||
private constructor() {}
|
||||
|
||||
public static readonly HTTP_REQUEST_PREFIX: string = "https://open.chinanetcenter.com";
|
||||
public static readonly HTTPS_REQUEST_PREFIX: string = "https://";
|
||||
public static readonly HTTP_DOMAIN: string = "open.chinanetcenter.com";
|
||||
|
||||
public static readonly APPLICATION_JSON: string = "application/json";
|
||||
|
||||
public static readonly HEAD_SIGN_ACCESS_KEY: string = "x-cnc-accessKey";
|
||||
public static readonly HEAD_SIGN_TIMESTAMP: string = "x-cnc-timestamp";
|
||||
public static readonly HEAD_SIGN_ALGORITHM: string = "CNC-HMAC-SHA256";
|
||||
|
||||
public static readonly X_CNC_AUTH_METHOD: string = "x-cnc-auth-method";
|
||||
|
||||
public static readonly AUTH_METHOD: string = "AKSK";
|
||||
|
||||
public static readonly END_POINT: string = "{endPoint}";
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export class ApiAuthException extends Error {
|
||||
public cause?: any;
|
||||
|
||||
constructor(message: string, cause?: any) {
|
||||
super(message);
|
||||
this.cause = cause;
|
||||
this.name = 'ApiAuthException';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { AkSkConfig } from "./model/AkSkConfig.js";
|
||||
import { AkSkAuth } from "./auth/AkSkAuth.js";
|
||||
|
||||
export { AkSkAuth, AkSkConfig}
|
||||
@@ -0,0 +1,56 @@
|
||||
export class AkSkConfig {
|
||||
private _accessKey: string | undefined;
|
||||
private _secretKey: string | undefined;
|
||||
private _uri: string | undefined;
|
||||
private _endPoint: string | undefined;
|
||||
private _method: string | undefined;
|
||||
private _signedHeaders: string | undefined;
|
||||
|
||||
public get accessKey(): string {
|
||||
return this._accessKey;
|
||||
}
|
||||
|
||||
public set accessKey(value: string) {
|
||||
this._accessKey = value;
|
||||
}
|
||||
|
||||
public get secretKey(): string {
|
||||
return this._secretKey;
|
||||
}
|
||||
|
||||
public set secretKey(value: string) {
|
||||
this._secretKey = value;
|
||||
}
|
||||
|
||||
public get uri(): string {
|
||||
return this._uri;
|
||||
}
|
||||
|
||||
public set uri(value: string) {
|
||||
this._uri = value;
|
||||
}
|
||||
|
||||
public get endPoint(): string {
|
||||
return this._endPoint;
|
||||
}
|
||||
|
||||
public set endPoint(value: string) {
|
||||
this._endPoint = value;
|
||||
}
|
||||
|
||||
public get method(): string {
|
||||
return this._method;
|
||||
}
|
||||
|
||||
public set method(value: string) {
|
||||
this._method = value;
|
||||
}
|
||||
|
||||
public get signedHeaders(): string {
|
||||
return this._signedHeaders;
|
||||
}
|
||||
|
||||
public set signedHeaders(value: string) {
|
||||
this._signedHeaders = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { Constant } from '../common/Constant.js'; // Assuming you have a TypeScript version of this
|
||||
|
||||
export class HttpRequestMsg {
|
||||
uri: string ;
|
||||
url: string;
|
||||
host: string;
|
||||
method: string;
|
||||
protocol: string;
|
||||
params: Record<string, string>;
|
||||
headers: Record<string, string>;
|
||||
body: string;
|
||||
signedHeaders: string;
|
||||
msg: any;
|
||||
|
||||
constructor() {
|
||||
this.params = {};
|
||||
this.headers = {};
|
||||
this.putHeader('Content-Type', Constant.APPLICATION_JSON);
|
||||
this.putHeader(Constant.X_CNC_AUTH_METHOD, Constant.AUTH_METHOD);
|
||||
}
|
||||
|
||||
putParam(name: string, value: string): void {
|
||||
this.params[name] = value;
|
||||
}
|
||||
|
||||
getParam(name: string): string | null {
|
||||
const value = this.params[name];
|
||||
return value && value.trim() !== '' ? value : null;
|
||||
}
|
||||
|
||||
getQueryString(): string {
|
||||
if(this.uri == undefined)
|
||||
return "";
|
||||
const index = this.uri.indexOf("?");
|
||||
if (this.method === 'POST' || index === -1) {
|
||||
return "";
|
||||
}
|
||||
return this.uri.substring(index + 1);
|
||||
}
|
||||
|
||||
putHeader(name: string, value: string): void {
|
||||
this.headers[name] = value;
|
||||
}
|
||||
|
||||
getHeader(name: string): string | null {
|
||||
for (const key in this.headers) {
|
||||
if (key.toLowerCase() === name.toLowerCase()) {
|
||||
return this.headers[key];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getHeaderByNames(...names: string[]): string | null {
|
||||
for (const name of names) {
|
||||
const value = this.getHeader(name);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
removeHeader(name: string): void {
|
||||
for (const key in this.headers) {
|
||||
if (key.toLowerCase() === name.toLowerCase()) {
|
||||
delete this.headers[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setJsonBody(object: any): void {
|
||||
this.body = JSON.stringify(object);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import CryptoJS from 'crypto-js';
|
||||
|
||||
export class CryptoUtils {
|
||||
private constructor() {}
|
||||
|
||||
/**
|
||||
* hmac+sha256+hex
|
||||
*/
|
||||
public static sha256Hex(s: string): string {
|
||||
const hash = CryptoJS.SHA256(s);
|
||||
return hash.toString(CryptoJS.enc.Hex).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* hmac+sha256
|
||||
*/
|
||||
public static hmac256(secretKey: string, message: string): string {
|
||||
const keyWordArray = CryptoJS.enc.Utf8.parse(secretKey);
|
||||
const messageWordArray = CryptoJS.enc.Utf8.parse(message);
|
||||
const hash = CryptoJS.HmacSHA256(messageWordArray, keyWordArray);
|
||||
return hash.toString(CryptoJS.enc.Hex).toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { HttpRequestMsg } from '../model/HttpRequestMsg.js'; // Assuming you have a TypeScript version of this
|
||||
import { ApiAuthException } from '../exception/ApiAuthException.js'; // Assuming you have a TypeScript version of this
|
||||
import axios, { AxiosError } from 'axios';
|
||||
|
||||
export class HttpUtils {
|
||||
private constructor() { }
|
||||
public static async call(requestMsg: HttpRequestMsg): Promise<string | null> {
|
||||
var response;
|
||||
try {
|
||||
response = await axios({
|
||||
method: requestMsg.method,
|
||||
url: requestMsg.url,
|
||||
headers: requestMsg.headers,
|
||||
data: requestMsg.body
|
||||
});
|
||||
console.info("API invoke success. Response:", response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
if (error instanceof AxiosError) {
|
||||
// Handle AxiosError specifically
|
||||
console.error('API invoke failed. Response:', error.response.data);
|
||||
return error.response.data;
|
||||
} else {
|
||||
// Handle other types of errors
|
||||
console.error('API invoke failed.', error);
|
||||
}
|
||||
throw new ApiAuthException('API invoke failed.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./plugin-refresh-cert.js";
|
||||
@@ -0,0 +1,121 @@
|
||||
import {
|
||||
AbstractTaskPlugin,
|
||||
IsTaskPlugin,
|
||||
PageSearch,
|
||||
pluginGroups,
|
||||
RunStrategy,
|
||||
TaskInput
|
||||
} from "@certd/pipeline";
|
||||
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
|
||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
|
||||
import { WangsuAccess } from "../access.js";
|
||||
|
||||
@IsTaskPlugin({
|
||||
//命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名
|
||||
name: "WangsuRefreshCert",
|
||||
title: "网宿-更新证书",
|
||||
desc: "网宿证书自动更新",
|
||||
icon: "svg:icon-lucky",
|
||||
//插件分组
|
||||
group: pluginGroups.cdn.key,
|
||||
needPlus: false,
|
||||
default: {
|
||||
//默认值配置照抄即可
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed
|
||||
}
|
||||
}
|
||||
})
|
||||
//类名规范,跟上面插件名称(name)一致
|
||||
export class WangsuRefreshCert extends AbstractTaskPlugin {
|
||||
//证书选择,此项必须要有
|
||||
@TaskInput({
|
||||
title: "域名证书",
|
||||
helper: "请选择前置任务输出的域名证书",
|
||||
component: {
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames]
|
||||
}
|
||||
// required: true, // 必填
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||
certDomains!: string[];
|
||||
|
||||
//授权选择框
|
||||
@TaskInput({
|
||||
title: "网宿授权",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "wangsu" //固定授权类型
|
||||
},
|
||||
required: true //必填
|
||||
})
|
||||
accessId!: string;
|
||||
//
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: "证书Id",
|
||||
helper: "要更新的网宿证书id",
|
||||
action: WangsuRefreshCert.prototype.onGetCertList.name,
|
||||
pager: false,
|
||||
search: false
|
||||
})
|
||||
)
|
||||
certList!: string[];
|
||||
|
||||
//插件实例化时执行的方法
|
||||
async onInstance() {
|
||||
}
|
||||
|
||||
//插件执行方法
|
||||
async execute(): Promise<void> {
|
||||
const access = await this.getAccess<WangsuAccess>(this.accessId);
|
||||
|
||||
for (const item of this.certList) {
|
||||
this.logger.info(`----------- 开始更新证书:${item}`);
|
||||
await access.updateCert({
|
||||
certId: item,
|
||||
cert: this.cert
|
||||
});
|
||||
this.logger.info(`----------- 更新证书${item}成功`);
|
||||
}
|
||||
|
||||
this.logger.info("部署完成");
|
||||
}
|
||||
|
||||
async onGetCertList(data: PageSearch = {}) {
|
||||
const access = await this.getAccess<WangsuAccess>(this.accessId);
|
||||
|
||||
const list = await access.getCertList({});
|
||||
if (!list || list.length === 0) {
|
||||
throw new Error("没有找到证书,请先在控制台上传一次证书且关联域名");
|
||||
}
|
||||
|
||||
/**
|
||||
* certificate-id
|
||||
* name
|
||||
* dns-names
|
||||
*/
|
||||
const options = list.map((item: any) => {
|
||||
const domains = item["dns-names"]
|
||||
const certId = item["certificate-id"];
|
||||
return {
|
||||
label: `${item.name}<${certId}-${domains[0]}>`,
|
||||
value: certId,
|
||||
domain: item["dns-names"]
|
||||
};
|
||||
});
|
||||
return {
|
||||
list: this.ctx.utils.options.buildGroupOptions(options, this.certDomains),
|
||||
total: list.length,
|
||||
pageNo: 1,
|
||||
pageSize: list.length
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//实例化一下,注册插件
|
||||
new WangsuRefreshCert();
|
||||
203
pnpm-lock.yaml
generated
203
pnpm-lock.yaml
generated
@@ -46,7 +46,7 @@ importers:
|
||||
packages/core/acme-client:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../basic
|
||||
'@peculiar/x509':
|
||||
specifier: ^1.11.0
|
||||
@@ -207,11 +207,11 @@ importers:
|
||||
packages/core/pipeline:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../basic
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.35.5
|
||||
version: link:../../pro/plus-core
|
||||
specifier: ^1.36.1
|
||||
version: 1.36.1
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
version: 1.11.13
|
||||
@@ -415,7 +415,7 @@ importers:
|
||||
packages/libs/lib-k8s:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/basic
|
||||
'@kubernetes/client-node':
|
||||
specifier: 0.21.0
|
||||
@@ -455,17 +455,17 @@ importers:
|
||||
packages/libs/lib-server:
|
||||
dependencies:
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.35.5
|
||||
version: link:../../pro/plus-core
|
||||
specifier: ^1.36.1
|
||||
version: 1.36.1
|
||||
'@midwayjs/cache':
|
||||
specifier: ~3.14.0
|
||||
version: 3.14.0
|
||||
@@ -607,16 +607,16 @@ importers:
|
||||
packages/plugins/plugin-cert:
|
||||
dependencies:
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../plugin-lib
|
||||
'@google-cloud/publicca':
|
||||
specifier: ^1.3.0
|
||||
@@ -698,10 +698,10 @@ importers:
|
||||
specifier: ^3.787.0
|
||||
version: 3.810.0(aws-crt@1.26.2)
|
||||
'@certd/basic':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/pipeline
|
||||
'@kubernetes/client-node':
|
||||
specifier: 0.21.0
|
||||
@@ -789,19 +789,19 @@ importers:
|
||||
packages/pro/commercial-core:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../../core/basic
|
||||
'@certd/lib-server':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../../libs/lib-server
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-plus':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../plugin-plus
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../plus-core
|
||||
'@midwayjs/core':
|
||||
specifier: ~3.20.3
|
||||
@@ -886,22 +886,22 @@ importers:
|
||||
specifier: ^1.0.2
|
||||
version: 1.0.3
|
||||
'@certd/basic':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../../core/basic
|
||||
'@certd/lib-k8s':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../../libs/lib-k8s
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-cert':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../../plugins/plugin-cert
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../plus-core
|
||||
ali-oss:
|
||||
specifier: ^6.21.0
|
||||
@@ -1004,7 +1004,7 @@ importers:
|
||||
packages/pro/plus-core:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.1
|
||||
version: link:../../core/basic
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
@@ -1294,10 +1294,10 @@ importers:
|
||||
version: 0.1.3(zod@3.24.4)
|
||||
devDependencies:
|
||||
'@certd/lib-iframe':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../libs/lib-iframe
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/pipeline
|
||||
'@rollup/plugin-commonjs':
|
||||
specifier: ^25.0.7
|
||||
@@ -1480,47 +1480,47 @@ importers:
|
||||
specifier: ^3.705.0
|
||||
version: 3.810.0(aws-crt@1.26.2)
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/basic
|
||||
'@certd/commercial-core':
|
||||
specifier: ^1.35.5
|
||||
version: link:../../pro/commercial-core
|
||||
specifier: ^1.36.1
|
||||
version: 1.36.1(better-sqlite3@11.10.0)(encoding@0.1.13)(mysql2@3.14.1)(pg@8.16.0)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@18.19.100)(typescript@5.8.3))
|
||||
'@certd/cv4pve-api-javascript':
|
||||
specifier: ^8.4.1
|
||||
version: 8.4.1
|
||||
'@certd/jdcloud':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../libs/lib-jdcloud
|
||||
'@certd/lib-huawei':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../libs/lib-huawei
|
||||
'@certd/lib-k8s':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../libs/lib-k8s
|
||||
'@certd/lib-server':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../libs/lib-server
|
||||
'@certd/midway-flyway-js':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../libs/midway-flyway-js
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-cert':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../plugins/plugin-cert
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.35.5
|
||||
specifier: ^1.36.2
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plugin-plus':
|
||||
specifier: ^1.35.5
|
||||
version: link:../../pro/plugin-plus
|
||||
specifier: ^1.36.1
|
||||
version: 1.36.1(encoding@0.1.13)
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.35.5
|
||||
version: link:../../pro/plus-core
|
||||
specifier: ^1.36.1
|
||||
version: 1.36.1
|
||||
'@huaweicloud/huaweicloud-sdk-cdn':
|
||||
specifier: ^3.1.120
|
||||
version: 3.1.149
|
||||
@@ -1599,9 +1599,6 @@ importers:
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
version: 1.11.13
|
||||
dns2:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
form-data:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.2
|
||||
@@ -1840,6 +1837,9 @@ packages:
|
||||
'@alicloud/credentials@2.4.3':
|
||||
resolution: {integrity: sha512-r2thNtthchTz/c8/HryGSey1vY0UZx2FkAvb+vd+j7xhD/v/KUwnp8RJNQKNG3E4kfs4wSx2bgDSkcPAiXHQLQ==}
|
||||
|
||||
'@alicloud/credentials@2.4.4':
|
||||
resolution: {integrity: sha512-/eRAGSKcniLIFQ1UCpDhB/IrHUZisQ1sc65ws/c2avxUMpXwH1rWAohb76SVAUJhiF4mwvLzLJM1Mn1XL4Xe/Q==}
|
||||
|
||||
'@alicloud/darabonba-array@0.1.1':
|
||||
resolution: {integrity: sha512-UPP7p9//jywqM8EN6BjSbw1ovl/BzqreXdi5FmxT6m3PmFxsxabe+yamjeopyf2Gi0p3WqwJTBCeNji5eYUsJw==}
|
||||
|
||||
@@ -2760,9 +2760,18 @@ packages:
|
||||
'@better-scroll/zoom@2.5.1':
|
||||
resolution: {integrity: sha512-aGvFY5ooeZWS4RcxQLD+pGLpQHQxpPy0sMZV3yadcd2QK53PK9gS4Dp+BYfRv8lZ4/P2LoNEhr6Wq1DN6+uPlA==}
|
||||
|
||||
'@certd/commercial-core@1.36.1':
|
||||
resolution: {integrity: sha512-CpZ7K7s0JoXJ8MD3FyeryKnA62fvX3DKVQ7XkSSomaqgH/a8DgP4QrJGrt2ytIYtu2SzJvJsBfy14UhVM6174Q==}
|
||||
|
||||
'@certd/cv4pve-api-javascript@8.4.1':
|
||||
resolution: {integrity: sha512-jxlRieJmCA0Z9LnwX6Ra6ZekRGJEu8o8RGYoKU0Jjkhc9jm6ChEbVyfE7Iw49/hlpA+2yaHdAXb46au/afCISg==}
|
||||
|
||||
'@certd/plugin-plus@1.36.1':
|
||||
resolution: {integrity: sha512-Bd3tFwn/jDrpSWqUH9488YxFHnEIGI15NFoqQaLv58L+Ycm7mRbyTUC/S3xpiUkfhDI6wqvKL8SOtdpgo0IEzA==}
|
||||
|
||||
'@certd/plus-core@1.36.1':
|
||||
resolution: {integrity: sha512-TiRpqWCC7RGJxmVaDkSkMAFYe2zehRqZFKmNcfG8DZJTgKpQhd98HvXlyXCJD5qUtPmyvFoffTD1Q8bGqN84Vw==}
|
||||
|
||||
'@colors/colors@1.5.0':
|
||||
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
|
||||
engines: {node: '>=0.1.90'}
|
||||
@@ -7138,9 +7147,6 @@ packages:
|
||||
resolution: {integrity: sha512-SIEkjrG7cZ9GWZQYk/mH+mWtcRPly/3ibVuXO/tP/MFoWz6KiRK77tSMq6YQBPl7RljPtXPQ/JhxbNuCdi1bNw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
dns2@2.1.0:
|
||||
resolution: {integrity: sha512-m27K11aQalRbmUs7RLaz6aPyceLjAoqjPRNTdE7qUouQpl+PC8Bi67O+i9SuJUPbQC8dxFrczAxfmTPuTKHNkw==}
|
||||
|
||||
doctrine@2.1.0:
|
||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -13588,6 +13594,15 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@alicloud/credentials@2.4.4':
|
||||
dependencies:
|
||||
'@alicloud/tea-typescript': 1.8.0
|
||||
httpx: 2.3.3
|
||||
ini: 1.3.8
|
||||
kitx: 2.2.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@alicloud/darabonba-array@0.1.1':
|
||||
dependencies:
|
||||
'@alicloud/tea-typescript': 1.8.0
|
||||
@@ -13639,7 +13654,7 @@ snapshots:
|
||||
|
||||
'@alicloud/gateway-pop@0.0.6':
|
||||
dependencies:
|
||||
'@alicloud/credentials': 2.4.3
|
||||
'@alicloud/credentials': 2.4.4
|
||||
'@alicloud/darabonba-array': 0.1.1
|
||||
'@alicloud/darabonba-encode-util': 0.0.2
|
||||
'@alicloud/darabonba-map': 0.0.1
|
||||
@@ -13673,7 +13688,7 @@ snapshots:
|
||||
|
||||
'@alicloud/openapi-core@1.0.4':
|
||||
dependencies:
|
||||
'@alicloud/credentials': 2.4.3
|
||||
'@alicloud/credentials': 2.4.4
|
||||
'@alicloud/gateway-pop': 0.0.6
|
||||
'@alicloud/gateway-spi': 0.0.8
|
||||
'@darabonba/typescript': 1.0.3
|
||||
@@ -15432,12 +15447,84 @@ snapshots:
|
||||
dependencies:
|
||||
'@better-scroll/core': 2.5.1
|
||||
|
||||
'@certd/commercial-core@1.36.1(better-sqlite3@11.10.0)(encoding@0.1.13)(mysql2@3.14.1)(pg@8.16.0)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@18.19.100)(typescript@5.8.3))':
|
||||
dependencies:
|
||||
'@certd/basic': link:packages/core/basic
|
||||
'@certd/lib-server': link:packages/libs/lib-server
|
||||
'@certd/pipeline': link:packages/core/pipeline
|
||||
'@certd/plugin-plus': 1.36.1(encoding@0.1.13)
|
||||
'@certd/plus-core': 1.36.1
|
||||
'@midwayjs/core': 3.20.4
|
||||
'@midwayjs/koa': 3.20.5
|
||||
'@midwayjs/logger': 3.4.2
|
||||
'@midwayjs/typeorm': 3.20.4
|
||||
alipay-sdk: 4.14.0
|
||||
dayjs: 1.11.13
|
||||
typeorm: 0.3.24(better-sqlite3@11.10.0)(mysql2@3.14.1)(pg@8.16.0)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@18.19.100)(typescript@5.8.3))
|
||||
wechatpay-node-v3: 2.2.1
|
||||
transitivePeerDependencies:
|
||||
- '@google-cloud/spanner'
|
||||
- '@sap/hana-client'
|
||||
- babel-plugin-macros
|
||||
- better-sqlite3
|
||||
- encoding
|
||||
- hdb-pool
|
||||
- ioredis
|
||||
- mongodb
|
||||
- mssql
|
||||
- mysql2
|
||||
- oracledb
|
||||
- pg
|
||||
- pg-native
|
||||
- pg-query-stream
|
||||
- proxy-agent
|
||||
- redis
|
||||
- reflect-metadata
|
||||
- sql.js
|
||||
- sqlite3
|
||||
- supports-color
|
||||
- ts-node
|
||||
- typeorm-aurora-data-api-driver
|
||||
|
||||
'@certd/cv4pve-api-javascript@8.4.1':
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@certd/plugin-plus@1.36.1(encoding@0.1.13)':
|
||||
dependencies:
|
||||
'@alicloud/pop-core': 1.8.0
|
||||
'@baiducloud/sdk': 1.0.3
|
||||
'@certd/basic': link:packages/core/basic
|
||||
'@certd/lib-k8s': link:packages/libs/lib-k8s
|
||||
'@certd/pipeline': link:packages/core/pipeline
|
||||
'@certd/plugin-cert': link:packages/plugins/plugin-cert
|
||||
'@certd/plugin-lib': link:packages/plugins/plugin-lib
|
||||
'@certd/plus-core': 1.36.1
|
||||
ali-oss: 6.23.0
|
||||
baidu-aip-sdk: 4.16.16
|
||||
basic-ftp: 5.0.5
|
||||
cos-nodejs-sdk-v5: 2.14.7
|
||||
crypto-js: 4.2.0
|
||||
dayjs: 1.11.13
|
||||
form-data: 4.0.2
|
||||
https-proxy-agent: 7.0.6
|
||||
js-yaml: 4.1.0
|
||||
jsencrypt: 3.3.2
|
||||
jsrsasign: 11.1.0
|
||||
qiniu: 7.14.0
|
||||
tencentcloud-sdk-nodejs: 4.1.37(encoding@0.1.13)
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- proxy-agent
|
||||
- supports-color
|
||||
|
||||
'@certd/plus-core@1.36.1':
|
||||
dependencies:
|
||||
'@certd/basic': link:packages/core/basic
|
||||
dayjs: 1.11.13
|
||||
|
||||
'@colors/colors@1.5.0':
|
||||
optional: true
|
||||
|
||||
@@ -21030,8 +21117,6 @@ snapshots:
|
||||
test-value: 3.0.0
|
||||
walk-back: 5.1.1
|
||||
|
||||
dns2@2.1.0: {}
|
||||
|
||||
doctrine@2.1.0:
|
||||
dependencies:
|
||||
esutils: 2.0.3
|
||||
@@ -21514,13 +21599,13 @@ snapshots:
|
||||
resolve: 1.22.10
|
||||
semver: 6.3.1
|
||||
|
||||
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8):
|
||||
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8):
|
||||
dependencies:
|
||||
eslint: 7.32.0
|
||||
prettier: 2.8.8
|
||||
prettier-linter-helpers: 1.0.0
|
||||
optionalDependencies:
|
||||
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
||||
eslint-config-prettier: 8.10.0(eslint@8.57.0)
|
||||
|
||||
eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8):
|
||||
dependencies:
|
||||
@@ -24228,7 +24313,7 @@ snapshots:
|
||||
eslint: 7.32.0
|
||||
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
||||
eslint-plugin-node: 11.1.0(eslint@7.32.0)
|
||||
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8)
|
||||
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8)
|
||||
execa: 5.1.1
|
||||
inquirer: 7.3.3
|
||||
json5: 2.2.3
|
||||
|
||||
Reference in New Issue
Block a user