Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1656e91296 | ||
|
|
5b7df9c175 | ||
|
|
8d8600aaa8 | ||
|
|
54d136cc6a | ||
|
|
661293c189 | ||
|
|
d10d42e206 | ||
|
|
b780eab5f5 | ||
|
|
315e43746b | ||
|
|
526c48450b | ||
|
|
abd2dcf2e8 | ||
|
|
87defa569c | ||
|
|
b4db5518db | ||
|
|
a50b635424 | ||
|
|
40a794f624 | ||
|
|
6876790374 | ||
|
|
586725a15c | ||
|
|
34300a19a6 | ||
|
|
11def7e42a | ||
|
|
4f3fb3766e | ||
|
|
cbc3eb9453 | ||
|
|
c31bc0266a | ||
|
|
b6176d7629 | ||
|
|
bc2e78db39 | ||
|
|
fdda8985de | ||
|
|
be2f0aa435 | ||
|
|
513a5b49c1 | ||
|
|
0c50ede129 | ||
|
|
d5a17f9e6a | ||
|
|
4b09a0a27f | ||
|
|
cba38f6e12 | ||
|
|
a672043e2e | ||
|
|
e1c6d8a2d0 | ||
|
|
9041602cfd | ||
|
|
bcbefaaa35 | ||
|
|
925edef0a5 | ||
|
|
90c54fd9e0 | ||
|
|
95df56cc5c | ||
|
|
ebced940d4 | ||
|
|
b21db8da6b | ||
|
|
55c76cb89c | ||
|
|
11d0daa59a | ||
|
|
22764abd38 | ||
|
|
a7414047ee | ||
|
|
c4164c66e2 | ||
|
|
a90d1e68ee | ||
|
|
7aac1460c3 | ||
|
|
1cc1d1c03c | ||
|
|
b421798a1b | ||
|
|
f876ac99b0 | ||
|
|
4075be7849 | ||
|
|
98ef9aa479 | ||
|
|
25689efc99 | ||
|
|
a8a45d7f75 | ||
|
|
a3ef3fb5cf | ||
|
|
d782655cb4 | ||
|
|
f126f9f932 | ||
|
|
5b148b7ed9 | ||
|
|
de62abf0e7 | ||
|
|
f9e29ef041 | ||
|
|
11255a1ecf | ||
|
|
3a78cb9929 | ||
|
|
b2f8ee3836 | ||
|
|
3681d89a61 | ||
|
|
4ea3edd59e | ||
|
|
1291e98e82 | ||
|
|
09847ce074 | ||
|
|
18ee87daff | ||
|
|
2b89fba7eb | ||
|
|
41d9c3ac83 | ||
|
|
a705182b85 | ||
|
|
f8b99b81a2 | ||
|
|
ffeede38af | ||
|
|
3db216f515 | ||
|
|
4a7018ac26 | ||
|
|
0e859d32ee | ||
|
|
5840247f3e | ||
|
|
74a1873e58 | ||
|
|
f984472257 | ||
|
|
e9a4b26595 |
13
.github/workflows/deploy-demo.yml
vendored
@@ -37,8 +37,7 @@ jobs:
|
||||
- uses: GuillaumeFalourd/wait-sleep-action@v1
|
||||
with:
|
||||
time: '10' # for 60 seconds
|
||||
- name: Send HTTP request
|
||||
id: request
|
||||
- name: deploy-certd-demo
|
||||
uses: tyrrrz/action-http-request@master
|
||||
with:
|
||||
url: http://flow-openapi.aliyun.com/pipeline/webhook/lzCzlGrLCOHQaTMMt0mG
|
||||
@@ -52,4 +51,12 @@ jobs:
|
||||
retry-count: 3
|
||||
retry-delay: 5000
|
||||
|
||||
|
||||
- name: deploy-certd-doc
|
||||
uses: tyrrrz/action-http-request@master
|
||||
with:
|
||||
url: http://flow-openapi.aliyun.com/pipeline/webhook/IiSxLDp9aOhgDUxJPytv
|
||||
method: POST
|
||||
headers: |
|
||||
Content-Type: application/json
|
||||
retry-count: 3
|
||||
retry-delay: 5000
|
||||
|
||||
54
CHANGELOG.md
@@ -3,6 +3,60 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云部署大杀器报插件_还未注册错误的bug ([abd2dcf](https://github.com/certd/certd/commit/abd2dcf2e85a545321bae6451406d081f773b132))
|
||||
* 修复启动时自签证书无法保存的bug ([526c484](https://github.com/certd/certd/commit/526c48450bcd37b3ccded9b448f17de8140bdc6e))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 顶部菜单自定义 ([54d136c](https://github.com/certd/certd/commit/54d136cc6ae122f7c891b7a5c7232fe5de8e5cb5))
|
||||
* 禁用readonly用户 ([d10d42e](https://github.com/certd/certd/commit/d10d42e20619bb55a50d636b8867ff33db4e3b4b))
|
||||
* 限制其他用户流水线数量 ([315e437](https://github.com/certd/certd/commit/315e43746baf01682737f82e41579237a48409af))
|
||||
* 用户管理优化头像上传 ([661293c](https://github.com/certd/certd/commit/661293c189a3abf3cdc953b5225192372f57930d))
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复对话框全屏按钮与关闭按钮重叠的bug ([95df56c](https://github.com/certd/certd/commit/95df56cc5ca5e3eb843cd17cb7078cde47729f1e))
|
||||
* deprecated的运行时不要报错,只报警告 ([bcbefaa](https://github.com/certd/certd/commit/bcbefaaa35cf6d0eec085b3a2c5bfc7c6a8de9e1))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 更新certd本身的证书文档说明 ([0c50ede](https://github.com/certd/certd/commit/0c50ede129337b82df54575cbd2f4c2a783a0732))
|
||||
* 支持同时监听https端口,7002 ([d5a17f9](https://github.com/certd/certd/commit/d5a17f9e6afd63fda2df0981118480f25a1fac2e))
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 部署到阿里云任意云资源,阿里云部署大杀器 ([4075be7](https://github.com/certd/certd/commit/4075be7849b140acb92bd8da8a9acbf4eef85180))
|
||||
* 文件名特殊字符限制输入 ([c4164c6](https://github.com/certd/certd/commit/c4164c66e29f3ec799f98108a344806ca61e94ff))
|
||||
* 新增部署到百度云CDN插件 ([f126f9f](https://github.com/certd/certd/commit/f126f9f932d37fa01fff1accc7bdd17d349f8db5))
|
||||
* 新增部署到腾讯云CDN-v2,推荐使用 ([d782655](https://github.com/certd/certd/commit/d782655cb4dfbb74138178afbffeee76fc755115))
|
||||
* 优化cron选择器,增加下次触发时间显示 ([5b148b7](https://github.com/certd/certd/commit/5b148b7ed960ca6f7f5b733b2eadd56eeecbd4c2))
|
||||
* 支持部署到腾讯云COS ([a8a45d7](https://github.com/certd/certd/commit/a8a45d7f757820990e278533277a3deda5ba48f3))
|
||||
* 支持配置公共ZeroSSL授权 ([a90d1e6](https://github.com/certd/certd/commit/a90d1e68ee9cbc3705223457b8a86f071b150968))
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 申请证书没有使用到系统设置的http代理的bug ([3db216f](https://github.com/certd/certd/commit/3db216f515ba404cb4330fdab452971b22a50f08))
|
||||
* 修复移动任务后出现空阶段的bug ([4ea3edd](https://github.com/certd/certd/commit/4ea3edd59e93ca4f5b2e43b20dd4ef33909caddb))
|
||||
* 修复google证书*.xx.com与xx.com同时申请时报错的bug ([f8b99b8](https://github.com/certd/certd/commit/f8b99b81a23e7e9fd5e05ebd5caf355c41d67a90))
|
||||
* 允许七牛云cdn插件输入.号开头的通配符域名 ([18ee87d](https://github.com/certd/certd/commit/18ee87daff6eafc2201b58e28d85aafd3cb7a5b9))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 申请证书启用新的反代地址 ([a705182](https://github.com/certd/certd/commit/a705182b85e51157883e48f23463263793bf3c12))
|
||||
* 优化日志颜色 ([1291e98](https://github.com/certd/certd/commit/1291e98e821c5b1810aab7f0aebe3f5f5cd44a20))
|
||||
* 优化证书申请速度和成功率,反代地址优化,google基本可以稳定请求。增加请求重试。 ([41d9c3a](https://github.com/certd/certd/commit/41d9c3ac8398def541e65351cbe920d4a927182d))
|
||||
* 优化pfx密码密码输入框,让浏览器不自动填写密码 ([ffeede3](https://github.com/certd/certd/commit/ffeede38afa70c5ff6f2015516bead23d2c4df87))
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
157
README.md
@@ -17,6 +17,8 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||
* 支持sqlite,postgresql数据库
|
||||
|
||||
|
||||
|
||||
|
||||
## 二、在线体验
|
||||
|
||||
官方Demo地址,自助注册后体验
|
||||
@@ -27,6 +29,10 @@ https://certd.handsfree.work/
|
||||
> 包含敏感信息,务必自己本地部署进行生产使用
|
||||
|
||||
## 三、使用教程
|
||||
|
||||
更多教程请访问文档网站 [certd.docmirror.cn](https://certd.docmirror.cn/)
|
||||
|
||||
|
||||
本案例演示,如何配置自动申请证书,并部署到阿里云CDN,然后快要到期前自动更新证书并重新部署
|
||||
|
||||

|
||||
@@ -40,64 +46,20 @@ https://certd.handsfree.work/
|
||||
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
|
||||
|
||||
当前支持的部署插件列表
|
||||

|
||||

|
||||
|
||||
## 四、私有化部署
|
||||
|
||||
由于证书、授权信息等属于高度敏感数据,请务必私有化部署,保障数据安全
|
||||
由于证书、授权信息等属于高度敏感数据,请务必私有化部署,保障数据安全
|
||||
|
||||
### 4.1 宝塔面板一键部署
|
||||
您可以根据实际情况从如下方式中选择一种方式进行私有化部署:
|
||||
|
||||
1. 安装宝塔面板,前往 [宝塔面板](https://www.bt.cn/u/CL3JHS) 官网,选择9.2.0以上正式版的脚本下载安装
|
||||
1. [宝塔面板方式部署](./install/baota/)
|
||||
2. [1Panel面板方式部署](./install/1panel/)
|
||||
2. [Docker方式部署](./install/docker/)
|
||||
3. [源码方式部署](./install/source/)
|
||||
|
||||
2. 安装后登录宝塔面板,在菜单栏中点击 Docker,首次进入会提示安装Docker服务,点击立即安装,按提示完成安装
|
||||
|
||||
3. 安装完成后在应用商店中找到`certd`(要先点右上角更新应用),点击安装,配置域名等基本信息即可完成安装
|
||||
|
||||
### 4.2 宝塔面板容器编排部署
|
||||
|
||||
[宝塔面板容器编排部署教程](./doc/deploy/baota/baota.md)
|
||||
|
||||
### 4.3 Docker部署
|
||||
#### 1. 安装docker、docker-compose
|
||||
|
||||
1.1 准备一台云服务器
|
||||
* 【阿里云】云服务器2核2G,新老用户同享,99元/年,续费同价!【 [立即购买](https://www.aliyun.com/benefit?scm=20140722.M_10244282._.V_1&source=5176.11533457&userCode=qya11txb )】
|
||||
* 【腾讯云】云服务器2核2G,新老用户同享,99元/年,续费同价!【 [立即购买](https://cloud.tencent.com/act/cps/redirect?redirect=6094&cps_key=b3ef73330335d7a6efa4a4bbeeb6b2c9&from=console)】
|
||||
|
||||
1.2 安装docker
|
||||
|
||||
https://docs.docker.com/engine/install/
|
||||
选择对应的操作系统,按照官方文档执行命令即可
|
||||
|
||||
#### 2. 运行certd
|
||||
|
||||
[docker-compose.yaml 下载](https://gitee.com/certd/certd/raw/v2/docker/run/docker-compose.yaml)
|
||||
|
||||
当前版本号: 
|
||||
|
||||
```bash
|
||||
# 随便创建一个目录
|
||||
mkdir certd
|
||||
# 进入目录
|
||||
cd certd
|
||||
# 下载docker-compose.yaml文件,或者手动下载放到certd目录下
|
||||
wget https://gitee.com/certd/certd/raw/v2/docker/run/docker-compose.yaml
|
||||
|
||||
# 可以根据需要修改里面的配置
|
||||
# 1.修改镜像版本号【可选】
|
||||
# 2.配置数据保存路径【可选】
|
||||
# 3.修改端口号【可选】
|
||||
vi docker-compose.yaml # 【可选】
|
||||
|
||||
# 启动certd
|
||||
docker compose up -d
|
||||
|
||||
```
|
||||
> 如果提示 没有compose命令,请安装docker-compose
|
||||
> https://docs.docker.com/compose/install/linux/
|
||||
|
||||
#### 3. 镜像说明:
|
||||
#### Docker镜像说明:
|
||||
* 国内镜像地址:
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest`
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:armv7`、`[version]-armv7`
|
||||
@@ -109,25 +71,7 @@ docker compose up -d
|
||||
* 镜像构建通过`Actions`自动执行,过程公开透明,请放心使用
|
||||
* [点我查看镜像构建日志](https://github.com/certd/certd/actions/workflows/build-image.yml)
|
||||
|
||||

|
||||
|
||||
#### 4. 访问测试
|
||||
|
||||
http://your_server_ip:7001
|
||||
默认账号密码:admin/123456
|
||||
记得修改密码
|
||||
|
||||
### 4.4 源码部署
|
||||
```shell
|
||||
# 克隆代码
|
||||
git clone https://github.com/certd/certd
|
||||
git checkout v1.26.7 # 这里换成最新版本号
|
||||
cd certd
|
||||
# 启动服务
|
||||
./start.sh
|
||||
# 数据默认保存在 ./packages/ui/certd-server/data 目录下,注意数据备份
|
||||
```
|
||||
如果是windows,请先安装`git for windows` ,然后右键,选择`open git bash here`打开终端,再执行`./start.sh`命令
|
||||

|
||||
|
||||
|
||||
## 五、 升级
|
||||
@@ -151,7 +95,7 @@ docker compose up -d
|
||||
|
||||
|
||||
## 六、一些说明
|
||||
* 本项目ssl证书提供商为letencrypt
|
||||
* 本项目ssl证书提供商为letencrypt/Google/ZeroSSL
|
||||
* 申请过程遵循acme协议
|
||||
* 需要验证域名所有权,一般有两种方式(目前本项目仅支持dns-01)
|
||||
* http-01: 在网站根目录下放置一份txt文件
|
||||
@@ -165,48 +109,26 @@ docker compose up -d
|
||||
|
||||
## 七、不同平台的设置说明
|
||||
|
||||
* [Cloudflare](./docs/plugins/cf/cf.md)
|
||||
* [腾讯云](./docs/plugins/tencent/tencent.md)
|
||||
* [windows主机](./docs/plugins/host/host.md)
|
||||
* [google证书](./docs/plugins/google/google.md)
|
||||
* [群晖部署certd及证书更新教程](./docs/plugins/synology/index.md)
|
||||
|
||||
* [CNAME证书校验方式说明](./docs/feature/cname/index.md)
|
||||
* 已迁移到新的文档网站,请到常见问题章节查看
|
||||
* [最新文档站链接 https://certd.docmirror.cn](https://certd.docmirror.cn/)
|
||||
|
||||
## 八、问题处理
|
||||
### 7.1 忘记管理员密码
|
||||
解决方法如下:
|
||||
1. 修改docker-compose.yaml文件,将环境变量`certd_system_resetAdminPasswd`改为`true`
|
||||
```yaml
|
||||
services:
|
||||
certd:
|
||||
environment: # 环境变量
|
||||
- certd_system_resetAdminPasswd=false
|
||||
```
|
||||
2. 重启容器
|
||||
```shell
|
||||
docker compose up -d
|
||||
docker logs -f --tail 500 certd
|
||||
# 观察日志,当日志中输出“重置1号管理员用户的密码完成”,即可操作下一步
|
||||
```
|
||||
3. 修改docker-compose.yaml,将`certd_system_resetAdminPasswd`改回`false`
|
||||
4. 再次重启容器
|
||||
```shell
|
||||
docker compose up -d
|
||||
```
|
||||
5. 使用`admin/123456`登录系统,请及时修改管理员密码
|
||||
[重置管理员密码方法](https://certd.docmirror.cn/guide/use/forgotpasswd/)
|
||||
|
||||
## 九、联系作者
|
||||
如有疑问,欢迎加入群聊(请备注certd)
|
||||
* QQ群:141236433
|
||||
* 微信群:
|
||||

|
||||
|
||||
| 加群 | 微信群 | QQ群 |
|
||||
|---------|-------|-------|
|
||||
| 二维码 | <img height="230" src="./docs/guide/contact/images/wx.png"> | <img height="230" src="./docs/guide/contact/images/qq.png"> |
|
||||
|
||||
也可以加作者好友
|
||||
|
||||
| 加作者好友 | 微信 QQ |
|
||||
|---------|-------------------------------------------------------------|
|
||||
| 二维码 | <img height="230" src="./docs/guide/contact/images/me.png"> |
|
||||
|
||||
加作者好友
|
||||
<p align="center">
|
||||
<img height="230" src="./doc/images/me.png">
|
||||
</p>
|
||||
|
||||
## 十、捐赠
|
||||
************************
|
||||
@@ -222,18 +144,18 @@ https://afdian.com/a/greper
|
||||
|
||||
专业版特权对比
|
||||
|
||||
| 功能 | 免费版 | 专业版 |
|
||||
|---------|------------------------|-----------------------|
|
||||
| 免费证书申请 | 免费无限制 | 免费无限制 |
|
||||
| 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署等 | 支持群晖、宝塔、1Panel等,持续开发中 |
|
||||
| 发邮件功能 | 需要配置 | 免配置 |
|
||||
| 证书流水线条数 | 10条 | 无限制 |
|
||||
| 功能 | 免费版 | 专业版 |
|
||||
|---------|-------------------|-----------------------|
|
||||
| 免费证书申请 | 免费无限制 | 免费无限制 |
|
||||
| 自动部署插件 | 阿里云、腾讯云、七牛云、主机部署等 | 支持群晖、宝塔、1Panel等,持续开发中 |
|
||||
| 发邮件功能 | 需要配置 | 免配置 |
|
||||
| 证书流水线条数 | 10条 | 无限制 |
|
||||
|
||||
************************
|
||||
|
||||
## 十一、贡献代码
|
||||
|
||||
1. 本地开发 [贡献插件教程](./doc/dev/development.md)
|
||||
1. 本地开发 [贡献插件教程](https://certd.docmirror.cn/guide/development/)
|
||||
2. 作为贡献者,代表您同意您贡献的代码如下许可:
|
||||
1. 可以调整开源协议以使其更严格或更宽松。
|
||||
2. 可以用于商业用途。
|
||||
@@ -247,9 +169,12 @@ https://afdian.com/a/greper
|
||||
* 如需商业授权,请联系作者。
|
||||
|
||||
## 十三、我的其他项目(求Star)
|
||||
* [袖手GPT](https://ai.handsfree.work/) ChatGPT,国内可用,无需FQ,每日免费额度
|
||||
* [fast-crud](https://gitee.com/fast-crud/fast-crud/) 基于vue3的crud快速开发框架
|
||||
* [dev-sidecar](https://github.com/docmirror/dev-sidecar/) 直连访问github工具,无需FQ,解决github无法访问的问题
|
||||
|
||||
| 项目名称 | stars | 项目描述 |
|
||||
|---------------------------------------------------------|-------------------------------------------------------------------------------------------------------|-----------------------------------|
|
||||
| [袖手AI](https://ai.handsfree.work/) | | 袖手GPT,国内可用,无需FQ,每日免费额度 |
|
||||
| [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无法访问的问题 |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
03:13
|
||||
20:31
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
# 宝塔部署教程
|
||||
|
||||
## 编排模版部署
|
||||
|
||||
### 创建docker模版
|
||||
打开docker-compose.yaml,
|
||||
https://gitee.com/certd/certd/raw/v2/docker/run/docker-compose.yaml
|
||||
|
||||
整个内容复制下来
|
||||
|
||||
然后到宝塔里面进到docker的编排模版,新建模版
|
||||

|
||||
|
||||
### 启动应用
|
||||
|
||||

|
||||
|
||||
等待启动完成
|
||||
|
||||
### 打开应用
|
||||
|
||||
http://ip:7001
|
||||
|
||||
|
||||
## 二、一键应用部署
|
||||
需要宝塔9.2.0版本
|
||||
|
||||
### 应用商店
|
||||
进入应用商店,更新应用列表
|
||||
|
||||
### 搜索certd
|
||||
点击安装
|
||||
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 31 KiB |
@@ -1,96 +0,0 @@
|
||||
# 本地开发
|
||||
欢迎贡献插件
|
||||
|
||||
## 1.本地调试运行
|
||||
|
||||
### 克隆代码
|
||||
```shell
|
||||
|
||||
# 克隆代码
|
||||
git clone https://github.com/certd/certd
|
||||
|
||||
#进入项目目录
|
||||
cd certd
|
||||
|
||||
# 切换到最新版本代码
|
||||
git checkout v1.26.7 # 这里换成最新版本号
|
||||
|
||||
```
|
||||
|
||||
### 修改pnpm-workspace.yaml文件
|
||||
重要:否则无法正确加载专业版的access和plugin
|
||||
```yaml
|
||||
# pnpm-workspace.yaml
|
||||
packages:
|
||||
- 'packages/**' # <--------------注释掉这一行,PR时不要提交此修改
|
||||
- 'packages/ui/**'
|
||||
```
|
||||
|
||||
### 安装依赖和初始化:
|
||||
```shell
|
||||
# 安装pnpm,如果提示npm命令不存在,就需要先安装nodejs
|
||||
npm install -g pnpm@8.15.7 --registry=https://registry.npmmirror.com
|
||||
|
||||
# 使用国内镜像源,如果有代理,就不需要
|
||||
pnpm config set registry https://registry.npmmirror.com
|
||||
# 安装依赖
|
||||
pnpm install
|
||||
|
||||
# 初始化构建
|
||||
npm run init
|
||||
```
|
||||
|
||||
### 启动 server:
|
||||
```shell
|
||||
cd packages/ui/certd-server
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 启动 client:
|
||||
```shell
|
||||
cd packages/ui/certd-client
|
||||
npm run dev
|
||||
|
||||
# 会自动打开浏览器,确认正常运行
|
||||
|
||||
```
|
||||
|
||||
## 开发插件
|
||||
进入 `packages/ui/certd-server/src/plugins`
|
||||
|
||||
### 1.复制`plugin-demo`目录作为你的插件目录
|
||||
比如你想做`cloudflare`的插件,那么你可以复制`plugin-demo`目录,将其命名成`plugin-cloudflare`。
|
||||
以下均以`plugin-cloudflare`为例进行说明,你需要将其替换成你的插件名称
|
||||
|
||||
### 2. access授权
|
||||
如果这是一个新的平台,它应该有授权方式,比如accessKey accessSecret之类的
|
||||
参考`plugin-cloudflare/access.ts` 修改为你要做的平台的`access`
|
||||
这样用户就可以在`certd`后台中创建这种授权凭证了
|
||||
|
||||
### 3. dns-provider
|
||||
如果域名是这个平台进行解析的,那么你需要实现dns-provider,(申请证书需要)
|
||||
参考`plugin-cloudflare/dns-provider.ts` 修改为你要做的平台的`dns-provider`
|
||||
|
||||
### 4. plugin-deploy
|
||||
如果这个平台有需要部署证书的地方
|
||||
参考`plugin-cloudflare/plugins/plugin-deploy-to-xx.ts` 修改为你要做的平台的`plugin-deploy-to-xx`
|
||||
|
||||
### 5. 增加导入
|
||||
在`plugin-cloudflare/index.ts`中增加你的插件的`import`
|
||||
```ts
|
||||
export * from './dns-provider'
|
||||
export * from './access'
|
||||
export * from './plugins/plugin-deploy-to-xx'
|
||||
````
|
||||
|
||||
在`./src/plugins/index.ts`中增加`import`
|
||||
|
||||
```ts
|
||||
export * from "./plugin-cloudflare.js"
|
||||
```
|
||||
|
||||
## 重启服务进行调试
|
||||
刷新浏览器,检查你的插件是否工作正常, 确保能够正常进行证书申请和部署
|
||||
|
||||
## 提交PR
|
||||
我们将尽快审核PR
|
||||
|
Before Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 374 KiB |
|
Before Width: | Height: | Size: 327 KiB |
@@ -11,6 +11,8 @@ services:
|
||||
ports: # 端口映射
|
||||
# ↓↓↓↓ ---------------------------------------------------------- 如果端口有冲突,可以修改第一个7001为其他不冲突的端口号
|
||||
- "7001:7001"
|
||||
# ↓↓↓↓ ---------------------------------------------------------- https端口,可以根据实际情况,是否暴露相关服务端口
|
||||
- "7002:7002"
|
||||
dns:
|
||||
# ↓↓↓↓ ---------------------------------------------------------- 如果出现getaddrinfo ENOTFOUND等错误,可以尝试修改或注释dns配置
|
||||
- 223.5.5.5
|
||||
|
||||
@@ -5,7 +5,7 @@ import lightbox from "vitepress-plugin-lightbox";
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
title: "Certd",
|
||||
description: "Certd帮助文档,Certd是一款开源免费的全自动SSL证书管理工具;自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔。",
|
||||
description: "Certd帮助文档,Certd是一款开源免费的全自动SSL证书管理工具;证书自动化申请部署流水线;自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔。",
|
||||
markdown: {
|
||||
config: (md) => {
|
||||
// Use lightbox plugin
|
||||
@@ -23,12 +23,11 @@ export default defineConfig({
|
||||
// ],
|
||||
["meta", {
|
||||
name: "keywords",
|
||||
content: "证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具、Certd、SSL证书自动部署、证书自动化,https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署"
|
||||
}],
|
||||
["meta", {
|
||||
name: "google-site-verification",
|
||||
content: "V5XLTSnXoT15uQotwpxJoQolUo2d5UbSL-TacsyOsC0"
|
||||
content: "证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具、Certd、SSL证书自动部署、证书自动化,https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署,SSL平台,证书管理平台,证书流水线"
|
||||
}],
|
||||
["meta", { name: "google-site-verification",content: "V5XLTSnXoT15uQotwpxJoQolUo2d5UbSL-TacsyOsC0"}],
|
||||
//<meta name="baidu-site-verification" content="codeva-MiWN8Y07Ua" />
|
||||
["meta", {name: "baidu-site-verification",content: "codeva-MiWN8Y07Ua"}],
|
||||
["link", { rel: "icon", href: "/static/logo/logo.svg" }]
|
||||
],
|
||||
themeConfig: {
|
||||
@@ -95,8 +94,10 @@ export default defineConfig({
|
||||
{ text: "腾讯云密钥获取", link: "/guide/use/tencent/" },
|
||||
{ text: "连接windows主机", link: "/guide/use/host/windows.md" },
|
||||
{ text: "Google EAB获取", link: "/guide/use/google/" },
|
||||
{ text: "阿里云相关", link: "/guide/use/aliyun/" },
|
||||
{ text: "忘记密码", link: "/guide/use/forgotpasswd/" },
|
||||
{ text: "数据备份", link: "/guide/use/backup/" },
|
||||
{ text: "Certd本身的证书更新", link: "/guide/use/https/index.md" },
|
||||
{ text: "如何贡献代码", link: "/guide/development/index.md" },
|
||||
]
|
||||
},
|
||||
|
||||
@@ -2,19 +2,14 @@
|
||||
|
||||
## 1. 交流群
|
||||
如有疑问,欢迎加入群聊(请备注certd)
|
||||
### QQ群:141236433
|
||||
<p align="center">
|
||||
<img height="230" src="./images/qq.png">
|
||||
</p>
|
||||
|
||||
|
||||
### 微信群:
|
||||
<p align="center">
|
||||
<img height="230" src="./images/wx.png">
|
||||
</p>
|
||||
如有疑问,欢迎加入群聊(请备注certd)
|
||||
|
||||
| 加群 | 微信群 | QQ群 |
|
||||
|---------|-------|-------|
|
||||
| 二维码 | <img height="230" src="./images/wx.png"> | <img height="230" src="./images/qq.png"> |
|
||||
|
||||
## 2. 加作者好友
|
||||
<p align="center">
|
||||
<img height="230" src="./images/me.png">
|
||||
</p>
|
||||
|
||||
| 加作者好友 | 微信 QQ |
|
||||
|---------|-------------------------------------------------------------|
|
||||
| 二维码 | <img height="230" src="./images/me.png"> |
|
||||
|
||||
@@ -20,7 +20,7 @@ _acme-challenge.cert.com ---> xxxxx.cname.proxy.com ----> txt-record-abcdefg
|
||||
```
|
||||
* 证书颁发机构就可以从`_acme-challenge.cert.com`查到TXT记录 `txt-record-abcdefg`,从而完成域名所有权校验。
|
||||
* 以上可以看出 `xxxxx.cname.proxy.com ----> txt-record-abcdefg` 这一段`Certd`可以自动添加的。
|
||||
* 剩下的只需要在你的`proxy.com`域名中手动添加一条固定的`CNAME解析`即可
|
||||
* 剩下的只需要在你的`cert.com`域名中手动添加一条固定的`CNAME解析`即可
|
||||
|
||||
|
||||
## 3. Certd CNAME使用步骤
|
||||
@@ -36,6 +36,7 @@ _acme-challenge.cert.com ---> xxxxx.cname.proxy.com ----> txt-record-abcdefg
|
||||

|
||||

|
||||
4. 申请过程中,Certd会在`xxxxxx.cname.proxy.com`下自动添加TXT记录。
|
||||
5. 到此即可自动化申请证书了
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -23,8 +23,11 @@ https://1panel.cn/docs/installation/online_installation/
|
||||
|
||||
3. 访问测试
|
||||
|
||||
http://ip:7001
|
||||
|
||||
http://ip:7001
|
||||
https://ip:7002
|
||||
默认账号密码
|
||||
admin/123456
|
||||
登录后请及时修改密码
|
||||
|
||||
## 三、升级
|
||||
|
||||
@@ -42,3 +45,7 @@ http://ip:7001
|
||||
|
||||
> 默认数据保存在`/data/certd`目录下,可以手动备份
|
||||
> 建议配置一条 [数据库备份流水线](../../use/backup/),自动备份
|
||||
|
||||
## 五、备份恢复
|
||||
|
||||
将备份的`db.sqlite`覆盖到原来的位置即可
|
||||
|
||||
BIN
docs/guide/install/baota/images/upgrade.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
@@ -31,19 +31,26 @@
|
||||
|
||||
## 二、访问应用
|
||||
|
||||
http://ip:7001
|
||||
|
||||
http://ip:7001
|
||||
https://ip:7002
|
||||
默认账号密码
|
||||
admin/123456
|
||||
登录后请及时修改密码
|
||||
|
||||
## 三、如何升级
|
||||
|
||||
### 1. 通用方式
|
||||
### 1. 应用商店安装,直接更新镜像即可
|
||||
|
||||
先主机上拉取最新镜像,然后面板上重启容器
|
||||

|
||||
|
||||
|
||||
### 2. latest更新方式
|
||||
在主机上拉取最新镜像,然后面板上重启容器
|
||||
```shell
|
||||
docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||
```
|
||||
|
||||
### 2. 固定版本号方式
|
||||
### 3. 固定版本号方式
|
||||
|
||||
修改容器编排模版中的镜像版本号,然后面板上重启容器
|
||||
```shell
|
||||
@@ -71,3 +78,7 @@ services:
|
||||
### 4.3 自动备份
|
||||
|
||||
> 建议配置一条 [数据库备份流水线](../../use/backup/),自动备份
|
||||
|
||||
## 五、备份恢复
|
||||
|
||||
将备份的`db.sqlite`覆盖到原来的位置即可
|
||||
|
||||
@@ -45,9 +45,10 @@ docker compose up -d
|
||||
|
||||
### 3. 访问测试
|
||||
|
||||
http://your_server_ip:7001
|
||||
默认账号密码:admin/123456
|
||||
记得修改密码
|
||||
http://your_server_ip:7001
|
||||
https://your_server_ip:7002
|
||||
默认账号密码:admin/123456
|
||||
记得修改密码
|
||||
|
||||
|
||||
## 二、升级
|
||||
@@ -64,6 +65,10 @@ docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## 三、数据备份
|
||||
> 数据默认存在`/data/certd`目录下,不用担心数据丢失
|
||||
> 建议配置一条[数据库备份流水线](../../use/backup/) 自动备份
|
||||
|
||||
## 四、备份恢复
|
||||
|
||||
将备份的`db.sqlite`覆盖到原来的位置即可
|
||||
@@ -17,7 +17,8 @@ cd certd
|
||||
|
||||
### 访问测试
|
||||
|
||||
http://your_server_ip:7001
|
||||
http://your_server_ip:7001
|
||||
https://your_server_ip:7002
|
||||
默认账号密码:admin/123456
|
||||
记得修改密码
|
||||
|
||||
@@ -33,8 +34,12 @@ kill -9 $(lsof -t -i:7001)
|
||||
# 重新编译启动
|
||||
./start.sh
|
||||
```
|
||||
|
||||
## 三、数据备份
|
||||
> 数据默认保存在 `./packages/ui/certd-server/data` 目录下
|
||||
> 建议配置一条[数据库备份流水线](../../use/backup/) 自动备份
|
||||
|
||||
|
||||
## 四、备份恢复
|
||||
|
||||
将备份的`db.sqlite`覆盖到原来的位置即可
|
||||
|
||||
@@ -25,7 +25,8 @@ https://certd.handsfree.work/
|
||||
|
||||
### 2. 访问测试
|
||||
|
||||
http://your_server_ip:7001
|
||||
http://your_server_ip:7001
|
||||
https://your_server_ip:7002
|
||||
默认账号密码:admin/123456
|
||||
记得修改密码
|
||||
|
||||
|
||||
11
docs/guide/use/aliyun/index.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# 阿里云相关
|
||||
|
||||
|
||||
## 阿里云客户端请求超时配置
|
||||
|
||||
配置环境变量
|
||||
```shell
|
||||
ALIYUN_CLIENT_CONNECT_TIMEOUT=10000 # 连接超时,单位毫秒
|
||||
ALIYUN_CLIENT_READ_TIMEOUT=10000 #读取数据超时,单位毫秒
|
||||
|
||||
```
|
||||
@@ -1,5 +1,17 @@
|
||||
# 数据库自动备份
|
||||
|
||||
## 一、手动备份
|
||||
数据库文件根据不同的部署方式保存的位置不一样,您可以手动复制出来进行备份
|
||||
|
||||
* docker: 默认保存在`/data/certd/db.sqlite`
|
||||
* 源码: 默认保存在 `./packages/ui/certd-server/data/db.sqlite`
|
||||
* 宝塔: [手动数据备份位置](https://certd.docmirror.cn/guide/install/baota/#%E5%9B%9B%E3%80%81%E6%95%B0%E6%8D%AE%E5%A4%87%E4%BB%BD)
|
||||
* 1panel: 默认保存在`/data/certd/db.sqlite`
|
||||
|
||||
|
||||
## 二、自动备份
|
||||
通过配置数据库自动备份流水线实现数据备份
|
||||
|
||||
## 1. 创建自动备份流水线
|
||||

|
||||
|
||||
@@ -7,7 +19,12 @@
|
||||

|
||||
|
||||
## 3. 选择备份方法
|
||||

|
||||

|
||||
|
||||
## 4. 配置定时和失败通知
|
||||

|
||||

|
||||
|
||||
|
||||
## 三、备份恢复
|
||||
|
||||
将备份的`db.sqlite`覆盖到原来的位置即可
|
||||
BIN
docs/guide/use/https/images/1.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
docs/guide/use/https/images/2.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
docs/guide/use/https/images/3.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
docs/guide/use/https/images/ok.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
38
docs/guide/use/https/index.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Certd本身的https证书配置
|
||||
|
||||
## 一、启用https
|
||||
|
||||
`Certd`默认启用https,监听7002端口
|
||||
如果你想关闭https,或者修改端口,可以在环境变量中配置
|
||||
```shell
|
||||
CERTD_HTTPS_ENABLE=true
|
||||
CERTD_HTTPS_port=7002
|
||||
|
||||
```
|
||||
|
||||
## 二、自动更新Certd的https证书
|
||||
|
||||
### 1、创建证书流水线
|
||||
|
||||
参考Certd顶部的创建证书流水线教程
|
||||
|
||||
### 2、配置复制到本机任务
|
||||
将证书复制到certd的证书安装位置
|
||||
|
||||

|
||||

|
||||
|
||||
### 3、配置重启Certd任务
|
||||
重启certd的https server,让证书生效
|
||||

|
||||
|
||||
|
||||
|
||||
### 4、配置定时任务
|
||||
每天定时执行,最终效果如下
|
||||
|
||||

|
||||
|
||||
:::warning
|
||||
建议将本流水线的触发时间与其他流水线时间错开,避免重启时影响其他流水线的执行
|
||||
:::
|
||||
BIN
docs/guide/use/rerun/images/rerun.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
5
docs/guide/use/rerun/index.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 如何强制重新执行任务
|
||||
|
||||
## 强制重新执行任务
|
||||
|
||||

|
||||
BIN
docs/guide/use/synology/images/deploy1.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/guide/use/synology/images/deploy2.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/guide/use/synology/images/deploy3.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/guide/use/synology/images/deploy4.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
docs/guide/use/synology/images/notify.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
docs/guide/use/synology/images/setting1.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/guide/use/synology/images/setting2.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -37,4 +37,22 @@
|
||||
* 群晖上已经设置好了证书(证书建议设置好描述,插件需要根据描述查找证书)
|
||||
|
||||
## 2. 在certd上配置自动更新群晖证书插件
|
||||

|
||||

|
||||
|
||||
## 3. 配置任务参数
|
||||

|
||||
|
||||
## 4. 创建授权
|
||||

|
||||
> 注意群晖上要做两个设置
|
||||
|
||||

|
||||

|
||||
|
||||
## 5. 运行部署
|
||||
点击手动运行即可
|
||||

|
||||

|
||||
|
||||
## 6. 配置通知和自动运行
|
||||

|
||||
@@ -28,7 +28,7 @@ features:
|
||||
- title: 多域名、泛域名打到一个证书上
|
||||
details: 支持通配符域名/泛域名,支持多个域名打到一个证书上
|
||||
- title: 多证书格式支持
|
||||
details: 支持pem、pfx、der等多种证书格式
|
||||
details: 支持pem、pfx、der等多种证书格式,支持Google、Letsencrypt、ZeroSSL证书颁发机构
|
||||
- title: 支持私有化部署
|
||||
details: 保障数据安全
|
||||
- title: 多数据库支持
|
||||
|
||||
2
docs/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.26.10"
|
||||
"version": "1.26.14"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,31 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.26.14](https://github.com/publishlab/node-acme-client/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复启动时自签证书无法保存的bug ([526c484](https://github.com/publishlab/node-acme-client/commit/526c48450bcd37b3ccded9b448f17de8140bdc6e))
|
||||
|
||||
## [1.26.13](https://github.com/publishlab/node-acme-client/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.26.12](https://github.com/publishlab/node-acme-client/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.26.11](https://github.com/publishlab/node-acme-client/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 申请证书没有使用到系统设置的http代理的bug ([3db216f](https://github.com/publishlab/node-acme-client/commit/3db216f515ba404cb4330fdab452971b22a50f08))
|
||||
* 修复google证书*.xx.com与xx.com同时申请时报错的bug ([f8b99b8](https://github.com/publishlab/node-acme-client/commit/f8b99b81a23e7e9fd5e05ebd5caf355c41d67a90))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化证书申请速度和成功率,反代地址优化,google基本可以稳定请求。增加请求重试。 ([41d9c3a](https://github.com/publishlab/node-acme-client/commit/41d9c3ac8398def541e65351cbe920d4a927182d))
|
||||
|
||||
## [1.26.10](https://github.com/publishlab/node-acme-client/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
**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.26.10",
|
||||
"version": "1.26.14",
|
||||
"main": "src/index.js",
|
||||
"types": "types/index.d.ts",
|
||||
"license": "MIT",
|
||||
@@ -20,6 +20,7 @@
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
"debug": "^4.3.5",
|
||||
"http-proxy-agent": "^7.0.2",
|
||||
"https-proxy-agent": "^7.0.5",
|
||||
"node-forge": "^1.3.1"
|
||||
},
|
||||
@@ -59,5 +60,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "f36b6e382484ba8d07fa1718c438b097ad04c8da"
|
||||
"gitHead": "586725a15c561436cda37de830b278907a6fc3f5"
|
||||
}
|
||||
|
||||
94
packages/core/acme-client/src/agents.js
Normal file
@@ -0,0 +1,94 @@
|
||||
const nodeHttp = require('node:http');
|
||||
const https = require('node:https');
|
||||
const { HttpProxyAgent } = require('http-proxy-agent');
|
||||
const { HttpsProxyAgent } = require('https-proxy-agent');
|
||||
const { log } = require('./logger');
|
||||
|
||||
function createAgent(opts = {}) {
|
||||
let httpAgent;
|
||||
let
|
||||
httpsAgent;
|
||||
const httpProxy = opts.httpProxy || process.env.HTTP_PROXY || process.env.http_proxy;
|
||||
if (httpProxy) {
|
||||
log(`acme use httpProxy:${httpProxy}`);
|
||||
httpAgent = new HttpProxyAgent(httpProxy, opts);
|
||||
}
|
||||
else {
|
||||
httpAgent = new nodeHttp.Agent(opts);
|
||||
}
|
||||
const httpsProxy = opts.httpsProxy || process.env.HTTPS_PROXY || process.env.https_proxy;
|
||||
if (httpsProxy) {
|
||||
log(`acme use httpsProxy:${httpsProxy}`);
|
||||
httpsAgent = new HttpsProxyAgent(httpsProxy, opts);
|
||||
}
|
||||
else {
|
||||
httpsAgent = new https.Agent(opts);
|
||||
}
|
||||
return {
|
||||
httpAgent,
|
||||
httpsAgent,
|
||||
};
|
||||
}
|
||||
|
||||
let defaultAgents = createAgent();
|
||||
|
||||
function getGlobalAgents() {
|
||||
return defaultAgents;
|
||||
}
|
||||
|
||||
function setGlobalProxy(opts) {
|
||||
log('acme setGlobalProxy:', opts);
|
||||
defaultAgents = createAgent(opts);
|
||||
}
|
||||
|
||||
class HttpError extends Error {
|
||||
constructor(error) {
|
||||
super(error || error.message);
|
||||
if (!error) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (error.message.indexOf('ssl3_get_record:wrong version number') >= 0) {
|
||||
this.message = 'http协议错误,服务端要求http协议,请检查是否使用了https请求';
|
||||
}
|
||||
|
||||
this.name = error.name;
|
||||
this.code = error.code;
|
||||
this.cause = error.cause;
|
||||
|
||||
if (error.response) {
|
||||
this.status = error.response.status;
|
||||
this.statusText = error.response.statusText;
|
||||
this.response = {
|
||||
data: error.response.data,
|
||||
};
|
||||
}
|
||||
|
||||
let url = '';
|
||||
if (error.config) {
|
||||
this.request = {
|
||||
baseURL: error.config.baseURL,
|
||||
url: error.config.url,
|
||||
method: error.config.method,
|
||||
params: error.config.params,
|
||||
data: error.config.data,
|
||||
};
|
||||
url = error.config.baseURL + error.config.url;
|
||||
}
|
||||
if (url) {
|
||||
this.message = `${this.message}:${url}`;
|
||||
}
|
||||
|
||||
delete error.response;
|
||||
delete error.config;
|
||||
delete error.request;
|
||||
// logger.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setGlobalProxy,
|
||||
createAgent,
|
||||
getGlobalAgents,
|
||||
HttpError,
|
||||
};
|
||||
@@ -30,6 +30,7 @@ class AcmeApi {
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(locationUrl, mapping);
|
||||
return locationUrl;
|
||||
}
|
||||
|
||||
|
||||
@@ -182,12 +182,19 @@ module.exports = async (client, userOpts) => {
|
||||
|
||||
authorizations.forEach((authz) => {
|
||||
const d = authz.identifier.value;
|
||||
log(`authorization:domain = ${d}, value = ${JSON.stringify(authz)}`);
|
||||
|
||||
if (authz.status === 'valid') {
|
||||
log(`[auto] [${d}] Authorization already has valid status, no need to complete challenges`);
|
||||
return;
|
||||
}
|
||||
let setd = false;
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const group of domainSets) {
|
||||
if (!group[d]) {
|
||||
group[d] = authz;
|
||||
setd = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!setd) {
|
||||
@@ -197,6 +204,8 @@ module.exports = async (client, userOpts) => {
|
||||
}
|
||||
});
|
||||
|
||||
// log(`domainSets:${JSON.stringify(domainSets)}`);
|
||||
|
||||
const allChallengePromises = [];
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const domainSet of domainSets) {
|
||||
@@ -233,28 +242,52 @@ module.exports = async (client, userOpts) => {
|
||||
return Promise.all(results);
|
||||
}
|
||||
|
||||
log(`开始challenge,共${allChallengePromises.length}组`);
|
||||
let i = 0;
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const challengePromises of allChallengePromises) {
|
||||
i += 1;
|
||||
log(`开始第${i}组`);
|
||||
if (opts.signal && opts.signal.aborted) {
|
||||
throw new Error('用户取消');
|
||||
}
|
||||
try {
|
||||
log(`开始challenge,共${allChallengePromises.length}组`);
|
||||
let i = 0;
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const challengePromises of allChallengePromises) {
|
||||
i += 1;
|
||||
log(`开始第${i}组`);
|
||||
if (opts.signal && opts.signal.aborted) {
|
||||
throw new Error('用户取消');
|
||||
}
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await runPromisePa(challengePromises);
|
||||
}
|
||||
catch (e) {
|
||||
log(`证书申请失败${e.message}`);
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
log(`清理challenge痕迹,length:${clearTasks.length}`);
|
||||
try {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await runPromisePa(challengePromises);
|
||||
}
|
||||
catch (e) {
|
||||
log(`证书申请失败${e.message}`);
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
if (client.opts.sslProvider !== 'google') {
|
||||
// letsencrypt 如果同时检出两个TXT记录,会以第一个为准,就会校验失败,所以需要提前删除
|
||||
// zerossl 此方式测试无问题
|
||||
log(`清理challenge痕迹,length:${clearTasks.length}`);
|
||||
try {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await runAllPromise(clearTasks);
|
||||
}
|
||||
catch (e) {
|
||||
log('清理challenge失败');
|
||||
log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (client.opts.sslProvider === 'google') {
|
||||
// google 相同的域名txt记录是一样的,不能提前删除,否则校验失败,报错如下
|
||||
// Error: The TXT record retrieved from _acme-challenge.bbc.handsfree.work.
|
||||
// at the time the challenge was validated did not contain JshHVu7dt_DT6uYILWhokHefFVad2Q6Mw1L-fNZFcq8
|
||||
// (the base64url-encoded SHA-256 digest of RlJZNBR0LWnxNK_xd2zqtYVvCiNJOKJ3J1NmCjU_9BjaUJgL3k-qSpIhQ-uF4FBS.NRyqT8fRiq6THzzrvkgzgR5Xai2LsA2SyGLAq_wT3qc).
|
||||
// See https://tools.ietf.org/html/rfc8555#section-8.4 for more information.
|
||||
log(`清理challenge痕迹,length:${clearTasks.length}`);
|
||||
try {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await runAllPromise(clearTasks);
|
||||
}
|
||||
catch (e) {
|
||||
@@ -263,6 +296,7 @@ module.exports = async (client, userOpts) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log('challenge结束');
|
||||
|
||||
// log('[auto] Waiting for challenge valid status');
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* Axios instance
|
||||
*/
|
||||
|
||||
const axios = require('axios');
|
||||
const { parseRetryAfterHeader } = require('./util');
|
||||
const { log } = require('./logger');
|
||||
const pkg = require('./../package.json');
|
||||
const Agents = require('./agents');
|
||||
|
||||
const { AxiosError } = axios;
|
||||
|
||||
@@ -24,8 +24,8 @@ instance.defaults.acmeSettings = {
|
||||
httpsChallengePort: 443,
|
||||
tlsAlpnChallengePort: 443,
|
||||
|
||||
retryMaxAttempts: 5,
|
||||
retryDefaultDelay: 5,
|
||||
retryMaxAttempts: 3,
|
||||
retryDefaultDelay: 3,
|
||||
};
|
||||
// instance.defaults.proxy = {
|
||||
// host: '192.168.34.139',
|
||||
@@ -56,19 +56,26 @@ function isRetryableError(error) {
|
||||
|
||||
/* https://github.com/axios/axios/blob/main/lib/core/settle.js */
|
||||
function validateStatus(response) {
|
||||
const validator = response.config.retryValidateStatus;
|
||||
|
||||
if (!response) {
|
||||
return new Error('Response is undefined');
|
||||
}
|
||||
let validator = null;
|
||||
if (response.config) {
|
||||
validator = response.config.retryValidateStatus;
|
||||
}
|
||||
if (!response.status || !validator || validator(response.status)) {
|
||||
return response;
|
||||
}
|
||||
|
||||
throw new AxiosError(
|
||||
const err = new AxiosError(
|
||||
`Request failed with status code ${response.status}`,
|
||||
(Math.floor(response.status / 100) === 4) ? AxiosError.ERR_BAD_REQUEST : AxiosError.ERR_BAD_RESPONSE,
|
||||
response.config,
|
||||
response.request,
|
||||
response,
|
||||
);
|
||||
|
||||
throw new Agents.HttpError(err);
|
||||
}
|
||||
|
||||
/* Pass all responses through the error interceptor */
|
||||
@@ -76,8 +83,17 @@ instance.interceptors.request.use((config) => {
|
||||
if (!('retryValidateStatus' in config)) {
|
||||
config.retryValidateStatus = config.validateStatus;
|
||||
}
|
||||
|
||||
config.validateStatus = () => false;
|
||||
|
||||
const agents = Agents.getGlobalAgents();
|
||||
// if (config.skipSslVerify) {
|
||||
// logger.info('跳过SSL验证');
|
||||
// agents = createAgent({ rejectUnauthorized: false } as any);
|
||||
// }
|
||||
// delete config.skipSslVerify;
|
||||
config.httpsAgent = agents.httpsAgent;
|
||||
config.httpAgent = agents.httpAgent;
|
||||
config.proxy = false; // 必须 否则还会走一层代理,
|
||||
return config;
|
||||
});
|
||||
|
||||
@@ -86,7 +102,7 @@ instance.interceptors.response.use(null, async (error) => {
|
||||
const { config, response } = error;
|
||||
|
||||
if (!config) {
|
||||
return Promise.reject(error);
|
||||
return Promise.reject(new Agents.HttpError(error));
|
||||
}
|
||||
|
||||
/* Pick up errors we want to retry */
|
||||
@@ -115,6 +131,9 @@ instance.interceptors.response.use(null, async (error) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (!response) {
|
||||
return Promise.reject(new Agents.HttpError(error));
|
||||
}
|
||||
/* Validate and return response */
|
||||
return validateStatus(response);
|
||||
});
|
||||
|
||||
@@ -558,6 +558,7 @@ class AcmeClient {
|
||||
|
||||
const verifyFn = async (abort) => {
|
||||
if (this.opts.signal && this.opts.signal.aborted) {
|
||||
abort();
|
||||
throw new Error('用户取消');
|
||||
}
|
||||
|
||||
|
||||
@@ -3,21 +3,9 @@
|
||||
*/
|
||||
|
||||
const { createHmac, createSign, constants: { RSA_PKCS1_PADDING } } = require('crypto');
|
||||
const { HttpsProxyAgent } = require('https-proxy-agent');
|
||||
const { getJwk } = require('./crypto');
|
||||
const { log } = require('./logger');
|
||||
const axios1 = require('./axios');
|
||||
|
||||
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
|
||||
let httpsAgent = null;
|
||||
if (httpsProxy) {
|
||||
httpsAgent = new HttpsProxyAgent(httpsProxy);
|
||||
log(`use https_proxy:${httpsProxy}`);
|
||||
}
|
||||
const axios = axios1.create({
|
||||
proxy: false,
|
||||
httpsAgent,
|
||||
});
|
||||
const axios = require('./axios');
|
||||
|
||||
/**
|
||||
* ACME HTTP client
|
||||
|
||||
@@ -39,6 +39,7 @@ exports.forge = require('./crypto/forge');
|
||||
*/
|
||||
|
||||
exports.axios = require('./axios');
|
||||
exports.agents = require('./agents');
|
||||
|
||||
/**
|
||||
* Logger
|
||||
|
||||
@@ -22,7 +22,7 @@ exports.setLogger = (fn) => {
|
||||
* @param {string} msg Message
|
||||
*/
|
||||
|
||||
exports.log = (msg) => {
|
||||
debug(msg);
|
||||
logger(msg);
|
||||
exports.log = (...msg) => {
|
||||
debug(...msg);
|
||||
logger(...msg);
|
||||
};
|
||||
|
||||
2
packages/core/acme-client/types/index.d.ts
vendored
@@ -37,6 +37,7 @@ export type UrlMapping={
|
||||
*/
|
||||
|
||||
export interface ClientOptions {
|
||||
sslProvider:string;
|
||||
directoryUrl: string;
|
||||
accountKey: PrivateKeyBuffer | PrivateKeyString;
|
||||
accountUrl?: string;
|
||||
@@ -192,6 +193,7 @@ export const forge: CryptoLegacyInterface;
|
||||
|
||||
export const axios: AxiosInstance;
|
||||
|
||||
export const agents: any;
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复启动时自签证书无法保存的bug ([526c484](https://github.com/certd/certd/commit/526c48450bcd37b3ccded9b448f17de8140bdc6e))
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 新增部署到百度云CDN插件 ([f126f9f](https://github.com/certd/certd/commit/f126f9f932d37fa01fff1accc7bdd17d349f8db5))
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 申请证书没有使用到系统设置的http代理的bug ([3db216f](https://github.com/certd/certd/commit/3db216f515ba404cb4330fdab452971b22a50f08))
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
@@ -1 +1 @@
|
||||
12:31
|
||||
02:53
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.26.10",
|
||||
"version": "1.26.14",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -64,5 +64,5 @@
|
||||
"vite": "^4.3.8",
|
||||
"vue-tsc": "^1.6.5"
|
||||
},
|
||||
"gitHead": "f36b6e382484ba8d07fa1718c438b097ad04c8da"
|
||||
"gitHead": "586725a15c561436cda37de830b278907a6fc3f5"
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ import { fileUtils } from './util.file.js';
|
||||
import * as _ from 'lodash-es';
|
||||
import { cache } from './util.cache.js';
|
||||
import dayjs from 'dayjs';
|
||||
import { domainUtils } from './util.domain.js';
|
||||
import { optionsUtils } from './util.options.js';
|
||||
|
||||
export const utils = {
|
||||
sleep,
|
||||
@@ -30,4 +32,6 @@ export const utils = {
|
||||
cache,
|
||||
nanoid,
|
||||
dayjs,
|
||||
domain: domainUtils,
|
||||
options: optionsUtils,
|
||||
};
|
||||
|
||||
51
packages/core/basic/src/utils/util.domain.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
//域名是否匹配,支持通配符
|
||||
function match(targetDomains: string | string[], inDomains: string[]) {
|
||||
if (!targetDomains || targetDomains.length == 0) {
|
||||
return false;
|
||||
}
|
||||
if (!inDomains || inDomains.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof targetDomains === 'string') {
|
||||
targetDomains = [targetDomains];
|
||||
}
|
||||
for (let targetDomain of targetDomains) {
|
||||
let matched = false;
|
||||
if (targetDomain.startsWith('.')) {
|
||||
targetDomain = '*' + targetDomain;
|
||||
}
|
||||
for (let inDomain of inDomains) {
|
||||
if (inDomain.startsWith('.')) {
|
||||
inDomain = '*' + inDomain;
|
||||
}
|
||||
if (targetDomain === inDomain) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!inDomain.startsWith('*.')) {
|
||||
//不可能匹配
|
||||
continue;
|
||||
}
|
||||
//子域名匹配通配符即可
|
||||
const firstDotIndex = targetDomain.indexOf('.');
|
||||
const targetDomainSuffix = targetDomain.substring(firstDotIndex + 1);
|
||||
if (targetDomainSuffix === inDomain.substring(2)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//有一个没有匹配上,就失败
|
||||
if (!matched) {
|
||||
return false;
|
||||
}
|
||||
//这个匹配上了,检查下一个
|
||||
}
|
||||
//没有提前return 全部匹配上了
|
||||
return true;
|
||||
}
|
||||
|
||||
export const domainUtils = {
|
||||
match,
|
||||
};
|
||||
42
packages/core/basic/src/utils/util.options.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { domainUtils } from './util.domain.js';
|
||||
|
||||
function groupByDomain(options: any[], inDomains: string[]) {
|
||||
const matched = [];
|
||||
const notMatched = [];
|
||||
for (const item of options) {
|
||||
if (domainUtils.match(item.domain, inDomains)) {
|
||||
matched.push(item);
|
||||
} else {
|
||||
notMatched.push(item);
|
||||
}
|
||||
}
|
||||
return {
|
||||
matched,
|
||||
notMatched,
|
||||
};
|
||||
}
|
||||
|
||||
function buildGroupOptions(options: any[], inDomains: string[]) {
|
||||
const grouped = groupByDomain(options, inDomains);
|
||||
const groupOptions = [];
|
||||
groupOptions.push({ value: '', disabled: true, label: '----已匹配----' });
|
||||
if (grouped.matched.length === 0) {
|
||||
options.push({ value: '', disabled: true, label: '没有可以匹配的域名' });
|
||||
} else {
|
||||
for (const matched of grouped.matched) {
|
||||
groupOptions.push(matched);
|
||||
}
|
||||
}
|
||||
if (grouped.notMatched.length > 0) {
|
||||
groupOptions.push({ value: '', disabled: true, label: '----未匹配----' });
|
||||
for (const notMatched of grouped.notMatched) {
|
||||
groupOptions.push(notMatched);
|
||||
}
|
||||
}
|
||||
return groupOptions;
|
||||
}
|
||||
|
||||
export const optionsUtils = {
|
||||
groupByDomain,
|
||||
buildGroupOptions,
|
||||
};
|
||||
@@ -5,6 +5,7 @@ import { HttpProxyAgent } from 'http-proxy-agent';
|
||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||
import nodeHttp from 'http';
|
||||
import * as https from 'node:https';
|
||||
import { merge } from 'lodash-es';
|
||||
export class HttpError extends Error {
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
@@ -35,6 +36,14 @@ export class HttpError extends Error {
|
||||
params: error.config?.params,
|
||||
data: error.config?.data,
|
||||
};
|
||||
let url = error.config?.url;
|
||||
if (error.config?.baseURL) {
|
||||
url = error.config?.baseURL + url;
|
||||
}
|
||||
if (url) {
|
||||
this.message = `${this.message} : url=${url}`;
|
||||
}
|
||||
|
||||
this.response = {
|
||||
data: error.response?.data,
|
||||
};
|
||||
@@ -52,14 +61,11 @@ let defaultAgents = createAgent();
|
||||
|
||||
export function setGlobalProxy(opts: { httpProxy?: string; httpsProxy?: string }) {
|
||||
logger.info('setGlobalProxy:', opts);
|
||||
if (opts.httpProxy) {
|
||||
process.env.HTTP_PROXY = opts.httpProxy;
|
||||
}
|
||||
if (opts.httpsProxy) {
|
||||
process.env.HTTPS_PROXY = opts.httpsProxy;
|
||||
}
|
||||
defaultAgents = createAgent(opts);
|
||||
}
|
||||
|
||||
defaultAgents = createAgent();
|
||||
export function getGlobalAgents() {
|
||||
return defaultAgents;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,7 +78,10 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
// 请求拦截
|
||||
service.interceptors.request.use(
|
||||
(config: any) => {
|
||||
logger.info(`http request:${config.url},method:${config.method},params:${JSON.stringify(config.params)}`);
|
||||
logger.info(`http request:${config.url},method:${config.method}`);
|
||||
if (config.logParams !== false && config.params) {
|
||||
logger.info(`params:${JSON.stringify(config.params)}`);
|
||||
}
|
||||
if (config.timeout == null) {
|
||||
config.timeout = 15000;
|
||||
}
|
||||
@@ -84,6 +93,11 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
delete config.skipSslVerify;
|
||||
config.httpsAgent = agents.httpsAgent;
|
||||
config.httpAgent = agents.httpAgent;
|
||||
|
||||
// const agent = new https.Agent({
|
||||
// rejectUnauthorized: false // 允许自签名证书
|
||||
// });
|
||||
// config.httpsAgent = agent;
|
||||
config.proxy = false; //必须 否则还会走一层代理,
|
||||
return config;
|
||||
},
|
||||
@@ -96,7 +110,11 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
// 响应拦截
|
||||
service.interceptors.response.use(
|
||||
(response: any) => {
|
||||
logger.info('http response:', JSON.stringify(response?.data));
|
||||
if (response?.config?.logRes !== false) {
|
||||
logger.info(`http response : status=${response?.status},data=${JSON.stringify(response?.data)}`);
|
||||
} else {
|
||||
logger.info('http response status:', response?.status);
|
||||
}
|
||||
return response.data;
|
||||
},
|
||||
(error: any) => {
|
||||
@@ -157,27 +175,35 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
|
||||
export const http = createAxiosService({ logger }) as HttpClient;
|
||||
export type HttpClientResponse<R> = any;
|
||||
export type HttpRequestConfig<D> = {
|
||||
export type HttpRequestConfig<D = any> = {
|
||||
skipSslVerify?: boolean;
|
||||
skipCheckRes?: boolean;
|
||||
logParams?: boolean;
|
||||
logRes?: boolean;
|
||||
} & AxiosRequestConfig<D>;
|
||||
export type HttpClient = {
|
||||
request<D = any, R = any>(config: HttpRequestConfig<D>): Promise<HttpClientResponse<R>>;
|
||||
};
|
||||
|
||||
export function createAgent(opts: nodeHttp.AgentOptions = {}) {
|
||||
export type CreateAgentOptions = {
|
||||
httpProxy?: string;
|
||||
httpsProxy?: string;
|
||||
} & nodeHttp.AgentOptions;
|
||||
export function createAgent(opts: CreateAgentOptions = {}) {
|
||||
let httpAgent, httpsAgent;
|
||||
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
|
||||
const httpProxy = opts.httpProxy || process.env.HTTP_PROXY || process.env.http_proxy;
|
||||
if (httpProxy) {
|
||||
logger.info('use httpProxy:', httpProxy);
|
||||
httpAgent = new HttpProxyAgent(httpProxy, opts as any);
|
||||
merge(httpAgent.options, opts);
|
||||
} else {
|
||||
httpAgent = new nodeHttp.Agent(opts);
|
||||
}
|
||||
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
|
||||
const httpsProxy = opts.httpsProxy || process.env.HTTPS_PROXY || process.env.https_proxy;
|
||||
if (httpsProxy) {
|
||||
logger.info('use httpsProxy:', httpsProxy);
|
||||
httpsAgent = new HttpsProxyAgent(httpsProxy, opts as any);
|
||||
merge(httpsAgent.options, opts);
|
||||
} else {
|
||||
httpsAgent = new https.Agent(opts);
|
||||
}
|
||||
|
||||
@@ -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.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 申请证书启用新的反代地址 ([a705182](https://github.com/certd/certd/commit/a705182b85e51157883e48f23463263793bf3c12))
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.26.10",
|
||||
"version": "1.26.14",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -15,8 +15,8 @@
|
||||
"test": "mocha --loader=ts-node/esm"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.26.10",
|
||||
"@certd/plus-core": "^1.26.10",
|
||||
"@certd/basic": "^1.26.14",
|
||||
"@certd/plus-core": "^1.26.14",
|
||||
"axios": "^1.7.2",
|
||||
"dayjs": "^1.11.7",
|
||||
"fix-path": "^4.0.0",
|
||||
@@ -66,5 +66,5 @@
|
||||
"vite": "^4.3.8",
|
||||
"vue-tsc": "^1.6.5"
|
||||
},
|
||||
"gitHead": "f36b6e382484ba8d07fa1718c438b097ad04c8da"
|
||||
"gitHead": "586725a15c561436cda37de830b278907a6fc3f5"
|
||||
}
|
||||
|
||||
@@ -128,6 +128,10 @@ export class Executor {
|
||||
this.runtime.skip(runnable);
|
||||
return resultType;
|
||||
}
|
||||
if (resultType == ResultType.disabled) {
|
||||
this.runtime.disabled(runnable);
|
||||
return resultType;
|
||||
}
|
||||
this.runtime.success(runnable);
|
||||
return ResultType.success;
|
||||
} catch (e: any) {
|
||||
@@ -164,12 +168,14 @@ export class Executor {
|
||||
|
||||
let resList: ResultType[] = [];
|
||||
if (stage.concurrency === ConcurrencyStrategy.Parallel) {
|
||||
//并行
|
||||
const pList = [];
|
||||
for (const item of runnerList) {
|
||||
pList.push(item());
|
||||
}
|
||||
resList = await Promise.all(pList);
|
||||
} else {
|
||||
//串行
|
||||
for (let i = 0; i < runnerList.length; i++) {
|
||||
const runner = runnerList[i];
|
||||
resList[i] = await runner();
|
||||
@@ -181,6 +187,7 @@ export class Executor {
|
||||
compositionResultType(resList: ResultType[]): ResultType {
|
||||
let hasSuccess = false;
|
||||
let hasSkip = false;
|
||||
let hasDisabled = false;
|
||||
for (const type of resList) {
|
||||
if (type === ResultType.error) {
|
||||
return ResultType.error;
|
||||
@@ -188,8 +195,14 @@ export class Executor {
|
||||
hasSuccess = true;
|
||||
} else if (type === ResultType.skip) {
|
||||
hasSkip = true;
|
||||
} else if (type === ResultType.disabled) {
|
||||
hasDisabled = true;
|
||||
}
|
||||
}
|
||||
if (!hasSuccess && !hasSkip && hasDisabled) {
|
||||
//全是disabled
|
||||
return ResultType.disabled;
|
||||
}
|
||||
if (!hasSuccess && hasSkip) {
|
||||
//全是跳过
|
||||
return ResultType.skip;
|
||||
|
||||
@@ -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.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.26.10",
|
||||
"version": "1.26.14",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -17,5 +17,5 @@
|
||||
"rimraf": "^5.0.5",
|
||||
"rollup": "^3.7.4"
|
||||
},
|
||||
"gitHead": "f36b6e382484ba8d07fa1718c438b097ad04c8da"
|
||||
"gitHead": "586725a15c561436cda37de830b278907a6fc3f5"
|
||||
}
|
||||
|
||||
@@ -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.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.26.10",
|
||||
"version": "1.26.14",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -39,5 +39,5 @@
|
||||
"tslib": "^2.5.2",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f36b6e382484ba8d07fa1718c438b097ad04c8da"
|
||||
"gitHead": "586725a15c561436cda37de830b278907a6fc3f5"
|
||||
}
|
||||
|
||||
@@ -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.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-jdcloud
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-jdcloud
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-jdcloud
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-jdcloud
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-jdcloud
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-jdcloud",
|
||||
"private": false,
|
||||
"version": "1.26.10",
|
||||
"version": "1.26.14",
|
||||
"main": "./dist/bundle.mjs",
|
||||
"module": "./dist/bundle.mjs",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -27,5 +27,5 @@
|
||||
"rimraf": "^5.0.5",
|
||||
"rollup": "^3.7.4"
|
||||
},
|
||||
"gitHead": "f36b6e382484ba8d07fa1718c438b097ad04c8da"
|
||||
"gitHead": "586725a15c561436cda37de830b278907a6fc3f5"
|
||||
}
|
||||
|
||||
@@ -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.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.26.10",
|
||||
"version": "1.26.14",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -18,7 +18,7 @@
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/pipeline": "^1.26.10",
|
||||
"@certd/pipeline": "^1.26.14",
|
||||
"@rollup/plugin-commonjs": "^23.0.4",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
@@ -40,5 +40,5 @@
|
||||
"tslib": "^2.5.2",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f36b6e382484ba8d07fa1718c438b097ad04c8da"
|
||||
"gitHead": "586725a15c561436cda37de830b278907a6fc3f5"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,31 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 限制其他用户流水线数量 ([315e437](https://github.com/certd/certd/commit/315e43746baf01682737f82e41579237a48409af))
|
||||
* 用户管理优化头像上传 ([661293c](https://github.com/certd/certd/commit/661293c189a3abf3cdc953b5225192372f57930d))
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 申请证书没有使用到系统设置的http代理的bug ([3db216f](https://github.com/certd/certd/commit/3db216f515ba404cb4330fdab452971b22a50f08))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 申请证书启用新的反代地址 ([a705182](https://github.com/certd/certd/commit/a705182b85e51157883e48f23463263793bf3c12))
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.26.10",
|
||||
"version": "1.26.14",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -26,8 +26,9 @@
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.26.10",
|
||||
"@certd/pipeline": "^1.26.10",
|
||||
"@certd/acme-client": "^1.26.14",
|
||||
"@certd/basic": "^1.26.14",
|
||||
"@certd/pipeline": "^1.26.14",
|
||||
"@midwayjs/cache": "~3.14.0",
|
||||
"@midwayjs/core": "~3.17.1",
|
||||
"@midwayjs/i18n": "~3.17.3",
|
||||
@@ -68,5 +69,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f36b6e382484ba8d07fa1718c438b097ad04c8da"
|
||||
"gitHead": "586725a15c561436cda37de830b278907a6fc3f5"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Provide } from '@midwayjs/core';
|
||||
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import dayjs from 'dayjs';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
@@ -14,6 +14,7 @@ export const uploadTmpFileCacheKey = 'tmpfile_key_';
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Singleton)
|
||||
export class FileService {
|
||||
async saveFile(userId: number, tmpCacheKey: any, permission: 'public' | 'private') {
|
||||
if (tmpCacheKey.startsWith(`/${permission}`)) {
|
||||
|
||||
@@ -15,6 +15,7 @@ export class SysPublicSettings extends BaseSettings {
|
||||
static __title__ = '系统公共设置';
|
||||
static __access__ = 'public';
|
||||
registerEnabled = false;
|
||||
limitUserPipelineCount = 0;
|
||||
managerOtherUserPipeline = false;
|
||||
icpNo?: string;
|
||||
// triggerOnStartup = false;
|
||||
@@ -102,3 +103,20 @@ export class SysSiteEnv {
|
||||
contactLink?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type MenuItem = {
|
||||
id: string;
|
||||
title: string;
|
||||
icon: string;
|
||||
link: string;
|
||||
auth: boolean;
|
||||
permission?: string;
|
||||
children?: MenuItem[];
|
||||
};
|
||||
export class SysHeaderMenus extends BaseSettings {
|
||||
static __title__ = '顶部菜单';
|
||||
static __key__ = 'sys.header.menus';
|
||||
static __access__ = 'public';
|
||||
|
||||
menus: MenuItem[];
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { BaseSettings, SysInstallInfo, SysPrivateSettings, SysPublicSettings, Sy
|
||||
import * as _ from 'lodash-es';
|
||||
import { BaseService } from '../../../basic/index.js';
|
||||
import { logger, setGlobalProxy } from '@certd/basic';
|
||||
|
||||
import { agents } from '@certd/acme-client';
|
||||
/**
|
||||
* 设置
|
||||
*/
|
||||
@@ -23,7 +23,6 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
async getById(id: any): Promise<SysSettingsEntity | null> {
|
||||
const entity = await this.info(id);
|
||||
if (!entity) {
|
||||
@@ -128,12 +127,12 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
|
||||
async reloadPrivateSettings() {
|
||||
const bean = await this.getPrivateSettings();
|
||||
if (bean.httpProxy || bean.httpsProxy) {
|
||||
setGlobalProxy({
|
||||
httpProxy: bean.httpProxy,
|
||||
httpsProxy: bean.httpsProxy,
|
||||
});
|
||||
}
|
||||
const opts = {
|
||||
httpProxy: bean.httpProxy,
|
||||
httpsProxy: bean.httpsProxy,
|
||||
};
|
||||
setGlobalProxy(opts);
|
||||
agents.setGlobalProxy(opts);
|
||||
}
|
||||
|
||||
async updateByKey(key: string, setting: any) {
|
||||
@@ -149,10 +148,10 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
|
||||
async backupSecret() {
|
||||
const settings = await this.getSettingByKey(SysSecretBackup.__key__);
|
||||
const privateSettings = await this.getPrivateSettings();
|
||||
const installInfo = await this.getSetting<SysInstallInfo>(SysInstallInfo);
|
||||
if (settings == null) {
|
||||
const backup = new SysSecretBackup();
|
||||
const privateSettings = await this.getPrivateSettings();
|
||||
const installInfo = await this.getSetting<SysInstallInfo>(SysInstallInfo);
|
||||
if (installInfo.siteId == null || privateSettings.encryptSecret == null) {
|
||||
logger.error('备份密钥失败,siteId或encryptSecret为空');
|
||||
return;
|
||||
@@ -161,6 +160,14 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
backup.encryptSecret = privateSettings.encryptSecret;
|
||||
await this.saveSetting(backup);
|
||||
logger.info('备份密钥成功');
|
||||
} else {
|
||||
//校验是否有变化
|
||||
if (settings.siteId !== installInfo.siteId) {
|
||||
throw new Error(`siteId与备份不一致,可能是数据异常,请检查:backup=${settings.siteId}, current=${installInfo.siteId}`);
|
||||
}
|
||||
if (settings.encryptSecret !== privateSettings.encryptSecret) {
|
||||
throw new Error('encryptSecret与备份不一致,可能是数据异常,请检查');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.26.10",
|
||||
"version": "1.26.14",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -56,5 +56,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f36b6e382484ba8d07fa1718c438b097ad04c8da"
|
||||
"gitHead": "586725a15c561436cda37de830b278907a6fc3f5"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,30 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* deprecated的运行时不要报错,只报警告 ([bcbefaa](https://github.com/certd/certd/commit/bcbefaaa35cf6d0eec085b3a2c5bfc7c6a8de9e1))
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持配置公共ZeroSSL授权 ([a90d1e6](https://github.com/certd/certd/commit/a90d1e68ee9cbc3705223457b8a86f071b150968))
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 申请证书启用新的反代地址 ([a705182](https://github.com/certd/certd/commit/a705182b85e51157883e48f23463263793bf3c12))
|
||||
* 优化证书申请速度和成功率,反代地址优化,google基本可以稳定请求。增加请求重试。 ([41d9c3a](https://github.com/certd/certd/commit/41d9c3ac8398def541e65351cbe920d4a927182d))
|
||||
* 优化pfx密码密码输入框,让浏览器不自动填写密码 ([ffeede3](https://github.com/certd/certd/commit/ffeede38afa70c5ff6f2015516bead23d2c4df87))
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.26.10",
|
||||
"version": "1.26.14",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -15,9 +15,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.26.10",
|
||||
"@certd/basic": "^1.26.10",
|
||||
"@certd/pipeline": "^1.26.10",
|
||||
"@certd/acme-client": "^1.26.14",
|
||||
"@certd/basic": "^1.26.14",
|
||||
"@certd/pipeline": "^1.26.14",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jszip": "^3.10.1",
|
||||
@@ -57,5 +57,5 @@
|
||||
"vite": "^3.1.0",
|
||||
"vue-tsc": "^0.38.9"
|
||||
},
|
||||
"gitHead": "f36b6e382484ba8d07fa1718c438b097ad04c8da"
|
||||
"gitHead": "586725a15c561436cda37de830b278907a6fc3f5"
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export async function createDnsProvider(opts: { dnsProviderType: string; context
|
||||
const DnsProviderClass = dnsProviderPlugin.target;
|
||||
const dnsProviderDefine = dnsProviderPlugin.define as DnsProviderDefine;
|
||||
if (dnsProviderDefine.deprecated) {
|
||||
throw new Error(dnsProviderDefine.deprecated);
|
||||
context.logger.warn(dnsProviderDefine.deprecated);
|
||||
}
|
||||
// @ts-ignore
|
||||
const dnsProvider: IDnsProvider = new DnsProviderClass();
|
||||
|
||||
@@ -89,12 +89,15 @@ export class AcmeService {
|
||||
}
|
||||
|
||||
async getAcmeClient(email: string, isTest = false): Promise<acme.Client> {
|
||||
const mappings = {};
|
||||
if (this.sslProvider === "letsencrypt") {
|
||||
mappings["acme-v02.api.letsencrypt.org"] = this.options.reverseProxy || "le.px.certd.handfree.work";
|
||||
} else if (this.sslProvider === "google") {
|
||||
mappings["dv.acme-v02.api.pki.goog"] = this.options.reverseProxy || "gg.px.certd.handfree.work";
|
||||
}
|
||||
const urlMapping: UrlMapping = {
|
||||
enabled: false,
|
||||
mappings: {
|
||||
"acme-v02.api.letsencrypt.org": this.options.reverseProxy || "letsencrypt.proxy.handsfree.work",
|
||||
"dv.acme-v02.api.pki.goog": this.options.reverseProxy || "google.proxy.handsfree.work",
|
||||
},
|
||||
mappings,
|
||||
};
|
||||
const conf = await this.getAccountConfig(email, urlMapping);
|
||||
if (conf.key == null) {
|
||||
@@ -119,6 +122,7 @@ export class AcmeService {
|
||||
}
|
||||
}
|
||||
const client = new acme.Client({
|
||||
sslProvider: this.sslProvider,
|
||||
directoryUrl: directoryUrl,
|
||||
accountKey: conf.key,
|
||||
accountUrl: conf.accountUrl,
|
||||
@@ -172,7 +176,7 @@ export class AcmeService {
|
||||
this.logger.info(`Would create TXT record "${fullRecord}" with value "${recordValue}"`);
|
||||
|
||||
let domain = parseDomain(fullDomain);
|
||||
this.logger.info("解析到域名domain=", domain);
|
||||
this.logger.info("解析到域名domain=" + domain);
|
||||
|
||||
if (domainsVerifyPlan) {
|
||||
//按照计划执行
|
||||
@@ -384,7 +388,7 @@ export class AcmeService {
|
||||
timeout: 10000,
|
||||
});
|
||||
} catch (e) {
|
||||
this.logger.error(`${directoryUrl},测试访问失败`, e.stack);
|
||||
this.logger.error(`${directoryUrl},测试访问失败`, e.message);
|
||||
return false;
|
||||
}
|
||||
this.logger.info(`${directoryUrl},测试访问成功`);
|
||||
|
||||
@@ -40,7 +40,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
name: "a-input",
|
||||
vModel: "value",
|
||||
},
|
||||
rules: [{ type: "email" }],
|
||||
rules: [{ type: "email", message: "请输入正确的邮箱" }],
|
||||
required: true,
|
||||
order: -1,
|
||||
helper: "请输入邮箱",
|
||||
@@ -50,7 +50,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: "PFX证书密码",
|
||||
component: {
|
||||
name: "a-input-password",
|
||||
name: "input-password",
|
||||
vModel: "value",
|
||||
},
|
||||
required: false,
|
||||
@@ -227,7 +227,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
* "successNotify": true,
|
||||
* "pfxPassword": "123456"
|
||||
*/
|
||||
const checkInputChanges = ["domains", "sslProvider", "privateKeyType", "dnsProviderType", "dnsProviderAccess", "pfxPassword"];
|
||||
const checkInputChanges = ["domains", "sslProvider", "privateKeyType", "dnsProviderType", "pfxPassword"];
|
||||
const oldInput = JSON.stringify(pick(this.lastStatus?.input, checkInputChanges));
|
||||
const thisInput = JSON.stringify(pick(this, checkInputChanges));
|
||||
inputChanged = oldInput !== thisInput;
|
||||
|
||||
@@ -162,7 +162,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
maybeNeed: true,
|
||||
required: false,
|
||||
helper:
|
||||
"需要提供EAB授权\nZeroSSL:请前往[zerossl开发者中心](https://app.zerossl.com/developer),生成 'EAB Credentials'\n Google:请查看[google获取eab帮助文档](https://gitee.com/certd/certd/blob/v2/doc/google/google.md),用过一次后会绑定邮箱,后续复用EAB要用同一个邮箱",
|
||||
"需要提供EAB授权\nZeroSSL:请前往[zerossl开发者中心](https://app.zerossl.com/developer),生成 'EAB Credentials'\n Google:请查看[google获取eab帮助文档](https://certd.docmirror.cn/guide/use/google/),用过一次后会绑定邮箱,后续复用EAB要用同一个邮箱",
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
@@ -182,7 +182,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
maybeNeed: true,
|
||||
required: false,
|
||||
helper:
|
||||
"google服务账号授权与EAB授权选填其中一个,[服务账号授权获取方法](https://gitee.com/certd/certd/blob/v2/doc/google/google.md)\n服务账号授权需要配置代理或者服务器本身在海外",
|
||||
"google服务账号授权与EAB授权选填其中一个,[服务账号授权获取方法](https://certd.docmirror.cn/guide/use/google/)\n服务账号授权需要配置代理或者服务器本身在海外",
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
|
||||
@@ -3,6 +3,52 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.26.14](https://github.com/certd/certd/compare/v1.26.13...v1.26.14) (2024-10-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复启动时自签证书无法保存的bug ([526c484](https://github.com/certd/certd/commit/526c48450bcd37b3ccded9b448f17de8140bdc6e))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 顶部菜单自定义 ([54d136c](https://github.com/certd/certd/commit/54d136cc6ae122f7c891b7a5c7232fe5de8e5cb5))
|
||||
* 禁用readonly用户 ([d10d42e](https://github.com/certd/certd/commit/d10d42e20619bb55a50d636b8867ff33db4e3b4b))
|
||||
* 限制其他用户流水线数量 ([315e437](https://github.com/certd/certd/commit/315e43746baf01682737f82e41579237a48409af))
|
||||
* 用户管理优化头像上传 ([661293c](https://github.com/certd/certd/commit/661293c189a3abf3cdc953b5225192372f57930d))
|
||||
|
||||
## [1.26.13](https://github.com/certd/certd/compare/v1.26.12...v1.26.13) (2024-10-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复对话框全屏按钮与关闭按钮重叠的bug ([95df56c](https://github.com/certd/certd/commit/95df56cc5ca5e3eb843cd17cb7078cde47729f1e))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持同时监听https端口,7002 ([d5a17f9](https://github.com/certd/certd/commit/d5a17f9e6afd63fda2df0981118480f25a1fac2e))
|
||||
|
||||
## [1.26.12](https://github.com/certd/certd/compare/v1.26.11...v1.26.12) (2024-10-25)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 部署到阿里云任意云资源,阿里云部署大杀器 ([4075be7](https://github.com/certd/certd/commit/4075be7849b140acb92bd8da8a9acbf4eef85180))
|
||||
* 文件名特殊字符限制输入 ([c4164c6](https://github.com/certd/certd/commit/c4164c66e29f3ec799f98108a344806ca61e94ff))
|
||||
* 新增部署到百度云CDN插件 ([f126f9f](https://github.com/certd/certd/commit/f126f9f932d37fa01fff1accc7bdd17d349f8db5))
|
||||
* 优化cron选择器,增加下次触发时间显示 ([5b148b7](https://github.com/certd/certd/commit/5b148b7ed960ca6f7f5b733b2eadd56eeecbd4c2))
|
||||
* 支持配置公共ZeroSSL授权 ([a90d1e6](https://github.com/certd/certd/commit/a90d1e68ee9cbc3705223457b8a86f071b150968))
|
||||
|
||||
## [1.26.11](https://github.com/certd/certd/compare/v1.26.10...v1.26.11) (2024-10-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复移动任务后出现空阶段的bug ([4ea3edd](https://github.com/certd/certd/commit/4ea3edd59e93ca4f5b2e43b20dd4ef33909caddb))
|
||||
* 允许七牛云cdn插件输入.号开头的通配符域名 ([18ee87d](https://github.com/certd/certd/commit/18ee87daff6eafc2201b58e28d85aafd3cb7a5b9))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化日志颜色 ([1291e98](https://github.com/certd/certd/commit/1291e98e821c5b1810aab7f0aebe3f5f5cd44a20))
|
||||
* 优化证书申请速度和成功率,反代地址优化,google基本可以稳定请求。增加请求重试。 ([41d9c3a](https://github.com/certd/certd/commit/41d9c3ac8398def541e65351cbe920d4a927182d))
|
||||
* 优化pfx密码密码输入框,让浏览器不自动填写密码 ([ffeede3](https://github.com/certd/certd/commit/ffeede38afa70c5ff6f2015516bead23d2c4df87))
|
||||
|
||||
## [1.26.10](https://github.com/certd/certd/compare/v1.26.9...v1.26.10) (2024-10-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.26.10",
|
||||
"version": "1.26.14",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -11,6 +11,7 @@
|
||||
"debug:force": "vite --force --mode debug",
|
||||
"build": " vite build ",
|
||||
"dev-build": "echo 1",
|
||||
"test:unit": "vitest",
|
||||
"serve": "vite preview",
|
||||
"preview": "vite preview",
|
||||
"pretty-quick": "pretty-quick",
|
||||
@@ -25,10 +26,10 @@
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^7.0.2",
|
||||
"@ant-design/icons-vue": "^6.1.0",
|
||||
"@fast-crud/fast-crud": "^1.21.2",
|
||||
"@fast-crud/fast-extends": "^1.21.2",
|
||||
"@fast-crud/ui-antdv4": "^1.21.2",
|
||||
"@fast-crud/ui-interface": "^1.21.2",
|
||||
"@fast-crud/fast-crud": "^1.22.2",
|
||||
"@fast-crud/fast-extends": "^1.22.2",
|
||||
"@fast-crud/ui-antdv4": "^1.22.2",
|
||||
"@fast-crud/ui-interface": "^1.22.2",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@soerenmartius/vue3-clipboard": "^0.1.2",
|
||||
"@vue-js-cron/light": "^4.0.5",
|
||||
@@ -41,6 +42,7 @@
|
||||
"china-division": "^2.7.0",
|
||||
"core-js": "^3.36.0",
|
||||
"cos-js-sdk-v5": "^1.7.0",
|
||||
"cron-parser": "^4.9.0",
|
||||
"cropperjs": "^1.6.1",
|
||||
"dayjs": "^1.11.10",
|
||||
"highlight.js": "^11.9.0",
|
||||
@@ -61,8 +63,8 @@
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.26.10",
|
||||
"@certd/pipeline": "^1.26.10",
|
||||
"@certd/lib-iframe": "^1.26.14",
|
||||
"@certd/pipeline": "^1.26.14",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
@@ -77,7 +79,7 @@
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"@vue/compiler-sfc": "^3.4.21",
|
||||
"@vue/eslint-config-typescript": "^13.0.0",
|
||||
"@vue/test-utils": "^2.4.5",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"autoprefixer": "^10.4.18",
|
||||
"caller-path": "^4.0.0",
|
||||
"chai": "^5.1.0",
|
||||
@@ -113,6 +115,7 @@
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite-plugin-windicss": "^1.9.3",
|
||||
"vitest": "^2.1.2",
|
||||
"vue-eslint-parser": "^9.4.2",
|
||||
"vue-tsc": "^1.8.8"
|
||||
},
|
||||
|
||||
@@ -32,6 +32,16 @@ export type SysPublicSetting = {
|
||||
export type SysInstallInfo = {
|
||||
siteId: string;
|
||||
};
|
||||
export type MenuItem = {
|
||||
id: string;
|
||||
title: string;
|
||||
icon?: string;
|
||||
path?: string;
|
||||
children?: MenuItem[];
|
||||
};
|
||||
export type HeaderMenus = {
|
||||
menus: MenuItem[];
|
||||
};
|
||||
|
||||
export type AllSettings = {
|
||||
sysPublic: SysPublicSetting;
|
||||
@@ -39,6 +49,7 @@ export type AllSettings = {
|
||||
plusInfo: PlusInfo;
|
||||
siteInfo: SiteInfo;
|
||||
siteEnv: SiteEnv;
|
||||
headerMenus: HeaderMenus;
|
||||
};
|
||||
|
||||
export async function loadAllSettings(): Promise<AllSettings> {
|
||||
|
||||
@@ -53,7 +53,9 @@ function createService() {
|
||||
// @ts-ignore
|
||||
response.config.onError(new Error(errorMessage));
|
||||
}
|
||||
errorCreate(`${errorMessage}: ${response.config.url}`);
|
||||
//@ts-ignore
|
||||
const showErrorNotify = response?.config?.showErrorNotify;
|
||||
errorCreate(`${errorMessage}: ${response.config.url}`, showErrorNotify);
|
||||
return dataAxios;
|
||||
}
|
||||
}
|
||||
@@ -97,7 +99,7 @@ function createService() {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
errorLog(error);
|
||||
errorLog(error, error?.response?.config?.showErrorNotify);
|
||||
if (status === 401) {
|
||||
const userStore = useUserStore();
|
||||
userStore.logout();
|
||||
@@ -122,7 +124,7 @@ function createRequestFunction(service: any) {
|
||||
headers: {
|
||||
"Content-Type": get(config, "headers.Content-Type", "application/json")
|
||||
},
|
||||
timeout: 10000,
|
||||
timeout: 20000,
|
||||
baseURL: env.API,
|
||||
data: {}
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ export function responseError(data = {}, msg = "请求失败", code = 500) {
|
||||
* @description 记录和显示错误
|
||||
* @param {Error} error 错误对象
|
||||
*/
|
||||
export function errorLog(error: any) {
|
||||
export function errorLog(error: any, notify = true) {
|
||||
// 打印到控制台
|
||||
console.error("errorLog", error);
|
||||
let message = error.message;
|
||||
@@ -58,17 +58,22 @@ export function errorLog(error: any) {
|
||||
if (message.indexOf("ssl3_get_record:wrong version number") >= 0) {
|
||||
message = "http协议错误,服务端要求http协议,请检查是否使用了https请求";
|
||||
}
|
||||
// 显示提示
|
||||
uiContext.get().notification.error({ message });
|
||||
if (notify) {
|
||||
// 显示提示
|
||||
uiContext.get().notification.error({ message });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 创建一个错误
|
||||
* @param {String} msg 错误信息
|
||||
*/
|
||||
export function errorCreate(msg: string) {
|
||||
export function errorCreate(msg: string, notify = true) {
|
||||
const err = new Error(msg);
|
||||
console.error("errorCreate", err);
|
||||
uiContext.get().notification.error({ message: err.message });
|
||||
if (notify) {
|
||||
uiContext.get().notification.error({ message: err.message });
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
@@ -16,12 +16,15 @@
|
||||
<div class="mt-5">
|
||||
<a-input :disabled="true" :readonly="readonly" :value="modelValue" @change="onChange"></a-input>
|
||||
</div>
|
||||
<div class="helper">下次触发时间:{{ nextTime }}</div>
|
||||
<div class="fs-helper">{{ errorMessage }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import parser from "cron-parser";
|
||||
import { computed, ref } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
defineOptions({
|
||||
name: "CronEditor"
|
||||
});
|
||||
@@ -31,8 +34,10 @@ const props = defineProps<{
|
||||
readonly?: boolean;
|
||||
}>();
|
||||
|
||||
const period = ref<string>("day");
|
||||
|
||||
const period = ref<string>("");
|
||||
if (props.modelValue == null) {
|
||||
period.value = "day";
|
||||
}
|
||||
const emit = defineEmits<{
|
||||
"update:modelValue": any;
|
||||
}>();
|
||||
@@ -58,6 +63,17 @@ const onChange = (e: any) => {
|
||||
const onError = (error: any) => {
|
||||
errorMessage.value = error;
|
||||
};
|
||||
|
||||
const nextTime = computed(() => {
|
||||
try {
|
||||
const interval = parser.parseExpression(props.modelValue);
|
||||
const next = interval.next().getTime();
|
||||
return dayjs(next).format("YYYY-MM-DD HH:mm:ss");
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return "请先设置正确的cron表达式";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
.cron-editor {
|
||||
|
||||
50
packages/ui/certd-client/src/components/fold-box.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div class="cd-fold-box">
|
||||
<div class="handle pointer">
|
||||
<div class="line"></div>
|
||||
<div class="icon">
|
||||
<fs-icon icon="ion:chevron-collapse-sharp"></fs-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content" :class="{ hidden: !props.open }">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
open: boolean;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.cd-fold-box {
|
||||
.handle {
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.line {
|
||||
//虚线
|
||||
border-top: 1px dashed #ccc;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
}
|
||||
.icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -3,6 +3,7 @@ import TextEditable from "./editable.vue";
|
||||
import vip from "./vip-button/install.js";
|
||||
import { CheckCircleOutlined, InfoCircleOutlined, UndoOutlined } from "@ant-design/icons-vue";
|
||||
import CronEditor from "./cron-editor/index.vue";
|
||||
import FoldBox from "./fold-box.vue";
|
||||
import { CronLight } from "@vue-js-cron/light";
|
||||
import "@vue-js-cron/light/dist/light.css";
|
||||
import Plugins from "./plugins/index";
|
||||
@@ -15,6 +16,8 @@ export default {
|
||||
app.component("CronLight", CronLight);
|
||||
app.component("CronEditor", CronEditor);
|
||||
|
||||
app.component("FoldBox", FoldBox);
|
||||
|
||||
app.component("CheckCircleOutlined", CheckCircleOutlined);
|
||||
app.component("InfoCircleOutlined", InfoCircleOutlined);
|
||||
app.component("UndoOutlined", UndoOutlined);
|
||||
|
||||
@@ -28,9 +28,9 @@ export default {
|
||||
});
|
||||
}
|
||||
options.value = array;
|
||||
if (props.modelValue == null && options.value.length > 0) {
|
||||
ctx.emit("update:modelValue", options.value[0].value);
|
||||
}
|
||||
// if (props.modelValue == null && options.value.length > 0) {
|
||||
// ctx.emit("update:modelValue", options.value[0].value);
|
||||
// }
|
||||
}
|
||||
onCreate();
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@ import { request } from "/src/api/service";
|
||||
const apiPrefix = "/cname/record";
|
||||
|
||||
export type CnameRecord = {
|
||||
id: number;
|
||||
status: string;
|
||||
id?: number;
|
||||
status?: string;
|
||||
hostRecord?: string;
|
||||
recordValue?: string;
|
||||
};
|
||||
|
||||
export async function GetList() {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<td class="host-record" :title="'域名:' + props.domain">
|
||||
<fs-copyable v-model="cnameRecord.hostRecord"></fs-copyable>
|
||||
</td>
|
||||
<td style="text-align: center">CNAME</td>
|
||||
<td class="record-value">
|
||||
<fs-copyable v-model="cnameRecord.recordValue"></fs-copyable>
|
||||
</td>
|
||||
@@ -44,10 +45,12 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: {
|
||||
id: number | null;
|
||||
status: string | null;
|
||||
};
|
||||
change: [
|
||||
{
|
||||
id: number | null;
|
||||
status: string | null;
|
||||
}
|
||||
];
|
||||
}>();
|
||||
|
||||
const cnameRecord = ref<CnameRecord | null>(null);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<td style="width: 160px">主机记录</td>
|
||||
<td style="width: 100px; text-align: center">记录类型</td>
|
||||
<td style="width: 250px">请设置CNAME记录(验证成功以后不要删除)</td>
|
||||
<td style="width: 120px" class="center">状态</td>
|
||||
<td style="width: 80px" class="center">操作</td>
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="api-test">
|
||||
<div>
|
||||
<fs-button :loading="loading" type="primary" text="测试" icon="ion:refresh-outline" @click="doTest"></fs-button>
|
||||
</div>
|
||||
|
||||
<div class="helper" :class="{ error: hasError }">
|
||||
{{ message }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ComponentPropsType, doRequest } from "/@/components/plugins/lib";
|
||||
import { ref } from "vue";
|
||||
|
||||
defineOptions({
|
||||
name: "ApiTest"
|
||||
});
|
||||
|
||||
const props = defineProps<{} & ComponentPropsType>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
"update:value": any;
|
||||
}>();
|
||||
|
||||
const message = ref("");
|
||||
const hasError = ref(false);
|
||||
const loading = ref(false);
|
||||
const doTest = async () => {
|
||||
if (loading.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
message.value = "";
|
||||
hasError.value = false;
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await doRequest(
|
||||
{
|
||||
type: props.type,
|
||||
typeName: props.typeName,
|
||||
action: props.action,
|
||||
input: props.form
|
||||
},
|
||||
{
|
||||
onError(err: any) {
|
||||
hasError.value = true;
|
||||
message.value = `错误:${err.message}`;
|
||||
},
|
||||
showErrorNotify: false
|
||||
}
|
||||
);
|
||||
if (res && res.length > 0) {
|
||||
message.value = "测试请求成功";
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<a-select mode="tags" readonly :value="modelValue" />
|
||||
<div>{{ errorRef }}</div>
|
||||
<div class="cert-domains-getter">
|
||||
<div>
|
||||
<a-tag v-for="item of modelValue" :key="item" type="success" class="m-3">{{ item }}</a-tag>
|
||||
</div>
|
||||
<div class="helper">{{ errorRef }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -34,17 +38,29 @@ function findStepFromPipeline(targetStepId: string) {
|
||||
}
|
||||
|
||||
const errorRef = ref("");
|
||||
function getDomainFromPipeline(inputKey: string) {
|
||||
function getStepIdFromInputKey(inputKey: string) {
|
||||
if (!inputKey) {
|
||||
errorRef.value = "请先选择域名证书";
|
||||
return;
|
||||
}
|
||||
const targetStepId = inputKey.split(".")[1];
|
||||
const certStep = findStepFromPipeline(targetStepId);
|
||||
return inputKey.split(".")[1];
|
||||
}
|
||||
function getDomainFromPipeline(inputKey: string) {
|
||||
let targetStepId = getStepIdFromInputKey(inputKey);
|
||||
let certStep = findStepFromPipeline(targetStepId);
|
||||
if (!certStep) {
|
||||
errorRef.value = "找不到目标步骤,请先选择域名证书";
|
||||
return;
|
||||
}
|
||||
if (certStep.type !== "CertApply" && certStep.type !== "CertApplyLego") {
|
||||
targetStepId = getStepIdFromInputKey(certStep.input?.cert);
|
||||
certStep = findStepFromPipeline(targetStepId);
|
||||
if (!certStep) {
|
||||
errorRef.value = "找不到目标步骤,请先选择域名证书";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const domain = certStep.input["domains"];
|
||||
emit("update:modelValue", domain);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<a-input class="cd-input-password" :class="{ show: showRef }">
|
||||
<template #suffix>
|
||||
<fs-icon class="pointer" :icon="computedIcon" @click="showRef = !showRef" />
|
||||
</template>
|
||||
</a-input>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
|
||||
const showRef = ref(false);
|
||||
const computedIcon = computed(() => {
|
||||
return showRef.value ? "ion:eye-outline" : "ion:eye-off-outline";
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
.cd-input-password {
|
||||
text-security: disc;
|
||||
-webkit-text-security: disc;
|
||||
.fs-iconify {
|
||||
font-size: 16px;
|
||||
}
|
||||
&.show {
|
||||
text-security: none;
|
||||
-webkit-text-security: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||