mirror of
https://github.com/certd/certd.git
synced 2026-04-05 07:20:56 +08:00
Compare commits
24 Commits
alert-auto
...
v1.36.15
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb7341f1f7 | ||
|
|
f327daa12d | ||
|
|
2872b9fbf9 | ||
|
|
cedd5c9c96 | ||
|
|
60e6aa9b54 | ||
|
|
541f482518 | ||
|
|
4019b7939a | ||
|
|
013b9c4c7c | ||
|
|
79addfda42 | ||
|
|
8546bda471 | ||
|
|
0770f174a1 | ||
|
|
5f4a89cecc | ||
|
|
cbe0b1c5a6 | ||
|
|
0af193c505 | ||
|
|
fdcfcc77a0 | ||
|
|
06d166d0d7 | ||
|
|
b1b3e39fcd | ||
|
|
5ec025a3b9 | ||
|
|
58b7fbcf75 | ||
|
|
be053d47e4 | ||
|
|
fae1981161 | ||
|
|
fd95549de9 | ||
|
|
ff10bc05ec | ||
|
|
eb8cd53de2 |
@@ -1,21 +1,28 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: 报告一个错误或问题
|
||||
title: "[BUG] "
|
||||
labels: bug
|
||||
---
|
||||
|
||||
|
||||
> 感谢您支持certd,请按如下规范提交issue
|
||||
> 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||
|
||||
|
||||
## 一、问题描述
|
||||
# bug提交
|
||||
## 1、问题描述
|
||||
`请在此处简要描述你所遇到的问题,必要时请贴出相关截图辅助理解和定位`
|
||||
|
||||
### 复现步骤
|
||||
### 2、复现步骤
|
||||
`请描述复现问题的详细步骤`
|
||||
`如果非示例页面的问题,最好能提供最小复现示例的代码、或者仓库链接`
|
||||
|
||||
|
||||
### 报错截图
|
||||
### 3.报错截图
|
||||
`请贴出报错日志截图`
|
||||
|
||||
### 效果截图
|
||||
### 4、效果截图
|
||||
`请贴出效果截图`
|
||||
#### 1. 期望效果
|
||||
|
||||
#### 2. 实际效果
|
||||
#### 4.1. 期望效果
|
||||
|
||||
#### 4.2. 实际效果
|
||||
36
.github/ISSUE_TEMPLATE/dns.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/dns.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: DNS Provider Apply
|
||||
about: 请求支持新的域名提供商
|
||||
title: "[DNS] "
|
||||
labels: feature
|
||||
---
|
||||
|
||||
|
||||
> 感谢您支持certd,请按如下规范提交issue
|
||||
> 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||
|
||||
# 新域名提供商支持申请
|
||||
|
||||
## 1. 基本信息
|
||||
请填写如下内容:
|
||||
|
||||
1. 域名提供商名称:
|
||||
|
||||
|
||||
2. 管理页面地址:
|
||||
|
||||
|
||||
3. 是否有API接口,接口地址:
|
||||
|
||||
|
||||
4. 如果没有API接口,网页登录是否有验证码:
|
||||
|
||||
|
||||
5. 是否可以提供测试账号?(如果可以请留下联系方式或者加作者好友)
|
||||
|
||||
|
||||
|
||||
## 2. 截图
|
||||
|
||||
`域名管理页面截图`
|
||||
|
||||
23
.github/ISSUE_TEMPLATE/feature.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/feature.md
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: 新需求、新特性
|
||||
title: "[Feature] "
|
||||
labels: feature
|
||||
---
|
||||
|
||||
> > 感谢您支持certd,请按如下规范提交issue
|
||||
> 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||
|
||||
|
||||
# 新需求申请
|
||||
|
||||
## 1. 需求描述,需求背景
|
||||
`请在此处简要描述你所遇到的问题,必要时请贴出相关截图辅助理解`
|
||||
|
||||
|
||||
## 2. 期望效果
|
||||
`必要时可以截图描述你的期望效果`
|
||||
|
||||
|
||||
## 3. 你的解决方案
|
||||
`如果你有解决方案,请描述你的方案`
|
||||
36
.github/ISSUE_TEMPLATE/plugin.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/plugin.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: Plugin Apply
|
||||
about: 请求支持新部署插件
|
||||
title: "[Plugin] "
|
||||
labels: feature
|
||||
---
|
||||
|
||||
> > 感谢您支持certd,请按如下规范提交issue
|
||||
> 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||
|
||||
# 新部署插件申请支持
|
||||
|
||||
## 1. 需求描述
|
||||
`请在此处简要描述你的需求`
|
||||
|
||||
|
||||
## 2. 要部署证书应用的信息
|
||||
|
||||
1. 应用名称:
|
||||
|
||||
|
||||
2. 应用网址/项目地址/官方网站:
|
||||
|
||||
|
||||
3. 管理证书界面截图(或者手动部署证书方式介绍及截图):
|
||||
|
||||
|
||||
4. 是否有API接口,接口地址:
|
||||
|
||||
|
||||
5. 如果没有API接口,网页登录是否需要验证码:
|
||||
|
||||
|
||||
6. 是否可以提供测试账号?(如果可以请留下联系方式或者加作者好友)
|
||||
|
||||
|
||||
17
CHANGELOG.md
17
CHANGELOG.md
@@ -3,6 +3,23 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复 https://cas.undefined.aliyuncs.com 的bug ([60e6aa9](https://github.com/certd/certd/commit/60e6aa9b54a761a47e39acee4a1ff947a745be27))
|
||||
* 修复阿里云clb api接口没有使用region的问题 ([0770f17](https://github.com/certd/certd/commit/0770f174a14313e28d08113e69829ef6cc02d719))
|
||||
* 修复站点监控使用自定义dns解析域名报错的bug ([eb8cd53](https://github.com/certd/certd/commit/eb8cd53de27991321e36dd14e5ce95f42b51351f))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 部署到阿里云支持选择bucket和域名 ([013b9c4](https://github.com/certd/certd/commit/013b9c4c7c2adf485d086123ccea448719577fd4))
|
||||
* 清理数据库备份的临时目录 ([fd95549](https://github.com/certd/certd/commit/fd95549de9a5d8cec09772ee2630bb7521e15e1f))
|
||||
* 添加免费通知,OneBot V11协议通知支持 ([#491](https://github.com/certd/certd/issues/491)) [@ayakasuki](https://github.com/ayakasuki) ([be053d4](https://github.com/certd/certd/commit/be053d47e41084f817882400882b64143d036d1a))
|
||||
* 支持webhook部署证书 ([cbe0b1c](https://github.com/certd/certd/commit/cbe0b1c5a6538f232e9a63f1693d20d5acf0a306))
|
||||
* 注册时支持填写用户名 ([fdcfcc7](https://github.com/certd/certd/commit/fdcfcc77a0db87954e0b026635d3ccdd9bc6cee8))
|
||||
* add start:server npm script for quick server launch from root directory ([#484](https://github.com/certd/certd/issues/484)) [@orzyyyy](https://github.com/orzyyyy) ([fae1981](https://github.com/certd/certd/commit/fae1981161080f698c3f1263b712306d63baae64))
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
* 登录宝塔面板,在菜单栏中点击 Docker,首次进入会提示安装Docker服务,点击立即安装,按提示完成安装
|
||||
|
||||
### 2、部署certd
|
||||
以下两种方式人选一种:
|
||||
以下两种方式任选一种:
|
||||
|
||||
#### 2.1 应用商店方式一键部署【推荐】
|
||||
|
||||
* 在宝塔Docker应用商店中找到`certd`(要先点右上角更新应用)
|
||||
|
||||
@@ -2,19 +2,24 @@
|
||||
|
||||
## 配置步骤
|
||||
|
||||
1. 创建应用,获取APPID
|
||||
|
||||
1. 注册支付宝商家账号
|
||||
* 开通电脑网站支付产品(需营业执照): https://b.alipay.com/page/product-workspace/all-product
|
||||
|
||||
|
||||
2. 开放平台,创建应用,获取APPID
|
||||
* 登录支付宝开放平台,进入开发者中心,创建网页应用,获取应用的AppId(左上角复制)
|
||||
* 开发者中心:https://open.alipay.com/develop/manage
|
||||
|
||||
|
||||
2. 进入应用详情,选择开发设置,配置接口加签方式 (选择密钥类型)
|
||||
3. 进入应用详情,选择开发设置,配置接口加签方式 (选择密钥类型)
|
||||
|
||||
* 参考文档:https://opendocs.alipay.com/common/02kdnc?pathHash=fb0c752a
|
||||
* 此步骤完成后,可以获取应用的私钥、支付宝公钥。
|
||||
* 注意:支付宝不会保存应用的私钥,你需要自己保管好私钥。
|
||||
|
||||
|
||||
3. 在Certd后台配置支付宝
|
||||
4. 在Certd后台配置支付宝
|
||||
|
||||
* 进入“系统”->"设置"->“支付设置”
|
||||
* 启用支付宝,选择“支付宝配置”,点击添加
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.36.14"
|
||||
"version": "1.36.15"
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"start": "lerna bootstrap --hoist",
|
||||
"start:server": "cd ./packages/ui/certd-server && npm start",
|
||||
"devb": "lerna run dev-build",
|
||||
"i-all": "lerna link && lerna exec npm install ",
|
||||
"publish": "npm run prepublishOnly2 && lerna publish --force-publish=pro/plus-core --conventional-commits --create-release github && npm run afterpublishOnly && npm run commitAll",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/publishlab/node-acme-client/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.36.14](https://github.com/publishlab/node-acme-client/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"type": "module",
|
||||
"module": "scr/index.js",
|
||||
"main": "src/index.js",
|
||||
@@ -18,7 +18,7 @@
|
||||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.36.14",
|
||||
"@certd/basic": "^1.36.15",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
@@ -1 +1 @@
|
||||
23:38
|
||||
23:18
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -17,8 +17,8 @@
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.36.14",
|
||||
"@certd/plus-core": "^1.36.14",
|
||||
"@certd/basic": "^1.36.15",
|
||||
"@certd/plus-core": "^1.36.15",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/jdcloud",
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"description": "jdcloud openApi sdk",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -17,7 +17,7 @@
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.36.14",
|
||||
"@certd/basic": "^1.36.15",
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -27,10 +27,10 @@
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.36.14",
|
||||
"@certd/basic": "^1.36.14",
|
||||
"@certd/pipeline": "^1.36.14",
|
||||
"@certd/plus-core": "^1.36.14",
|
||||
"@certd/acme-client": "^1.36.15",
|
||||
"@certd/basic": "^1.36.15",
|
||||
"@certd/pipeline": "^1.36.15",
|
||||
"@certd/plus-core": "^1.36.15",
|
||||
"@midwayjs/cache": "~3.14.0",
|
||||
"@midwayjs/core": "~3.20.3",
|
||||
"@midwayjs/i18n": "~3.20.3",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -16,10 +16,10 @@
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.36.14",
|
||||
"@certd/basic": "^1.36.14",
|
||||
"@certd/pipeline": "^1.36.14",
|
||||
"@certd/plugin-lib": "^1.36.14",
|
||||
"@certd/acme-client": "^1.36.15",
|
||||
"@certd/basic": "^1.36.15",
|
||||
"@certd/pipeline": "^1.36.15",
|
||||
"@certd/plugin-lib": "^1.36.15",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jszip": "^3.10.1",
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持webhook部署证书 ([cbe0b1c](https://github.com/certd/certd/commit/cbe0b1c5a6538f232e9a63f1693d20d5acf0a306))
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-lib",
|
||||
"private": false,
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"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.14",
|
||||
"@certd/pipeline": "^1.36.14",
|
||||
"@certd/basic": "^1.36.15",
|
||||
"@certd/pipeline": "^1.36.15",
|
||||
"@kubernetes/client-node": "0.21.0",
|
||||
"ali-oss": "^6.22.0",
|
||||
"basic-ftp": "^5.0.5",
|
||||
|
||||
@@ -45,8 +45,8 @@ export class SshAccess extends BaseAccess {
|
||||
title: "私钥登录",
|
||||
helper: "私钥或密码必填一项",
|
||||
component: {
|
||||
name: "a-textarea",
|
||||
vModel: "value",
|
||||
name: "pem-input",
|
||||
vModel: "modelValue",
|
||||
},
|
||||
encrypt: true,
|
||||
})
|
||||
|
||||
@@ -9,4 +9,5 @@ VITE_APP_COPYRIGHT_URL=https://certd.handsfree.work
|
||||
VITE_APP_LOGO=static/images/logo/logo.svg
|
||||
VITE_APP_LOGIN_LOGO=static/images/logo/rect-black.svg
|
||||
VITE_APP_PROJECT_PATH=https://github.com/certd/certd
|
||||
VITE_APP_NAMESPACE=fs
|
||||
VITE_APP_NAMESPACE=fs
|
||||
VITE_APP_VIP_PRODUCT_URL=http://localhost:1017/subject#/product/list
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 部署到阿里云支持选择bucket和域名 ([013b9c4](https://github.com/certd/certd/commit/013b9c4c7c2adf485d086123ccea448719577fd4))
|
||||
* 支持webhook部署证书 ([cbe0b1c](https://github.com/certd/certd/commit/cbe0b1c5a6538f232e9a63f1693d20d5acf0a306))
|
||||
* 注册时支持填写用户名 ([fdcfcc7](https://github.com/certd/certd/commit/fdcfcc77a0db87954e0b026635d3ccdd9bc6cee8))
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -103,8 +103,8 @@
|
||||
"zod-defaults": "^0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.36.14",
|
||||
"@certd/pipeline": "^1.36.14",
|
||||
"@certd/lib-iframe": "^1.36.15",
|
||||
"@certd/pipeline": "^1.36.15",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="pem-input">
|
||||
<FileInput v-bind="fileInput" class="mb-5" type="primary" text="选择文件" @change="onChange" />
|
||||
<a-textarea v-bind="textarea" :value="modelValue" @update:value="emitValue"></a-textarea>
|
||||
<a-textarea placeholder="或直接粘贴" v-bind="textarea" :value="modelValue" @update:value="emitValue"></a-textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -27,7 +27,7 @@ function onChange(e: any) {
|
||||
const size = file.size;
|
||||
if (size > 100 * 1024) {
|
||||
notification.error({
|
||||
message: "文件超过100k,请选择正确的证书文件",
|
||||
message: "文件超过100k,请选择正确的文件",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,6 +100,8 @@ const getOptions = async () => {
|
||||
const list = res?.list || res || [];
|
||||
if (list.length > 0) {
|
||||
message.value = "获取数据成功,请从下拉框中选择";
|
||||
} else {
|
||||
message.value = "获取数据成功,没有数据";
|
||||
}
|
||||
optionsRef.value = list;
|
||||
|
||||
|
||||
@@ -145,6 +145,8 @@ const getOptions = async () => {
|
||||
const list = res?.list || res || [];
|
||||
if (list.length > 0) {
|
||||
message.value = "获取数据成功,请从下拉框中选择";
|
||||
} else {
|
||||
message.value = "获取数据成功,没有数据";
|
||||
}
|
||||
optionsRef.value = list;
|
||||
pagerRef.value.total = list.length;
|
||||
|
||||
@@ -32,6 +32,13 @@
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="email" tab="邮箱注册" :disabled="!settingsStore.sysPublic.emailRegisterEnabled">
|
||||
<template v-if="registerType === 'email'">
|
||||
<a-form-item required has-feedback name="username" label="用户名" :rules="rules.username">
|
||||
<a-input v-model:value="formState.username" placeholder="用户名" size="large" autocomplete="off">
|
||||
<template #prefix>
|
||||
<fs-icon icon="ion:person-outline"></fs-icon>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item required has-feedback name="email" label="邮箱">
|
||||
<a-input v-model:value="formState.email" placeholder="邮箱" size="large" autocomplete="off">
|
||||
<template #prefix>
|
||||
|
||||
@@ -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.15](https://github.com/certd/certd/compare/v1.36.14...v1.36.15) (2025-08-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复 https://cas.undefined.aliyuncs.com 的bug ([60e6aa9](https://github.com/certd/certd/commit/60e6aa9b54a761a47e39acee4a1ff947a745be27))
|
||||
* 修复阿里云clb api接口没有使用region的问题 ([0770f17](https://github.com/certd/certd/commit/0770f174a14313e28d08113e69829ef6cc02d719))
|
||||
* 修复站点监控使用自定义dns解析域名报错的bug ([eb8cd53](https://github.com/certd/certd/commit/eb8cd53de27991321e36dd14e5ce95f42b51351f))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 部署到阿里云支持选择bucket和域名 ([013b9c4](https://github.com/certd/certd/commit/013b9c4c7c2adf485d086123ccea448719577fd4))
|
||||
* 清理数据库备份的临时目录 ([fd95549](https://github.com/certd/certd/commit/fd95549de9a5d8cec09772ee2630bb7521e15e1f))
|
||||
* 添加免费通知,OneBot V11协议通知支持 ([#491](https://github.com/certd/certd/issues/491)) [@ayakasuki](https://github.com/ayakasuki) ([be053d4](https://github.com/certd/certd/commit/be053d47e41084f817882400882b64143d036d1a))
|
||||
* 支持webhook部署证书 ([cbe0b1c](https://github.com/certd/certd/commit/cbe0b1c5a6538f232e9a63f1693d20d5acf0a306))
|
||||
* 注册时支持填写用户名 ([fdcfcc7](https://github.com/certd/certd/commit/fdcfcc77a0db87954e0b026635d3ccdd9bc6cee8))
|
||||
|
||||
## [1.36.14](https://github.com/certd/certd/compare/v1.36.13...v1.36.14) (2025-07-28)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-server",
|
||||
"version": "1.36.14",
|
||||
"version": "1.36.15",
|
||||
"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.14",
|
||||
"@certd/basic": "^1.36.14",
|
||||
"@certd/commercial-core": "^1.36.14",
|
||||
"@certd/acme-client": "^1.36.15",
|
||||
"@certd/basic": "^1.36.15",
|
||||
"@certd/commercial-core": "^1.36.15",
|
||||
"@certd/cv4pve-api-javascript": "^8.4.1",
|
||||
"@certd/jdcloud": "^1.36.14",
|
||||
"@certd/lib-huawei": "^1.36.14",
|
||||
"@certd/lib-k8s": "^1.36.14",
|
||||
"@certd/lib-server": "^1.36.14",
|
||||
"@certd/midway-flyway-js": "^1.36.14",
|
||||
"@certd/pipeline": "^1.36.14",
|
||||
"@certd/plugin-cert": "^1.36.14",
|
||||
"@certd/plugin-lib": "^1.36.14",
|
||||
"@certd/plugin-plus": "^1.36.14",
|
||||
"@certd/plus-core": "^1.36.14",
|
||||
"@certd/jdcloud": "^1.36.15",
|
||||
"@certd/lib-huawei": "^1.36.15",
|
||||
"@certd/lib-k8s": "^1.36.15",
|
||||
"@certd/lib-server": "^1.36.15",
|
||||
"@certd/midway-flyway-js": "^1.36.15",
|
||||
"@certd/pipeline": "^1.36.15",
|
||||
"@certd/plugin-cert": "^1.36.15",
|
||||
"@certd/plugin-lib": "^1.36.15",
|
||||
"@certd/plugin-plus": "^1.36.15",
|
||||
"@certd/plus-core": "^1.36.15",
|
||||
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120",
|
||||
"@huaweicloud/huaweicloud-sdk-core": "^3.1.120",
|
||||
"@koa/cors": "^5.0.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Controller, Get, Inject, Provide } from '@midwayjs/core';
|
||||
import {Body, Controller, Get, Inject, Post, Provide} from '@midwayjs/core';
|
||||
import { BaseController, Constants, FileService, SysSettingsService, SysSiteInfo } from '@certd/lib-server';
|
||||
import { http, logger } from '@certd/basic';
|
||||
import { isComm } from '@certd/plus-core';
|
||||
@@ -46,4 +46,10 @@ export class AppController extends BaseController {
|
||||
this.ctx.response.redirect(redirect);
|
||||
this.ctx.response.set('Cache-Control', 'public,max-age=25920');
|
||||
}
|
||||
|
||||
@Post('/webhook', { summary: Constants.per.guest })
|
||||
public async webhook( @Body() body: any) {
|
||||
logger.info('webhook', JSON.stringify(body))
|
||||
return this.ok("success")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,10 +40,18 @@ export class RegisterController extends BaseController {
|
||||
throw new Error('当前站点已禁止自助注册功能');
|
||||
}
|
||||
|
||||
if (body.username && ["admin","certd"].includes(body.username) ) {
|
||||
throw new Error('用户名不能为保留字');
|
||||
}
|
||||
|
||||
if (body.type === 'username') {
|
||||
if (sysPublicSettings.usernameRegisterEnabled === false) {
|
||||
throw new Error('当前站点已禁止用户名注册功能');
|
||||
}
|
||||
if (!body.username) {
|
||||
throw new Error('用户名不能为空');
|
||||
}
|
||||
|
||||
await this.codeService.checkCaptcha(body.randomStr, body.imgCode);
|
||||
const newUser = await this.userService.register(body.type, {
|
||||
username: body.username,
|
||||
@@ -64,6 +72,7 @@ export class RegisterController extends BaseController {
|
||||
throwError: true,
|
||||
});
|
||||
const newUser = await this.userService.register(body.type, {
|
||||
username: body.username,
|
||||
phoneCode: body.phoneCode,
|
||||
mobile: body.mobile,
|
||||
password: body.password,
|
||||
@@ -81,6 +90,7 @@ export class RegisterController extends BaseController {
|
||||
throwError: true,
|
||||
});
|
||||
const newUser = await this.userService.register(body.type, {
|
||||
username: body.username,
|
||||
email: body.email,
|
||||
password: body.password,
|
||||
} as any);
|
||||
|
||||
@@ -1,60 +1,110 @@
|
||||
import { LocalCache } from '@certd/basic';
|
||||
import dnsSdk from 'dns'
|
||||
import {LocalCache, logger} from '@certd/basic';
|
||||
import dnsSdk, {AnyRecord} from 'dns'
|
||||
import {LookupAddress} from "node:dns";
|
||||
|
||||
const dns = dnsSdk.promises
|
||||
|
||||
export class DnsCustom{
|
||||
resolver: any;
|
||||
private resolver: dnsSdk.promises.Resolver;
|
||||
// private cache = new LRUCache<string, any>({
|
||||
// max: 1000,
|
||||
// ttl: 1000 * 60 * 5,
|
||||
// });
|
||||
|
||||
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)
|
||||
// async lookup(hostname:string,options?:{ family: any, hints: number, all: boolean }):Promise<LookupAddress[]>{
|
||||
// const cacheKey = hostname + JSON.stringify(options)
|
||||
// let res = this.cache.get(cacheKey)
|
||||
// if (res){
|
||||
// return res
|
||||
// }
|
||||
// res = await this.doLookup(hostname,options)
|
||||
// this.cache.set(cacheKey,res)
|
||||
// return res
|
||||
// }
|
||||
async lookup(hostname:string,options?:{ family: any, hints: number, all: boolean }):Promise<LookupAddress[]>{
|
||||
// { family: undefined, hints: 0, all: true }
|
||||
let v4:LookupAddress[] = []
|
||||
let v6:LookupAddress[] = []
|
||||
let errors = []
|
||||
const queryV6 = async ()=>{
|
||||
try{
|
||||
const list = await this.resolver.resolve6(hostname)
|
||||
if (list && list.length > 0) {
|
||||
v6 = list.map(item=>{
|
||||
return {
|
||||
address: item,
|
||||
family: 6
|
||||
}
|
||||
})
|
||||
}
|
||||
}catch (e) {
|
||||
logger.warn("query v6 error",e)
|
||||
errors.push(e)
|
||||
}
|
||||
}
|
||||
let v4 = []
|
||||
let v6 = []
|
||||
const queryV4 = async ()=>{
|
||||
try{
|
||||
const list =await this.resolver.resolve4(hostname)
|
||||
if (list && list.length > 0) {
|
||||
v4 = list.map(item=>{
|
||||
return {
|
||||
address: item,
|
||||
family: 4
|
||||
}
|
||||
})
|
||||
}
|
||||
}catch (e) {
|
||||
logger.warn("query v4 error",e)
|
||||
errors.push(e)
|
||||
}
|
||||
}
|
||||
|
||||
const queries:Promise<any>[] = []
|
||||
|
||||
|
||||
const {family, all} = options
|
||||
if(family === 6 && !all){
|
||||
v6= await this.resolver.resolve6(hostname)
|
||||
if (all){
|
||||
queries.push(queryV6())
|
||||
queries.push(queryV4())
|
||||
}else{
|
||||
if(family === 6 ){
|
||||
queries.push(queryV6())
|
||||
}
|
||||
if(family === 4 ){
|
||||
queries.push(queryV4())
|
||||
}
|
||||
}
|
||||
if(family === 4 && !all){
|
||||
v4 = await this.resolver.resolve4(hostname)
|
||||
await Promise.all(queries)
|
||||
const res = [...v4,...v6]
|
||||
if(res.length === 0){
|
||||
if (errors.length > 0){
|
||||
const e = new Error(errors[0])
|
||||
// @ts-ignore
|
||||
e.errors = errors
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
if(all){
|
||||
v4 = await this.resolver.resolve4(hostname)
|
||||
v6 = await this.resolver.resolve6(hostname)
|
||||
}
|
||||
|
||||
return [...v4,...v6,...cnameIps]
|
||||
return res
|
||||
}
|
||||
|
||||
async resolve4(hostname:string,options:any):Promise<string[]>{
|
||||
return await this.resolver.resolve4(hostname,options)
|
||||
async resolve4(hostname:string):Promise<string[]>{
|
||||
return await this.resolver.resolve4(hostname)
|
||||
}
|
||||
async resolve6(hostname:string,options:any):Promise<string[]>{
|
||||
return await this.resolver.resolve6(hostname,options)
|
||||
async resolve6(hostname:string):Promise<string[]>{
|
||||
return await this.resolver.resolve6(hostname)
|
||||
}
|
||||
async resolveAny(hostname:string,options:any):Promise<string[]>{
|
||||
return await this.resolver.resolveAny(hostname,options)
|
||||
async resolveAny(hostname:string):Promise<AnyRecord[]>{
|
||||
return await this.resolver.resolveAny(hostname)
|
||||
}
|
||||
|
||||
async resolveCname(hostname:string,options:any):Promise<string[]>{
|
||||
return await this.resolver.resolveCname(hostname,options)
|
||||
async resolveCname(hostname:string):Promise<string[]>{
|
||||
return await this.resolver.resolveCname(hostname)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -112,9 +112,9 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
|
||||
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(site.userId, UserSiteMonitorSetting);
|
||||
const dnsServer = setting.dnsServer
|
||||
let resolver = null
|
||||
let customDns = null
|
||||
if (dnsServer && dnsServer.length > 0) {
|
||||
resolver = dnsContainer.getDns(dnsServer) as any
|
||||
customDns = dnsContainer.getDns(dnsServer) as any
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -127,7 +127,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
host: site.domain,
|
||||
port: site.httpsPort,
|
||||
retryTimes,
|
||||
resolver
|
||||
customDns
|
||||
});
|
||||
|
||||
const certi: PeerCertificate = res.certificate;
|
||||
@@ -154,7 +154,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
error: null,
|
||||
checkStatus: "ok"
|
||||
};
|
||||
|
||||
logger.info(`测试站点成功:id=${updateData.id},site=${site.name},expiresTime=${updateData.certExpiresTime}`)
|
||||
if (site.ipCheck) {
|
||||
delete updateData.checkStatus
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
if (!entity) {
|
||||
return;
|
||||
}
|
||||
logger.info(`开始测试站点ip: id=${entity.id},ip=${entity.ipAddress}`)
|
||||
try {
|
||||
await this.update({
|
||||
id: entity.id,
|
||||
@@ -173,7 +174,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
};
|
||||
|
||||
await this.update(updateData);
|
||||
|
||||
logger.info(`测试站点ip成功: id=${updateData.id},ip=${entity.ipAddress},expiresTime=${updateData.certExpiresTime}`)
|
||||
return updateData
|
||||
|
||||
} catch (e) {
|
||||
@@ -231,7 +232,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
try{
|
||||
return await resolver.resolve4(domain);
|
||||
}catch (err) {
|
||||
logger.error(`[${domain}] resolve4 error`, err)
|
||||
logger.warn(`[${domain}] resolve4 error`, err)
|
||||
return []
|
||||
}
|
||||
}
|
||||
@@ -239,7 +240,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||
try{
|
||||
return await resolver.resolve6(domain);
|
||||
}catch (err) {
|
||||
logger.error(`[${domain}] resolve6 error`, err)
|
||||
logger.warn(`[${domain}] resolve6 error`, err)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { logger, safePromise, utils } from "@certd/basic";
|
||||
import { merge } from "lodash-es";
|
||||
import https from "https";
|
||||
import { PeerCertificate } from "tls";
|
||||
import {DnsCustom} from "./dns-custom.js";
|
||||
|
||||
export type SiteTestReq = {
|
||||
host: string; // 只用域名部分
|
||||
@@ -10,7 +11,7 @@ export type SiteTestReq = {
|
||||
retryTimes?: number;
|
||||
ipAddress?: string;
|
||||
|
||||
resolver?: any;
|
||||
customDns?: DnsCustom;
|
||||
};
|
||||
|
||||
export type SiteTestRes = {
|
||||
@@ -19,7 +20,9 @@ export type SiteTestRes = {
|
||||
|
||||
export class SiteTester {
|
||||
async test(req: SiteTestReq): Promise<SiteTestRes> {
|
||||
logger.info("测试站点:", JSON.stringify(req));
|
||||
const req_ = {...req}
|
||||
delete req_.customDns
|
||||
logger.info("测试站点:", JSON.stringify(req_));
|
||||
const maxRetryTimes = req.retryTimes == null ? 3 : req.retryTimes;
|
||||
let tryCount = 0;
|
||||
let result: SiteTestRes = {};
|
||||
@@ -61,15 +64,18 @@ export class SiteTester {
|
||||
servername: options.host
|
||||
};
|
||||
options.host = ipAddress;
|
||||
}else if (req.resolver ) {
|
||||
}else if (req.customDns ) {
|
||||
// 非ip address 请求时
|
||||
const resolver = req.resolver
|
||||
const customDns = req.customDns
|
||||
customLookup = async (hostname:string, options:any, callback)=> {
|
||||
console.log(hostname, options);
|
||||
|
||||
// { family: undefined, hints: 0, all: true }
|
||||
const res = await resolver.resolve(hostname, options)
|
||||
const res = await customDns.lookup(hostname, options)
|
||||
console.log("custom lookup res:",res)
|
||||
if (!res || res.length === 0) {
|
||||
callback(new Error("没有解析到IP"));
|
||||
}
|
||||
callback(null, res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,10 +458,10 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
}
|
||||
cron = cron.trim();
|
||||
if (cron.startsWith("* *")) {
|
||||
cron = cron.replace("* *", "0 0");
|
||||
cron = cron.replace("\* \*", "0 0");
|
||||
}
|
||||
if (cron.startsWith("*")) {
|
||||
cron = cron.replace("*", "0");
|
||||
cron = cron.replace("\*", "0");
|
||||
}
|
||||
const triggerId = trigger.id;
|
||||
const name = this.buildCronKey(pipelineId, triggerId);
|
||||
|
||||
@@ -175,25 +175,26 @@ export class UserService extends BaseService<UserEntity> {
|
||||
if (!user.password) {
|
||||
user.password = simpleNanoId();
|
||||
}
|
||||
if (!user.username) {
|
||||
user.username = 'user_' + simpleNanoId();
|
||||
}
|
||||
|
||||
if (type === 'username') {
|
||||
|
||||
if (user.username) {
|
||||
const username = user.username;
|
||||
const old = await this.findOne([{ username: username }, { mobile: username }, { email: username }]);
|
||||
if (old != null) {
|
||||
throw new CommonException('用户名已被注册');
|
||||
}
|
||||
} else if (type === 'mobile') {
|
||||
}
|
||||
|
||||
if (user.mobile) {
|
||||
const mobile = user.mobile;
|
||||
|
||||
user.nickName = mobile.substring(0, 3) + '****' + mobile.substring(7);
|
||||
user.nickName = user.username || mobile.substring(0, 3) + '****' + mobile.substring(7);
|
||||
const old = await this.findOne([{ username: mobile }, { mobile: mobile }, { email: mobile }]);
|
||||
if (old != null) {
|
||||
throw new CommonException('手机号已被注册');
|
||||
}
|
||||
} else if (type === 'email') {
|
||||
}
|
||||
if (user.email) {
|
||||
const email = user.email;
|
||||
const old = await this.findOne([{ username: email }, { mobile: email }, { email: email }]);
|
||||
if (old != null) {
|
||||
@@ -201,6 +202,11 @@ export class UserService extends BaseService<UserEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!user.username) {
|
||||
user.username = 'user_' + simpleNanoId();
|
||||
}
|
||||
|
||||
let newUser: UserEntity = UserEntity.of({
|
||||
username: user.username,
|
||||
password: user.password,
|
||||
|
||||
@@ -202,16 +202,22 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
|
||||
const backupDir = this.backupDir || defaultBackupDir;
|
||||
const backupFilePath = `${backupDir}/${dbZipFilename}`;
|
||||
|
||||
if (this.backupMode === 'local') {
|
||||
await this.localBackup(dbZipPath, backupDir, backupFilePath);
|
||||
} else if (this.backupMode === 'ssh') {
|
||||
await this.sshBackup(dbZipPath, backupDir, backupFilePath);
|
||||
} else if (this.backupMode === 'oss') {
|
||||
await this.ossBackup(dbZipPath, backupDir, backupFilePath);
|
||||
} else {
|
||||
throw new Error(`不支持的备份方式:${this.backupMode}`);
|
||||
try{
|
||||
if (this.backupMode === 'local') {
|
||||
await this.localBackup(dbZipPath, backupDir, backupFilePath);
|
||||
} else if (this.backupMode === 'ssh') {
|
||||
await this.sshBackup(dbZipPath, backupDir, backupFilePath);
|
||||
} else if (this.backupMode === 'oss') {
|
||||
await this.ossBackup(dbZipPath, backupDir, backupFilePath);
|
||||
} else {
|
||||
throw new Error(`不支持的备份方式:${this.backupMode}`);
|
||||
}
|
||||
}finally{
|
||||
//删除临时目录
|
||||
await fs.promises.rm(tempDir, {recursive: true, force: true});
|
||||
}
|
||||
|
||||
|
||||
this.logger.info('数据库备份完成');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import {AliyunAccess, AliyunSslClient} from '@certd/plugin-lib';
|
||||
import {AbstractTaskPlugin, IsTaskPlugin, Pager, pluginGroups, RunStrategy, TaskInput} from '@certd/pipeline';
|
||||
import {
|
||||
AliyunAccess,
|
||||
AliyunSslClient,
|
||||
createCertDomainGetterInputDefine,
|
||||
createRemoteSelectInputDefine
|
||||
} from '@certd/plugin-lib';
|
||||
import {CertInfo, CertReader} from '@certd/plugin-cert';
|
||||
import { CertApplyPluginNames} from '@certd/plugin-cert';
|
||||
import {optionsUtils} from "@certd/basic/dist/utils/util.options.js";
|
||||
import {isArray} from "lodash-es";
|
||||
@IsTaskPlugin({
|
||||
name: 'DeployCertToAliyunOSS',
|
||||
title: '阿里云-部署证书至OSS',
|
||||
@@ -15,6 +22,22 @@ import { CertApplyPluginNames} from '@certd/plugin-cert';
|
||||
},
|
||||
})
|
||||
export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: [...CertApplyPluginNames,"uploadCertToAliyun"],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo | string;
|
||||
|
||||
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||
certDomains!: string[];
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: '大区',
|
||||
component: {
|
||||
@@ -72,12 +95,14 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
|
||||
})
|
||||
bucket!: string;
|
||||
|
||||
@TaskInput({
|
||||
@TaskInput(createRemoteSelectInputDefine({
|
||||
title: '绑定的域名',
|
||||
helper: '你在阿里云OSS上绑定的域名,比如:certd.docmirror.cn',
|
||||
required: true,
|
||||
})
|
||||
domainName!: string;
|
||||
action: DeployCertToAliyunOSS.prototype.onGetDomainList.name,
|
||||
watches: ['certDomains', 'accessId','bucket'],
|
||||
}))
|
||||
domainName!: string | string[];
|
||||
|
||||
|
||||
@TaskInput({
|
||||
@@ -86,16 +111,7 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
|
||||
})
|
||||
certName!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: [...CertApplyPluginNames,"uploadCertToAliyun"],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo | string;
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: '证书服务接入点',
|
||||
@@ -134,16 +150,58 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
|
||||
await this.getAliyunCertId(access)
|
||||
this.logger.info(`bucket: ${this.bucket}, region: ${this.region}, domainName: ${this.domainName}`);
|
||||
const client = await this.getClient(access);
|
||||
await this.doRequest(client, {});
|
||||
if (typeof this.domainName === "string"){
|
||||
this.domainName = [this.domainName];
|
||||
}
|
||||
for (const domainName of this.domainName) {
|
||||
this.logger.info("开始部署证书到阿里云oss自定义域名:", domainName)
|
||||
await this.updateCert(domainName,client, {});
|
||||
}
|
||||
|
||||
this.logger.info('部署完成');
|
||||
}
|
||||
|
||||
|
||||
async updateCert(domainName:string,client: any, params: any) {
|
||||
params = client._bucketRequestParams('POST', this.bucket, {
|
||||
cname: '',
|
||||
comp: 'add',
|
||||
});
|
||||
|
||||
let certStr = ""
|
||||
if (typeof this.cert === "object" ){
|
||||
certStr = `
|
||||
<PrivateKey>${this.cert.key}</PrivateKey>
|
||||
<Certificate>${this.cert.crt}</Certificate>
|
||||
`
|
||||
}else{
|
||||
certStr = `<CertId>${this.cert}-${this.casRegion}</CertId>`
|
||||
}
|
||||
|
||||
const xml = `
|
||||
<BucketCnameConfiguration>
|
||||
<Cname>
|
||||
<Domain>${domainName}</Domain>
|
||||
<CertificateConfiguration>
|
||||
${certStr}
|
||||
<Force>true</Force>
|
||||
</CertificateConfiguration>
|
||||
</Cname>
|
||||
</BucketCnameConfiguration>`;
|
||||
params.content = xml;
|
||||
params.mime = 'xml';
|
||||
params.successStatuses = [200];
|
||||
const res = await client.request(params);
|
||||
this.checkRet(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
async getAliyunCertId(access: AliyunAccess) {
|
||||
let certId: any = this.cert;
|
||||
let certName: any = this.appendTimeSuffix("certd");
|
||||
if (typeof this.cert === "object") {
|
||||
let endpoint = `cas.${this.casRegion}.aliyuncs.com`;
|
||||
if (this.casRegion === "cn-hangzhou"){
|
||||
if (this.casRegion === "cn-hangzhou" || !this.casRegion){
|
||||
endpoint = "cas.aliyuncs.com";
|
||||
}
|
||||
const sslClient = new AliyunSslClient({
|
||||
@@ -181,8 +239,7 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
|
||||
});
|
||||
}
|
||||
|
||||
async onGetBucketList(data: any) {
|
||||
console.log('data', data)
|
||||
async onGetBucketList(data: Pager) {
|
||||
|
||||
const access = (await this.getAccess(this.accessId)) as AliyunAccess;
|
||||
const client = await this.getClient(access);
|
||||
@@ -199,43 +256,49 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
|
||||
.map(bucket => ({label: `${bucket.name}<${bucket.region}>`, value: bucket.name}));
|
||||
}
|
||||
|
||||
async doRequest(client: any, params: any) {
|
||||
params = client._bucketRequestParams('POST', this.bucket, {
|
||||
cname: '',
|
||||
comp: 'add',
|
||||
});
|
||||
async onGetDomainList(data: any) {
|
||||
|
||||
let certStr = ""
|
||||
if (typeof this.cert === "object" ){
|
||||
certStr = `
|
||||
<PrivateKey>${this.cert.key}</PrivateKey>
|
||||
<Certificate>${this.cert.crt}</Certificate>
|
||||
`
|
||||
}else{
|
||||
certStr = `<CertId>${this.cert}-${this.casRegion}</CertId>`
|
||||
const access = (await this.getAccess(this.accessId)) as AliyunAccess;
|
||||
const client = await this.getClient(access);
|
||||
|
||||
const res = await this.doListCnameRequest(client,this.bucket)
|
||||
let domains = res.data?.Cname
|
||||
if (domains == null || domains.length === 0){
|
||||
return []
|
||||
}
|
||||
if (!isArray(domains)){
|
||||
domains = [domains]
|
||||
}
|
||||
|
||||
const xml = `
|
||||
<BucketCnameConfiguration>
|
||||
<Cname>
|
||||
<Domain>${this.domainName}</Domain>
|
||||
<CertificateConfiguration>
|
||||
${certStr}
|
||||
<Force>true</Force>
|
||||
</CertificateConfiguration>
|
||||
</Cname>
|
||||
</BucketCnameConfiguration>`;
|
||||
params.content = xml;
|
||||
const options = domains.map((item: any) => {
|
||||
return {
|
||||
value: item.Domain,
|
||||
label: item.Domain,
|
||||
domain: item.Domain,
|
||||
};
|
||||
});
|
||||
return optionsUtils.buildGroupOptions(options, this.certDomains);
|
||||
}
|
||||
|
||||
|
||||
async doListCnameRequest(client: any,bucket:string) {
|
||||
const params = client._bucketRequestParams('GET', this.bucket, {
|
||||
cname: '',
|
||||
bucket
|
||||
});
|
||||
params.mime = 'xml';
|
||||
params.successStatuses = [200];
|
||||
params.xmlResponse = true;
|
||||
const res = await client.request(params);
|
||||
this.checkRet(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
checkRet(ret: any) {
|
||||
if (ret.Code != null) {
|
||||
throw new Error('执行失败:' + ret.Message);
|
||||
if (ret.Code != null || ret.status!==200) {
|
||||
throw new Error('执行失败:' + ret.Message || ret.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ export class AliyunDeployCertToSLB extends AbstractTaskPlugin {
|
||||
}
|
||||
|
||||
getCLBClientV2(access: AliyunAccess) {
|
||||
return access.getClient("slb.aliyuncs.com")
|
||||
return access.getClient(`slb.${this.regionId}.aliyuncs.com`)
|
||||
}
|
||||
|
||||
resolveListenerKey(listener: string) {
|
||||
@@ -383,7 +383,7 @@ export class AliyunDeployCertToSLB extends AbstractTaskPlugin {
|
||||
access: AliyunAccess
|
||||
}) {
|
||||
const {loadBalancerId, listenerPort, listenerProtocol, access} = data;
|
||||
const client = access.getClient("slb.aliyuncs.com")
|
||||
const client = access.getClient(`slb.${this.regionId}.aliyuncs.com`)
|
||||
|
||||
let queries = {
|
||||
RegionId: this.regionId,
|
||||
|
||||
@@ -12,3 +12,4 @@ export * from './bark/index.js';
|
||||
export * from './feishu/index.js';
|
||||
export * from './dingtalk/index.js';
|
||||
export * from './vocechat/index.js';
|
||||
export * from './onebot/index.js';
|
||||
140
packages/ui/certd-server/src/plugins/plugin-notification/onebot/index.ts
Executable file
140
packages/ui/certd-server/src/plugins/plugin-notification/onebot/index.ts
Executable file
@@ -0,0 +1,140 @@
|
||||
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
|
||||
import axios from "axios";
|
||||
|
||||
/**
|
||||
* 文档: https://github.com/botuniverse/onebot-11
|
||||
* 教程: https://ayakasuki.com/
|
||||
*/
|
||||
|
||||
@IsNotification({
|
||||
name: 'onebot',
|
||||
title: 'OneBot V11 通知',
|
||||
desc: '通过动态拼接URL发送 OneBot V11 协议消息',
|
||||
needPlus: false,
|
||||
})
|
||||
export class OneBotNotification extends BaseNotification {
|
||||
// 基础服务地址(不含路径)
|
||||
@NotificationInput({
|
||||
title: '服务地址',
|
||||
component: {
|
||||
placeholder: 'http://xxxx.xxxx.xxxx',
|
||||
},
|
||||
helper: 'OneBot 服务的基础地址(不包含action路径)',
|
||||
required: true,
|
||||
rules: [
|
||||
{
|
||||
validator: (value) => /^https?:\/\/\S+$/.test(value),
|
||||
message: '请输入有效的HTTP/HTTPS地址'
|
||||
}
|
||||
]
|
||||
})
|
||||
baseUrl = '';
|
||||
|
||||
// 目标类型选择
|
||||
@NotificationInput({
|
||||
title: '目标类型',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
options: [
|
||||
{ value: 'group', label: '群聊' },
|
||||
{ value: 'private', label: '私聊' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
helper: '选择消息发送的目标类型',
|
||||
})
|
||||
targetType = 'group';
|
||||
|
||||
// 目标ID配置
|
||||
@NotificationInput({
|
||||
title: '目标ID',
|
||||
component: {
|
||||
placeholder: '123456789',
|
||||
},
|
||||
helper: '群聊ID或用户ID(纯数字)',
|
||||
required: true,
|
||||
rules: [
|
||||
{
|
||||
validator: (value) => /^\d+$/.test(value),
|
||||
message: 'ID必须为纯数字'
|
||||
}
|
||||
]
|
||||
})
|
||||
targetId = '';
|
||||
|
||||
// 鉴权密钥(非必填)
|
||||
@NotificationInput({
|
||||
title: '鉴权密钥',
|
||||
component: {
|
||||
placeholder: 'xxxxxxxxxx',
|
||||
},
|
||||
helper: '(选填)访问API的授权令牌(无token时留空)',
|
||||
required: false, // 关键修改点
|
||||
})
|
||||
accessToken = '';
|
||||
|
||||
// 构建完整请求URL(支持无token场景)
|
||||
private buildFullUrl(): string {
|
||||
const action = this.targetType === 'group'
|
||||
? 'send_group_msg'
|
||||
: 'send_private_msg';
|
||||
|
||||
let url = `${this.baseUrl}/${action}`;
|
||||
|
||||
// 动态添加access_token参数(仅当存在时)
|
||||
if (this.accessToken) {
|
||||
url += `?access_token=${encodeURIComponent(this.accessToken)}`;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
// 构建消息内容
|
||||
private buildMessage(body: NotificationBody): string {
|
||||
return body.title
|
||||
? `${body.title}\n${body.content}`
|
||||
: body.content;
|
||||
}
|
||||
|
||||
// 构建请求体(动态字段)
|
||||
private buildRequestBody(body: NotificationBody): object {
|
||||
return {
|
||||
[this.targetType === 'group' ? 'group_id' : 'user_id']: Number(this.targetId),
|
||||
message: this.buildMessage(body),
|
||||
auto_escape: false
|
||||
};
|
||||
}
|
||||
|
||||
// 发送通知主逻辑
|
||||
async send(body: NotificationBody) {
|
||||
const fullUrl = this.buildFullUrl();
|
||||
const requestBody = this.buildRequestBody(body);
|
||||
|
||||
try {
|
||||
console.debug("[ONEBOT] 最终请求URL:", fullUrl);
|
||||
console.debug("[ONEBOT] 请求体:", JSON.stringify(requestBody));
|
||||
console.debug("[ONEBOT] 使用Token:", !!this.accessToken); // 明确token使用状态
|
||||
|
||||
const response = await axios.post(fullUrl, requestBody, {
|
||||
timeout: 5000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'Certd-Notification/1.0'
|
||||
}
|
||||
});
|
||||
|
||||
// 响应验证(保持不变)
|
||||
if (response.data?.retcode !== 0) {
|
||||
throw new Error(`[${response.data.retcode}] ${response.data.message}`);
|
||||
}
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('[ONEBOT] 请求失败:', {
|
||||
url: fullUrl,
|
||||
tokenUsed: !!this.accessToken, // 记录token使用状态
|
||||
error: error.response?.data || error.message
|
||||
});
|
||||
throw new Error(`OneBot通知发送失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './plugin-wait.js';
|
||||
export * from './plugin-deploy-to-mail.js';
|
||||
export * from './plugin-webhook.js';
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
import qs from 'qs';
|
||||
import {
|
||||
AbstractTaskPlugin,
|
||||
IsTaskPlugin,
|
||||
pluginGroups,
|
||||
RunStrategy,
|
||||
TaskInput
|
||||
} from '@certd/pipeline';
|
||||
import {CertApplyPluginNames, CertInfo, CertReader} from "@certd/plugin-cert";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'WebhookDeployCert',
|
||||
title: 'webhook方式部署证书',
|
||||
icon: 'ion:send-sharp',
|
||||
desc: '调用webhook部署证书',
|
||||
group: pluginGroups.other.key,
|
||||
showRunStrategy: false,
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
})
|
||||
export class WebhookDeployCert extends AbstractTaskPlugin {
|
||||
|
||||
@TaskInput({
|
||||
title: "域名证书",
|
||||
helper: "请选择前置任务输出的域名证书",
|
||||
component: {
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames]
|
||||
},
|
||||
required: true
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput({
|
||||
title: 'webhook地址',
|
||||
component: {
|
||||
placeholder: 'https://xxxxx.com/xxxx',
|
||||
},
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
webhook = '';
|
||||
|
||||
@TaskInput({
|
||||
title: '请求方式',
|
||||
value: 'POST',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
placeholder: 'post/put/get',
|
||||
options: [
|
||||
{value: 'POST', label: 'POST'},
|
||||
{value: 'PUT', label: 'PUT'},
|
||||
{value: 'GET', label: 'GET'},
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
method = '';
|
||||
|
||||
@TaskInput({
|
||||
title: 'ContentType',
|
||||
value: 'application/json',
|
||||
component: {
|
||||
name: 'a-auto-complete',
|
||||
options: [
|
||||
{value: 'application/json', label: 'application/json'},
|
||||
{value: 'application/x-www-form-urlencoded', label: 'application/x-www-form-urlencoded'},
|
||||
],
|
||||
},
|
||||
helper: '也可以自定义填写',
|
||||
required: true,
|
||||
})
|
||||
contentType = '';
|
||||
|
||||
@TaskInput({
|
||||
title: 'Headers',
|
||||
component: {
|
||||
name: 'a-textarea',
|
||||
vModel: 'value',
|
||||
rows: 2,
|
||||
},
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
helper: '一行一个,格式为key=value',
|
||||
required: false,
|
||||
})
|
||||
headers = '';
|
||||
|
||||
@TaskInput({
|
||||
title: '消息body模版',
|
||||
value: `{
|
||||
"id":"123",
|
||||
"crt":"\${crt}",
|
||||
"key":"\${key}"
|
||||
}`,
|
||||
component: {
|
||||
name: 'a-textarea',
|
||||
rows: 4,
|
||||
},
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
helper: `根据对应的webhook接口文档,构建一个json对象作为参数(默认值只是一个示例,一般不是正确的参数)
|
||||
变量用\${}包裹\n字符串需要双引号,使用\\n换行
|
||||
如果是get方式,将作为query参数拼接到url上
|
||||
变量列表:\${domain} 主域名、\${domains} 全部域名、\${crt} 证书、\${key} 私钥、\${ic} 中间证书、\${one} 一体证书、\${der} der证书(base64)、\${pfx} pfx证书(base64)、\${jks} jks证书(base64)、`,
|
||||
required: true,
|
||||
})
|
||||
template = '';
|
||||
|
||||
@TaskInput({
|
||||
title: '忽略证书校验',
|
||||
value: false,
|
||||
component: {
|
||||
name: 'a-switch',
|
||||
vModel: 'checked',
|
||||
},
|
||||
required: false,
|
||||
})
|
||||
skipSslVerify: boolean;
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: '成功判定',
|
||||
helper: "返回结果中包含此字符串则表示部署成功,不填则仅通过statusCode判定",
|
||||
component: {
|
||||
name: 'a-input',
|
||||
placeholder: '例如: status:"success"',
|
||||
},
|
||||
})
|
||||
successStr = '';
|
||||
|
||||
replaceTemplate(target: string, body: any, urlEncode = false) {
|
||||
let bodyStr = target;
|
||||
const keys = Object.keys(body);
|
||||
for (const key of keys) {
|
||||
let value = urlEncode ? encodeURIComponent(body[key]) : body[key];
|
||||
value = value.replaceAll(`\n`, "\\n");
|
||||
bodyStr = bodyStr.replaceAll(`\${${key}}`, value);
|
||||
|
||||
}
|
||||
return bodyStr;
|
||||
}
|
||||
|
||||
async send() {
|
||||
if (!this.template) {
|
||||
throw new Error('模版不能为空');
|
||||
}
|
||||
if (!this.webhook) {
|
||||
throw new Error('webhook不能为空');
|
||||
}
|
||||
|
||||
|
||||
const certReader = new CertReader(this.cert)
|
||||
|
||||
const replaceBody = {
|
||||
domain: certReader.getMainDomain(),
|
||||
domains: certReader.getAllDomains().join(","),
|
||||
...this.cert
|
||||
};
|
||||
const bodyStr = this.replaceTemplate(this.template, replaceBody);
|
||||
let data = JSON.parse(bodyStr);
|
||||
|
||||
let url = this.webhook;
|
||||
if (this.method.toLowerCase() === 'get') {
|
||||
const query = qs.stringify(data);
|
||||
if (url.includes('?')) {
|
||||
url = `${url}&${query}`;
|
||||
} else {
|
||||
url = `${url}?${query}`;
|
||||
}
|
||||
data = null;
|
||||
}
|
||||
|
||||
const headers: any = {};
|
||||
if (this.headers && this.headers.trim()) {
|
||||
this.headers.split('\n').forEach(item => {
|
||||
item = item.trim();
|
||||
if (item) {
|
||||
const eqIndex = item.indexOf('=');
|
||||
if (eqIndex <= 0) {
|
||||
this.logger.warn('header格式错误,请使用=号分割', item);
|
||||
return;
|
||||
}
|
||||
const key = item.substring(0, eqIndex);
|
||||
headers[key] = item.substring(eqIndex + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let res = null
|
||||
try {
|
||||
res = await this.http.request({
|
||||
url: url,
|
||||
method: this.method,
|
||||
headers: {
|
||||
'Content-Type': `${this.contentType}; charset=UTF-8`,
|
||||
...headers,
|
||||
},
|
||||
data: data,
|
||||
skipSslVerify: this.skipSslVerify,
|
||||
responseType: "text",
|
||||
returnOriginRes: true
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.response?.data) {
|
||||
throw new Error(e.message + ',' + JSON.stringify(e.response.data));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (this.successStr && !res?.data?.includes(this.successStr)) {
|
||||
throw new Error(`请求失败,期望包含:${this.successStr},实际返回:${res.data}`);
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
async onInstance() {
|
||||
}
|
||||
|
||||
async execute(): Promise<void> {
|
||||
this.logger.info(`通过webhook部署开始`);
|
||||
await this.send();
|
||||
this.logger.info('部署成功');
|
||||
}
|
||||
}
|
||||
|
||||
new WebhookDeployCert();
|
||||
@@ -122,7 +122,7 @@ export class VolcengineDeployToCLB extends AbstractTaskPlugin {
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: "监听器列表",
|
||||
helper: "选择要部署证书的监听器\n需要在监听器中选择证书中心,进行跨服务访问授权",
|
||||
helper: "选择要部署证书的监听器\n<span class='color-blue'>需要在监听器中选择证书中心,进行跨服务访问授权</span>",
|
||||
action: VolcengineDeployToCLB.prototype.onGetListenerList.name,
|
||||
watches: ["certDomains", "accessId", "regionId"],
|
||||
required: true
|
||||
|
||||
@@ -54,7 +54,7 @@ async function login() {
|
||||
'redirectTo': 'https://www.51dns.com/domain',
|
||||
'_token': _token
|
||||
}
|
||||
console.log(JSON.stringify(obj, null, 2))
|
||||
// console.log(JSON.stringify(obj, null, 2)) // Avoid logging sensitive data
|
||||
const res2 = await instance.request({
|
||||
url: 'https://www.51dns.com/login',
|
||||
method: 'post',
|
||||
|
||||
Reference in New Issue
Block a user