mirror of
https://github.com/certd/certd.git
synced 2026-04-14 20:40:53 +08:00
Compare commits
147 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed5634ff83 | ||
|
|
884af1ea62 | ||
|
|
01ad62df16 | ||
|
|
512a667e44 | ||
|
|
d0e841f7de | ||
|
|
c04641d835 | ||
|
|
f9128d4d45 | ||
|
|
2026211622 | ||
|
|
9d0f21a9e5 | ||
|
|
26adf7d437 | ||
|
|
d2d6f12218 | ||
|
|
b31c0b6a8d | ||
|
|
472f06c2d1 | ||
|
|
f5ec9870fd | ||
|
|
66fb9e5f49 | ||
|
|
a323f3aa2c | ||
|
|
fe4786e168 | ||
|
|
83185c8c50 | ||
|
|
83ae9db02d | ||
|
|
8bf328ca94 | ||
|
|
36993cb6f8 | ||
|
|
c854415319 | ||
|
|
aecc1cd979 | ||
|
|
b2f3b0b584 | ||
|
|
c937f5afc7 | ||
|
|
2d580a26af | ||
|
|
4a00a3cc1b | ||
|
|
d3935219f2 | ||
|
|
040788c793 | ||
|
|
005622307e | ||
|
|
8ebf95a222 | ||
|
|
7f596ed315 | ||
|
|
ffa4de6911 | ||
|
|
cb27d4b490 | ||
|
|
bb4910f4e5 | ||
|
|
89c7f07034 | ||
|
|
b150b2f034 | ||
|
|
45d6347f5b | ||
|
|
67d762b6a5 | ||
|
|
faa28f88f9 | ||
|
|
9c8c7a7812 | ||
|
|
a019956698 | ||
|
|
d70e2b66a3 | ||
|
|
5d568efac3 | ||
|
|
08111f1418 | ||
|
|
45839f227a | ||
|
|
8814ffeda6 | ||
|
|
d224c4c124 | ||
|
|
549525fb37 | ||
|
|
1c8e25beb3 | ||
|
|
eda45c1528 | ||
|
|
53c38cf714 | ||
|
|
0e7578043e | ||
|
|
21f50e0b38 | ||
|
|
515f00c7cd | ||
|
|
8057586dc1 | ||
|
|
b101ac7c7f | ||
|
|
64319937a1 | ||
|
|
1c0cfd6769 | ||
|
|
f8e17d5285 | ||
|
|
d4385ad8a5 | ||
|
|
da07ce419f | ||
|
|
714e0206c4 | ||
|
|
40da82666a | ||
|
|
79f7ec4672 | ||
|
|
0f5c69040b | ||
|
|
c9d1c45d97 | ||
|
|
ea8fdb120c | ||
|
|
f6fa830ffe | ||
|
|
992e50c014 | ||
|
|
bd705d91ba | ||
|
|
2656394195 | ||
|
|
c8df9e698c | ||
|
|
19b78a1d2f | ||
|
|
8039e8baf8 | ||
|
|
9c5142c73c | ||
|
|
8e3dcdde17 | ||
|
|
34023adafb | ||
|
|
79914e8d08 | ||
|
|
454fbda581 | ||
|
|
2c32703e6b | ||
|
|
b561535626 | ||
|
|
1fc684d995 | ||
|
|
7595d9fdfd | ||
|
|
3bf7732a21 | ||
|
|
71b5aaf8ab | ||
|
|
e1e5347476 | ||
|
|
cdcdb6a2d9 | ||
|
|
ec79104ad2 | ||
|
|
ff083ce684 | ||
|
|
0f051e322e | ||
|
|
657a2ae032 | ||
|
|
0db3570026 | ||
|
|
0ae39f160a | ||
|
|
b45977c29a | ||
|
|
b7f5740c57 | ||
|
|
21e23369d3 | ||
|
|
fca598991a | ||
|
|
aa5b909486 | ||
|
|
0a888cf51a | ||
|
|
e5c164065c | ||
|
|
8bc241ca14 | ||
|
|
15beb79631 | ||
|
|
fef1305e41 | ||
|
|
498cf34999 | ||
|
|
7cde1fdc4a | ||
|
|
228fdf0a0d | ||
|
|
fdb5ea0ff4 | ||
|
|
a0e838d1ee | ||
|
|
30ddf5ec41 | ||
|
|
cfd3b7b3ae | ||
|
|
a6cd532035 | ||
|
|
b1db952fcb | ||
|
|
51e8bab352 | ||
|
|
618ec93786 | ||
|
|
a673f9c8ca | ||
|
|
e8c9c2a47d | ||
|
|
aafa5d5f90 | ||
|
|
8b9c47daf1 | ||
|
|
4042577c0b | ||
|
|
6c9f9940e3 | ||
|
|
8f7b3f29ce | ||
|
|
6bca7333c9 | ||
|
|
3dfeeec899 | ||
|
|
138dc286f6 | ||
|
|
07cee2aadf | ||
|
|
1b267813c9 | ||
|
|
96b5981f8c | ||
|
|
a2fd9559c5 | ||
|
|
3f06419d47 | ||
|
|
2aefca3813 | ||
|
|
6aa487269c | ||
|
|
393ea27fa4 | ||
|
|
febe87508c | ||
|
|
30db27980c | ||
|
|
4e768ec50f | ||
|
|
4467e09426 | ||
|
|
66b95d52fd | ||
|
|
1398417829 | ||
|
|
58dd5e2750 | ||
|
|
70210f567a | ||
|
|
49e7dc56e1 | ||
|
|
72cc586f88 | ||
|
|
94fa77fcd2 | ||
|
|
2c0cbdd29e | ||
|
|
68a503796c | ||
|
|
48cf28dd7f |
22
.github/workflows/build-image.yml
vendored
22
.github/workflows/build-image.yml
vendored
@@ -91,14 +91,14 @@ jobs:
|
|||||||
# greper/certd:armv7
|
# greper/certd:armv7
|
||||||
# greper/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
# greper/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
||||||
|
|
||||||
- name: Build agent
|
# - name: Build agent
|
||||||
uses: docker/build-push-action@v6
|
# uses: docker/build-push-action@v6
|
||||||
with:
|
# with:
|
||||||
platforms: linux/amd64,linux/arm64
|
# platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
# push: true
|
||||||
context: ./packages/ui/agent/
|
# context: ./packages/ui/agent/
|
||||||
tags: |
|
# tags: |
|
||||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd-agent:latest
|
# registry.cn-shenzhen.aliyuncs.com/handsfree/certd-agent:latest
|
||||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd-agent:${{steps.get_certd_version.outputs.result}}
|
# registry.cn-shenzhen.aliyuncs.com/handsfree/certd-agent:${{steps.get_certd_version.outputs.result}}
|
||||||
greper/certd-agent:latest
|
# greper/certd-agent:latest
|
||||||
greper/certd-agent:${{steps.get_certd_version.outputs.result}}
|
# greper/certd-agent:${{steps.get_certd_version.outputs.result}}
|
||||||
|
|||||||
97
CHANGELOG.md
97
CHANGELOG.md
@@ -3,6 +3,103 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复套餐关闭状态下,仍然限制用户流水线数量的bug ([66fb9e5](https://github.com/certd/certd/commit/66fb9e5f49491f9c159363b48af14720a37673b1))
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 免费套餐支持购买 ([f5ec987](https://github.com/certd/certd/commit/f5ec9870fd6af1f0c9099852bbdb4d07813ccce8))
|
||||||
|
* 修复某处金额转换丢失精度的bug ([d2d6f12](https://github.com/certd/certd/commit/d2d6f12218cbe7bd55f4ae082b93084be85f0a7b))
|
||||||
|
* 修复新版本小红点显示错误问题 ([fe4786e](https://github.com/certd/certd/commit/fe4786e168afe03a5243dd67971476c348339809))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 用户创建证书流水线没有购买套餐或者超限时提前报错 ([472f06c](https://github.com/certd/certd/commit/472f06c2d190d0ae48e8b53c18bc278437656a1c))
|
||||||
|
* 优化插件名称显示 ([26adf7d](https://github.com/certd/certd/commit/26adf7d437e674385f26a8f92fded6521a620671))
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复手机模式下,查询框被文字遮盖的bug ([040788c](https://github.com/certd/certd/commit/040788c793642c3bb2a3ede87fe30fcf3be471bd))
|
||||||
|
* 修复左侧菜单收起时无法展开子菜单的bug ([0056223](https://github.com/certd/certd/commit/005622307e612717a5408aa1484717ef03003a22))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 基础版不再限制流水线数量 ([cb27d4b](https://github.com/certd/certd/commit/cb27d4b4906b2782eaceb0a95bbdc5d0534370d2))
|
||||||
|
* 套餐购买支持易支付、支付宝支付 ([faa28f8](https://github.com/certd/certd/commit/faa28f88f954cba4c1dd29125562e5acd2fd99af))
|
||||||
|
* 用户套餐,用户支付功能 ([a019956](https://github.com/certd/certd/commit/a019956698acaf2c4beb620b5ad8c18918ead6a1))
|
||||||
|
* 站点证书监控 ([9c8c7a7](https://github.com/certd/certd/commit/9c8c7a781223f4217f45510db1e89495600e3cd5))
|
||||||
|
* 支持微信支付 ([45d6347](https://github.com/certd/certd/commit/45d6347f5b6199493b11aabdd74177f6dca2cea4))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 调整创建证书表单字段的顺序 ([d393521](https://github.com/certd/certd/commit/d3935219f2aa50d6662c5b5ebf7ee25ad696ab2b))
|
||||||
|
* 同一时间只允许一个套餐生效 ([8ebf95a](https://github.com/certd/certd/commit/8ebf95a222a900d1707716c7b1f3b39f8a6d8f94))
|
||||||
|
* 用户名支持修改 ([89c7f07](https://github.com/certd/certd/commit/89c7f070343e86453c84677ebe1669f9b266d871))
|
||||||
|
* 优化证书申请跳过的状态显示,成功通知现在在跳过时不会发送 ([67d762b](https://github.com/certd/certd/commit/67d762b6a520f1fa24719a124e5ae975a81f5f82))
|
||||||
|
* 站点证书监控通知发送,每天定时检查 ([bb4910f](https://github.com/certd/certd/commit/bb4910f4e57234e42b44505f4620ae7af66025c5))
|
||||||
|
* 支持一体证书 ([53c38cf](https://github.com/certd/certd/commit/53c38cf714a6f7486abbf1d71c9f48f56a790100))
|
||||||
|
* 支持plesk网站证书部署 ([eda45c1](https://github.com/certd/certd/commit/eda45c1528199648b3970505e87f492d398226cd))
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复证书成功通知发送失败的bug ([0f5c690](https://github.com/certd/certd/commit/0f5c69040ba77340c909813220a26bc7ddada3ea))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 群晖支持6.x ([79f7ec4](https://github.com/certd/certd/commit/79f7ec4672f4fd5744cc45e4a6f104da943f4026))
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复没有配置eab时,报order无法读取的问题 ([657a2ae](https://github.com/certd/certd/commit/657a2ae032e6f61ac27fbdd26c7bf169c041219e))
|
||||||
|
* 修复授权被删除后,无法清空的bug ([b45977c](https://github.com/certd/certd/commit/b45977c29a29084c11e496bec3415eaaebafdd74))
|
||||||
|
* mysql下access.setting字段改成text ([b7f5740](https://github.com/certd/certd/commit/b7f5740c57743914f754f3b4fdd94b59a2e8338c))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 点击版本红点按钮,跳转到升级帮助页面 ([454fbda](https://github.com/certd/certd/commit/454fbda581bbe22abca5b91e5086ea9d9d58a020))
|
||||||
|
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||||
|
* 支持腾讯虚拟机开关机([@wujingke](https://github.com/wujingke)) ([8039e8b](https://github.com/certd/certd/commit/8039e8baf83c82d03f1a6198cf61c372026b962b))
|
||||||
|
* 支持aws cloudfront ([0ae39f1](https://github.com/certd/certd/commit/0ae39f160a7c6b6696b3bf513d68aa28905810ad))
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复创建流水线通知设置无效的bug ([498cf34](https://github.com/certd/certd/commit/498cf34999fddfa24ce088e2e678469fa669abb8))
|
||||||
|
* 修复流水线分组可以被所有人看见的bug ([a0e838d](https://github.com/certd/certd/commit/a0e838d1eec918e5dc92fe95dc72ac14facb930e))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 优化数据表索引 ([228fdf0](https://github.com/certd/certd/commit/228fdf0a0d28013f5dd156a97bbde80537e8e97e))
|
||||||
|
* 支持mysql ([7cde1fd](https://github.com/certd/certd/commit/7cde1fdc4a9ed851900d231a5460c8dbfbcd148e))
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复cname排查方法 nslookup命令显示黑色的问题 ([3dfeeec](https://github.com/certd/certd/commit/3dfeeec899d7d0d7292695ce410f78548e076c03))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 通知选择器优化 ([2c0cbdd](https://github.com/certd/certd/commit/2c0cbdd29ecb74cc939b2ae7ee86b8d40f70ba31))
|
||||||
|
* 新增七牛云插件分组 ([49e7dc5](https://github.com/certd/certd/commit/49e7dc56e1a95fbdea3e30cdeb945b48415b69e3))
|
||||||
|
* 新增server酱3通知 ([6aa4872](https://github.com/certd/certd/commit/6aa487269c9f6862e188b37a0d6c73f79c937d94))
|
||||||
|
* 支持邀请奖励 ([618ec93](https://github.com/certd/certd/commit/618ec937866b24ebcf8164db43acb1ed66a5b329))
|
||||||
|
* 支持易发云短信 ([94fa77f](https://github.com/certd/certd/commit/94fa77fcd2b9bea294fb05736c0d8cdc81f56103))
|
||||||
|
* cname value优化 ([e8c9c2a](https://github.com/certd/certd/commit/e8c9c2a47d47048ae743b16f7bc932dbe18a89e9))
|
||||||
|
* favicon支持自定义 ([8b9c47d](https://github.com/certd/certd/commit/8b9c47daf194515006689a212ae9cf586bdf5993))
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
75
README.md
75
README.md
@@ -9,14 +9,16 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
|||||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||||
|
|
||||||
* 全自动申请证书(支持所有注册商注册的域名)
|
* 全自动申请证书(支持所有注册商注册的域名)
|
||||||
* 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等,目前已支持30+部署插件)
|
* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等,目前已支持40+部署插件)
|
||||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式
|
* 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式
|
||||||
* 邮件通知
|
* 邮件通知、webhook通知
|
||||||
* 私有化部署,数据保存本地,镜像由Github Actions构建,过程公开透明
|
* 私有化部署,数据保存本地,授权信息加密存储,镜像由Github Actions构建,过程公开透明
|
||||||
* 支持sqlite,postgresql数据库
|
* 支持SQLite,PostgreSQL、MySQL数据库
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>
|
||||||
|
> 流水线数量现已调整为无限制,欢迎大家使用
|
||||||
|
>
|
||||||
|
|
||||||
## 二、在线体验
|
## 二、在线体验
|
||||||
|
|
||||||
@@ -90,7 +92,7 @@ https://certd.handfree.work/
|
|||||||
1. 修改`docker-compose.yaml`中的镜像版本号
|
1. 修改`docker-compose.yaml`中的镜像版本号
|
||||||
2. 运行`docker compose up -d` 即可
|
2. 运行`docker compose up -d` 即可
|
||||||
|
|
||||||
如果使用`latest`版本
|
如果需要使用最新版本
|
||||||
```shell
|
```shell
|
||||||
#重新拉取镜像
|
#重新拉取镜像
|
||||||
docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||||
@@ -98,7 +100,54 @@ docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
|||||||
docker compose down
|
docker compose down
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
关于自动升级(仅限尝鲜建议非生产使用)
|
||||||
|
```yaml
|
||||||
|
version: '3.3'
|
||||||
|
services:
|
||||||
|
certd:
|
||||||
|
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||||
|
container_name: certd
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /data/certd:/app/data
|
||||||
|
ports:
|
||||||
|
- "7001:7001"
|
||||||
|
- "7002:7002"
|
||||||
|
# 如果需要修改系统配置,可以通过环境变量传递;初次运行请保持默认配置
|
||||||
|
environment:
|
||||||
|
- certd_system_resetAdminPasswd=false
|
||||||
|
# 如果需要切换数据库类型,可以在此处设置为mysql或postgres
|
||||||
|
# - certd_typeorm_dataSource_default_type=mysql
|
||||||
|
# - certd_typeorm_dataSource_default_host=localhost
|
||||||
|
# - certd_typeorm_dataSource_default_port=3306
|
||||||
|
# - certd_typeorm_dataSource_default_username=root
|
||||||
|
# - certd_typeorm_dataSource_default_password=123456
|
||||||
|
# - certd_typeorm_dataSource_default_database=certd
|
||||||
|
labels:
|
||||||
|
com.centurylinklabs.watchtower.enable: "true"
|
||||||
|
|
||||||
|
certd-updater: # 添加 Watchtower 服务
|
||||||
|
image: containrrr/watchtower:latest
|
||||||
|
container_name: certd-updater
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
# 配置 自动更新
|
||||||
|
environment:
|
||||||
|
- WATCHTOWER_CLEANUP=true # 自动清理旧版本容器
|
||||||
|
- WATCHTOWER_INCLUDE_STOPPED=false # 不更新已停止的容器
|
||||||
|
- WATCHTOWER_LABEL_ENABLE=true # 根据容器标签进行更新
|
||||||
|
- WATCHTOWER_POLL_INTERVAL=300 # 每 5 分钟检查一次更新
|
||||||
|
|
||||||
|
# 如果需要支持 IPv6,请取消以下注释
|
||||||
|
# networks:
|
||||||
|
# ip6net:
|
||||||
|
# enable_ipv6: true
|
||||||
|
# ipam:
|
||||||
|
# config:
|
||||||
|
# - subnet: 2001:db8::/64
|
||||||
|
|
||||||
|
```
|
||||||
> 数据默认存在`/data/certd`目录下,不用担心数据丢失
|
> 数据默认存在`/data/certd`目录下,不用担心数据丢失
|
||||||
|
|
||||||
|
|
||||||
@@ -155,12 +204,14 @@ https://afdian.com/a/greper
|
|||||||
|
|
||||||
专业版特权对比
|
专业版特权对比
|
||||||
|
|
||||||
| 功能 | 免费版 | 专业版 |
|
| 功能 | 基础版 | 专业版 |
|
||||||
|---------|-------------------|-----------------------|
|
|------|-----------------|-------------------|
|
||||||
| 免费证书申请 | 免费无限制 | 免费无限制 |
|
| 免费证书申请 | 免费无限制 | 无限制 |
|
||||||
| 自动部署插件 | 阿里云、腾讯云、七牛云、主机部署等 | 支持群晖、宝塔、1Panel等,持续开发中 |
|
| 域名数量 | 免费无限制 | 无限制 |
|
||||||
| 发邮件功能 | 需要配置 | 免配置 |
|
| 证书流水线条数 | 免费无限制 | 无限制 |
|
||||||
| 证书流水线条数 | 10条 | 无限制 |
|
| 站点证书监控 | 1条 | 无限制 |
|
||||||
|
| 自动部署插件 | 阿里云、腾讯云、七牛云、SSH | 支持群晖、宝塔、1Panel等,持续开发中 |
|
||||||
|
| 通知 | 邮件、webhook | server酱、企微、anpush等 |
|
||||||
|
|
||||||
************************
|
************************
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
15:28
|
01:43
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
version: '3.3' # 兼容旧版docker-compose
|
version: '3.3' # 兼容旧版docker-compose
|
||||||
services:
|
services:
|
||||||
certd:
|
certd:
|
||||||
# 镜像 # ↓↓↓↓↓ ---- 镜像版本号,建议改成固定版本号
|
# 镜像 # ↓↓↓↓↓ ---- 镜像版本号,建议改成固定版本号,例如:certd:1.29.0
|
||||||
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||||
container_name: certd # 容器名
|
container_name: certd # 容器名
|
||||||
restart: unless-stopped # 自动重启
|
restart: unless-stopped # 自动重启
|
||||||
@@ -23,10 +23,9 @@ services:
|
|||||||
# # ↓↓↓↓ --------------------------------------------------------- 如果你服务器部署在国外,可以用这个替换上面阿里云的公共dns
|
# # ↓↓↓↓ --------------------------------------------------------- 如果你服务器部署在国外,可以用这个替换上面阿里云的公共dns
|
||||||
# - 8.8.8.8 # 谷歌公共dns
|
# - 8.8.8.8 # 谷歌公共dns
|
||||||
# - 8.8.4.4
|
# - 8.8.4.4
|
||||||
|
|
||||||
# extra_hosts:
|
# extra_hosts:
|
||||||
# # ↓↓↓↓ -------------------------------------------------------- 这里可以配置自定义hosts,外网域名可以指向本地局域网ip地址
|
# # ↓↓↓↓ -------------------------------------------------------- 这里可以配置自定义hosts,外网域名可以指向本地局域网ip地址
|
||||||
# - "localdomain.comm:192.168.1.3"
|
# - "localdomain.com:192.168.1.3"
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
# 设置环境变量即可自定义certd配置
|
# 设置环境变量即可自定义certd配置
|
||||||
@@ -34,7 +33,10 @@ services:
|
|||||||
# 配置规则: certd_ + 配置项, 点号用_代替
|
# 配置规则: certd_ + 配置项, 点号用_代替
|
||||||
# #↓↓↓↓ ----------------------------- 如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false
|
# #↓↓↓↓ ----------------------------- 如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false
|
||||||
- certd_system_resetAdminPasswd=false
|
- certd_system_resetAdminPasswd=false
|
||||||
# #↓↓↓↓ ----------------------------- 使用postgresql数据库
|
# 默认使用sqlite文件数据库,如果需要使用其他数据库,请设置以下环境变量
|
||||||
|
# 注意: 选定使用一种数据库之后,不支持更换数据库。
|
||||||
|
# 数据库迁移方法:1、使用新数据库重新部署一套,然后将旧数据同步过去,注意flyway_history表的数据不要同步
|
||||||
|
# #↓↓↓↓ ----------------------------- 使用postgresql数据库,需要提前创建数据库
|
||||||
# - certd_flyway_scriptDir=./db/migration-pg # 升级脚本目录
|
# - certd_flyway_scriptDir=./db/migration-pg # 升级脚本目录
|
||||||
# - certd_typeorm_dataSource_default_type=postgres # 数据库类型
|
# - certd_typeorm_dataSource_default_type=postgres # 数据库类型
|
||||||
# - certd_typeorm_dataSource_default_host=localhost # 数据库地址
|
# - certd_typeorm_dataSource_default_host=localhost # 数据库地址
|
||||||
@@ -43,6 +45,19 @@ services:
|
|||||||
# - certd_typeorm_dataSource_default_password=yourpasswd # 密码
|
# - certd_typeorm_dataSource_default_password=yourpasswd # 密码
|
||||||
# - certd_typeorm_dataSource_default_database=certd # 数据库名
|
# - certd_typeorm_dataSource_default_database=certd # 数据库名
|
||||||
|
|
||||||
|
# #↓↓↓↓ ----------------------------- 使用mysql数据库,需要提前创建数据库 charset=utf8mb4, collation=utf8mb4_bin
|
||||||
|
# - certd_flyway_scriptDir=./db/migration-mysql # 升级脚本目录
|
||||||
|
# - certd_typeorm_dataSource_default_type=mysql # 数据库类型, 或者 mariadb
|
||||||
|
# - certd_typeorm_dataSource_default_host=localhost # 数据库地址
|
||||||
|
# - certd_typeorm_dataSource_default_port=3306 # 数据库端口
|
||||||
|
# - certd_typeorm_dataSource_default_username=root # 用户名
|
||||||
|
# - certd_typeorm_dataSource_default_password=yourpasswd # 密码
|
||||||
|
# - certd_typeorm_dataSource_default_database=certd # 数据库名
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# #↓↓↓↓ ------------------------------------------------------------- 启用ipv6网络
|
# #↓↓↓↓ ------------------------------------------------------------- 启用ipv6网络
|
||||||
# networks:
|
# networks:
|
||||||
# - ip6net
|
# - ip6net
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ export default defineConfig({
|
|||||||
{ text: "源码部署", link: "/guide/install/source/" }
|
{ text: "源码部署", link: "/guide/install/source/" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ text: "演示教程", link: "/guide/tutorial.md" }
|
{ text: "演示教程", link: "/guide/tutorial.md" },
|
||||||
|
{ text: "版本升级", link: "/guide/install/upgrade.md" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,122 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 免费套餐支持购买 ([f5ec987](https://github.com/certd/certd/commit/f5ec9870fd6af1f0c9099852bbdb4d07813ccce8))
|
||||||
|
* 修复某处金额转换丢失精度的bug ([d2d6f12](https://github.com/certd/certd/commit/d2d6f12218cbe7bd55f4ae082b93084be85f0a7b))
|
||||||
|
* 修复新版本小红点显示错误问题 ([fe4786e](https://github.com/certd/certd/commit/fe4786e168afe03a5243dd67971476c348339809))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 用户创建证书流水线没有购买套餐或者超限时提前报错 ([472f06c](https://github.com/certd/certd/commit/472f06c2d190d0ae48e8b53c18bc278437656a1c))
|
||||||
|
* 优化插件名称显示 ([26adf7d](https://github.com/certd/certd/commit/26adf7d437e674385f26a8f92fded6521a620671))
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复手机模式下,查询框被文字遮盖的bug ([040788c](https://github.com/certd/certd/commit/040788c793642c3bb2a3ede87fe30fcf3be471bd))
|
||||||
|
* 修复左侧菜单收起时无法展开子菜单的bug ([0056223](https://github.com/certd/certd/commit/005622307e612717a5408aa1484717ef03003a22))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 基础版不再限制流水线数量 ([cb27d4b](https://github.com/certd/certd/commit/cb27d4b4906b2782eaceb0a95bbdc5d0534370d2))
|
||||||
|
* 套餐购买支持易支付、支付宝支付 ([faa28f8](https://github.com/certd/certd/commit/faa28f88f954cba4c1dd29125562e5acd2fd99af))
|
||||||
|
* 用户套餐,用户支付功能 ([a019956](https://github.com/certd/certd/commit/a019956698acaf2c4beb620b5ad8c18918ead6a1))
|
||||||
|
* 站点证书监控 ([9c8c7a7](https://github.com/certd/certd/commit/9c8c7a781223f4217f45510db1e89495600e3cd5))
|
||||||
|
* 支持微信支付 ([45d6347](https://github.com/certd/certd/commit/45d6347f5b6199493b11aabdd74177f6dca2cea4))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 调整创建证书表单字段的顺序 ([d393521](https://github.com/certd/certd/commit/d3935219f2aa50d6662c5b5ebf7ee25ad696ab2b))
|
||||||
|
* 同一时间只允许一个套餐生效 ([8ebf95a](https://github.com/certd/certd/commit/8ebf95a222a900d1707716c7b1f3b39f8a6d8f94))
|
||||||
|
* 用户名支持修改 ([89c7f07](https://github.com/certd/certd/commit/89c7f070343e86453c84677ebe1669f9b266d871))
|
||||||
|
* 优化证书申请跳过的状态显示,成功通知现在在跳过时不会发送 ([67d762b](https://github.com/certd/certd/commit/67d762b6a520f1fa24719a124e5ae975a81f5f82))
|
||||||
|
* 站点证书监控通知发送,每天定时检查 ([bb4910f](https://github.com/certd/certd/commit/bb4910f4e57234e42b44505f4620ae7af66025c5))
|
||||||
|
* 支持一体证书 ([53c38cf](https://github.com/certd/certd/commit/53c38cf714a6f7486abbf1d71c9f48f56a790100))
|
||||||
|
* 支持plesk网站证书部署 ([eda45c1](https://github.com/certd/certd/commit/eda45c1528199648b3970505e87f492d398226cd))
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复证书成功通知发送失败的bug ([0f5c690](https://github.com/certd/certd/commit/0f5c69040ba77340c909813220a26bc7ddada3ea))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 群晖支持6.x ([79f7ec4](https://github.com/certd/certd/commit/79f7ec4672f4fd5744cc45e4a6f104da943f4026))
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复没有配置eab时,报order无法读取的问题 ([657a2ae](https://github.com/certd/certd/commit/657a2ae032e6f61ac27fbdd26c7bf169c041219e))
|
||||||
|
* 修复授权被删除后,无法清空的bug ([b45977c](https://github.com/certd/certd/commit/b45977c29a29084c11e496bec3415eaaebafdd74))
|
||||||
|
* mysql下access.setting字段改成text ([b7f5740](https://github.com/certd/certd/commit/b7f5740c57743914f754f3b4fdd94b59a2e8338c))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 点击版本红点按钮,跳转到升级帮助页面 ([454fbda](https://github.com/certd/certd/commit/454fbda581bbe22abca5b91e5086ea9d9d58a020))
|
||||||
|
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||||
|
* 支持腾讯虚拟机开关机([@wujingke](https://github.com/wujingke)) ([8039e8b](https://github.com/certd/certd/commit/8039e8baf83c82d03f1a6198cf61c372026b962b))
|
||||||
|
* 支持aws cloudfront ([0ae39f1](https://github.com/certd/certd/commit/0ae39f160a7c6b6696b3bf513d68aa28905810ad))
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复创建流水线通知设置无效的bug ([498cf34](https://github.com/certd/certd/commit/498cf34999fddfa24ce088e2e678469fa669abb8))
|
||||||
|
* 修复流水线分组可以被所有人看见的bug ([a0e838d](https://github.com/certd/certd/commit/a0e838d1eec918e5dc92fe95dc72ac14facb930e))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 优化数据表索引 ([228fdf0](https://github.com/certd/certd/commit/228fdf0a0d28013f5dd156a97bbde80537e8e97e))
|
||||||
|
* 支持mysql ([7cde1fd](https://github.com/certd/certd/commit/7cde1fdc4a9ed851900d231a5460c8dbfbcd148e))
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复cname排查方法 nslookup命令显示黑色的问题 ([3dfeeec](https://github.com/certd/certd/commit/3dfeeec899d7d0d7292695ce410f78548e076c03))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 通知选择器优化 ([2c0cbdd](https://github.com/certd/certd/commit/2c0cbdd29ecb74cc939b2ae7ee86b8d40f70ba31))
|
||||||
|
* 新增七牛云插件分组 ([49e7dc5](https://github.com/certd/certd/commit/49e7dc56e1a95fbdea3e30cdeb945b48415b69e3))
|
||||||
|
* 新增server酱3通知 ([6aa4872](https://github.com/certd/certd/commit/6aa487269c9f6862e188b37a0d6c73f79c937d94))
|
||||||
|
* 支持邀请奖励 ([618ec93](https://github.com/certd/certd/commit/618ec937866b24ebcf8164db43acb1ed66a5b329))
|
||||||
|
* 支持易发云短信 ([94fa77f](https://github.com/certd/certd/commit/94fa77fcd2b9bea294fb05736c0d8cdc81f56103))
|
||||||
|
* cname value优化 ([e8c9c2a](https://github.com/certd/certd/commit/e8c9c2a47d47048ae743b16f7bc932dbe18a89e9))
|
||||||
|
* favicon支持自定义 ([8b9c47d](https://github.com/certd/certd/commit/8b9c47daf194515006689a212ae9cf586bdf5993))
|
||||||
|
|
||||||
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复自定义webhook contextType的bug ([7e5ea0c](https://github.com/certd/certd/commit/7e5ea0cee003acda952d922ca70592f1e8a2ed80))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 手机号登录、邮箱验证码注册 ([7b55337](https://github.com/certd/certd/commit/7b55337c5edb470cca7aa62201eda8d274784004))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 部署到IIS插件 ([1534f45](https://github.com/certd/certd/commit/1534f4523633265d219d7b3a249a9ea1af99c512))
|
||||||
|
* 登录失败增加重试次数限制及冷却时间 ([954b6df](https://github.com/certd/certd/commit/954b6df3608695fe074130f8149a33e311d80cc4))
|
||||||
|
* 流水线支持批量修改分组,批量删除 ([a847e66](https://github.com/certd/certd/commit/a847e66c4fc843b98f1520b2b8072d3586ce8b81))
|
||||||
|
* 取消docker-compose的dns配置 ([87bbf6f](https://github.com/certd/certd/commit/87bbf6f14080b9fa287c250d7fc4d33279c83ff7))
|
||||||
|
* 首页新增修改密码提示 ([0772d3b](https://github.com/certd/certd/commit/0772d3b3fd24afdde4086d9f09ef19d037b431b4))
|
||||||
|
* 选项显示图标 ([aedc462](https://github.com/certd/certd/commit/aedc46213571a3bd93809b7af7fa17a08d546237))
|
||||||
|
* 优化七牛云cdn,获取域名列表可以选择 ([5a20242](https://github.com/certd/certd/commit/5a20242111d6bd255b25dac86fe1f062c8543096))
|
||||||
|
* 优化七牛云cdn部署,保持http2和forceHttp设置,当未开启https时,主动开启https ([196f7d9](https://github.com/certd/certd/commit/196f7d9dc23d7dd96b663c686542e85270b81aef))
|
||||||
|
* 优化证书申请成功通知发送方式 ([8002a56](https://github.com/certd/certd/commit/8002a56efc5998aa03db5711ae87f9eb4bc9e160))
|
||||||
|
* 支持短信验证码登录 ([387bcc5](https://github.com/certd/certd/commit/387bcc5fa418cdeea81a06da5e3f8cd6b43cd082))
|
||||||
|
* 支持威联通证书部署 ([0d8913e](https://github.com/certd/certd/commit/0d8913ea2f56fdebbcc9bb207eae59e8ddbb8cad))
|
||||||
|
* 自定义webhook显示详细的错误信息 ([3254afc](https://github.com/certd/certd/commit/3254afc75640eed3729d0fc02a818fefbe5c7fc3))
|
||||||
|
|
||||||
## [1.27.9](https://github.com/certd/certd/compare/v1.27.8...v1.27.9) (2024-11-26)
|
## [1.27.9](https://github.com/certd/certd/compare/v1.27.8...v1.27.9) (2024-11-26)
|
||||||
|
|
||||||
### Performance Improvements
|
### Performance Improvements
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ git clone https://github.com/certd/certd --depth=1
|
|||||||
#进入项目目录
|
#进入项目目录
|
||||||
cd certd
|
cd certd
|
||||||
|
|
||||||
# 切换到最新版本代码【如果v2分支无法编译,请尝试切换到最新版tag】
|
|
||||||
# git checkout v1.27.0 # 这里换成最新版本号
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 修改pnpm-workspace.yaml文件
|
### 修改pnpm-workspace.yaml文件
|
||||||
@@ -109,4 +106,4 @@ throw new Error("错误信息")
|
|||||||
## 五、贡献插件送激活码
|
## 五、贡献插件送激活码
|
||||||
|
|
||||||
- PR要求,插件功能完整,代码规范
|
- PR要求,插件功能完整,代码规范
|
||||||
- PR通过后,联系我们,送您一个专业版激活码
|
- PR通过后,联系我们,送您一个半年期专业版激活码
|
||||||
@@ -14,7 +14,7 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
|
|||||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上
|
* 支持通配符域名/泛域名,支持多个域名打到一个证书上
|
||||||
* 邮件通知
|
* 邮件通知
|
||||||
* 私有化部署,保障数据安全
|
* 私有化部署,保障数据安全
|
||||||
* 支持sqlite,postgresql数据库
|
* 支持SQLite、Postgresql、MySQL数据库
|
||||||
|
|
||||||
|
|
||||||
## 二、一些说明
|
## 二、一些说明
|
||||||
@@ -30,5 +30,5 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
|
|||||||
|
|
||||||
## 三、证书颁发机构对比
|
## 三、证书颁发机构对比
|
||||||
* Let's Encrypt:申请最简单。
|
* Let's Encrypt:申请最简单。
|
||||||
* Google: 大厂光环,兼容性好,需要翻墙获取EAB。
|
* Google: 大厂光环,兼容性好,首次需要翻墙获取EAB。
|
||||||
* ZeroSSL: 有数量限制,获取EAB无需翻墙。
|
* ZeroSSL: 需要EAB,获取EAB无需翻墙。
|
||||||
BIN
docs/guide/install/1panel/images/upgrade-1.png
Normal file
BIN
docs/guide/install/1panel/images/upgrade-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
BIN
docs/guide/install/1panel/images/upgrade-2.png
Normal file
BIN
docs/guide/install/1panel/images/upgrade-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -31,15 +31,12 @@ admin/123456
|
|||||||
|
|
||||||
## 三、升级
|
## 三、升级
|
||||||
|
|
||||||
1. 找到容器,点击编辑
|
1. 找到容器,点击更多->升级
|
||||||

|

|
||||||
|
|
||||||
2. 将latest修改为最新版本号
|
2. 选择强制拉取镜像,点击确认即可
|
||||||

|

|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
3. 点击确定,重启容器
|
|
||||||
|
|
||||||
## 四、数据备份
|
## 四、数据备份
|
||||||
|
|
||||||
|
|||||||
@@ -38,28 +38,12 @@ admin/123456
|
|||||||
登录后请及时修改密码
|
登录后请及时修改密码
|
||||||
|
|
||||||
## 三、如何升级
|
## 三、如何升级
|
||||||
|
宝塔升级certd非常简单
|
||||||
|
|
||||||
### 1. 应用商店安装,直接更新镜像即可
|
`docker`->`容器编排`->`左侧选择Certd`->`更新镜像`
|
||||||
`docker`->`容器编排`->`左侧选择Certd-xxxx`->`更新镜像`
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
### 2. latest更新方式
|
|
||||||
在主机上拉取最新镜像,然后面板上重启容器
|
|
||||||
```shell
|
|
||||||
docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 固定版本号方式
|
|
||||||
|
|
||||||
修改容器编排模版中的镜像版本号,然后面板上重启容器
|
|
||||||
```shell
|
|
||||||
services:
|
|
||||||
certd:
|
|
||||||
# 镜像 # 修改最新版本号 ---- ↓↓↓↓↓
|
|
||||||
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:v1.xx.x
|
|
||||||
```
|
|
||||||
|
|
||||||
## 四、数据备份
|
## 四、数据备份
|
||||||
|
|
||||||
### 4.1 应用商店部署方式
|
### 4.1 应用商店部署方式
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ docker compose up -d
|
|||||||
|
|
||||||
> 如果提示 没有docker compose命令,请安装docker-compose
|
> 如果提示 没有docker compose命令,请安装docker-compose
|
||||||
> https://docs.docker.com/compose/install/linux/
|
> https://docs.docker.com/compose/install/linux/
|
||||||
> 然后使用 `docker-compose up -d` 启动
|
|
||||||
|
|
||||||
### 3. 访问测试
|
### 3. 访问测试
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
```shell
|
```shell
|
||||||
# 克隆代码
|
# 克隆代码
|
||||||
git clone https://github.com/certd/certd
|
git clone https://github.com/certd/certd
|
||||||
# git checkout v1.x.x # 1.x.x换成最新版本号,当v2主干分支代码无法正常启动时,可以尝试此命令
|
# git checkout v1.x.x # 当v2主干分支代码无法正常启动时,可以尝试此命令,1.x.x换成最新版本号
|
||||||
cd certd
|
cd certd
|
||||||
# 启动服务
|
# 启动服务
|
||||||
./start.sh
|
./start.sh
|
||||||
@@ -29,9 +29,15 @@ https://your_server_ip:7002
|
|||||||
## 二、升级
|
## 二、升级
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# 更新代码并启动
|
|
||||||
cd certd
|
cd certd
|
||||||
|
# 确保数据安全,备份一下数据
|
||||||
|
cp -rf ./packages/ui/certd-server/data ../certd-data-backup
|
||||||
|
|
||||||
git pull
|
git pull
|
||||||
|
# 如果提示pull失败,可以尝试强制更新
|
||||||
|
# git checkout v2 -f && git pull
|
||||||
|
|
||||||
# 先停止旧的服务,7001是certd的默认端口
|
# 先停止旧的服务,7001是certd的默认端口
|
||||||
kill -9 $(lsof -t -i:7001)
|
kill -9 $(lsof -t -i:7001)
|
||||||
# 重新编译启动
|
# 重新编译启动
|
||||||
|
|||||||
12
docs/guide/install/upgrade.md
Normal file
12
docs/guide/install/upgrade.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# 版本升级
|
||||||
|
|
||||||
|
## 升级方法
|
||||||
|
根据不同部署方式查看升级方法
|
||||||
|
|
||||||
|
1. [Docker方式部署升级](./docker/#二、升级)
|
||||||
|
2. [宝塔面板方式部署升级](./baota/#三、如何升级)
|
||||||
|
3. [1Panel面板方式部署升级](./1panel/#三、升级)
|
||||||
|
4. [源码方式部署](./source/#二、升级)
|
||||||
|
|
||||||
|
## 升级日志
|
||||||
|
[CHANGELOG](../changelogs/CHANGELOG.md)
|
||||||
10
docs/guide/use/cert/index.md
Normal file
10
docs/guide/use/cert/index.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# 证书申请失败情况
|
||||||
|
|
||||||
|
|
||||||
|
## DNS记录问题
|
||||||
|
|
||||||
|
1. DNS 不要设置CAA记录,删除即可
|
||||||
|
|
||||||
|
2. DNSSEC相关报错,DNSSEC管理中删除即可
|
||||||
|
|
||||||
|
3. DNS 有其他平台申请过的_acme-challenge记录,删除即可
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 53 KiB |
@@ -1,8 +1,12 @@
|
|||||||
# 群晖部署和证书更新
|
# 群晖部署和证书更新
|
||||||
|
|
||||||
|
支持群晖`6.x`、`7.x`
|
||||||
|
|
||||||
## 一、群晖部署Certd
|
## 一、群晖部署Certd
|
||||||
|
|
||||||
|
以下是群晖`7.x`的部署`certd`步骤。
|
||||||
|
群晖`6.x`请参考[docker部署](./../../install/docker/)
|
||||||
|
|
||||||
### 1. 打开Container Manager
|
### 1. 打开Container Manager
|
||||||
|
|
||||||

|

|
||||||
@@ -32,6 +36,8 @@
|
|||||||
|
|
||||||
## 二、更新群晖证书
|
## 二、更新群晖证书
|
||||||
|
|
||||||
|
证书部署插件支持群晖`6.x`、`7.x`
|
||||||
|
|
||||||
## 1. 前提条件
|
## 1. 前提条件
|
||||||
* 已经部署了certd
|
* 已经部署了certd
|
||||||
* 群晖上已经设置好了证书(证书建议设置好描述,插件需要根据描述查找证书)
|
* 群晖上已经设置好了证书(证书建议设置好描述,插件需要根据描述查找证书)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ features:
|
|||||||
- title: 多证书格式支持
|
- title: 多证书格式支持
|
||||||
details: 支持pem、pfx、der、jks等多种证书格式,支持Google、Letsencrypt、ZeroSSL证书颁发机构
|
details: 支持pem、pfx、der、jks等多种证书格式,支持Google、Letsencrypt、ZeroSSL证书颁发机构
|
||||||
- title: 支持私有化部署
|
- title: 支持私有化部署
|
||||||
details: 保障数据安全
|
details: 授权数据加密存储,保障数据安全
|
||||||
- title: 多数据库支持
|
- title: 多数据库支持
|
||||||
details: 支持sqlite,postgresql数据库
|
details: 支持SQLite、Postgresql、MySQL数据库
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -9,5 +9,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"npmClient": "pnpm",
|
"npmClient": "pnpm",
|
||||||
"version": "1.28.0"
|
"version": "1.29.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,36 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/publishlab/node-acme-client/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/publishlab/node-acme-client/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/publishlab/node-acme-client/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/publishlab/node-acme-client/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/publishlab/node-acme-client/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/publishlab/node-acme-client/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 支持mysql ([7cde1fd](https://github.com/publishlab/node-acme-client/commit/7cde1fdc4a9ed851900d231a5460c8dbfbcd148e))
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/publishlab/node-acme-client/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
# [1.28.0](https://github.com/publishlab/node-acme-client/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/publishlab/node-acme-client/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/acme-client
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "Simple and unopinionated ACME client",
|
"description": "Simple and unopinionated ACME client",
|
||||||
"private": false,
|
"private": false,
|
||||||
"author": "nmorsman",
|
"author": "nmorsman",
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"module": "scr/index.js",
|
"module": "scr/index.js",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"types"
|
"types"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@certd/basic": "^1.28.0",
|
"@certd/basic": "^1.29.2",
|
||||||
"@peculiar/x509": "^1.11.0",
|
"@peculiar/x509": "^1.11.0",
|
||||||
"asn1js": "^3.0.5",
|
"asn1js": "^3.0.5",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
@@ -65,5 +65,5 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||||
},
|
},
|
||||||
"gitHead": "cf1936309241d3cf05c2fba767f530bbb3b62b15"
|
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||||
}
|
}
|
||||||
|
|||||||
137
packages/core/acme-client/types/index.test-d.js
Normal file
137
packages/core/acme-client/types/index.test-d.js
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
"use strict";
|
||||||
|
/**
|
||||||
|
* acme-client type definition tests
|
||||||
|
*/
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||||
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||||
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||||
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||||
|
function step(op) {
|
||||||
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
|
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
||||||
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||||
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||||
|
switch (op[0]) {
|
||||||
|
case 0: case 1: t = op; break;
|
||||||
|
case 4: _.label++; return { value: op[1], done: false };
|
||||||
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||||
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||||
|
default:
|
||||||
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||||
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||||
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||||
|
if (t[2]) _.ops.pop();
|
||||||
|
_.trys.pop(); continue;
|
||||||
|
}
|
||||||
|
op = body.call(thisArg, _);
|
||||||
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||||
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
var acme = require("acme-client");
|
||||||
|
(function () { return __awaiter(void 0, void 0, void 0, function () {
|
||||||
|
var accountKey, client, order, authorizations, authorization, challenge, _a, certKey, certCsr;
|
||||||
|
return __generator(this, function (_b) {
|
||||||
|
switch (_b.label) {
|
||||||
|
case 0: return [4 /*yield*/, acme.crypto.createPrivateKey()];
|
||||||
|
case 1:
|
||||||
|
accountKey = _b.sent();
|
||||||
|
client = new acme.Client({
|
||||||
|
accountKey: accountKey,
|
||||||
|
directoryUrl: acme.directory.letsencrypt.staging
|
||||||
|
});
|
||||||
|
/* Account */
|
||||||
|
return [4 /*yield*/, client.createAccount({
|
||||||
|
termsOfServiceAgreed: true,
|
||||||
|
contact: ['mailto:test@example.com']
|
||||||
|
})];
|
||||||
|
case 2:
|
||||||
|
/* Account */
|
||||||
|
_b.sent();
|
||||||
|
return [4 /*yield*/, client.createOrder({
|
||||||
|
identifiers: [
|
||||||
|
{ type: 'dns', value: 'example.com' },
|
||||||
|
{ type: 'dns', value: '*.example.com' },
|
||||||
|
]
|
||||||
|
})];
|
||||||
|
case 3:
|
||||||
|
order = _b.sent();
|
||||||
|
return [4 /*yield*/, client.getOrder(order)];
|
||||||
|
case 4:
|
||||||
|
_b.sent();
|
||||||
|
return [4 /*yield*/, client.getAuthorizations(order)];
|
||||||
|
case 5:
|
||||||
|
authorizations = _b.sent();
|
||||||
|
authorization = authorizations[0];
|
||||||
|
challenge = authorization.challenges[0];
|
||||||
|
return [4 /*yield*/, client.getChallengeKeyAuthorization(challenge)];
|
||||||
|
case 6:
|
||||||
|
_b.sent();
|
||||||
|
return [4 /*yield*/, client.verifyChallenge(authorization, challenge)];
|
||||||
|
case 7:
|
||||||
|
_b.sent();
|
||||||
|
return [4 /*yield*/, client.completeChallenge(challenge)];
|
||||||
|
case 8:
|
||||||
|
_b.sent();
|
||||||
|
return [4 /*yield*/, client.waitForValidStatus(challenge)];
|
||||||
|
case 9:
|
||||||
|
_b.sent();
|
||||||
|
return [4 /*yield*/, acme.crypto.createCsr({
|
||||||
|
commonName: 'example.com',
|
||||||
|
altNames: ['example.com', '*.example.com']
|
||||||
|
})];
|
||||||
|
case 10:
|
||||||
|
_a = _b.sent(), certKey = _a[0], certCsr = _a[1];
|
||||||
|
return [4 /*yield*/, client.finalizeOrder(order, certCsr)];
|
||||||
|
case 11:
|
||||||
|
_b.sent();
|
||||||
|
return [4 /*yield*/, client.getCertificate(order)];
|
||||||
|
case 12:
|
||||||
|
_b.sent();
|
||||||
|
return [4 /*yield*/, client.getCertificate(order, 'DST Root CA X3')];
|
||||||
|
case 13:
|
||||||
|
_b.sent();
|
||||||
|
/* Auto */
|
||||||
|
return [4 /*yield*/, client.auto({
|
||||||
|
csr: certCsr,
|
||||||
|
challengeCreateFn: function (authz, challenge, keyAuthorization) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
||||||
|
return [2 /*return*/];
|
||||||
|
}); }); },
|
||||||
|
challengeRemoveFn: function (authz, challenge, keyAuthorization) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
||||||
|
return [2 /*return*/];
|
||||||
|
}); }); }
|
||||||
|
})];
|
||||||
|
case 14:
|
||||||
|
/* Auto */
|
||||||
|
_b.sent();
|
||||||
|
return [4 /*yield*/, client.auto({
|
||||||
|
csr: certCsr,
|
||||||
|
email: 'test@example.com',
|
||||||
|
termsOfServiceAgreed: false,
|
||||||
|
skipChallengeVerification: false,
|
||||||
|
challengePriority: ['http-01', 'dns-01'],
|
||||||
|
preferredChain: 'DST Root CA X3',
|
||||||
|
challengeCreateFn: function (authz, challenge, keyAuthorization) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
||||||
|
return [2 /*return*/];
|
||||||
|
}); }); },
|
||||||
|
challengeRemoveFn: function (authz, challenge, keyAuthorization) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
||||||
|
return [2 /*return*/];
|
||||||
|
}); }); }
|
||||||
|
})];
|
||||||
|
case 15:
|
||||||
|
_b.sent();
|
||||||
|
return [2 /*return*/];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}); })();
|
||||||
@@ -3,6 +3,46 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/basic
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复某处金额转换丢失精度的bug ([d2d6f12](https://github.com/certd/certd/commit/d2d6f12218cbe7bd55f4ae082b93084be85f0a7b))
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 用户套餐,用户支付功能 ([a019956](https://github.com/certd/certd/commit/a019956698acaf2c4beb620b5ad8c18918ead6a1))
|
||||||
|
* 支持微信支付 ([45d6347](https://github.com/certd/certd/commit/45d6347f5b6199493b11aabdd74177f6dca2cea4))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 站点证书监控通知发送,每天定时检查 ([bb4910f](https://github.com/certd/certd/commit/bb4910f4e57234e42b44505f4620ae7af66025c5))
|
||||||
|
* 支持plesk网站证书部署 ([eda45c1](https://github.com/certd/certd/commit/eda45c1528199648b3970505e87f492d398226cd))
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/basic
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/basic
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/basic
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 通知选择器优化 ([2c0cbdd](https://github.com/certd/certd/commit/2c0cbdd29ecb74cc939b2ae7ee86b8d40f70ba31))
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
### Performance Improvements
|
### Performance Improvements
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
03:20
|
01:51
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/basic",
|
"name": "@certd/basic",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"log4js": "^6.9.1",
|
"log4js": "^6.9.1",
|
||||||
"lru-cache": "^10.0.0",
|
"lru-cache": "^10.0.0",
|
||||||
|
"mitt": "^3.0.1",
|
||||||
"nanoid": "^5.0.7",
|
"nanoid": "^5.0.7",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
"nodemailer": "^6.9.3"
|
"nodemailer": "^6.9.3"
|
||||||
@@ -43,5 +44,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "cf1936309241d3cf05c2fba767f530bbb3b62b15"
|
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ export * from './util.hash.js';
|
|||||||
export * from './util.merge.js';
|
export * from './util.merge.js';
|
||||||
export * from './util.cache.js';
|
export * from './util.cache.js';
|
||||||
export * from './util.string.js';
|
export * from './util.string.js';
|
||||||
|
export * from './util.lock.js';
|
||||||
|
export * from './util.mitter.js';
|
||||||
|
export * from './util.id.js';
|
||||||
|
export * from './util.domain.js';
|
||||||
|
export * from './util.amount.js';
|
||||||
import { stringUtils } from './util.string.js';
|
import { stringUtils } from './util.string.js';
|
||||||
import sleep from './util.sleep.js';
|
import sleep from './util.sleep.js';
|
||||||
import { http, download } from './util.request.js';
|
import { http, download } from './util.request.js';
|
||||||
@@ -22,8 +27,11 @@ import { cache } from './util.cache.js';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { domainUtils } from './util.domain.js';
|
import { domainUtils } from './util.domain.js';
|
||||||
import { optionsUtils } from './util.options.js';
|
import { optionsUtils } from './util.options.js';
|
||||||
|
import { amountUtils } from './util.amount.js';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import * as id from './util.id.js';
|
import * as id from './util.id.js';
|
||||||
|
import { locker } from './util.lock.js';
|
||||||
|
import { mitter } from './util.mitter.js';
|
||||||
export const utils = {
|
export const utils = {
|
||||||
sleep,
|
sleep,
|
||||||
http,
|
http,
|
||||||
@@ -41,4 +49,7 @@ export const utils = {
|
|||||||
domain: domainUtils,
|
domain: domainUtils,
|
||||||
options: optionsUtils,
|
options: optionsUtils,
|
||||||
string: stringUtils,
|
string: stringUtils,
|
||||||
|
locker,
|
||||||
|
mitter,
|
||||||
|
amount: amountUtils,
|
||||||
};
|
};
|
||||||
|
|||||||
9
packages/core/basic/src/utils/util.amount.ts
Normal file
9
packages/core/basic/src/utils/util.amount.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export const amountUtils = {
|
||||||
|
toCent(amount: number): number {
|
||||||
|
return parseInt((amount * 100).toFixed(0));
|
||||||
|
},
|
||||||
|
|
||||||
|
toYuan(amount: number): number {
|
||||||
|
return parseFloat((amount / 100).toFixed(2));
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export function isDev() {
|
export function isDev() {
|
||||||
const nodeEnv = process.env.NODE_ENV || '';
|
const nodeEnv = process.env.NODE_ENV || '';
|
||||||
return nodeEnv === 'development' || nodeEnv.indexOf('local') >= 0;
|
return nodeEnv === 'development' || nodeEnv.includes('local') || nodeEnv.startsWith('dev');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ import crypto from 'crypto';
|
|||||||
function md5(data: string) {
|
function md5(data: string) {
|
||||||
return crypto.createHash('md5').update(data).digest('hex');
|
return crypto.createHash('md5').update(data).digest('hex');
|
||||||
}
|
}
|
||||||
|
function sha256(data: string) {
|
||||||
|
return crypto.createHash('sha256').update(data).digest('hex');
|
||||||
|
}
|
||||||
export const hashUtils = {
|
export const hashUtils = {
|
||||||
md5,
|
md5,
|
||||||
|
sha256,
|
||||||
};
|
};
|
||||||
|
|||||||
47
packages/core/basic/src/utils/util.lock.ts
Normal file
47
packages/core/basic/src/utils/util.lock.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { logger, utils } from './index.js';
|
||||||
|
|
||||||
|
export class Locker {
|
||||||
|
locked: Record<string, any> = {};
|
||||||
|
|
||||||
|
async execute(lockStr: string, callback: any) {
|
||||||
|
await this.lock(lockStr);
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
logger.warn('Lock timeout,自动解锁', lockStr);
|
||||||
|
this.unlock(lockStr);
|
||||||
|
}, 20000);
|
||||||
|
try {
|
||||||
|
return await callback();
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
this.unlock(lockStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async lock(str: string) {
|
||||||
|
const isLocked = this.isLocked(str);
|
||||||
|
if (isLocked) {
|
||||||
|
let count = 0;
|
||||||
|
while (true) {
|
||||||
|
await utils.sleep(100);
|
||||||
|
if (!this.isLocked(str)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
if (count > 20) {
|
||||||
|
throw new Error('Lock timeout');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.locked[str] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock(str: string) {
|
||||||
|
delete this.locked[str];
|
||||||
|
}
|
||||||
|
|
||||||
|
isLocked(str: string) {
|
||||||
|
return this.locked[str] ?? false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const locker = new Locker();
|
||||||
2
packages/core/basic/src/utils/util.mitter.ts
Normal file
2
packages/core/basic/src/utils/util.mitter.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import mitt from 'mitt';
|
||||||
|
export const mitter = mitt();
|
||||||
@@ -37,6 +37,8 @@ function buildGroupOptions(options: any[], inDomains: string[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const optionsUtils = {
|
export const optionsUtils = {
|
||||||
|
//获取分组
|
||||||
groupByDomain,
|
groupByDomain,
|
||||||
|
//构建分组后的选项列表,常用
|
||||||
buildGroupOptions,
|
buildGroupOptions,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import axios, { AxiosRequestConfig } from 'axios';
|
import axios, { AxiosHeaders, AxiosRequestConfig } from 'axios';
|
||||||
import { ILogger, logger } from './util.log.js';
|
import { ILogger, logger } from './util.log.js';
|
||||||
import { Logger } from 'log4js';
|
import { Logger } from 'log4js';
|
||||||
import { HttpProxyAgent } from 'http-proxy-agent';
|
import { HttpProxyAgent } from 'http-proxy-agent';
|
||||||
@@ -13,7 +13,7 @@ export class HttpError extends Error {
|
|||||||
statusText?: string;
|
statusText?: string;
|
||||||
code?: string;
|
code?: string;
|
||||||
request?: { baseURL: string; url: string; method: string; params?: any; data?: any };
|
request?: { baseURL: string; url: string; method: string; params?: any; data?: any };
|
||||||
response?: { data: any };
|
response?: { data: any; headers: AxiosHeaders };
|
||||||
cause?: any;
|
cause?: any;
|
||||||
constructor(error: any) {
|
constructor(error: any) {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
@@ -55,6 +55,7 @@ export class HttpError extends Error {
|
|||||||
|
|
||||||
this.response = {
|
this.response = {
|
||||||
data: error.response?.data,
|
data: error.response?.data,
|
||||||
|
headers: error.response?.headers,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { stack, cause } = error;
|
const { stack, cause } = error;
|
||||||
@@ -98,10 +99,22 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
|||||||
config.timeout = 15000;
|
config.timeout = 15000;
|
||||||
}
|
}
|
||||||
let agents = defaultAgents;
|
let agents = defaultAgents;
|
||||||
if (config.skipSslVerify) {
|
if (config.skipSslVerify || config.httpProxy) {
|
||||||
logger.info('跳过SSL验证');
|
let rejectUnauthorized = true;
|
||||||
agents = createAgent({ rejectUnauthorized: false } as any);
|
if (config.skipSslVerify) {
|
||||||
|
logger.info('跳过SSL验证');
|
||||||
|
rejectUnauthorized = false;
|
||||||
|
}
|
||||||
|
const proxy: any = {};
|
||||||
|
if (config.httpProxy) {
|
||||||
|
logger.info('使用自定义http代理:', config.httpProxy);
|
||||||
|
proxy.httpProxy = config.httpProxy;
|
||||||
|
proxy.httpsProxy = config.httpProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
agents = createAgent({ rejectUnauthorized, ...proxy } as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete config.skipSslVerify;
|
delete config.skipSslVerify;
|
||||||
config.httpsAgent = agents.httpsAgent;
|
config.httpsAgent = agents.httpsAgent;
|
||||||
config.httpAgent = agents.httpAgent;
|
config.httpAgent = agents.httpAgent;
|
||||||
@@ -132,6 +145,9 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
|||||||
} else {
|
} else {
|
||||||
logger.info('http response status:', response?.status);
|
logger.info('http response status:', response?.status);
|
||||||
}
|
}
|
||||||
|
if (response?.config?.returnResponse) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
(error: any) => {
|
(error: any) => {
|
||||||
@@ -141,13 +157,13 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
|||||||
error.message = '请求错误';
|
error.message = '请求错误';
|
||||||
break;
|
break;
|
||||||
case 401:
|
case 401:
|
||||||
error.message = '未授权,请登录';
|
error.message = '认证/登录失败';
|
||||||
break;
|
break;
|
||||||
case 403:
|
case 403:
|
||||||
error.message = '拒绝访问';
|
error.message = '拒绝访问';
|
||||||
break;
|
break;
|
||||||
case 404:
|
case 404:
|
||||||
error.message = `请求地址出错: ${error.response.config.url}`;
|
error.message = `请求地址出错`;
|
||||||
break;
|
break;
|
||||||
case 408:
|
case 408:
|
||||||
error.message = '请求超时';
|
error.message = '请求超时';
|
||||||
@@ -200,6 +216,8 @@ export type HttpRequestConfig<D = any> = {
|
|||||||
skipCheckRes?: boolean;
|
skipCheckRes?: boolean;
|
||||||
logParams?: boolean;
|
logParams?: boolean;
|
||||||
logRes?: boolean;
|
logRes?: boolean;
|
||||||
|
httpProxy?: string;
|
||||||
|
returnResponse?: boolean;
|
||||||
} & AxiosRequestConfig<D>;
|
} & AxiosRequestConfig<D>;
|
||||||
export type HttpClient = {
|
export type HttpClient = {
|
||||||
request<D = any, R = any>(config: HttpRequestConfig<D>): Promise<HttpClientResponse<R>>;
|
request<D = any, R = any>(config: HttpRequestConfig<D>): Promise<HttpClientResponse<R>>;
|
||||||
|
|||||||
@@ -3,6 +3,53 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 用户创建证书流水线没有购买套餐或者超限时提前报错 ([472f06c](https://github.com/certd/certd/commit/472f06c2d190d0ae48e8b53c18bc278437656a1c))
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 套餐购买支持易支付、支付宝支付 ([faa28f8](https://github.com/certd/certd/commit/faa28f88f954cba4c1dd29125562e5acd2fd99af))
|
||||||
|
* 支持微信支付 ([45d6347](https://github.com/certd/certd/commit/45d6347f5b6199493b11aabdd74177f6dca2cea4))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 同一时间只允许一个套餐生效 ([8ebf95a](https://github.com/certd/certd/commit/8ebf95a222a900d1707716c7b1f3b39f8a6d8f94))
|
||||||
|
* 优化证书申请跳过的状态显示,成功通知现在在跳过时不会发送 ([67d762b](https://github.com/certd/certd/commit/67d762b6a520f1fa24719a124e5ae975a81f5f82))
|
||||||
|
* 支持plesk网站证书部署 ([eda45c1](https://github.com/certd/certd/commit/eda45c1528199648b3970505e87f492d398226cd))
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复证书成功通知发送失败的bug ([0f5c690](https://github.com/certd/certd/commit/0f5c69040ba77340c909813220a26bc7ddada3ea))
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||||
|
* 支持aws cloudfront ([0ae39f1](https://github.com/certd/certd/commit/0ae39f160a7c6b6696b3bf513d68aa28905810ad))
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 通知选择器优化 ([2c0cbdd](https://github.com/certd/certd/commit/2c0cbdd29ecb74cc939b2ae7ee86b8d40f70ba31))
|
||||||
|
* 新增七牛云插件分组 ([49e7dc5](https://github.com/certd/certd/commit/49e7dc56e1a95fbdea3e30cdeb945b48415b69e3))
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/pipeline",
|
"name": "@certd/pipeline",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
"test": "mocha --loader=ts-node/esm"
|
"test": "mocha --loader=ts-node/esm"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@certd/basic": "^1.28.0",
|
"@certd/basic": "^1.29.2",
|
||||||
"@certd/plus-core": "^1.28.0",
|
"@certd/plus-core": "^1.29.2",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"reflect-metadata": "^0.1.13"
|
"reflect-metadata": "^0.1.13"
|
||||||
@@ -43,5 +43,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "cf1936309241d3cf05c2fba767f530bbb3b62b15"
|
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,12 @@ import { Decorator } from "../decorator/index.js";
|
|||||||
import { ICnameProxyService, IEmailService, IPluginConfigService, IUrlService } from "../service/index.js";
|
import { ICnameProxyService, IEmailService, IPluginConfigService, IUrlService } from "../service/index.js";
|
||||||
import { FileStore } from "./file-store.js";
|
import { FileStore } from "./file-store.js";
|
||||||
import { cloneDeep, forEach, merge } from "lodash-es";
|
import { cloneDeep, forEach, merge } from "lodash-es";
|
||||||
import { INotificationService, NotificationBody, NotificationContext, notificationRegistry } from "../notification/index.js";
|
import { INotificationService } from "../notification/index.js";
|
||||||
|
|
||||||
|
export type SysInfo = {
|
||||||
|
//系统标题
|
||||||
|
title?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type ExecutorOptions = {
|
export type ExecutorOptions = {
|
||||||
pipeline: Pipeline;
|
pipeline: Pipeline;
|
||||||
@@ -25,6 +30,7 @@ export type ExecutorOptions = {
|
|||||||
fileRootDir?: string;
|
fileRootDir?: string;
|
||||||
user: UserInfo;
|
user: UserInfo;
|
||||||
baseURL?: string;
|
baseURL?: string;
|
||||||
|
sysInfo?: SysInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Executor {
|
export class Executor {
|
||||||
@@ -86,13 +92,17 @@ export class Executor {
|
|||||||
await this.onChanged(this.runtime);
|
await this.onChanged(this.runtime);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
await this.runWithHistory(this.pipeline, "pipeline", async () => {
|
const result = await this.runWithHistory(this.pipeline, "pipeline", async () => {
|
||||||
return await this.runStages(this.pipeline);
|
return await this.runStages(this.pipeline);
|
||||||
});
|
});
|
||||||
if (this.lastRuntime && this.lastRuntime.pipeline.status?.status === ResultType.error) {
|
if (result === ResultType.success) {
|
||||||
await this.notification("turnToSuccess");
|
if (this.lastRuntime && this.lastRuntime.pipeline.status?.status === ResultType.error) {
|
||||||
|
await this.notification("turnToSuccess");
|
||||||
|
} else {
|
||||||
|
await this.notification("success");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await this.notification("success");
|
return result;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
await this.notification("error", e);
|
await this.notification("error", e);
|
||||||
this.logger.error("pipeline 执行失败", e);
|
this.logger.error("pipeline 执行失败", e);
|
||||||
@@ -330,7 +340,7 @@ export class Executor {
|
|||||||
instance.setCtx(taskCtx);
|
instance.setCtx(taskCtx);
|
||||||
|
|
||||||
await instance.onInstance();
|
await instance.onInstance();
|
||||||
await instance.execute();
|
const result = await instance.execute();
|
||||||
//执行结果处理
|
//执行结果处理
|
||||||
if (instance._result.clearLastStatus) {
|
if (instance._result.clearLastStatus) {
|
||||||
//是否需要清除所有状态
|
//是否需要清除所有状态
|
||||||
@@ -358,6 +368,8 @@ export class Executor {
|
|||||||
merge(vars, instance._result.pipelinePrivateVars);
|
merge(vars, instance._result.pipelinePrivateVars);
|
||||||
await this.pipelineContext.setObj("privateVars", vars);
|
await this.pipelineContext.setObj("privateVars", vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async notification(when: NotificationWhen, error?: any) {
|
async notification(when: NotificationWhen, error?: any) {
|
||||||
@@ -369,17 +381,17 @@ export class Executor {
|
|||||||
let content = "";
|
let content = "";
|
||||||
const errorMessage = error?.message;
|
const errorMessage = error?.message;
|
||||||
if (when === "start") {
|
if (when === "start") {
|
||||||
subject = `【Certd】开始执行,${this.pipeline.title}【${this.pipeline.id}】`;
|
subject = `开始执行,${this.pipeline.title}【${this.pipeline.id}】`;
|
||||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`;
|
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`;
|
||||||
} else if (when === "success") {
|
} else if (when === "success") {
|
||||||
subject = `【Certd】执行成功,${this.pipeline.title}【${this.pipeline.id}】`;
|
subject = `执行成功,${this.pipeline.title}【${this.pipeline.id}】`;
|
||||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`;
|
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`;
|
||||||
} else if (when === "turnToSuccess") {
|
} else if (when === "turnToSuccess") {
|
||||||
subject = `【Certd】执行成功(失败转成功),${this.pipeline.title}【${this.pipeline.id}】`;
|
subject = `执行成功(失败转成功),${this.pipeline.title}【${this.pipeline.id}】`;
|
||||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`;
|
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`;
|
||||||
} else if (when === "error") {
|
} else if (when === "error") {
|
||||||
subject = `【Certd】执行失败,${this.pipeline.title}【${this.pipeline.id}】`;
|
subject = `执行失败,${this.pipeline.title}【${this.pipeline.id}】`;
|
||||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}\n错误详情:${error.message}`;
|
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}\n\n${this.currentStatusMap?.currentStep?.title} 执行失败\n\n错误详情:${error.message}`;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -388,6 +400,7 @@ export class Executor {
|
|||||||
if (!notification.when.includes(when)) {
|
if (!notification.when.includes(when)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notification.type === "email") {
|
if (notification.type === "email") {
|
||||||
try {
|
try {
|
||||||
await this.options.emailService?.send({
|
await this.options.emailService?.send({
|
||||||
@@ -400,34 +413,24 @@ export class Executor {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
//构建notification插件,发送通知
|
|
||||||
const notifyConfig = await this.options.notificationService.getById(notification.notificationId);
|
|
||||||
const notificationPlugin = notificationRegistry.get(notifyConfig.type);
|
|
||||||
const notificationCls: any = notificationPlugin.target;
|
|
||||||
const notificationSender = new notificationCls();
|
|
||||||
const notificationCtx: NotificationContext = {
|
|
||||||
http: utils.http,
|
|
||||||
logger,
|
|
||||||
utils,
|
|
||||||
emailService: this.options.emailService,
|
|
||||||
};
|
|
||||||
//设置参数
|
|
||||||
merge(notificationSender, notifyConfig.setting);
|
|
||||||
notificationSender.setCtx(notificationCtx);
|
|
||||||
await notificationSender.onInstance();
|
|
||||||
const body: NotificationBody = {
|
|
||||||
title: subject,
|
|
||||||
content,
|
|
||||||
userId: this.pipeline.userId,
|
|
||||||
pipeline: this.pipeline,
|
|
||||||
result: this.lastRuntime.pipeline.status,
|
|
||||||
pipelineId: this.pipeline.id,
|
|
||||||
historyId: this.runtime.id,
|
|
||||||
errorMessage,
|
|
||||||
url,
|
|
||||||
};
|
|
||||||
//发送通知
|
//发送通知
|
||||||
await notificationSender.send(body);
|
await this.options.notificationService.send({
|
||||||
|
id: notification.notificationId,
|
||||||
|
useDefault: true,
|
||||||
|
useEmail: false,
|
||||||
|
logger: this.logger,
|
||||||
|
body: {
|
||||||
|
title: subject,
|
||||||
|
content,
|
||||||
|
userId: this.pipeline.userId,
|
||||||
|
pipeline: this.pipeline,
|
||||||
|
result: this.lastRuntime.pipeline.status,
|
||||||
|
pipelineId: this.pipeline.id,
|
||||||
|
historyId: this.runtime.id,
|
||||||
|
errorMessage,
|
||||||
|
url,
|
||||||
|
},
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("send notification error", e);
|
logger.error("send notification error", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ export class RunHistory {
|
|||||||
export class RunnableCollection {
|
export class RunnableCollection {
|
||||||
private collection: RunnableMap = {};
|
private collection: RunnableMap = {};
|
||||||
private pipeline!: Pipeline;
|
private pipeline!: Pipeline;
|
||||||
|
currentStep!: Step;
|
||||||
constructor(pipeline?: Pipeline) {
|
constructor(pipeline?: Pipeline) {
|
||||||
if (!pipeline) {
|
if (!pipeline) {
|
||||||
return;
|
return;
|
||||||
@@ -143,6 +144,23 @@ export class RunnableCollection {
|
|||||||
this.collection = map;
|
this.collection = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static initPipelineRunnableType(pipeline: Pipeline) {
|
||||||
|
pipeline.runnableType = "pipeline";
|
||||||
|
if (pipeline.stages === undefined) {
|
||||||
|
pipeline.stages = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pipeline.stages.forEach((stage) => {
|
||||||
|
stage.runnableType = "stage";
|
||||||
|
stage.tasks.forEach((task) => {
|
||||||
|
task.runnableType = "task";
|
||||||
|
task.steps.forEach((step) => {
|
||||||
|
step.runnableType = "step";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static each<T extends Runnable>(list: T[], exec: (item: Runnable) => void) {
|
static each<T extends Runnable>(list: T[], exec: (item: Runnable) => void) {
|
||||||
list.forEach((item) => {
|
list.forEach((item) => {
|
||||||
exec(item);
|
exec(item);
|
||||||
@@ -193,5 +211,8 @@ export class RunnableCollection {
|
|||||||
|
|
||||||
add(runnable: Runnable) {
|
add(runnable: Runnable) {
|
||||||
this.collection[runnable.id] = runnable;
|
this.collection[runnable.id] = runnable;
|
||||||
|
if (runnable.runnableType === "step") {
|
||||||
|
this.currentStep = runnable as Step;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,18 @@ export type NotificationInstanceConfig = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type NotificationSendReq = {
|
||||||
|
id?: number;
|
||||||
|
useDefault?: boolean;
|
||||||
|
useEmail?: boolean;
|
||||||
|
emailAddress?: string;
|
||||||
|
logger: ILogger;
|
||||||
|
body: NotificationBody;
|
||||||
|
};
|
||||||
export interface INotificationService {
|
export interface INotificationService {
|
||||||
getById(id: number): Promise<NotificationInstanceConfig>;
|
getById(id: number): Promise<NotificationInstanceConfig>;
|
||||||
getDefault(): Promise<NotificationInstanceConfig>;
|
getDefault(): Promise<NotificationInstanceConfig>;
|
||||||
|
send(req: NotificationSendReq): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INotification {
|
export interface INotification {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// src/decorator/memoryCache.decorator.ts
|
// src/decorator/memoryCache.decorator.ts
|
||||||
import { Decorator } from "../decorator/index.js";
|
import { Decorator } from "../decorator/index.js";
|
||||||
import * as _ from "lodash-es";
|
import * as _ from "lodash-es";
|
||||||
|
import { merge } from "lodash-es";
|
||||||
import { notificationRegistry } from "./registry.js";
|
import { notificationRegistry } from "./registry.js";
|
||||||
import { BaseNotification, NotificationBody, NotificationContext, NotificationDefine, NotificationInputDefine, NotificationInstanceConfig } from "./api.js";
|
import { BaseNotification, NotificationBody, NotificationContext, NotificationDefine, NotificationInputDefine, NotificationInstanceConfig } from "./api.js";
|
||||||
import { isPlus } from "@certd/plus-core";
|
|
||||||
|
|
||||||
// 提供一个唯一 key
|
// 提供一个唯一 key
|
||||||
export const NOTIFICATION_CLASS_KEY = "pipeline:notification";
|
export const NOTIFICATION_CLASS_KEY = "pipeline:notification";
|
||||||
@@ -47,9 +47,7 @@ export async function newNotification(type: string, input: any, ctx: Notificatio
|
|||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const plugin = new register.target();
|
const plugin = new register.target();
|
||||||
for (const key in input) {
|
merge(plugin, input);
|
||||||
plugin[key] = input[key];
|
|
||||||
}
|
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
throw new Error("ctx is required");
|
throw new Error("ctx is required");
|
||||||
}
|
}
|
||||||
@@ -61,8 +59,5 @@ export async function newNotification(type: string, input: any, ctx: Notificatio
|
|||||||
|
|
||||||
export async function sendNotification(opts: { config: NotificationInstanceConfig; ctx: NotificationContext; body: NotificationBody }) {
|
export async function sendNotification(opts: { config: NotificationInstanceConfig; ctx: NotificationContext; body: NotificationBody }) {
|
||||||
const notification: BaseNotification = await newNotification(opts.config.type, opts.config.setting, opts.ctx);
|
const notification: BaseNotification = await newNotification(opts.config.type, opts.config.setting, opts.ctx);
|
||||||
if (notification.define.needPlus && !isPlus()) {
|
|
||||||
opts.body.content = `${opts.body.content}\n\n注意:此通知渠道已调整为专业版功能,后续版本将不再支持发送,请尽快修改或升级为专业版`;
|
|
||||||
}
|
|
||||||
await notification.doSend(opts.body);
|
await notification.doSend(opts.body);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export type PluginDefine = Registrable & {
|
|||||||
|
|
||||||
export type ITaskPlugin = {
|
export type ITaskPlugin = {
|
||||||
onInstance(): Promise<void>;
|
onInstance(): Promise<void>;
|
||||||
execute(): Promise<void>;
|
execute(): Promise<void | string>;
|
||||||
onRequest(req: PluginRequestHandleReq<any>): Promise<any>;
|
onRequest(req: PluginRequestHandleReq<any>): Promise<any>;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
@@ -184,7 +184,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract execute(): Promise<void>;
|
abstract execute(): Promise<void | string>;
|
||||||
|
|
||||||
appendTimeSuffix(name?: string) {
|
appendTimeSuffix(name?: string) {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ export const pluginGroups = {
|
|||||||
aliyun: new PluginGroup("aliyun", "阿里云", 2),
|
aliyun: new PluginGroup("aliyun", "阿里云", 2),
|
||||||
huawei: new PluginGroup("huawei", "华为云", 3),
|
huawei: new PluginGroup("huawei", "华为云", 3),
|
||||||
tencent: new PluginGroup("tencent", "腾讯云", 4),
|
tencent: new PluginGroup("tencent", "腾讯云", 4),
|
||||||
host: new PluginGroup("host", "主机", 5),
|
qiniu: new PluginGroup("qiniu", "七牛云", 5),
|
||||||
cdn: new PluginGroup("cdn", "CDN", 6),
|
aws: new PluginGroup("aws", "亚马逊云", 6),
|
||||||
panel: new PluginGroup("panel", "面板", 7),
|
host: new PluginGroup("host", "主机", 7),
|
||||||
other: new PluginGroup("other", "其他", 8),
|
cdn: new PluginGroup("cdn", "CDN", 8),
|
||||||
|
panel: new PluginGroup("panel", "面板", 9),
|
||||||
|
other: new PluginGroup("other", "其他", 10),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,34 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-huawei
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-huawei
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-huawei
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-huawei
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-huawei
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-huawei
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-huawei
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/lib-huawei
|
**Note:** Version bump only for package @certd/lib-huawei
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/lib-huawei",
|
"name": "@certd/lib-huawei",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"main": "./dist/bundle.js",
|
"main": "./dist/bundle.js",
|
||||||
"module": "./dist/bundle.js",
|
"module": "./dist/bundle.js",
|
||||||
"types": "./dist/d/index.d.ts",
|
"types": "./dist/d/index.d.ts",
|
||||||
@@ -21,5 +21,5 @@
|
|||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"tslib": "^2.8.1"
|
"tslib": "^2.8.1"
|
||||||
},
|
},
|
||||||
"gitHead": "cf1936309241d3cf05c2fba767f530bbb3b62b15"
|
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,34 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-iframe
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-iframe
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-iframe
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-iframe
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-iframe
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-iframe
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-iframe
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/lib-iframe
|
**Note:** Version bump only for package @certd/lib-iframe
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/lib-iframe",
|
"name": "@certd/lib-iframe",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
@@ -30,5 +30,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "cf1936309241d3cf05c2fba767f530bbb3b62b15"
|
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,34 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/lib-k8s
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/lib-k8s",
|
"name": "@certd/lib-k8s",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@certd/basic": "^1.28.0",
|
"@certd/basic": "^1.29.2",
|
||||||
"@kubernetes/client-node": "0.21.0"
|
"@kubernetes/client-node": "0.21.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -31,5 +31,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "cf1936309241d3cf05c2fba767f530bbb3b62b15"
|
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,44 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-server
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-server
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 基础版不再限制流水线数量 ([cb27d4b](https://github.com/certd/certd/commit/cb27d4b4906b2782eaceb0a95bbdc5d0534370d2))
|
||||||
|
* 套餐购买支持易支付、支付宝支付 ([faa28f8](https://github.com/certd/certd/commit/faa28f88f954cba4c1dd29125562e5acd2fd99af))
|
||||||
|
* 用户套餐,用户支付功能 ([a019956](https://github.com/certd/certd/commit/a019956698acaf2c4beb620b5ad8c18918ead6a1))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 站点证书监控通知发送,每天定时检查 ([bb4910f](https://github.com/certd/certd/commit/bb4910f4e57234e42b44505f4620ae7af66025c5))
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-server
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-server
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-server
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* favicon支持自定义 ([8b9c47d](https://github.com/certd/certd/commit/8b9c47daf194515006689a212ae9cf586bdf5993))
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
### Performance Improvements
|
### Performance Improvements
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/lib-server",
|
"name": "@certd/lib-server",
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"description": "midway with flyway, sql upgrade way ",
|
"description": "midway with flyway, sql upgrade way ",
|
||||||
"private": false,
|
"private": false,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -27,10 +27,10 @@
|
|||||||
],
|
],
|
||||||
"license": "AGPL",
|
"license": "AGPL",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@certd/acme-client": "^1.28.0",
|
"@certd/acme-client": "^1.29.2",
|
||||||
"@certd/basic": "^1.28.0",
|
"@certd/basic": "^1.29.2",
|
||||||
"@certd/pipeline": "^1.28.0",
|
"@certd/pipeline": "^1.29.2",
|
||||||
"@certd/plus-core": "^1.28.0",
|
"@certd/plus-core": "^1.29.2",
|
||||||
"@midwayjs/cache": "~3.14.0",
|
"@midwayjs/cache": "~3.14.0",
|
||||||
"@midwayjs/core": "~3.17.1",
|
"@midwayjs/core": "~3.17.1",
|
||||||
"@midwayjs/i18n": "~3.17.3",
|
"@midwayjs/i18n": "~3.17.3",
|
||||||
@@ -61,5 +61,5 @@
|
|||||||
"typeorm": "^0.3.11",
|
"typeorm": "^0.3.11",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "cf1936309241d3cf05c2fba767f530bbb3b62b15"
|
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export abstract class BaseController {
|
|||||||
* @param msg
|
* @param msg
|
||||||
* @param code
|
* @param code
|
||||||
*/
|
*/
|
||||||
fail(msg: string, code: any) {
|
fail(msg: string, code?: any) {
|
||||||
return {
|
return {
|
||||||
code: code ? code : Constants.res.error.code,
|
code: code ? code : Constants.res.error.code,
|
||||||
msg: msg ? msg : Constants.res.error.code,
|
msg: msg ? msg : Constants.res.error.code,
|
||||||
@@ -39,4 +39,12 @@ export abstract class BaseController {
|
|||||||
}
|
}
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLoginUser() {
|
||||||
|
const user = this.ctx.user;
|
||||||
|
if (user == null) {
|
||||||
|
throw new Error('Token已过期');
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { In, Repository, SelectQueryBuilder } from 'typeorm';
|
|||||||
import { Inject } from '@midwayjs/core';
|
import { Inject } from '@midwayjs/core';
|
||||||
import { TypeORMDataSourceManager } from '@midwayjs/typeorm';
|
import { TypeORMDataSourceManager } from '@midwayjs/typeorm';
|
||||||
import { EntityManager } from 'typeorm/entity-manager/EntityManager.js';
|
import { EntityManager } from 'typeorm/entity-manager/EntityManager.js';
|
||||||
|
import { FindManyOptions } from 'typeorm';
|
||||||
|
|
||||||
export type PageReq<T = any> = {
|
export type PageReq<T = any> = {
|
||||||
page?: { offset: number; limit: number };
|
page?: { offset: number; limit: number };
|
||||||
@@ -15,6 +16,7 @@ export type ListReq<T = any> = {
|
|||||||
asc: boolean;
|
asc: boolean;
|
||||||
};
|
};
|
||||||
buildQuery?: (bq: SelectQueryBuilder<any>) => void;
|
buildQuery?: (bq: SelectQueryBuilder<any>) => void;
|
||||||
|
select?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,7 +55,7 @@ export abstract class BaseService<T> {
|
|||||||
* 非分页查询
|
* 非分页查询
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
async find(options) {
|
async find(options: FindManyOptions<T>) {
|
||||||
return await this.getRepository().find(options);
|
return await this.getRepository().find(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +101,7 @@ export abstract class BaseService<T> {
|
|||||||
* 新增|修改
|
* 新增|修改
|
||||||
* @param param 数据
|
* @param param 数据
|
||||||
*/
|
*/
|
||||||
async addOrUpdate(param) {
|
async addOrUpdate(param: any) {
|
||||||
await this.getRepository().save(param);
|
await this.getRepository().save(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +109,7 @@ export abstract class BaseService<T> {
|
|||||||
* 新增
|
* 新增
|
||||||
* @param param 数据
|
* @param param 数据
|
||||||
*/
|
*/
|
||||||
async add(param) {
|
async add(param: any) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
param.createTime = now;
|
param.createTime = now;
|
||||||
param.updateTime = now;
|
param.updateTime = now;
|
||||||
@@ -122,7 +124,7 @@ export abstract class BaseService<T> {
|
|||||||
* 修改
|
* 修改
|
||||||
* @param param 数据
|
* @param param 数据
|
||||||
*/
|
*/
|
||||||
async update(param) {
|
async update(param: any) {
|
||||||
if (!param.id) throw new ValidateException('id 不能为空');
|
if (!param.id) throw new ValidateException('id 不能为空');
|
||||||
param.updateTime = new Date();
|
param.updateTime = new Date();
|
||||||
await this.addOrUpdate(param);
|
await this.addOrUpdate(param);
|
||||||
@@ -148,6 +150,7 @@ export abstract class BaseService<T> {
|
|||||||
page.limit = 20;
|
page.limit = 20;
|
||||||
}
|
}
|
||||||
const qb = this.buildListQuery(pageReq);
|
const qb = this.buildListQuery(pageReq);
|
||||||
|
|
||||||
qb.offset(page.offset).limit(page.limit);
|
qb.offset(page.offset).limit(page.limit);
|
||||||
const list = await qb.getMany();
|
const list = await qb.getMany();
|
||||||
const total = await qb.getCount();
|
const total = await qb.getCount();
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ export const Constants = {
|
|||||||
code: 88,
|
code: 88,
|
||||||
message: '需要VIP',
|
message: '需要VIP',
|
||||||
},
|
},
|
||||||
|
needsuite: {
|
||||||
|
code: 89,
|
||||||
|
message: '需要购买或升级套餐',
|
||||||
|
},
|
||||||
loginError: {
|
loginError: {
|
||||||
code: 2,
|
code: 2,
|
||||||
message: '登录失败',
|
message: '登录失败',
|
||||||
|
|||||||
@@ -49,4 +49,10 @@ export abstract class CrudController<T> extends BaseController {
|
|||||||
await this.getService().delete([id]);
|
await this.getService().delete([id]);
|
||||||
return this.ok(null);
|
return this.ok(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('/deleteByIds')
|
||||||
|
async deleteByIds(@Body('ids') ids: number[]) {
|
||||||
|
await this.getService().delete(ids);
|
||||||
|
return this.ok(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,3 +8,9 @@ export class NeedVIPException extends BaseException {
|
|||||||
super('NeedVIPException', Constants.res.needvip.code, message ? message : Constants.res.needvip.message);
|
super('NeedVIPException', Constants.res.needvip.code, message ? message : Constants.res.needvip.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class NeedSuiteException extends BaseException {
|
||||||
|
constructor(message) {
|
||||||
|
super('NeedSuiteException', Constants.res.needsuite.code, message ? message : Constants.res.needsuite.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { SysSettingsEntity } from './system/index.js';
|
import { SysSettingsEntity } from './system/index.js';
|
||||||
|
import { AccessEntity } from './user/access/entity/access.js';
|
||||||
export * from './basic/index.js';
|
export * from './basic/index.js';
|
||||||
export * from './system/index.js';
|
export * from './system/index.js';
|
||||||
|
export * from './user/index.js';
|
||||||
export { LibServerConfiguration as Configuration } from './configuration.js';
|
export { LibServerConfiguration as Configuration } from './configuration.js';
|
||||||
|
|
||||||
export const libServerEntities = [SysSettingsEntity];
|
export const libServerEntities = [SysSettingsEntity, AccessEntity];
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const uploadTmpFileCacheKey = 'tmpfile_key_';
|
|||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Singleton)
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class FileService {
|
export class FileService {
|
||||||
async saveFile(userId: number, tmpCacheKey: any, permission: 'public' | 'private') {
|
async saveFile(userId: number, tmpCacheKey: any, permission: 'public' | 'private') {
|
||||||
if (tmpCacheKey.startsWith(`/${permission}`)) {
|
if (tmpCacheKey.startsWith(`/${permission}`)) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { SysInstallInfo, SysLicenseInfo, SysSettingsService } from '../../settin
|
|||||||
import { merge } from 'lodash-es';
|
import { merge } from 'lodash-es';
|
||||||
|
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Singleton)
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class PlusService {
|
export class PlusService {
|
||||||
@Inject()
|
@Inject()
|
||||||
sysSettingsService: SysSettingsService;
|
sysSettingsService: SysSettingsService;
|
||||||
@@ -38,9 +38,9 @@ export class PlusService {
|
|||||||
return installInfo.siteId;
|
return installInfo.siteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
async active(code: string) {
|
async active(code: string, inviteCode?: string) {
|
||||||
const plusRequestService = await this.getPlusRequestService();
|
const plusRequestService = await this.getPlusRequestService();
|
||||||
return await plusRequestService.active(code);
|
return await plusRequestService.active(code, inviteCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateLicense(license: string) {
|
async updateLicense(license: string) {
|
||||||
|
|||||||
@@ -136,3 +136,35 @@ export class SysHeaderMenus extends BaseSettings {
|
|||||||
|
|
||||||
menus: MenuItem[];
|
menus: MenuItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PaymentItem = {
|
||||||
|
enabled: boolean;
|
||||||
|
accessId?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class SysPaymentSetting extends BaseSettings {
|
||||||
|
static __title__ = '支付设置';
|
||||||
|
static __key__ = 'sys.payment';
|
||||||
|
static __access__ = 'private';
|
||||||
|
|
||||||
|
yizhifu?: PaymentItem = { enabled: false };
|
||||||
|
|
||||||
|
alipay?: PaymentItem = { enabled: false };
|
||||||
|
|
||||||
|
wxpay?: PaymentItem = { enabled: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SysSuiteSetting extends BaseSettings {
|
||||||
|
static __title__ = '套餐设置';
|
||||||
|
static __key__ = 'sys.suite';
|
||||||
|
static __access__ = 'private';
|
||||||
|
|
||||||
|
enabled = false;
|
||||||
|
|
||||||
|
registerGift?: {
|
||||||
|
productId: number;
|
||||||
|
duration: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
intro?: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import * as dns from 'node:dns';
|
|||||||
* 设置
|
* 设置
|
||||||
*/
|
*/
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Singleton)
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||||
@InjectEntityModel(SysSettingsEntity)
|
@InjectEntityModel(SysSettingsEntity)
|
||||||
repository: Repository<SysSettingsEntity>;
|
repository: Repository<SysSettingsEntity>;
|
||||||
|
|||||||
5
packages/libs/lib-server/src/user/access/index.ts
Normal file
5
packages/libs/lib-server/src/user/access/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export * from './entity/access.js';
|
||||||
|
export * from './service/access-service.js';
|
||||||
|
export * from './service/access-sys-getter.js';
|
||||||
|
export * from './service/access-getter.js';
|
||||||
|
export * from './service/encrypt-service.js';
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { BaseService, PageReq, PermissionException, ValidateException } from '@certd/lib-server';
|
import { BaseService, PageReq, PermissionException, ValidateException } from '../../../index.js';
|
||||||
import { AccessEntity } from '../entity/access.js';
|
import { AccessEntity } from '../entity/access.js';
|
||||||
import { AccessDefine, accessRegistry, newAccess } from '@certd/pipeline';
|
import { AccessDefine, accessRegistry, newAccess } from '@certd/pipeline';
|
||||||
import { EncryptService } from './encrypt-service.js';
|
import { EncryptService } from './encrypt-service.js';
|
||||||
@@ -10,7 +10,7 @@ import { EncryptService } from './encrypt-service.js';
|
|||||||
* 授权
|
* 授权
|
||||||
*/
|
*/
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Singleton)
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class AccessService extends BaseService<AccessEntity> {
|
export class AccessService extends BaseService<AccessEntity> {
|
||||||
@InjectEntityModel(AccessEntity)
|
@InjectEntityModel(AccessEntity)
|
||||||
repository: Repository<AccessEntity>;
|
repository: Repository<AccessEntity>;
|
||||||
@@ -18,6 +18,7 @@ export class AccessService extends BaseService<AccessEntity> {
|
|||||||
@Inject()
|
@Inject()
|
||||||
encryptService: EncryptService;
|
encryptService: EncryptService;
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
getRepository() {
|
getRepository() {
|
||||||
return this.repository;
|
return this.repository;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Init, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Init, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { SysSettingsService } from '@certd/lib-server';
|
import { SysPrivateSettings, SysSettingsService } from '../../../system/index.js';
|
||||||
import { SysPrivateSettings } from '@certd/lib-server';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 授权
|
* 授权
|
||||||
1
packages/libs/lib-server/src/user/index.ts
Normal file
1
packages/libs/lib-server/src/user/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './access/index.js';
|
||||||
@@ -3,6 +3,34 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/midway-flyway-js",
|
"name": "@certd/midway-flyway-js",
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"description": "midway with flyway, sql upgrade way ",
|
"description": "midway with flyway, sql upgrade way ",
|
||||||
"private": false,
|
"private": false,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -46,5 +46,5 @@
|
|||||||
"typeorm": "^0.3.11",
|
"typeorm": "^0.3.11",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "cf1936309241d3cf05c2fba767f530bbb3b62b15"
|
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,49 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-cert
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-cert
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复左侧菜单收起时无法展开子菜单的bug ([0056223](https://github.com/certd/certd/commit/005622307e612717a5408aa1484717ef03003a22))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 调整创建证书表单字段的顺序 ([d393521](https://github.com/certd/certd/commit/d3935219f2aa50d6662c5b5ebf7ee25ad696ab2b))
|
||||||
|
* 优化证书申请跳过的状态显示,成功通知现在在跳过时不会发送 ([67d762b](https://github.com/certd/certd/commit/67d762b6a520f1fa24719a124e5ae975a81f5f82))
|
||||||
|
* 站点证书监控通知发送,每天定时检查 ([bb4910f](https://github.com/certd/certd/commit/bb4910f4e57234e42b44505f4620ae7af66025c5))
|
||||||
|
* 支持一体证书 ([53c38cf](https://github.com/certd/certd/commit/53c38cf714a6f7486abbf1d71c9f48f56a790100))
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-cert
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复没有配置eab时,报order无法读取的问题 ([657a2ae](https://github.com/certd/certd/commit/657a2ae032e6f61ac27fbdd26c7bf169c041219e))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-cert
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-cert
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/plugin-cert",
|
"name": "@certd/plugin-cert",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@@ -15,9 +15,9 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@certd/acme-client": "^1.28.0",
|
"@certd/acme-client": "^1.29.2",
|
||||||
"@certd/basic": "^1.28.0",
|
"@certd/basic": "^1.29.2",
|
||||||
"@certd/pipeline": "^1.28.0",
|
"@certd/pipeline": "^1.29.2",
|
||||||
"@google-cloud/publicca": "^1.3.0",
|
"@google-cloud/publicca": "^1.3.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
@@ -40,5 +40,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "cf1936309241d3cf05c2fba767f530bbb3b62b15"
|
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,15 @@ export type DomainsVerifyPlan = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type CertInfo = {
|
export type CertInfo = {
|
||||||
crt: string;
|
crt: string; //fullchain证书
|
||||||
key: string;
|
key: string; //私钥
|
||||||
csr: string;
|
csr: string; //csr
|
||||||
ic?: string;
|
oc?: string; //仅证书,非fullchain证书
|
||||||
|
ic?: string; //中间证书
|
||||||
pfx?: string;
|
pfx?: string;
|
||||||
der?: string;
|
der?: string;
|
||||||
jks?: string;
|
jks?: string;
|
||||||
|
one?: string;
|
||||||
};
|
};
|
||||||
export type SSLProvider = "letsencrypt" | "google" | "zerossl";
|
export type SSLProvider = "letsencrypt" | "google" | "zerossl";
|
||||||
export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521";
|
export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AbstractTaskPlugin, IContext, NotificationBody, sendNotification, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
import { AbstractTaskPlugin, IContext, NotificationBody, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import type { CertInfo } from "./acme.js";
|
import type { CertInfo } from "./acme.js";
|
||||||
import { CertReader } from "./cert-reader.js";
|
import { CertReader } from "./cert-reader.js";
|
||||||
@@ -120,10 +120,11 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
|||||||
|
|
||||||
abstract doCertApply(): Promise<any>;
|
abstract doCertApply(): Promise<any>;
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<string | void> {
|
||||||
const oldCert = await this.condition();
|
const oldCert = await this.condition();
|
||||||
if (oldCert != null) {
|
if (oldCert != null) {
|
||||||
return await this.output(oldCert, false);
|
await this.output(oldCert, false);
|
||||||
|
return "skip";
|
||||||
}
|
}
|
||||||
const cert = await this.doCertApply();
|
const cert = await this.doCertApply();
|
||||||
if (cert != null) {
|
if (cert != null) {
|
||||||
@@ -191,7 +192,8 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
|||||||
zip.file("cert.crt", cert.crt);
|
zip.file("cert.crt", cert.crt);
|
||||||
zip.file("cert.key", cert.key);
|
zip.file("cert.key", cert.key);
|
||||||
zip.file("intermediate.crt", cert.ic);
|
zip.file("intermediate.crt", cert.ic);
|
||||||
|
zip.file("origin.crt", cert.oc);
|
||||||
|
zip.file("one.pem", cert.one);
|
||||||
if (cert.pfx) {
|
if (cert.pfx) {
|
||||||
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
|
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
|
||||||
}
|
}
|
||||||
@@ -201,6 +203,21 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
|||||||
if (cert.jks) {
|
if (cert.jks) {
|
||||||
zip.file("cert.jks", Buffer.from(cert.jks, "base64"));
|
zip.file("cert.jks", Buffer.from(cert.jks, "base64"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zip.file(
|
||||||
|
"说明.txt",
|
||||||
|
`证书文件说明
|
||||||
|
cert.crt:证书文件,包含证书链,pem格式
|
||||||
|
cert.key:私钥文件,pem格式
|
||||||
|
intermediate.crt:中间证书文件,pem格式
|
||||||
|
origin.crt:原始证书文件,不含证书链,pem格式
|
||||||
|
one.pem: 证书和私钥简单合并成一个文件,pem格式,crt正文+key正文
|
||||||
|
cert.pfx:pfx格式证书文件,iis服务器使用
|
||||||
|
cert.der:der格式证书文件
|
||||||
|
cert.jks:jks格式证书文件,java服务器使用
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
const content = await zip.generateAsync({ type: "nodebuffer" });
|
const content = await zip.generateAsync({ type: "nodebuffer" });
|
||||||
this.saveFile(filename, content);
|
this.saveFile(filename, content);
|
||||||
this.logger.info(`已保存文件:${filename}`);
|
this.logger.info(`已保存文件:${filename}`);
|
||||||
@@ -216,35 +233,36 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
|||||||
// return null;
|
// return null;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let inputChanged = this.ctx.inputChanged;
|
let inputChanged = false;
|
||||||
if (inputChanged) {
|
//判断域名有没有变更
|
||||||
this.logger.info("input hash 有变更,检查是否需要重新申请证书");
|
/**
|
||||||
//判断域名有没有变更
|
* "renewDays": 35,
|
||||||
/**
|
* "certApplyPlugin": "CertApply",
|
||||||
* "renewDays": 35,
|
* "sslProvider": "letsencrypt",
|
||||||
* "certApplyPlugin": "CertApply",
|
* "privateKeyType": "rsa_2048_pkcs1",
|
||||||
* "sslProvider": "letsencrypt",
|
* "dnsProviderType": "aliyun",
|
||||||
* "privateKeyType": "rsa_2048_pkcs1",
|
* "domains": [
|
||||||
* "dnsProviderType": "aliyun",
|
* "*.handsfree.work"
|
||||||
* "domains": [
|
* ],
|
||||||
* "*.handsfree.work"
|
* "email": "xiaojunnuo@qq.com",
|
||||||
* ],
|
* "dnsProviderAccess": 3,
|
||||||
* "email": "xiaojunnuo@qq.com",
|
* "useProxy": false,
|
||||||
* "dnsProviderAccess": 3,
|
* "skipLocalVerify": false,
|
||||||
* "useProxy": false,
|
* "successNotify": true,
|
||||||
* "skipLocalVerify": false,
|
* "pfxPassword": "123456"
|
||||||
* "successNotify": true,
|
*/
|
||||||
* "pfxPassword": "123456"
|
const checkInputChanges = ["domains", "sslProvider", "privateKeyType", "dnsProviderType", "pfxPassword"];
|
||||||
*/
|
const oldInput = JSON.stringify(pick(this.lastStatus?.input, checkInputChanges));
|
||||||
const checkInputChanges = ["domains", "sslProvider", "privateKeyType", "dnsProviderType", "pfxPassword"];
|
const thisInput = JSON.stringify(pick(this, checkInputChanges));
|
||||||
const oldInput = JSON.stringify(pick(this.lastStatus?.input, checkInputChanges));
|
inputChanged = oldInput !== thisInput;
|
||||||
const thisInput = JSON.stringify(pick(this, checkInputChanges));
|
|
||||||
inputChanged = oldInput !== thisInput;
|
|
||||||
|
|
||||||
if (inputChanged) {
|
this.logger.info(`旧参数:${oldInput}`);
|
||||||
this.logger.info("输入参数变更,准备申请新证书");
|
this.logger.info(`新参数:${thisInput}`);
|
||||||
return null;
|
if (inputChanged) {
|
||||||
}
|
this.logger.info("输入参数变更,准备申请新证书");
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
this.logger.info("输入参数未变更,不需要更新证书");
|
||||||
}
|
}
|
||||||
|
|
||||||
let oldCert: CertReader | undefined = undefined;
|
let oldCert: CertReader | undefined = undefined;
|
||||||
@@ -295,7 +313,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
|||||||
* 检查是否过期,默认提前35天
|
* 检查是否过期,默认提前35天
|
||||||
* @param expires
|
* @param expires
|
||||||
* @param maxDays
|
* @param maxDays
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
*/
|
||||||
isWillExpire(expires: number, maxDays = 20) {
|
isWillExpire(expires: number, maxDays = 20) {
|
||||||
if (expires == null) {
|
if (expires == null) {
|
||||||
@@ -312,39 +329,20 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
|||||||
this.logger.info("发送证书申请成功通知");
|
this.logger.info("发送证书申请成功通知");
|
||||||
const url = await this.ctx.urlService.getPipelineDetailUrl(this.pipeline.id, this.ctx.runtime.id);
|
const url = await this.ctx.urlService.getPipelineDetailUrl(this.pipeline.id, this.ctx.runtime.id);
|
||||||
const body: NotificationBody = {
|
const body: NotificationBody = {
|
||||||
title: `【Certd】证书申请成功【${this.pipeline.title}】`,
|
title: `证书申请成功【${this.pipeline.title}】`,
|
||||||
content: `域名:${this.domains.join(",")}`,
|
content: `域名:${this.domains.join(",")}`,
|
||||||
url: url,
|
url: url,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const defNotification = await this.ctx.notificationService.getDefault();
|
await this.ctx.notificationService.send({
|
||||||
if (defNotification) {
|
useDefault: true,
|
||||||
this.logger.info(`通知渠道:${defNotification.name}`);
|
useEmail: true,
|
||||||
const notificationCtx = {
|
emailAddress: this.email,
|
||||||
http: this.ctx.http,
|
logger: this.logger,
|
||||||
logger: this.logger,
|
body,
|
||||||
utils: this.ctx.utils,
|
});
|
||||||
emailService: this.ctx.emailService,
|
|
||||||
};
|
|
||||||
await sendNotification({
|
|
||||||
config: defNotification,
|
|
||||||
ctx: notificationCtx,
|
|
||||||
body,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.logger.warn("未配置默认通知,将发送邮件通知");
|
|
||||||
await this.sendSuccessEmail(body);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.error("证书申请成功通知发送失败", e);
|
this.logger.error("证书申请成功通知发送失败", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async sendSuccessEmail(body: NotificationBody) {
|
|
||||||
this.logger.info("发送邮件通知:" + this.email);
|
|
||||||
await this.ctx.emailService.send({
|
|
||||||
receivers: [this.email],
|
|
||||||
subject: body.title,
|
|
||||||
content: body.content,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,19 +10,23 @@ export type CertReaderHandleContext = {
|
|||||||
reader: CertReader;
|
reader: CertReader;
|
||||||
tmpCrtPath: string;
|
tmpCrtPath: string;
|
||||||
tmpKeyPath: string;
|
tmpKeyPath: string;
|
||||||
|
tmpOcPath?: string;
|
||||||
tmpPfxPath?: string;
|
tmpPfxPath?: string;
|
||||||
tmpDerPath?: string;
|
tmpDerPath?: string;
|
||||||
tmpIcPath?: string;
|
tmpIcPath?: string;
|
||||||
tmpJksPath?: string;
|
tmpJksPath?: string;
|
||||||
|
tmpOnePath?: string;
|
||||||
};
|
};
|
||||||
export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise<void>;
|
export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise<void>;
|
||||||
export type HandleOpts = { logger: ILogger; handle: CertReaderHandle };
|
export type HandleOpts = { logger: ILogger; handle: CertReaderHandle };
|
||||||
export class CertReader {
|
export class CertReader {
|
||||||
cert: CertInfo;
|
cert: CertInfo;
|
||||||
|
oc: string; //仅证书,非fullchain证书
|
||||||
crt: string;
|
crt: string;
|
||||||
key: string;
|
key: string;
|
||||||
csr: string;
|
csr: string;
|
||||||
ic: string; //中间证书
|
ic: string; //中间证书
|
||||||
|
one: string; //crt + key 合成一个pem文件
|
||||||
|
|
||||||
detail: any;
|
detail: any;
|
||||||
expires: number;
|
expires: number;
|
||||||
@@ -38,6 +42,18 @@ export class CertReader {
|
|||||||
this.cert.ic = this.ic;
|
this.cert.ic = this.ic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.oc = certInfo.oc;
|
||||||
|
if (!this.oc) {
|
||||||
|
this.oc = this.getOc();
|
||||||
|
this.cert.oc = this.oc;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.one = certInfo.one;
|
||||||
|
if (!this.one) {
|
||||||
|
this.one = this.crt + "\n" + this.key;
|
||||||
|
this.cert.one = this.one;
|
||||||
|
}
|
||||||
|
|
||||||
const { detail, expires } = this.getCrtDetail(this.cert.crt);
|
const { detail, expires } = this.getCrtDetail(this.cert.crt);
|
||||||
this.detail = detail;
|
this.detail = detail;
|
||||||
this.expires = expires.getTime();
|
this.expires = expires.getTime();
|
||||||
@@ -56,11 +72,22 @@ export class CertReader {
|
|||||||
return ic.trim();
|
return ic.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOc() {
|
||||||
|
//原始证书 就是crt的第一个 -----END CERTIFICATE----- 之前的内容
|
||||||
|
const endStr = "-----END CERTIFICATE-----";
|
||||||
|
const arr = this.crt.split(endStr);
|
||||||
|
return arr[0] + endStr;
|
||||||
|
}
|
||||||
|
|
||||||
toCertInfo(): CertInfo {
|
toCertInfo(): CertInfo {
|
||||||
return this.cert;
|
return this.cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCrtDetail(crt: string = this.cert.crt) {
|
getCrtDetail(crt: string = this.cert.crt) {
|
||||||
|
return CertReader.readCertDetail(crt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static readCertDetail(crt: string) {
|
||||||
const detail = crypto.readCertificateInfo(crt.toString());
|
const detail = crypto.readCertificateInfo(crt.toString());
|
||||||
const expires = detail.notAfter;
|
const expires = detail.notAfter;
|
||||||
return { detail, expires };
|
return { detail, expires };
|
||||||
@@ -73,7 +100,7 @@ export class CertReader {
|
|||||||
return domains;
|
return domains;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveToFile(type: "crt" | "key" | "pfx" | "der" | "ic" | "jks", filepath?: string) {
|
saveToFile(type: "crt" | "key" | "pfx" | "der" | "oc" | "one" | "ic" | "jks", filepath?: string) {
|
||||||
if (!this.cert[type]) {
|
if (!this.cert[type]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -87,7 +114,7 @@ export class CertReader {
|
|||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
}
|
}
|
||||||
if (type === "crt" || type === "key" || type === "ic") {
|
if (type === "crt" || type === "key" || type === "ic" || type === "oc" || type === "one") {
|
||||||
fs.writeFileSync(filepath, this.cert[type]);
|
fs.writeFileSync(filepath, this.cert[type]);
|
||||||
} else {
|
} else {
|
||||||
fs.writeFileSync(filepath, Buffer.from(this.cert[type], "base64"));
|
fs.writeFileSync(filepath, Buffer.from(this.cert[type], "base64"));
|
||||||
@@ -102,9 +129,11 @@ export class CertReader {
|
|||||||
const tmpKeyPath = this.saveToFile("key");
|
const tmpKeyPath = this.saveToFile("key");
|
||||||
const tmpPfxPath = this.saveToFile("pfx");
|
const tmpPfxPath = this.saveToFile("pfx");
|
||||||
const tmpIcPath = this.saveToFile("ic");
|
const tmpIcPath = this.saveToFile("ic");
|
||||||
logger.info("本地文件写入成功");
|
const tmpOcPath = this.saveToFile("oc");
|
||||||
const tmpDerPath = this.saveToFile("der");
|
const tmpDerPath = this.saveToFile("der");
|
||||||
const tmpJksPath = this.saveToFile("jks");
|
const tmpJksPath = this.saveToFile("jks");
|
||||||
|
const tmpOnePath = this.saveToFile("one");
|
||||||
|
logger.info("本地文件写入成功");
|
||||||
try {
|
try {
|
||||||
return await opts.handle({
|
return await opts.handle({
|
||||||
reader: this,
|
reader: this,
|
||||||
@@ -114,6 +143,8 @@ export class CertReader {
|
|||||||
tmpDerPath: tmpDerPath,
|
tmpDerPath: tmpDerPath,
|
||||||
tmpIcPath: tmpIcPath,
|
tmpIcPath: tmpIcPath,
|
||||||
tmpJksPath: tmpJksPath,
|
tmpJksPath: tmpJksPath,
|
||||||
|
tmpOcPath: tmpOcPath,
|
||||||
|
tmpOnePath,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw err;
|
throw err;
|
||||||
@@ -128,9 +159,11 @@ export class CertReader {
|
|||||||
removeFile(tmpCrtPath);
|
removeFile(tmpCrtPath);
|
||||||
removeFile(tmpKeyPath);
|
removeFile(tmpKeyPath);
|
||||||
removeFile(tmpPfxPath);
|
removeFile(tmpPfxPath);
|
||||||
|
removeFile(tmpOcPath);
|
||||||
removeFile(tmpDerPath);
|
removeFile(tmpDerPath);
|
||||||
removeFile(tmpIcPath);
|
removeFile(tmpIcPath);
|
||||||
removeFile(tmpJksPath);
|
removeFile(tmpJksPath);
|
||||||
|
removeFile(tmpOnePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,23 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||||||
})
|
})
|
||||||
challengeType!: string;
|
challengeType!: string;
|
||||||
|
|
||||||
|
@TaskInput({
|
||||||
|
title: "证书颁发机构",
|
||||||
|
value: "letsencrypt",
|
||||||
|
component: {
|
||||||
|
name: "icon-select",
|
||||||
|
vModel: "value",
|
||||||
|
options: [
|
||||||
|
{ value: "letsencrypt", label: "Let's Encrypt", icon: "simple-icons:letsencrypt" },
|
||||||
|
{ value: "google", label: "Google", icon: "flat-color-icons:google" },
|
||||||
|
{ value: "zerossl", label: "ZeroSSL", icon: "emojione:digit-zero" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
helper: "Let's Encrypt:申请最简单\nGoogle:大厂光环,兼容性好,仅首次需要翻墙获取EAB授权\nZeroSSL:需要EAB授权,无需翻墙",
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
sslProvider!: SSLProvider;
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: "DNS解析服务商",
|
title: "DNS解析服务商",
|
||||||
component: {
|
component: {
|
||||||
@@ -125,23 +142,6 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||||||
})
|
})
|
||||||
domainsVerifyPlan!: DomainsVerifyPlanInput;
|
domainsVerifyPlan!: DomainsVerifyPlanInput;
|
||||||
|
|
||||||
@TaskInput({
|
|
||||||
title: "证书颁发机构",
|
|
||||||
value: "letsencrypt",
|
|
||||||
component: {
|
|
||||||
name: "icon-select",
|
|
||||||
vModel: "value",
|
|
||||||
options: [
|
|
||||||
{ value: "letsencrypt", label: "Let's Encrypt", icon: "simple-icons:letsencrypt" },
|
|
||||||
{ value: "google", label: "Google", icon: "flat-color-icons:google" },
|
|
||||||
{ value: "zerossl", label: "ZeroSSL", icon: "emojione:digit-zero" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
helper: "Let's Encrypt:申请最简单\nGoogle:大厂光环,兼容性好,需要翻墙获取EAB授权\nZeroSSL:有数量限制,获取EAB授权无需翻墙",
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
sslProvider!: SSLProvider;
|
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: "Google公共EAB授权",
|
title: "Google公共EAB授权",
|
||||||
isSys: true,
|
isSys: true,
|
||||||
@@ -271,8 +271,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||||||
this.logger.info("当前正在使用 google公共EAB授权");
|
this.logger.info("当前正在使用 google公共EAB授权");
|
||||||
eab = await this.ctx.accessService.getCommonById(this.googleCommonEabAccessId);
|
eab = await this.ctx.accessService.getCommonById(this.googleCommonEabAccessId);
|
||||||
} else {
|
} else {
|
||||||
this.logger.error("google需要配置EAB授权或服务账号授权");
|
throw new Error("google需要配置EAB授权或服务账号授权");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else if (this.sslProvider === "zerossl") {
|
} else if (this.sslProvider === "zerossl") {
|
||||||
if (this.eabAccessId) {
|
if (this.eabAccessId) {
|
||||||
@@ -282,8 +281,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||||||
this.logger.info("当前正在使用 zerossl 公共EAB授权");
|
this.logger.info("当前正在使用 zerossl 公共EAB授权");
|
||||||
eab = await this.ctx.accessService.getCommonById(this.zerosslCommonEabAccessId);
|
eab = await this.ctx.accessService.getCommonById(this.zerosslCommonEabAccessId);
|
||||||
} else {
|
} else {
|
||||||
this.logger.error("zerossl需要配置EAB授权");
|
throw new Error("zerossl需要配置EAB授权");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.eab = eab;
|
this.eab = eab;
|
||||||
|
|||||||
@@ -3,6 +3,34 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-lib
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-lib
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-lib
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-lib
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-lib
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-lib
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-lib
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/plugin-lib",
|
"name": "@certd/plugin-lib",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alicloud/pop-core": "^1.7.10",
|
"@alicloud/pop-core": "^1.7.10",
|
||||||
"@certd/basic": "^1.28.0",
|
"@certd/basic": "^1.29.2",
|
||||||
"@certd/pipeline": "^1.28.0",
|
"@certd/pipeline": "^1.29.2",
|
||||||
"@certd/plugin-cert": "^1.28.0",
|
"@certd/plugin-cert": "^1.29.2",
|
||||||
"@kubernetes/client-node": "0.21.0",
|
"@kubernetes/client-node": "0.21.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
@@ -44,5 +44,5 @@
|
|||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"gitHead": "cf1936309241d3cf05c2fba767f530bbb3b62b15"
|
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ RUN npm install -g pnpm@8.15.7
|
|||||||
RUN cp /workspace/certd-client/dist/* /workspace/certd-server/public/ -rf
|
RUN cp /workspace/certd-client/dist/* /workspace/certd-server/public/ -rf
|
||||||
RUN cd /workspace/certd-server && pnpm install && npm run build-on-docker
|
RUN cd /workspace/certd-server && pnpm install && npm run build-on-docker
|
||||||
|
|
||||||
|
|
||||||
FROM node:20-alpine
|
FROM node:20-alpine
|
||||||
EXPOSE 7001
|
EXPOSE 7001
|
||||||
EXPOSE 7002
|
EXPOSE 7002
|
||||||
|
|||||||
@@ -3,6 +3,81 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/ui-client
|
||||||
|
|
||||||
|
## [1.29.1](https://github.com/certd/certd/compare/v1.29.0...v1.29.1) (2024-12-25)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 免费套餐支持购买 ([f5ec987](https://github.com/certd/certd/commit/f5ec9870fd6af1f0c9099852bbdb4d07813ccce8))
|
||||||
|
* 修复某处金额转换丢失精度的bug ([d2d6f12](https://github.com/certd/certd/commit/d2d6f12218cbe7bd55f4ae082b93084be85f0a7b))
|
||||||
|
* 修复新版本小红点显示错误问题 ([fe4786e](https://github.com/certd/certd/commit/fe4786e168afe03a5243dd67971476c348339809))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 用户创建证书流水线没有购买套餐或者超限时提前报错 ([472f06c](https://github.com/certd/certd/commit/472f06c2d190d0ae48e8b53c18bc278437656a1c))
|
||||||
|
* 优化插件名称显示 ([26adf7d](https://github.com/certd/certd/commit/26adf7d437e674385f26a8f92fded6521a620671))
|
||||||
|
|
||||||
|
# [1.29.0](https://github.com/certd/certd/compare/v1.28.4...v1.29.0) (2024-12-24)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复手机模式下,查询框被文字遮盖的bug ([040788c](https://github.com/certd/certd/commit/040788c793642c3bb2a3ede87fe30fcf3be471bd))
|
||||||
|
* 修复左侧菜单收起时无法展开子菜单的bug ([0056223](https://github.com/certd/certd/commit/005622307e612717a5408aa1484717ef03003a22))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 基础版不再限制流水线数量 ([cb27d4b](https://github.com/certd/certd/commit/cb27d4b4906b2782eaceb0a95bbdc5d0534370d2))
|
||||||
|
* 套餐购买支持易支付、支付宝支付 ([faa28f8](https://github.com/certd/certd/commit/faa28f88f954cba4c1dd29125562e5acd2fd99af))
|
||||||
|
* 用户套餐,用户支付功能 ([a019956](https://github.com/certd/certd/commit/a019956698acaf2c4beb620b5ad8c18918ead6a1))
|
||||||
|
* 支持微信支付 ([45d6347](https://github.com/certd/certd/commit/45d6347f5b6199493b11aabdd74177f6dca2cea4))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 调整创建证书表单字段的顺序 ([d393521](https://github.com/certd/certd/commit/d3935219f2aa50d6662c5b5ebf7ee25ad696ab2b))
|
||||||
|
* 同一时间只允许一个套餐生效 ([8ebf95a](https://github.com/certd/certd/commit/8ebf95a222a900d1707716c7b1f3b39f8a6d8f94))
|
||||||
|
* 用户名支持修改 ([89c7f07](https://github.com/certd/certd/commit/89c7f070343e86453c84677ebe1669f9b266d871))
|
||||||
|
* 优化证书申请跳过的状态显示,成功通知现在在跳过时不会发送 ([67d762b](https://github.com/certd/certd/commit/67d762b6a520f1fa24719a124e5ae975a81f5f82))
|
||||||
|
* 站点证书监控通知发送,每天定时检查 ([bb4910f](https://github.com/certd/certd/commit/bb4910f4e57234e42b44505f4620ae7af66025c5))
|
||||||
|
|
||||||
|
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/ui-client
|
||||||
|
|
||||||
|
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复授权被删除后,无法清空的bug ([b45977c](https://github.com/certd/certd/commit/b45977c29a29084c11e496bec3415eaaebafdd74))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 点击版本红点按钮,跳转到升级帮助页面 ([454fbda](https://github.com/certd/certd/commit/454fbda581bbe22abca5b91e5086ea9d9d58a020))
|
||||||
|
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||||
|
|
||||||
|
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复创建流水线通知设置无效的bug ([498cf34](https://github.com/certd/certd/commit/498cf34999fddfa24ce088e2e678469fa669abb8))
|
||||||
|
|
||||||
|
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复cname排查方法 nslookup命令显示黑色的问题 ([3dfeeec](https://github.com/certd/certd/commit/3dfeeec899d7d0d7292695ce410f78548e076c03))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 通知选择器优化 ([2c0cbdd](https://github.com/certd/certd/commit/2c0cbdd29ecb74cc939b2ae7ee86b8d40f70ba31))
|
||||||
|
* 新增七牛云插件分组 ([49e7dc5](https://github.com/certd/certd/commit/49e7dc56e1a95fbdea3e30cdeb945b48415b69e3))
|
||||||
|
* 新增server酱3通知 ([6aa4872](https://github.com/certd/certd/commit/6aa487269c9f6862e188b37a0d6c73f79c937d94))
|
||||||
|
* 支持邀请奖励 ([618ec93](https://github.com/certd/certd/commit/618ec937866b24ebcf8164db43acb1ed66a5b329))
|
||||||
|
* 支持易发云短信 ([94fa77f](https://github.com/certd/certd/commit/94fa77fcd2b9bea294fb05736c0d8cdc81f56103))
|
||||||
|
* favicon支持自定义 ([8b9c47d](https://github.com/certd/certd/commit/8b9c47daf194515006689a212ae9cf586bdf5993))
|
||||||
|
|
||||||
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
# [1.28.0](https://github.com/certd/certd/compare/v1.27.9...v1.28.0) (2024-11-30)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8"/>
|
<meta charset="UTF-8"/>
|
||||||
<link rel="icon" href="/static/images/logo/logo.svg"/>
|
<link rel="icon" href="/api/app/favicon"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<title>Loading</title>
|
<title>Loading</title>
|
||||||
<script src="/static/icons/iconfont.js"></script>
|
<script src="/static/icons/iconfont.js"></script>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/ui-client",
|
"name": "@certd/ui-client",
|
||||||
"version": "1.28.0",
|
"version": "1.29.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --open",
|
"dev": "vite --open",
|
||||||
@@ -26,10 +26,10 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/colors": "^7.0.2",
|
"@ant-design/colors": "^7.0.2",
|
||||||
"@ant-design/icons-vue": "^6.1.0",
|
"@ant-design/icons-vue": "^6.1.0",
|
||||||
"@fast-crud/fast-crud": "^1.23.1",
|
"@fast-crud/fast-crud": "^1.23.4",
|
||||||
"@fast-crud/fast-extends": "^1.23.1",
|
"@fast-crud/fast-extends": "^1.23.4",
|
||||||
"@fast-crud/ui-antdv4": "^1.23.1",
|
"@fast-crud/ui-antdv4": "^1.23.4",
|
||||||
"@fast-crud/ui-interface": "^1.23.1",
|
"@fast-crud/ui-interface": "^1.23.4",
|
||||||
"@iconify/vue": "^4.1.1",
|
"@iconify/vue": "^4.1.1",
|
||||||
"@soerenmartius/vue3-clipboard": "^0.1.2",
|
"@soerenmartius/vue3-clipboard": "^0.1.2",
|
||||||
"@vue-js-cron/light": "^4.0.5",
|
"@vue-js-cron/light": "^4.0.5",
|
||||||
@@ -56,6 +56,7 @@
|
|||||||
"pinia": "2.1.7",
|
"pinia": "2.1.7",
|
||||||
"psl": "^1.9.0",
|
"psl": "^1.9.0",
|
||||||
"qiniu-js": "^3.4.2",
|
"qiniu-js": "^3.4.2",
|
||||||
|
"qrcode": "^1.5.4",
|
||||||
"sortablejs": "^1.15.2",
|
"sortablejs": "^1.15.2",
|
||||||
"vue": "^3.4.21",
|
"vue": "^3.4.21",
|
||||||
"vue-cropperjs": "^5.0.0",
|
"vue-cropperjs": "^5.0.0",
|
||||||
@@ -65,8 +66,8 @@
|
|||||||
"vuedraggable": "^4.1.0"
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@certd/lib-iframe": "^1.28.0",
|
"@certd/lib-iframe": "^1.29.2",
|
||||||
"@certd/pipeline": "^1.28.0",
|
"@certd/pipeline": "^1.29.2",
|
||||||
"@rollup/plugin-commonjs": "^25.0.7",
|
"@rollup/plugin-commonjs": "^25.0.7",
|
||||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
"@types/chai": "^4.3.12",
|
"@types/chai": "^4.3.12",
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ export type SysPublicSetting = {
|
|||||||
managerOtherUserPipeline?: boolean;
|
managerOtherUserPipeline?: boolean;
|
||||||
icpNo?: string;
|
icpNo?: string;
|
||||||
};
|
};
|
||||||
|
export type SuiteSetting = {
|
||||||
|
enabled?: boolean;
|
||||||
|
};
|
||||||
export type SysPrivateSetting = {
|
export type SysPrivateSetting = {
|
||||||
httpProxy?: string;
|
httpProxy?: string;
|
||||||
httpsProxy?: string;
|
httpsProxy?: string;
|
||||||
@@ -67,6 +69,7 @@ export type AllSettings = {
|
|||||||
siteInfo: SiteInfo;
|
siteInfo: SiteInfo;
|
||||||
siteEnv: SiteEnv;
|
siteEnv: SiteEnv;
|
||||||
headerMenus: HeaderMenus;
|
headerMenus: HeaderMenus;
|
||||||
|
suiteSetting: SuiteSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function loadAllSettings(): Promise<AllSettings> {
|
export async function loadAllSettings(): Promise<AllSettings> {
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ function createService() {
|
|||||||
if (response.config.responseType === "blob") {
|
if (response.config.responseType === "blob") {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
//@ts-ignore
|
||||||
|
if (response.config.returnResponse) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
// dataAxios 是 axios 返回数据中的 data
|
// dataAxios 是 axios 返回数据中的 data
|
||||||
const dataAxios = response.data;
|
const dataAxios = response.data;
|
||||||
|
|
||||||
@@ -76,7 +80,7 @@ function createService() {
|
|||||||
error.message = "拒绝访问";
|
error.message = "拒绝访问";
|
||||||
break;
|
break;
|
||||||
case 404:
|
case 404:
|
||||||
error.message = `请求地址出错: ${error.response.config.url}`;
|
error.message = `请求地址出错`;
|
||||||
break;
|
break;
|
||||||
case 408:
|
case 408:
|
||||||
error.message = "请求超时";
|
error.message = "请求超时";
|
||||||
@@ -102,6 +106,7 @@ function createService() {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
error.message += `: ${error.response?.config?.url}`;
|
||||||
errorLog(error, error?.response?.config?.showErrorNotify);
|
errorLog(error, error?.response?.config?.showErrorNotify);
|
||||||
if (status === 401) {
|
if (status === 401) {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<span class="cd-expires-time-text">
|
||||||
|
<component :is="wrapperComp" :color="color">
|
||||||
|
<template v-if="label != null">
|
||||||
|
{{ label }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<FsTimeHumanize :model-value="value" :use-format-greater="1000000000000000" :options="{ units: ['y', 'd'] }"></FsTimeHumanize>
|
||||||
|
</template>
|
||||||
|
</component>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "ExpiresTimeText"
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
value?: number;
|
||||||
|
mode?: "tag" | "text";
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const wrapperComp = computed(() => {
|
||||||
|
if (props.mode === "tag") {
|
||||||
|
return "a-tag";
|
||||||
|
}
|
||||||
|
return "span";
|
||||||
|
});
|
||||||
|
|
||||||
|
const color = computed(() => {
|
||||||
|
if (props.value == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
//距离今天多少天
|
||||||
|
const days = dayjs(props.value).diff(dayjs(), "day");
|
||||||
|
if (props.value === -1 || days > 365) {
|
||||||
|
return "green";
|
||||||
|
}
|
||||||
|
|
||||||
|
//小于3天 红色
|
||||||
|
if (days <= 6) {
|
||||||
|
return "red";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "blue";
|
||||||
|
});
|
||||||
|
|
||||||
|
const label = computed(() => {
|
||||||
|
if (props.value == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (props.value === -1) {
|
||||||
|
return "永久";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -9,6 +9,7 @@ import "@vue-js-cron/light/dist/light.css";
|
|||||||
import Plugins from "./plugins/index";
|
import Plugins from "./plugins/index";
|
||||||
import LoadingButton from "./loading-button.vue";
|
import LoadingButton from "./loading-button.vue";
|
||||||
import IconSelect from "./icon-select.vue";
|
import IconSelect from "./icon-select.vue";
|
||||||
|
import ExpiresTimeText from "./expires-time-text.vue";
|
||||||
export default {
|
export default {
|
||||||
install(app: any) {
|
install(app: any) {
|
||||||
app.component("PiContainer", PiContainer);
|
app.component("PiContainer", PiContainer);
|
||||||
@@ -25,7 +26,7 @@ export default {
|
|||||||
|
|
||||||
app.component("LoadingButton", LoadingButton);
|
app.component("LoadingButton", LoadingButton);
|
||||||
app.component("IconSelect", IconSelect);
|
app.component("IconSelect", IconSelect);
|
||||||
|
app.component("ExpiresTimeText", ExpiresTimeText);
|
||||||
app.use(vip);
|
app.use(vip);
|
||||||
app.use(Plugins);
|
app.use(Plugins);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,8 @@
|
|||||||
<div>1. 解析记录应该添加在{{ record.domain }}域名下</div>
|
<div>1. 解析记录应该添加在{{ record.domain }}域名下</div>
|
||||||
<div>2. 要添加的是CNAME类型的记录,不是TXT</div>
|
<div>2. 要添加的是CNAME类型的记录,不是TXT</div>
|
||||||
<div>3. 核对记录值是否是:{{ record.recordValue }}</div>
|
<div>3. 核对记录值是否是:{{ record.recordValue }}</div>
|
||||||
<div>
|
<div>4. 运行下面的命令,查看解析是否正确 <fs-copyable :style="{ color: '#52c41a' }" :model-value="nslookupCmd"></fs-copyable></div>
|
||||||
4. 运行命令 <a-tag>nslookup -qa=txt {{ record.hostRecord }}{{ record.domain }}</a-tag> 查看解析配置是否正确
|
<div>5. 如果以上检查都没有问题,则可能是DNS解析生效时间比较慢,某些提供商延迟可能高达几个小时</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<fs-icon class="ml-5 pointer" icon="mingcute:question-line"></fs-icon>
|
<fs-icon class="ml-5 pointer" icon="mingcute:question-line"></fs-icon>
|
||||||
@@ -16,7 +15,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { computed } from "vue";
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
record: any;
|
record: any;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const nslookupCmd = computed(() => {
|
||||||
|
return `nslookup -qa=txt _acme-challenge.${props.record.domain}`;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const slots = defineSlots();
|
|||||||
<template>
|
<template>
|
||||||
<div class="tutorial-button pointer" @click="open">
|
<div class="tutorial-button pointer" @click="open">
|
||||||
<template v-if="!slots.default">
|
<template v-if="!slots.default">
|
||||||
<fs-icon icon="mingcute:question-line"></fs-icon>
|
<fs-icon icon="ant-design:question-circle-outlined"></fs-icon>
|
||||||
<div class="ml-5">使用教程</div>
|
<div class="ml-5">使用教程</div>
|
||||||
</template>
|
</template>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
|||||||
@@ -118,7 +118,8 @@ const expiredDays = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const formState = reactive({
|
const formState = reactive({
|
||||||
code: ""
|
code: "",
|
||||||
|
inviteCode: ""
|
||||||
});
|
});
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -228,27 +229,44 @@ function openUpgrade() {
|
|||||||
const vipTypeDefine = {
|
const vipTypeDefine = {
|
||||||
free: {
|
free: {
|
||||||
title: "基础版",
|
title: "基础版",
|
||||||
desc: "免费使用",
|
desc: "社区免费版",
|
||||||
type: "free",
|
type: "free",
|
||||||
privilege: ["证书申请功能无限制", "证书流水线数量10条", "常用的主机、cdn等部署插件"]
|
icon: "lucide:package-open",
|
||||||
|
privilege: ["证书申请无限制", "域名数量无限制", "证书流水线数量无限制", "常用的主机、云平台、cdn等部署插件", "邮件、webhook通知方式"]
|
||||||
},
|
},
|
||||||
plus: {
|
plus: {
|
||||||
title: "专业版",
|
title: "专业版",
|
||||||
desc: "功能增强,适用于个人企业内部使用",
|
desc: "开源需要您的赞助支持",
|
||||||
type: "plus",
|
type: "plus",
|
||||||
privilege: ["可加VIP群,需求优先实现", "证书流水线数量无限制", "免配置发邮件功能", "支持宝塔、易盾、群晖、1Panel、cdnfly等部署插件"],
|
privilege: ["可加VIP群,您需求将优先实现", "站点证书监控无限制", "更多通知方式", "更多强大部署插件,宝塔、群晖、1Panel等"],
|
||||||
trial: {
|
trial: {
|
||||||
title: "7天试用",
|
title: "点击获取7天试用",
|
||||||
click: () => {
|
click: () => {
|
||||||
openStarModal();
|
openStarModal();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
icon: "stash:thumb-up",
|
||||||
|
price: 29.9,
|
||||||
|
get() {
|
||||||
|
return (
|
||||||
|
<a-tooltip title="爱发电赞助“VIP会员”后获取一年期专业版激活码,开源需要您的支持">
|
||||||
|
<a-button size="small" type="primary" href="https://afdian.com/a/greper" target="_blank">
|
||||||
|
爱发电赞助后获取
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
comm: {
|
comm: {
|
||||||
title: "商业版",
|
title: "商业版",
|
||||||
desc: "商业授权,可对外运营",
|
desc: "商业授权,可对外运营",
|
||||||
type: "comm",
|
type: "comm",
|
||||||
privilege: ["拥有专业版所有特权", "允许商用,可修改logo、标题", "数据统计", "插件管理", "多用户无限制", "支持用户支付(敬请期待)"]
|
icon: "vaadin:handshake",
|
||||||
|
privilege: ["拥有专业版所有特权", "允许商用,可修改logo、标题", "数据统计", "插件管理", "多用户无限制", "支持用户支付"],
|
||||||
|
price: 399,
|
||||||
|
get() {
|
||||||
|
return <a-button size="small">请联系作者获取</a-button>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -259,28 +277,16 @@ function openUpgrade() {
|
|||||||
},
|
},
|
||||||
maskClosable: true,
|
maskClosable: true,
|
||||||
okText: "激活",
|
okText: "激活",
|
||||||
width: 900,
|
width: 1000,
|
||||||
content: () => {
|
content: () => {
|
||||||
let activationCodeGetWay: any = null;
|
let activationCodeGetWay = (
|
||||||
if (settingStore.siteEnv.agent.enabled != null) {
|
<span>
|
||||||
const agent = settingStore.siteEnv.agent;
|
<a href="https://afdian.com/a/greper" target="_blank">
|
||||||
if (agent.enabled === false) {
|
爱发电赞助“VIP会员”后获取一年期专业版激活码
|
||||||
activationCodeGetWay = (
|
</a>
|
||||||
<span>
|
<span> 商业版请直接联系作者</span>
|
||||||
<a href="https://afdian.com/a/greper" target="_blank">
|
</span>
|
||||||
爱发电赞助“VIP会员”后获取专业版
|
);
|
||||||
</a>
|
|
||||||
<span> 商业版请直接联系作者</span>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
activationCodeGetWay = (
|
|
||||||
<a href={agent.contactLink} target="_blank">
|
|
||||||
{agent.contactText}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const vipLabel = settingStore.vipLabel;
|
const vipLabel = settingStore.vipLabel;
|
||||||
const slots = [];
|
const slots = [];
|
||||||
for (const key in vipTypeDefine) {
|
for (const key in vipTypeDefine) {
|
||||||
@@ -290,8 +296,8 @@ function openUpgrade() {
|
|||||||
slots.push(
|
slots.push(
|
||||||
<a-col span={8}>
|
<a-col span={8}>
|
||||||
<div class={vipBlockClass}>
|
<div class={vipBlockClass}>
|
||||||
<h3 class="block-header">
|
<h3 class="block-header ">
|
||||||
<span>{item.title}</span>
|
<span class="flex-o">{item.title}</span>
|
||||||
{item.trial && (
|
{item.trial && (
|
||||||
<span class="trial">
|
<span class="trial">
|
||||||
<a-tooltip title={item.trial.message}>
|
<a-tooltip title={item.trial.message}>
|
||||||
@@ -300,15 +306,34 @@ function openUpgrade() {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</h3>
|
</h3>
|
||||||
<div>{item.desc}</div>
|
<div style="color:green" class="flex-o">
|
||||||
<ul>
|
<fs-icon icon={item.icon} class="fs-16 flex-o" />
|
||||||
|
{item.desc}
|
||||||
|
</div>
|
||||||
|
<ul class="flex-1 privilege">
|
||||||
{item.privilege.map((p: string) => (
|
{item.privilege.map((p: string) => (
|
||||||
<li>
|
<li class="flex-baseline">
|
||||||
<fs-icon class="color-green" icon="ion:checkmark-sharp" />
|
<fs-icon class="color-green" icon="ion:checkmark-sharp" />
|
||||||
{p}
|
{p}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
<div class="footer flex-between flex-vc">
|
||||||
|
<div class="price-show">
|
||||||
|
{item.price && (
|
||||||
|
<span>
|
||||||
|
<span class="price-text">¥{item.price}</span>
|
||||||
|
/年
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{!item.price && (
|
||||||
|
<span>
|
||||||
|
<span class="price-text">免费</span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div class="get-show">{item.get && <div>{item.get()}</div>}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
);
|
);
|
||||||
@@ -327,6 +352,7 @@ function openUpgrade() {
|
|||||||
<fs-copyable class="flex-1" v-model={computedSiteId.value}></fs-copyable>
|
<fs-copyable class="flex-1" v-model={computedSiteId.value}></fs-copyable>
|
||||||
</div>
|
</div>
|
||||||
<a-input class="mt-10" v-model:value={formState.code} placeholder={placeholder} />
|
<a-input class="mt-10" v-model:value={formState.code} placeholder={placeholder} />
|
||||||
|
<a-input class="mt-10" v-model:value={formState.inviteCode} placeholder={"邀请码【选填】,可额外获得专业版30天/商业版15天时长"} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-10">
|
<div class="mt-10">
|
||||||
@@ -370,10 +396,12 @@ onMounted(() => {
|
|||||||
|
|
||||||
.vip-active-modal {
|
.vip-active-modal {
|
||||||
.vip-block {
|
.vip-block {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid #eee;
|
border: 1px solid #eee;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
height: 195px;
|
height: 250px;
|
||||||
//background-color: rgba(250, 237, 167, 0.79);
|
//background-color: rgba(250, 237, 167, 0.79);
|
||||||
&.current {
|
&.current {
|
||||||
border-color: green;
|
border-color: green;
|
||||||
@@ -387,6 +415,16 @@ onMounted(() => {
|
|||||||
font-wight: 400;
|
font-wight: 400;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
padding-top: 5px;
|
||||||
|
margin-top: 0px;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
.price-text {
|
||||||
|
font-size: 18px;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
@@ -398,9 +436,13 @@ onMounted(() => {
|
|||||||
color: green;
|
color: green;
|
||||||
}
|
}
|
||||||
.vip-type-vs {
|
.vip-type-vs {
|
||||||
|
.privilege {
|
||||||
|
.fs-icon {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
}
|
||||||
.fs-icon {
|
.fs-icon {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
color: green;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
124
packages/ui/certd-client/src/layout/components/menu/index.vue
Normal file
124
packages/ui/certd-client/src/layout/components/menu/index.vue
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<template>
|
||||||
|
<a-menu v-model:open-keys="openKeys" v-model:selected-keys="selectedKeys" class="fs-menu" mode="inline" theme="light" :items="items" @click="onClick" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="tsx" setup>
|
||||||
|
import { ref, watch, defineOptions } from "vue";
|
||||||
|
import { routerUtils } from "/@/utils/util.router";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
import { utils } from "@fast-crud/fast-crud";
|
||||||
|
import * as _ from "lodash-es";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "FsMenu"
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
menus: any[];
|
||||||
|
expandSelected: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const items = ref([]);
|
||||||
|
|
||||||
|
function buildItemMenus(menus: any) {
|
||||||
|
if (menus == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const list: any = [];
|
||||||
|
for (const sub of menus) {
|
||||||
|
if (sub.meta?.show != null) {
|
||||||
|
if (sub.meta.show === false || (typeof sub.meta.show === "function" && !sub.meta.show())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const item: any = {
|
||||||
|
key: sub.path,
|
||||||
|
label: sub.title,
|
||||||
|
title: sub.title,
|
||||||
|
icon: () => {
|
||||||
|
return <fsIcon icon={sub.icon ?? sub.meta?.icon} />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
list.push(item);
|
||||||
|
if (sub.children && sub.children.length > 0) {
|
||||||
|
item.children = buildItemMenus(sub.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.menus,
|
||||||
|
(menus) => {
|
||||||
|
items.value = buildItemMenus(menus);
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
async function onClick(item: any) {
|
||||||
|
await routerUtils.open(item.key);
|
||||||
|
}
|
||||||
|
const route = useRoute();
|
||||||
|
const selectedKeys = ref([]);
|
||||||
|
const openKeys = ref([]);
|
||||||
|
|
||||||
|
function openSelectedParents(fullPath: any) {
|
||||||
|
if (!props.expandSelected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (props.menus == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const keys: any = [];
|
||||||
|
let changed = false;
|
||||||
|
utils.deepdash.forEachDeep(props.menus, (value: any, key: any, parent: any, context: any) => {
|
||||||
|
if (value == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value.path === fullPath) {
|
||||||
|
_.forEach(context.parents, (item) => {
|
||||||
|
if (item.value instanceof Array) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
keys.push(item.value.path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (keys.length > 0) {
|
||||||
|
for (const key of keys) {
|
||||||
|
if (openKeys.value.indexOf(key) === -1) {
|
||||||
|
openKeys.value.push(key);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => {
|
||||||
|
return route.fullPath;
|
||||||
|
},
|
||||||
|
(path) => {
|
||||||
|
// path = route.fullPath;
|
||||||
|
selectedKeys.value = [path];
|
||||||
|
const changed = openSelectedParents(path);
|
||||||
|
if (changed) {
|
||||||
|
// onOpenChange();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style lang="less">
|
||||||
|
.fs-menu {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
.fs-icon {
|
||||||
|
font-size: 16px !important;
|
||||||
|
min-width: 16px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -6,60 +6,8 @@ import "./index.less";
|
|||||||
import { utils } from "@fast-crud/fast-crud";
|
import { utils } from "@fast-crud/fast-crud";
|
||||||
import { routerUtils } from "/@/utils/util.router";
|
import { routerUtils } from "/@/utils/util.router";
|
||||||
|
|
||||||
function useBetterScroll(enabled = true) {
|
defineOptions()
|
||||||
const bsRef = ref(null);
|
|
||||||
const asideMenuRef = ref();
|
|
||||||
|
|
||||||
let onOpenChange = () => {};
|
|
||||||
if (enabled) {
|
|
||||||
function bsInit() {
|
|
||||||
if (asideMenuRef.value == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bsRef.value = new BScroll(asideMenuRef.value, {
|
|
||||||
mouseWheel: true,
|
|
||||||
click: true,
|
|
||||||
momentum: false,
|
|
||||||
// 如果你愿意可以打开显示滚动条
|
|
||||||
scrollbar: {
|
|
||||||
fade: true,
|
|
||||||
interactive: false
|
|
||||||
},
|
|
||||||
bounce: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function bsDestroy() {
|
|
||||||
if (bsRef.value != null && bsRef.value.destroy) {
|
|
||||||
try {
|
|
||||||
bsRef.value.destroy();
|
|
||||||
} catch (e) {
|
|
||||||
// console.error(e);
|
|
||||||
} finally {
|
|
||||||
bsRef.value = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
bsInit();
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
bsDestroy();
|
|
||||||
});
|
|
||||||
onOpenChange = async () => {
|
|
||||||
console.log("onOpenChange");
|
|
||||||
setTimeout(() => {
|
|
||||||
bsRef.value?.refresh();
|
|
||||||
}, 300);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
onOpenChange,
|
|
||||||
asideMenuRef
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "FsMenu",
|
name: "FsMenu",
|
||||||
inheritAttrs: true,
|
inheritAttrs: true,
|
||||||
@@ -75,6 +23,31 @@ export default defineComponent({
|
|||||||
await routerUtils.open(item.key);
|
await routerUtils.open(item.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const items = ref([]);
|
||||||
|
|
||||||
|
function buildItemMenus(menus: any) {
|
||||||
|
if (menus == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const list: any = [];
|
||||||
|
for (const sub of menus) {
|
||||||
|
const item: any = {
|
||||||
|
key: sub.path,
|
||||||
|
label: sub.title,
|
||||||
|
title: sub.title,
|
||||||
|
icon: () => {
|
||||||
|
return <fsIcon icon={sub.icon ?? sub.meta?.icon} />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
list.push(item);
|
||||||
|
if (sub.children && sub.children.length > 0) {
|
||||||
|
item.children = buildItemMenus(sub.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
items.value = buildItemMenus(props.menus);
|
||||||
|
console.log("items", items.value);
|
||||||
const fsIcon = resolveComponent("FsIcon");
|
const fsIcon = resolveComponent("FsIcon");
|
||||||
|
|
||||||
const buildMenus = (children: any) => {
|
const buildMenus = (children: any) => {
|
||||||
@@ -114,7 +87,7 @@ export default defineComponent({
|
|||||||
open(sub.path);
|
open(sub.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
slots.push(<a-sub-menu key={sub.path} v-slots={subSlots} onTitleClick={onTitleClick} />);
|
slots.push(<a-sub-menu key={sub.path} v-slots={subSlots} />);
|
||||||
} else {
|
} else {
|
||||||
slots.push(
|
slots.push(
|
||||||
<a-menu-item key={sub.path} title={sub.title}>
|
<a-menu-item key={sub.path} title={sub.title}>
|
||||||
@@ -132,6 +105,7 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
const selectedKeys = ref([]);
|
const selectedKeys = ref([]);
|
||||||
const openKeys = ref([]);
|
const openKeys = ref([]);
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -153,7 +127,7 @@ export default defineComponent({
|
|||||||
if (item.value instanceof Array) {
|
if (item.value instanceof Array) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
keys.push(item.value.index);
|
keys.push(item.value.path);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -168,7 +142,7 @@ export default defineComponent({
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { asideMenuRef, onOpenChange } = useBetterScroll(props.scroll as any);
|
// const { asideMenuRef, onOpenChange } = useBetterScroll(props.scroll as any);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => {
|
() => {
|
||||||
@@ -179,7 +153,7 @@ export default defineComponent({
|
|||||||
selectedKeys.value = [path];
|
selectedKeys.value = [path];
|
||||||
const changed = openSelectedParents(path);
|
const changed = openSelectedParents(path);
|
||||||
if (changed) {
|
if (changed) {
|
||||||
onOpenChange();
|
// onOpenChange();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -191,22 +165,19 @@ export default defineComponent({
|
|||||||
<a-menu
|
<a-menu
|
||||||
mode={"inline"}
|
mode={"inline"}
|
||||||
theme={"light"}
|
theme={"light"}
|
||||||
v-slots={slots}
|
// v-slots={slots}
|
||||||
onClick={onSelect}
|
// onClick={onSelect}
|
||||||
onOpenChange={onOpenChange}
|
// onOpenChange={onOpenChange}
|
||||||
v-models={[
|
v-models={[
|
||||||
[openKeys.value, "openKeys"],
|
[openKeys.value, "openKeys"],
|
||||||
[selectedKeys.value, "selectedKeys"]
|
[selectedKeys.value, "selectedKeys"]
|
||||||
]}
|
]}
|
||||||
{...ctx.attrs}
|
items={items.value}
|
||||||
|
inlineCollapsed={!props.expandSelected}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const classNames = { "fs-menu-wrapper": true, "fs-menu-better-scroll": props.scroll };
|
const classNames = { "fs-menu-wrapper": true, "fs-menu-better-scroll": props.scroll };
|
||||||
return (
|
return <div>{menu}</div>;
|
||||||
<div ref={asideMenuRef} class={classNames}>
|
|
||||||
{menu}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -77,9 +77,7 @@ export default {
|
|||||||
closeAll: pageStore.closeAll,
|
closeAll: pageStore.closeAll,
|
||||||
openedSort: pageStore.openedSort
|
openedSort: pageStore.openedSort
|
||||||
};
|
};
|
||||||
console.log("opened", pageStore.getOpened);
|
|
||||||
const computeOpened = computed(() => {
|
const computeOpened = computed(() => {
|
||||||
console.log("opened", pageStore.getOpened);
|
|
||||||
return pageStore.getOpened;
|
return pageStore.getOpened;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ defineOptions({
|
|||||||
name: "FsUserInfo"
|
name: "FsUserInfo"
|
||||||
});
|
});
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
console.log("user", userStore);
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-layout class="fs-framework">
|
<a-layout class="fs-framework">
|
||||||
<a-layout-sider v-model:collapsed="asideCollapsed" :trigger="null" collapsible>
|
<a-layout-sider v-model:collapsed="asideCollapsed" :trigger="null" collapsible :width="210">
|
||||||
<div class="header-logo">
|
<div class="header-logo">
|
||||||
<img :src="siteInfo.logo" />
|
<img :src="siteInfo.logo" />
|
||||||
<span v-if="!asideCollapsed" class="title">{{ siteInfo.title }}</span>
|
<span v-if="!asideCollapsed" class="title">{{ siteInfo.title }}</span>
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onErrorCaptured, onMounted, ref } from "vue";
|
import { computed, onErrorCaptured, onMounted, ref } from "vue";
|
||||||
import FsMenu from "./components/menu/index.jsx";
|
import FsMenu from "./components/menu/index.vue";
|
||||||
import FsLocale from "./components/locale/index.vue";
|
import FsLocale from "./components/locale/index.vue";
|
||||||
import FsUserInfo from "./components/user-info/index.vue";
|
import FsUserInfo from "./components/user-info/index.vue";
|
||||||
import FsTabs from "./components/tabs/index.vue";
|
import FsTabs from "./components/tabs/index.vue";
|
||||||
|
|||||||
@@ -128,6 +128,15 @@ function install(app: App, options: any = {}) {
|
|||||||
return { currentPage, pageSize, records: res.records, total: res.total, ...res };
|
return { currentPage, pageSize, records: res.records, total: res.total, ...res };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
search: {
|
||||||
|
formItem: {
|
||||||
|
wrapperCol: {
|
||||||
|
style: {
|
||||||
|
width: "50%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
form: {
|
form: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
labelCol: {
|
labelCol: {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Validator from "async-validator";
|
import Validator from "async-validator";
|
||||||
// 自定义验证器函数
|
// 自定义验证器函数
|
||||||
export function isDomain(rule: any, value: any) {
|
export function isDomain(rule: any, value: any) {
|
||||||
if (value == null) {
|
if (value == null || value == "") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let domains: string[] = value;
|
let domains: string[] = value;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
|
|
||||||
export const certdResources = [
|
export const certdResources = [
|
||||||
{
|
{
|
||||||
title: "证书自动化",
|
title: "证书自动化",
|
||||||
@@ -39,47 +41,165 @@ export const certdResources = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "授权管理",
|
title: "站点证书监控",
|
||||||
name: "AccessManager",
|
name: "SiteCertMonitor",
|
||||||
path: "/certd/access",
|
path: "/certd/monitor/site",
|
||||||
component: "/certd/access/index.vue",
|
component: "/certd/monitor/site/index.vue",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:disc-outline",
|
icon: "ion:videocam-outline",
|
||||||
auth: true,
|
|
||||||
cache: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "通知设置",
|
|
||||||
name: "NotificationManager",
|
|
||||||
path: "/certd/notification",
|
|
||||||
component: "/certd/notification/index.vue",
|
|
||||||
meta: {
|
|
||||||
icon: "ion:megaphone-outline",
|
|
||||||
auth: true,
|
|
||||||
cache: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "CNAME记录管理",
|
|
||||||
name: "CnameRecord",
|
|
||||||
path: "/certd/cname/record",
|
|
||||||
component: "/certd/cname/record/index.vue",
|
|
||||||
meta: {
|
|
||||||
icon: "ion:link-outline",
|
|
||||||
auth: true
|
auth: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "分组管理",
|
title: "设置",
|
||||||
name: "PipelineGroupManager",
|
name: "MineSetting",
|
||||||
path: "/certd/pipeline/group",
|
path: "/certd/mine",
|
||||||
component: "/certd/pipeline/group/index.vue",
|
|
||||||
meta: {
|
meta: {
|
||||||
icon: "mdi:format-list-group",
|
icon: "ion:settings-outline",
|
||||||
auth: true
|
auth: true,
|
||||||
}
|
cache: true
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: "CNAME记录管理",
|
||||||
|
name: "CnameRecord",
|
||||||
|
path: "/certd/cname/record",
|
||||||
|
component: "/certd/cname/record/index.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ion:link-outline",
|
||||||
|
auth: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "流水线分组管理",
|
||||||
|
name: "PipelineGroupManager",
|
||||||
|
path: "/certd/pipeline/group",
|
||||||
|
component: "/certd/pipeline/group/index.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "mdi:format-list-group",
|
||||||
|
auth: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "证书仓库",
|
||||||
|
name: "CertStore",
|
||||||
|
path: "/certd/monitor/cert",
|
||||||
|
component: "/certd/monitor/cert/index.vue",
|
||||||
|
meta: {
|
||||||
|
show: () => {
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
return settingStore.isPlus;
|
||||||
|
},
|
||||||
|
icon: "ion:shield-checkmark-outline",
|
||||||
|
auth: true,
|
||||||
|
isMenu: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "授权管理",
|
||||||
|
name: "AccessManager",
|
||||||
|
path: "/certd/access",
|
||||||
|
component: "/certd/access/index.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ion:disc-outline",
|
||||||
|
auth: true,
|
||||||
|
cache: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "通知设置",
|
||||||
|
name: "NotificationManager",
|
||||||
|
path: "/certd/notification",
|
||||||
|
component: "/certd/notification/index.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ion:megaphone-outline",
|
||||||
|
auth: true,
|
||||||
|
cache: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "账号信息",
|
||||||
|
name: "UserProfile",
|
||||||
|
path: "/certd/mine/user-profile",
|
||||||
|
component: "/certd/mine/user-profile.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ion:person-outline",
|
||||||
|
auth: true,
|
||||||
|
isMenu: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "套餐",
|
||||||
|
name: "SuiteProduct",
|
||||||
|
path: "/certd/suite",
|
||||||
|
meta: {
|
||||||
|
show: () => {
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
return settingStore.isComm && settingStore.isSuiteEnabled;
|
||||||
|
},
|
||||||
|
icon: "ion:cart-outline",
|
||||||
|
auth: true
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: "我的套餐",
|
||||||
|
name: "MySuite",
|
||||||
|
path: "/certd/suite/mine",
|
||||||
|
component: "/certd/suite/mine/index.vue",
|
||||||
|
meta: {
|
||||||
|
show: () => {
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
return settingStore.isComm;
|
||||||
|
},
|
||||||
|
icon: "ion:gift-outline",
|
||||||
|
auth: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "套餐购买",
|
||||||
|
name: "SuiteProductBuy",
|
||||||
|
path: "/certd/suite/buy",
|
||||||
|
component: "/certd/suite/buy.vue",
|
||||||
|
meta: {
|
||||||
|
show: () => {
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
return settingStore.isComm;
|
||||||
|
},
|
||||||
|
icon: "ion:cart-outline",
|
||||||
|
auth: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "我的订单",
|
||||||
|
name: "MyTrade",
|
||||||
|
path: "/certd/trade",
|
||||||
|
component: "/certd/trade/index.vue",
|
||||||
|
meta: {
|
||||||
|
show: () => {
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
return settingStore.isComm;
|
||||||
|
},
|
||||||
|
icon: "ion:bag-check-outline",
|
||||||
|
auth: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "支付返回",
|
||||||
|
name: "PaymentReturn",
|
||||||
|
path: "/certd/payment/return/:type",
|
||||||
|
component: "/certd/payment/return.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ant-design:pay-circle-outlined",
|
||||||
|
auth: false,
|
||||||
|
isMenu: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// title: "邮箱设置",
|
// title: "邮箱设置",
|
||||||
// name: "EmailSetting",
|
// name: "EmailSetting",
|
||||||
@@ -90,17 +210,6 @@ export const certdResources = [
|
|||||||
// auth: true
|
// auth: true
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
{
|
|
||||||
title: "账号信息",
|
|
||||||
name: "UserProfile",
|
|
||||||
path: "/certd/mine/user-profile",
|
|
||||||
component: "/certd/mine/user-profile.vue",
|
|
||||||
meta: {
|
|
||||||
icon: "ion:person-outline",
|
|
||||||
auth: true,
|
|
||||||
isMenu: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -169,35 +169,65 @@ export const sysResources = [
|
|||||||
icon: "ion:person-outline",
|
icon: "ion:person-outline",
|
||||||
permission: "sys:auth:user:view"
|
permission: "sys:auth:user:view"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
// {
|
{
|
||||||
// title: "商业版设置",
|
title: "套餐管理",
|
||||||
// name: "SysCommercial",
|
name: "SuiteManager",
|
||||||
// meta: {
|
path: "/sys/suite",
|
||||||
// icon: "ion:document-text-outline",
|
meta: {
|
||||||
// permission: "sys:settings:view",
|
icon: "ion:cart-outline",
|
||||||
// show: () => {
|
permission: "sys:settings:edit",
|
||||||
// const settingStore = useSettingStore();
|
show: () => {
|
||||||
// return settingStore.isComm;
|
const settingStore = useSettingStore();
|
||||||
// }
|
return settingStore.isComm;
|
||||||
// },
|
}
|
||||||
// children: [
|
},
|
||||||
// {
|
children: [
|
||||||
// title: "套餐设置",
|
{
|
||||||
// name: "suite",
|
title: "套餐设置",
|
||||||
// path: "/sys/commercial/suite",
|
name: "SuiteSetting",
|
||||||
// meta: {
|
path: "/sys/suite/setting",
|
||||||
// icon: "ion:document-text-outline",
|
component: "/sys/suite/setting/index.vue",
|
||||||
// permission: "sys:settings:view",
|
meta: {
|
||||||
// show: () => {
|
show: () => {
|
||||||
// const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
// return settingStore.isComm;
|
return settingStore.isComm;
|
||||||
// }
|
},
|
||||||
// }
|
icon: "ion:cart",
|
||||||
// }
|
permission: "sys:settings:edit"
|
||||||
// ]
|
}
|
||||||
// }
|
},
|
||||||
|
{
|
||||||
|
title: "订单管理",
|
||||||
|
name: "OrderManager",
|
||||||
|
path: "/sys/suite/trade",
|
||||||
|
component: "/sys/suite/trade/index.vue",
|
||||||
|
meta: {
|
||||||
|
show: () => {
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
return settingStore.isComm;
|
||||||
|
},
|
||||||
|
icon: "ion:bag-check",
|
||||||
|
permission: "sys:settings:edit"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "用户套餐",
|
||||||
|
name: "UserSuites",
|
||||||
|
path: "/sys/suite/user-suite",
|
||||||
|
component: "/sys/suite/user-suite/index.vue",
|
||||||
|
meta: {
|
||||||
|
show: () => {
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
return settingStore.isComm;
|
||||||
|
},
|
||||||
|
icon: "ion:gift-outline",
|
||||||
|
auth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ interface ResourceState {
|
|||||||
|
|
||||||
export const useResourceStore = defineStore({
|
export const useResourceStore = defineStore({
|
||||||
id: "app.resource",
|
id: "app.resource",
|
||||||
|
//@ts-ignore
|
||||||
state: (): ResourceState => ({
|
state: (): ResourceState => ({
|
||||||
// user info
|
// user info
|
||||||
topMenus: [],
|
topMenus: [],
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as _ from "lodash-es";
|
|||||||
import { LocalStorage } from "/src/utils/util.storage";
|
import { LocalStorage } from "/src/utils/util.storage";
|
||||||
|
|
||||||
import * as basicApi from "/@/api/modules/api.basic";
|
import * as basicApi from "/@/api/modules/api.basic";
|
||||||
import { HeaderMenus, PlusInfo, SiteEnv, SiteInfo, SysInstallInfo, SysPublicSetting } from "/@/api/modules/api.basic";
|
import { HeaderMenus, PlusInfo, SiteEnv, SiteInfo, SuiteSetting, SysInstallInfo, SysPublicSetting } from "/@/api/modules/api.basic";
|
||||||
import { useUserStore } from "/@/store/modules/user";
|
import { useUserStore } from "/@/store/modules/user";
|
||||||
import { mitter } from "/@/utils/util.mitt";
|
import { mitter } from "/@/utils/util.mitt";
|
||||||
import { env } from "/@/utils/util.env";
|
import { env } from "/@/utils/util.env";
|
||||||
@@ -37,6 +37,7 @@ export interface SettingState {
|
|||||||
siteEnv?: SiteEnv;
|
siteEnv?: SiteEnv;
|
||||||
headerMenus?: HeaderMenus;
|
headerMenus?: HeaderMenus;
|
||||||
inited?: boolean;
|
inited?: boolean;
|
||||||
|
suiteSetting?: SuiteSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultThemeConfig = {
|
const defaultThemeConfig = {
|
||||||
@@ -88,6 +89,7 @@ export const useSettingStore = defineStore({
|
|||||||
headerMenus: {
|
headerMenus: {
|
||||||
menus: []
|
menus: []
|
||||||
},
|
},
|
||||||
|
suiteSetting: { enabled: false },
|
||||||
inited: false
|
inited: false
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
@@ -120,10 +122,13 @@ export const useSettingStore = defineStore({
|
|||||||
};
|
};
|
||||||
return vipLabelMap[this.plusInfo?.vipType || "free"];
|
return vipLabelMap[this.plusInfo?.vipType || "free"];
|
||||||
},
|
},
|
||||||
// @ts-ignore
|
getHeaderMenus(): { menus: any[] } {
|
||||||
getHeaderMenus() {
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return this.headerMenus?.menus || { menus: [] };
|
return this.headerMenus?.menus || { menus: [] };
|
||||||
|
},
|
||||||
|
isSuiteEnabled(): boolean {
|
||||||
|
// @ts-ignore
|
||||||
|
return this.suiteSetting?.enabled === true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@@ -142,6 +147,7 @@ export const useSettingStore = defineStore({
|
|||||||
_.merge(this.siteEnv, allSettings.siteEnv || {});
|
_.merge(this.siteEnv, allSettings.siteEnv || {});
|
||||||
_.merge(this.plusInfo, allSettings.plusInfo || {});
|
_.merge(this.plusInfo, allSettings.plusInfo || {});
|
||||||
_.merge(this.headerMenus, allSettings.headerMenus || {});
|
_.merge(this.headerMenus, allSettings.headerMenus || {});
|
||||||
|
_.merge(this.suiteSetting, allSettings.suiteSetting || {});
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
this.initSiteInfo(allSettings.siteInfo || {});
|
this.initSiteInfo(allSettings.siteInfo || {});
|
||||||
},
|
},
|
||||||
@@ -160,7 +166,7 @@ export const useSettingStore = defineStore({
|
|||||||
async checkUrlBound() {
|
async checkUrlBound() {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
if (!userStore.isAdmin || !settingStore.isPlus) {
|
if (!userStore.isAdmin) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user