mirror of
https://github.com/certd/certd.git
synced 2026-04-05 15:38:11 +08:00
Compare commits
265 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92446cb048 | ||
|
|
954ce4533f | ||
|
|
f7b88f9e3b | ||
|
|
736fe038eb | ||
|
|
abcd257db0 | ||
|
|
c38b5f3cdc | ||
|
|
b649617e04 | ||
|
|
a4e2287101 | ||
|
|
fbb66f3c43 | ||
|
|
fedf90ea78 | ||
|
|
d558d50102 | ||
|
|
656cb89fe8 | ||
|
|
1e6ddd250e | ||
|
|
1de8eee6ea | ||
|
|
425bba67c5 | ||
|
|
8b0daf7200 | ||
|
|
589a373142 | ||
|
|
0cfc71e4bf | ||
|
|
92dabe6276 | ||
|
|
d1b61b6bf9 | ||
|
|
873f2b618b | ||
|
|
4453070060 | ||
|
|
de40be430b | ||
|
|
29a6a992f0 | ||
|
|
0a7d2d6264 | ||
|
|
e09f92f9ee | ||
|
|
9be1ecc8aa | ||
|
|
729b19c8da | ||
|
|
a9fffa5180 | ||
|
|
0069c0e399 | ||
|
|
b6fd38e293 | ||
|
|
36aa7f82b0 | ||
|
|
d01004d530 | ||
|
|
d85a02feeb | ||
|
|
b82e1dcd62 | ||
|
|
74c6a2266f | ||
|
|
9754223f31 | ||
|
|
cfbbac9796 | ||
|
|
fece8955cf | ||
|
|
170b2afb0e | ||
|
|
ee8af18d0a | ||
|
|
27386ea04d | ||
|
|
0d71a8ee50 | ||
|
|
82a72e0b49 | ||
|
|
5035c123f0 | ||
|
|
474b3372d8 | ||
|
|
be87124ada | ||
|
|
aa3032db35 | ||
|
|
a4ead79888 | ||
|
|
98445afd3e | ||
|
|
3eb9671640 | ||
|
|
95fb4e3e8b | ||
|
|
818015d24a | ||
|
|
e11bd3e813 | ||
|
|
2a4d64af95 | ||
|
|
d73cb4be2b | ||
|
|
82752040f8 | ||
|
|
1bde6d8b9c | ||
|
|
be55d36f67 | ||
|
|
f07724372d | ||
|
|
5b8d5dd975 | ||
|
|
e36aa065e9 | ||
|
|
45486ef399 | ||
|
|
4fedf6f452 | ||
|
|
702b80ef75 | ||
|
|
a5c7789dbc | ||
|
|
bddef199ff | ||
|
|
fa6fc07009 | ||
|
|
8d9b44528b | ||
|
|
1d108d775c | ||
|
|
7af111ac57 | ||
|
|
6451f00639 | ||
|
|
31718d1a4a | ||
|
|
832b74b66b | ||
|
|
082802e119 | ||
|
|
efa9c748c5 | ||
|
|
fc8bef5aae | ||
|
|
441b15ed2f | ||
|
|
11d1f6e141 | ||
|
|
0f5b9564c6 | ||
|
|
0c8a84656a | ||
|
|
330f91e15b | ||
|
|
490141a920 | ||
|
|
1e288b14d0 | ||
|
|
81df96bf45 | ||
|
|
d1ab5f74a6 | ||
|
|
e43dd03132 | ||
|
|
2c6d64976f | ||
|
|
065713cdb6 | ||
|
|
746d3c97c3 | ||
|
|
9557fc799e | ||
|
|
8fcabc5e9f | ||
|
|
2b4b15f558 | ||
|
|
057b0b4565 | ||
|
|
70a2402521 | ||
|
|
de34db3394 | ||
|
|
0c2ae792ec | ||
|
|
a4c0b92777 | ||
|
|
b9d78135e0 | ||
|
|
5641c19502 | ||
|
|
0110dfdb70 | ||
|
|
140606744b | ||
|
|
335d175d57 | ||
|
|
779db9da70 | ||
|
|
5d29a08ab7 | ||
|
|
1fe3365e10 | ||
|
|
f0584c88e8 | ||
|
|
c7620dfc48 | ||
|
|
5d6a945763 | ||
|
|
4fe5939d0b | ||
|
|
bcaf54d4cb | ||
|
|
44d43f45cb | ||
|
|
de26ee9383 | ||
|
|
d442462952 | ||
|
|
558fc9f306 | ||
|
|
9f0ee219d0 | ||
|
|
5164116bde | ||
|
|
02404bc97e | ||
|
|
0ebdb037b5 | ||
|
|
a8b60c32b3 | ||
|
|
416621d503 | ||
|
|
b917eb447c | ||
|
|
2ce3c71b88 | ||
|
|
ca13bfa5f8 | ||
|
|
d8812196f3 | ||
|
|
4e750bdbe1 | ||
|
|
f59a37b77c | ||
|
|
ea3db93db9 | ||
|
|
26f2c9fea2 | ||
|
|
290cc0d1bb | ||
|
|
78044c062e | ||
|
|
3a2f653229 | ||
|
|
bbe22e6f36 | ||
|
|
d4474ff0fb | ||
|
|
c7979f1be5 | ||
|
|
ada0b7106e | ||
|
|
c3a5542935 | ||
|
|
2eebb3388a | ||
|
|
287c3688fd | ||
|
|
3948b3993f | ||
|
|
bcacafeb84 | ||
|
|
2193ddfabe | ||
|
|
29ae0b7dca | ||
|
|
904837df12 | ||
|
|
00c2da444f | ||
|
|
13d0dde9f4 | ||
|
|
548f2a960c | ||
|
|
fe4367c580 | ||
|
|
71803f891d | ||
|
|
75a38d95f3 | ||
|
|
c89686a2fd | ||
|
|
398323533a | ||
|
|
a773872cf3 | ||
|
|
2eb0d55f92 | ||
|
|
54bd1ad0fa | ||
|
|
089825d360 | ||
|
|
333629caff | ||
|
|
d715cd1129 | ||
|
|
15d6eaf553 | ||
|
|
ae5dfc3bee | ||
|
|
6ab83b662a | ||
|
|
52ae6902d2 | ||
|
|
c30adb2671 | ||
|
|
e95d29f446 | ||
|
|
c20bb38b06 | ||
|
|
d0213d275d | ||
|
|
9a78dad576 | ||
|
|
880f1aeb66 | ||
|
|
e764eabd97 | ||
|
|
235f9cf854 | ||
|
|
d10795ecd9 | ||
|
|
a7e45dace0 | ||
|
|
7e482f798c | ||
|
|
c085bac5d8 | ||
|
|
653940a0ca | ||
|
|
417d37b199 | ||
|
|
3b2107a4f1 | ||
|
|
7f6d03c02a | ||
|
|
5fc07d4dd4 | ||
|
|
3fb9524cbd | ||
|
|
e79703e49b | ||
|
|
b829bd1341 | ||
|
|
8cbab7525a | ||
|
|
93b37a89c9 | ||
|
|
87620b9072 | ||
|
|
6877b865a7 | ||
|
|
d6b3142a02 | ||
|
|
14cdb54212 | ||
|
|
91e7f45a1c | ||
|
|
709105120c | ||
|
|
865f26d75c | ||
|
|
52a4fd3318 | ||
|
|
e70732c9ac | ||
|
|
c6c269f9e4 | ||
|
|
42ad04cabd | ||
|
|
2a8eeaf240 | ||
|
|
f7dcff5113 | ||
|
|
98a81385a6 | ||
|
|
7bdc277b58 | ||
|
|
f57116d2be | ||
|
|
85c99f7f80 | ||
|
|
75081ceac3 | ||
|
|
65da3ca298 | ||
|
|
94509c64b9 | ||
|
|
4f36d94726 | ||
|
|
05c284b999 | ||
|
|
635b042690 | ||
|
|
1cb4a539cc | ||
|
|
46b87250b2 | ||
|
|
1a05355e54 | ||
|
|
c81c17d17b | ||
|
|
7b4f8d31e8 | ||
|
|
5cef28c5bd | ||
|
|
6e68da7936 | ||
|
|
0c130f9596 | ||
|
|
f156f4cb4e | ||
|
|
fa3bfa2ea8 | ||
|
|
ab5c7bb75a | ||
|
|
81b322cd60 | ||
|
|
e6dd7cd54a | ||
|
|
aa1da7c11a | ||
|
|
3f74d4d9e5 | ||
|
|
297d09c5ad | ||
|
|
07e1dbb4cc | ||
|
|
3c6618b4fc | ||
|
|
54db744282 | ||
|
|
03b751fa13 | ||
|
|
ec342708b2 | ||
|
|
405591c5d0 | ||
|
|
7f5e89d489 | ||
|
|
c504f33b1f | ||
|
|
67af67b92d | ||
|
|
8644348fc4 | ||
|
|
00dc226bd2 | ||
|
|
b6b7c3e2e0 | ||
|
|
246ef348d3 | ||
|
|
3e9ba1a30a | ||
|
|
598cde4865 | ||
|
|
fc4a716b4e | ||
|
|
ed6a18dae7 | ||
|
|
844c4bf983 | ||
|
|
43961c1c18 | ||
|
|
7b42d7252e | ||
|
|
4aa136189a | ||
|
|
c66802af2d | ||
|
|
49e65c611f | ||
|
|
abf29bc164 | ||
|
|
08854e0ab9 | ||
|
|
575416a16d | ||
|
|
3dd0783510 | ||
|
|
fadb1d35b3 | ||
|
|
27a9fc32a6 | ||
|
|
7008a408ca | ||
|
|
b928bb46c7 | ||
|
|
18c9c4a166 | ||
|
|
49fa01f209 | ||
|
|
fe9d443100 | ||
|
|
3dec43d8d4 | ||
|
|
5ab2943c3a | ||
|
|
6e8b0eeca9 | ||
|
|
d0c4dfca97 | ||
|
|
f4a11ed328 | ||
|
|
b2971cf5fb | ||
|
|
f97827ec76 | ||
|
|
f230a2a94d |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -21,7 +21,7 @@ gen
|
||||
/packages/ui/*/.idea
|
||||
/packages/ui/*/node_modules
|
||||
/packages/*/node_modules
|
||||
/pnpm-lock.yaml
|
||||
#/pnpm-lock.yaml
|
||||
|
||||
|
||||
tsconfig.tsbuildinfo
|
||||
|
||||
173
CHANGELOG.md
173
CHANGELOG.md
@@ -3,6 +3,179 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/certd/certd/compare/v1.31.4...v1.31.5) (2025-03-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复通知选择器无法选择的bug ([f7b88f9](https://github.com/certd/certd/commit/f7b88f9e3b7d9d9122e4fd2003a20c555bd50c7d))
|
||||
* 修复证书流水线创建失败的bug ([736fe03](https://github.com/certd/certd/commit/736fe038ebda56648bcc4c12884a700341d2c049))
|
||||
|
||||
## [1.31.4](https://github.com/certd/certd/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复站点监控通知通过webhook发送失败的bug ([9be1ecc](https://github.com/certd/certd/commit/9be1ecc8aab3ea23dd0dc2dab3688f4edb90ef2c))
|
||||
* 修复dns.la域名申请失败的bug ([1de8eee](https://github.com/certd/certd/commit/1de8eee6ea8307f3c11626af75303d3cc104bb95))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 宝塔支持doker站点证书部署 ([589a373](https://github.com/certd/certd/commit/589a373142ef7f50d64d3aa767a90b1f4b64da93))
|
||||
* 保存调整后的列宽 ([873f2b6](https://github.com/certd/certd/commit/873f2b618b9d7320045baf69d6da83afe48a780f))
|
||||
* 创建证书流水线时,支持更多参数展开 ([36aa7f8](https://github.com/certd/certd/commit/36aa7f82b078a053a102331b3c6f132fb9d492f9))
|
||||
* 流水线页面可以鼠标按住左右拖动 ([d85a02f](https://github.com/certd/certd/commit/d85a02feeb3183c5abd6c1ea790d5923a32d7271))
|
||||
* 流水线增加上传证书快捷方式 ([425bba6](https://github.com/certd/certd/commit/425bba67c539b734e2a85a83a4f9ecc9b2434fb4))
|
||||
* 手动上传证书部署流水线 ([fbb66f3](https://github.com/certd/certd/commit/fbb66f3c4389489aa8a43b194d82bc8cf391607b))
|
||||
* 优化选择任务时手机版展示效果 ([d01004d](https://github.com/certd/certd/commit/d01004d53071a75ac91ee21cc96bde9369f77ff3))
|
||||
* 站点监控,手动测试也发通知 ([729b19c](https://github.com/certd/certd/commit/729b19c8da60d5efb5baef7cf8df0518e7f6b471))
|
||||
* 站点证书监控支持模糊查询 ([0069c0e](https://github.com/certd/certd/commit/0069c0e3992946a8dd6410f299d4fc974ef0e76b))
|
||||
* 支持飞书通知 ([b82e1dc](https://github.com/certd/certd/commit/b82e1dcd6217b09a7d7e21cd648bb31de320cadf))
|
||||
* 支持手动上传证书并部署 ([a9fffa5](https://github.com/certd/certd/commit/a9fffa5180c83da27b35886aa2e858a92a2c5f94))
|
||||
|
||||
## [1.31.3](https://github.com/certd/certd/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云fc获取不到列表的bug ([474b337](https://github.com/certd/certd/commit/474b3372d8ce98e6d45900bf8046bc0b3f220686))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 1panel支持 apikey方式授权 ([170b2af](https://github.com/certd/certd/commit/170b2afb0e3b125e4ed057f633fe895b5ac3ac22))
|
||||
* 套餐支持3天7天等选项 ([0d71a8e](https://github.com/certd/certd/commit/0d71a8ee501a0e5bb69decf07e8729026e9d85bf))
|
||||
* 证书仓库增加有效期显示 ([be87124](https://github.com/certd/certd/commit/be87124ada7a093f281ca29a45c86b4ea4644ead))
|
||||
* 支持部署到天翼云CDN ([82a72e0](https://github.com/certd/certd/commit/82a72e0b497efa043d342ad0e33c083a2de79a05))
|
||||
* 支持dns.la ([ee8af18](https://github.com/certd/certd/commit/ee8af18d0ac0af82544d6dda1e4b4c678b733041))
|
||||
* cf授权支持配置http代理 ([27386ea](https://github.com/certd/certd/commit/27386ea04d3c1a5aebe3cfdd7ac48185eaa76629))
|
||||
|
||||
## [1.31.2](https://github.com/certd/certd/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复cname记录查找bug ([95fb4e3](https://github.com/certd/certd/commit/95fb4e3e8be6ca13cc43b451f6141d62190ba453))
|
||||
|
||||
## [1.31.1](https://github.com/certd/certd/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 一些手机端适配优化 ([5b8d5dd](https://github.com/certd/certd/commit/5b8d5dd97536456a9d5d1384216eac1093b2dc3d))
|
||||
|
||||
# [1.31.0](https://github.com/certd/certd/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复CDN插件我爱云因更换接口导致部署失败的问题 ([5641c19](https://github.com/certd/certd/commit/5641c19502970f67af19709bddf8c781b1a25bdc))
|
||||
* 修复CDN插件我爱云因更换接口导致部署失败的问题 ([0110dfd](https://github.com/certd/certd/commit/0110dfdb70b12dfb0a7a067717f3773ed75aae7c))
|
||||
* 修复webhook headers value中带等号是解析错误的bug ([1fe3365](https://github.com/certd/certd/commit/1fe3365e10c464c4c60c82f424cf74fe35b883e0))
|
||||
* ProxmoxUploadCert 增加强制部署证书 ([441b15e](https://github.com/certd/certd/commit/441b15ed2fe5a143a5bd5508613b3816ddbff596))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 历史记录查看详情,可以切换到对应的历史记录日志上去 ([082802e](https://github.com/certd/certd/commit/082802e1197156837800f814728ee0f6b300b18c))
|
||||
* 流水线同一个阶段任务优化为并行执行 ([efa9c74](https://github.com/certd/certd/commit/efa9c748c5c07fc950af3db742ef9310f1ac9a4b))
|
||||
* 升级midwayjs版本 ([057b0b4](https://github.com/certd/certd/commit/057b0b4565e19bb93195633f767b2942e8e40e59))
|
||||
* 是否允许爬虫爬取增加ui设置选项 ([779db9d](https://github.com/certd/certd/commit/779db9da705d2dfef36fec21f52bd38af9fc5f2e))
|
||||
* 通知支持钉钉群聊机器人 ([fc8bef5](https://github.com/certd/certd/commit/fc8bef5aae522d75d408d8c3aa74543269da5398))
|
||||
* 易支付支持固定支付方式,适合没有收银台版本使用 ([81df96b](https://github.com/certd/certd/commit/81df96bf4542ce8d8ef4a428a4460dd554e4719a))
|
||||
* 支持易盾RCDN部署 ([065713c](https://github.com/certd/certd/commit/065713cdb6953d16df08585c316c1a7a8eaec437))
|
||||
|
||||
## [1.30.6](https://github.com/certd/certd/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 禁止爬虫爬取本网站 ([5164116](https://github.com/certd/certd/commit/5164116bde60dabac774cdf94f5317ff386e95ca))
|
||||
* 上传到阿里云证书名称后缀增加毫秒时间戳 ([9f0ee21](https://github.com/certd/certd/commit/9f0ee219d02907ffe128a5cf10173397d934ccd7))
|
||||
* 支持部署到阿里云FC3.0 ([bcaf54d](https://github.com/certd/certd/commit/bcaf54d4cb7bc469486aae6cdb127ae017eb3abb))
|
||||
* 支持新版本LeCDN ([44d43f4](https://github.com/certd/certd/commit/44d43f45cb9094619df7494c2a64a51ba77ad116))
|
||||
|
||||
## [1.30.5](https://github.com/certd/certd/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package root
|
||||
|
||||
## [1.30.4](https://github.com/certd/certd/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 适配最新版1panel密码编码方式 ([78044c0](https://github.com/certd/certd/commit/78044c062e20cdd04f08baef9fb6745bf25eddcf))
|
||||
|
||||
## [1.30.3](https://github.com/certd/certd/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复腾讯云CLB多域名同证书部署报错的bug ([c3a5542](https://github.com/certd/certd/commit/c3a55429357e78f4b78c9592d3e5897db2d4d549))
|
||||
* 修复新版本1panel密码需要加密,无法登录的问题 ([ada0b71](https://github.com/certd/certd/commit/ada0b7106e97e551783829e4e719f76793a7123d))
|
||||
|
||||
## [1.30.2](https://github.com/certd/certd/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 当前置任务被删除时进行校验 ([c89686a](https://github.com/certd/certd/commit/c89686a2fda251484930f0ae715417b618c21690))
|
||||
* 修复cloudflare删除解析记录报错的bug ([00c2da4](https://github.com/certd/certd/commit/00c2da444f84adb89f3f1226d03294d7c6e3e4f1))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 上传自定义证书 ([75a38d9](https://github.com/certd/certd/commit/75a38d95f305b4271d9106babe7cffc1c89ae8f3))
|
||||
|
||||
## [1.30.1](https://github.com/certd/certd/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复部署到阿里云ALB、NLB插件加载混乱的bug ([6ab83b6](https://github.com/certd/certd/commit/6ab83b662a2c5e715b9cb7eb1244de2ebb7f47b0))
|
||||
* 修复腾讯clb重复执行会报错的bug ([e95d29f](https://github.com/certd/certd/commit/e95d29f446d06eced315a3087fc9e105a30b20bd))
|
||||
* 修复tg消息内容中存在.和*就会发送失败的bug ([ae5dfc3](https://github.com/certd/certd/commit/ae5dfc3bee950267123ae2fbd1c11e7ce36626ea))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 创建流水线时,默认成功时也发送通知 ([52ae690](https://github.com/certd/certd/commit/52ae6902d203ca56e0312692b50c55cb6ddd3e39))
|
||||
* http方式校验,选择sftp时,支持修改文件访问权限比如777 ([15d6eaf](https://github.com/certd/certd/commit/15d6eaf5532ed25acd4f8d58c429353a2f44206c))
|
||||
|
||||
# [1.30.0](https://github.com/certd/certd/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复查看任务日志偶发性无法自动滚动底部的bug ([7e482f7](https://github.com/certd/certd/commit/7e482f798c0142bce1866f84676cb40210f9638a))
|
||||
* 修复namesilo ttl太短的问题 ([865f26d](https://github.com/certd/certd/commit/865f26d75c0d3dd4dc8b41448f8830068e45957c))
|
||||
|
||||
### Features
|
||||
|
||||
* 支持open api接口,根据域名获取证书 ([52a4fd3](https://github.com/certd/certd/commit/52a4fd33180e9b3f71b8dc9f7671d7cd8e448c3b))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书仓库 ([91e7f45](https://github.com/certd/certd/commit/91e7f45a1c5ea1e0ec0aa3236b80028f03a6d0aa))
|
||||
* 支持部署到阿里云ALB ([653940a](https://github.com/certd/certd/commit/653940a0ca64fc380178c1b0b58ae0af64dfaf07))
|
||||
* 支持部署到阿里云NLB、SLB ([c085bac](https://github.com/certd/certd/commit/c085bac5d877c4250a8a79e17eb8673b8e4fc89c))
|
||||
* 支持部署到腾讯云直播 ([417d37b](https://github.com/certd/certd/commit/417d37b199b79a42f790f9edab8f178eedf8fbf7))
|
||||
* 支持部署证书到proxmox ([d10795e](https://github.com/certd/certd/commit/d10795ecd97eb8cf2ffa46aabfdbfc6812636396))
|
||||
|
||||
## [1.29.5](https://github.com/certd/certd/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复复制到本机插件,pfx格式复制时报错的bug ([f57116d](https://github.com/certd/certd/commit/f57116d2bebf33e47ad93e0b39c4efe8e4aea25c))
|
||||
* 修复授权管理,点击了查看原文按钮后,无法修改值的bug ([85c99f7](https://github.com/certd/certd/commit/85c99f7f80761ac6efaf3255c03b933442db1686))
|
||||
|
||||
## [1.29.4](https://github.com/certd/certd/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复站点监控域名校验无法通过的bug ([1cb4a53](https://github.com/certd/certd/commit/1cb4a539cc523721ffd4b22d40d0e3d2d68cd915))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化腾讯云CLB插件,支持非sni情况,sni情况支持填写多个域名 ([635b042](https://github.com/certd/certd/commit/635b042690637bff85e97e07c7aac4b87a8a124b))
|
||||
|
||||
## [1.29.3](https://github.com/certd/certd/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复系统级授权无法查看密钥的bug ([8644348](https://github.com/certd/certd/commit/8644348fc41ae2e1672f946ca37e5d3a674e0218))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化站点证书检查页面,检查增加3次重试 ([e6dd7cd](https://github.com/certd/certd/commit/e6dd7cd54a3e23897031b5df6e0c3cdc0545d35a))
|
||||
* 优化acme sdk ([54db744](https://github.com/certd/certd/commit/54db74428259de64d12230c2ab7353ae11197bbc))
|
||||
* 支持http校验方式申请证书 ([405591c](https://github.com/certd/certd/commit/405591c5d08fa1a3b228ee3980199e7731cfec4a))
|
||||
* http校验方式,支持七牛云oss、阿里云oss、腾讯云cos ([3f74d4d](https://github.com/certd/certd/commit/3f74d4d9e5f5d0e629b44cff1895b3f7a8fbcafc))
|
||||
|
||||
## [1.29.2](https://github.com/certd/certd/compare/v1.29.1...v1.29.2) (2024-12-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
47
README.md
47
README.md
@@ -9,17 +9,22 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
* 全自动申请证书(支持所有注册商注册的域名)
|
||||
* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等,目前已支持40+部署插件)
|
||||
* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等,目前已支持60+部署插件)
|
||||
* 支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式
|
||||
* 邮件通知、webhook通知
|
||||
* 私有化部署,数据保存本地,授权信息加密存储,镜像由Github Actions构建,过程公开透明
|
||||
* 支持SQLite,PostgreSQL、MySQL数据库
|
||||
|
||||
|
||||
>
|
||||
> 流水线数量现已调整为无限制,欢迎大家使用
|
||||
>
|
||||
|
||||
> 关于证书续期:
|
||||
>* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
>* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
|
||||
|
||||
## 二、在线体验
|
||||
|
||||
官方Demo地址,自助注册后体验
|
||||
@@ -88,11 +93,13 @@ https://certd.handfree.work/
|
||||
|
||||
|
||||
## 五、 升级
|
||||
如果使用固定版本号
|
||||
|
||||
### docker-compose方式部署
|
||||
#### 1. 如果使用固定版本号
|
||||
1. 修改`docker-compose.yaml`中的镜像版本号
|
||||
2. 运行`docker compose up -d` 即可
|
||||
|
||||
如果需要使用最新版本
|
||||
#### 2. 如果需要使用最新版本
|
||||
```shell
|
||||
#重新拉取镜像
|
||||
docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||
@@ -100,7 +107,9 @@ docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
关于自动升级(仅限尝鲜建议非生产使用)
|
||||
> 数据默认存在`/data/certd`目录下,不用担心数据丢失
|
||||
|
||||
### 自动升级(仅限尝鲜建议非生产使用)
|
||||
```yaml
|
||||
version: '3.3'
|
||||
services:
|
||||
@@ -113,16 +122,8 @@ services:
|
||||
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"
|
||||
|
||||
@@ -139,27 +140,21 @@ services:
|
||||
- WATCHTOWER_LABEL_ENABLE=true # 根据容器标签进行更新
|
||||
- WATCHTOWER_POLL_INTERVAL=300 # 每 5 分钟检查一次更新
|
||||
|
||||
# 如果需要支持 IPv6,请取消以下注释
|
||||
# networks:
|
||||
# ip6net:
|
||||
# enable_ipv6: true
|
||||
# ipam:
|
||||
# config:
|
||||
# - subnet: 2001:db8::/64
|
||||
|
||||
```
|
||||
> 数据默认存在`/data/certd`目录下,不用担心数据丢失
|
||||
|
||||
### 其他部署方式升级方法
|
||||
请参考 https://certd.docmirror.cn/guide/install/upgrade.html
|
||||
|
||||
|
||||
更新日志: [CHANGELOG](./CHANGELOG.md)
|
||||
|
||||
### 更新日志:
|
||||
|
||||
[CHANGELOG](./CHANGELOG.md)
|
||||
|
||||
|
||||
## 六、一些说明
|
||||
* 本项目ssl证书提供商为letencrypt/Google/ZeroSSL
|
||||
* 申请过程遵循acme协议
|
||||
* 需要验证域名所有权,一般有两种方式(目前本项目仅支持dns-01)
|
||||
* http-01: 在网站根目录下放置一份txt文件
|
||||
* dns-01: 需要给域名添加txt解析记录,通配符域名只能用这种方式
|
||||
* 证书续期:
|
||||
* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
|
||||
@@ -1 +1 @@
|
||||
01:43
|
||||
02:10
|
||||
|
||||
@@ -7,9 +7,10 @@ services:
|
||||
restart: unless-stopped # 自动重启
|
||||
volumes:
|
||||
# ↓↓↓↓↓ -------------------------------------------------------- 数据库以及证书存储路径,默认存在宿主机的/data/certd/目录下,【您需要定时备份此目录,以保障数据容灾】
|
||||
# 只要修改冒号前面的,冒号后面的/app/data不要动
|
||||
- /data/certd:/app/data
|
||||
ports: # 端口映射
|
||||
# ↓↓↓↓ ---------------------------------------------------------- 如果端口有冲突,可以修改第一个7001为其他不冲突的端口号
|
||||
# ↓↓↓↓ ---------------------------------------------------------- 如果端口有冲突,可以修改第一个7001为其他不冲突的端口号,第二个7001不要动
|
||||
- "7001:7001"
|
||||
# ↓↓↓↓ ---------------------------------------------------------- https端口,可以根据实际情况,是否暴露该端口
|
||||
- "7002:7002"
|
||||
@@ -26,13 +27,20 @@ services:
|
||||
# extra_hosts:
|
||||
# # ↓↓↓↓ -------------------------------------------------------- 这里可以配置自定义hosts,外网域名可以指向本地局域网ip地址
|
||||
# - "localdomain.com:192.168.1.3"
|
||||
|
||||
# # ↓↓↓↓ ------------------------------------------------ 直接使用主机的网络,如果网络问题实在找不到原因,可以尝试打开此参数
|
||||
# network_mode: host
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "true"
|
||||
# ↓↓↓↓ -------------------------------------------------------------- 启用ipv6网络,还需要把下面networks的注释放开
|
||||
# networks:
|
||||
# - ip6net
|
||||
environment:
|
||||
# 设置环境变量即可自定义certd配置
|
||||
# 配置项见: packages/ui/certd-server/src/config/config.default.ts
|
||||
# 配置规则: certd_ + 配置项, 点号用_代替
|
||||
# #↓↓↓↓ ----------------------------- 如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false
|
||||
- certd_system_resetAdminPasswd=false
|
||||
|
||||
# 默认使用sqlite文件数据库,如果需要使用其他数据库,请设置以下环境变量
|
||||
# 注意: 选定使用一种数据库之后,不支持更换数据库。
|
||||
# 数据库迁移方法:1、使用新数据库重新部署一套,然后将旧数据同步过去,注意flyway_history表的数据不要同步
|
||||
@@ -54,13 +62,22 @@ services:
|
||||
# - certd_typeorm_dataSource_default_password=yourpasswd # 密码
|
||||
# - certd_typeorm_dataSource_default_database=certd # 数据库名
|
||||
|
||||
# ↓↓↓↓ --------------------------------------------------------- 自动升级,上面certd的版本号要保持为latest
|
||||
# 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=600 # 每 10 分钟检查一次更新
|
||||
|
||||
|
||||
|
||||
|
||||
# #↓↓↓↓ ------------------------------------------------------------- 启用ipv6网络
|
||||
# networks:
|
||||
# - ip6net
|
||||
# ↓↓↓↓ -------------------------------------------------------------- 启用ipv6网络,还需要把上面networks的注释放开
|
||||
#networks:
|
||||
# ip6net:
|
||||
# enable_ipv6: true
|
||||
|
||||
@@ -12,6 +12,9 @@ export default defineConfig({
|
||||
md.use(lightbox, {});
|
||||
}
|
||||
},
|
||||
sitemap: {
|
||||
hostname: 'https://certd.docmirror.cn'
|
||||
},
|
||||
head: [
|
||||
// [
|
||||
// 'meta',
|
||||
@@ -25,9 +28,9 @@ export default defineConfig({
|
||||
name: "keywords",
|
||||
content: "证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具、Certd、SSL证书自动部署、证书自动化,https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署,SSL平台,证书管理平台,证书流水线"
|
||||
}],
|
||||
["meta", { name: "google-site-verification",content: "V5XLTSnXoT15uQotwpxJoQolUo2d5UbSL-TacsyOsC0"}],
|
||||
// ["meta", { name: "google-site-verification",content: "V5XLTSnXoT15uQotwpxJoQolUo2d5UbSL-TacsyOsC0"}],
|
||||
//<meta name="baidu-site-verification" content="codeva-MiWN8Y07Ua" />
|
||||
["meta", {name: "baidu-site-verification",content: "codeva-MiWN8Y07Ua"}],
|
||||
// ["meta", {name: "baidu-site-verification",content: "codeva-MiWN8Y07Ua"}],
|
||||
["link", { rel: "icon", href: "/static/logo/logo.svg" }]
|
||||
],
|
||||
themeConfig: {
|
||||
@@ -57,6 +60,7 @@ export default defineConfig({
|
||||
nav: [
|
||||
{ text: "首页", link: "/" },
|
||||
{ text: "指南", link: "/guide/" },
|
||||
{ text: "商业版", link: "/comm/" },
|
||||
{ text: "Demo体验", link: "https://certd.handfree.work" }
|
||||
],
|
||||
sidebar: {
|
||||
@@ -84,7 +88,9 @@ export default defineConfig({
|
||||
text: "特性",
|
||||
items: [
|
||||
{ text: "CNAME代理校验", link: "/guide/feature/cname/index.md" },
|
||||
{ text: "插件列表", link: "/guide/plugins.md" }
|
||||
{ text: "插件列表", link: "/guide/plugins.md" },
|
||||
{ text: "多数据库支持", link: "/guide/install/database.md" },
|
||||
{ text: "开放接口", link: "/guide/open/index.md" }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -101,12 +107,12 @@ export default defineConfig({
|
||||
{ text: "js脚本插件使用", link: "/guide/use/custom-script/index.md" },
|
||||
{ text: "邮箱配置", link: "/guide/use/email/index.md" },
|
||||
{ text: "IPv6支持", link: "/guide/use/setting/ipv6.md" },
|
||||
{ text: "如何贡献代码", link: "/guide/development/index.md" },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "其他",
|
||||
items: [
|
||||
{ text: "贡献代码", link: "/guide/development/index.md" },
|
||||
{ text: "更新日志", link: "/guide/changelogs/CHANGELOG.md" },
|
||||
{ text: "镜像说明", link: "/guide/image.md" },
|
||||
{ text: "联系我们", link: "/guide/contact/" },
|
||||
@@ -116,8 +122,20 @@ export default defineConfig({
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"/comm/": [
|
||||
{
|
||||
text: "商业版",
|
||||
items: [
|
||||
{ text: "支付宝配置", link: "/comm/payments/alipay.md" },
|
||||
{ text: "微信支付配置", link: "/comm/payments/wxpay.md" },
|
||||
{ text: "彩虹易支付配置", link: "/comm/payments/yizhifu.md" },
|
||||
]
|
||||
}
|
||||
]
|
||||
,
|
||||
},
|
||||
|
||||
socialLinks: [
|
||||
{ icon: "github", link: "https://github.com/certd/certd" }
|
||||
],
|
||||
|
||||
BIN
docs/comm/images/index.png
Normal file
BIN
docs/comm/images/index.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 165 KiB |
9
docs/comm/index.md
Normal file
9
docs/comm/index.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 商业版文档
|
||||
|
||||

|
||||
|
||||
## 支付方式配置
|
||||
|
||||
* [支付宝支付配置](./payments/alipay.md)
|
||||
* [微信支付配置](./payments/wxpay.md)
|
||||
* [彩虹易支付配置](./payments/yizhifu.md)
|
||||
21
docs/comm/payments/alipay.md
Normal file
21
docs/comm/payments/alipay.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# 支付宝配置
|
||||
|
||||
## 配置步骤
|
||||
|
||||
1. 创建应用,获取APPID
|
||||
* 登录支付宝开放平台,进入开发者中心,创建网页应用,获取应用的AppId(左上角复制)
|
||||
* 开发者中心:https://open.alipay.com/develop/manage
|
||||
|
||||
|
||||
2. 进入应用详情,选择开发设置,配置接口加签方式 (选择密钥类型)
|
||||
|
||||
* 参考文档:https://opendocs.alipay.com/common/02kdnc?pathHash=fb0c752a
|
||||
* 此步骤完成后,可以获取应用的私钥、支付宝公钥。
|
||||
* 注意:支付宝不会保存应用的私钥,你需要自己保管好私钥。
|
||||
|
||||
|
||||
3. 在Certd后台配置支付宝
|
||||
|
||||
* 进入“系统”->"设置"->“支付设置”
|
||||
* 启用支付宝,选择“支付宝配置”,点击添加
|
||||
* 填写支付宝AppId、应用私钥、支付宝公钥等信息即可。
|
||||
27
docs/comm/payments/wxpay.md
Normal file
27
docs/comm/payments/wxpay.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# 微信支付配置
|
||||
|
||||
## 配置步骤
|
||||
|
||||
1. 开通Native支付
|
||||
* 登录微信支付平台
|
||||
* 进入产品中心: https://pay.weixin.qq.com/index.php/extend/product/lists?tid=3
|
||||
* 选择开通Native支付
|
||||
|
||||
2. 申请证书
|
||||
|
||||
* 进入“账户中心”->“API安全”->“商户API证书”->“管理证书”
|
||||
* 根据指引生成证书
|
||||
* 得到私钥和公钥
|
||||
|
||||
|
||||
3. 填写APIv3密钥
|
||||
|
||||
* 进入“账户中心”->“API安全”->“解密回调”
|
||||
* 填写APIv3密钥
|
||||
* 参考文档 https://kf.qq.com/faq/180830E36vyQ180830AZFZvu.html
|
||||
|
||||
|
||||
4. 在Certd后台配置微信支付
|
||||
* 进入“系统”->"设置"->“支付设置”
|
||||
* 启用微信支付,选择“微信支付配置”,点击添加
|
||||
* 填写微信支付商户号、证书私钥、证书公钥、APIv3密钥即可。
|
||||
19
docs/comm/payments/yizhifu.md
Normal file
19
docs/comm/payments/yizhifu.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# 彩虹易支付配置
|
||||
|
||||
彩虹易支付是一款非常流行的php聚合支付系统。
|
||||
|
||||
## 配置步骤
|
||||
|
||||
1. 获取商户ID、商户密钥
|
||||
|
||||
* 登录彩虹易支付平台
|
||||
* 进入用户中心:https://xxxxxx.com/user/userinfo.php?mod=api
|
||||
* 点击API信息
|
||||
* 可以复制:接口地址、商户ID、商户密钥(key)
|
||||
* 点击查看文档,了解支持的签名类型,一般为MD5
|
||||
|
||||
2. 进入Certd后台配置彩虹易支付
|
||||
|
||||
* 进入“系统”->"设置"->“支付设置”
|
||||
* 启用彩虹易支付,选择“彩虹易支付配置”,点击添加
|
||||
* 填写接口地址、商户ID、商户密钥、签名方式等信息即可。
|
||||
@@ -3,6 +3,178 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.4](https://github.com/certd/certd/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复站点监控通知通过webhook发送失败的bug ([9be1ecc](https://github.com/certd/certd/commit/9be1ecc8aab3ea23dd0dc2dab3688f4edb90ef2c))
|
||||
* 修复dns.la域名申请失败的bug ([1de8eee](https://github.com/certd/certd/commit/1de8eee6ea8307f3c11626af75303d3cc104bb95))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 宝塔支持doker站点证书部署 ([589a373](https://github.com/certd/certd/commit/589a373142ef7f50d64d3aa767a90b1f4b64da93))
|
||||
* 保存调整后的列宽 ([873f2b6](https://github.com/certd/certd/commit/873f2b618b9d7320045baf69d6da83afe48a780f))
|
||||
* 创建证书流水线时,支持更多参数展开 ([36aa7f8](https://github.com/certd/certd/commit/36aa7f82b078a053a102331b3c6f132fb9d492f9))
|
||||
* 流水线页面可以鼠标按住左右拖动 ([d85a02f](https://github.com/certd/certd/commit/d85a02feeb3183c5abd6c1ea790d5923a32d7271))
|
||||
* 流水线增加上传证书快捷方式 ([425bba6](https://github.com/certd/certd/commit/425bba67c539b734e2a85a83a4f9ecc9b2434fb4))
|
||||
* 手动上传证书部署流水线 ([fbb66f3](https://github.com/certd/certd/commit/fbb66f3c4389489aa8a43b194d82bc8cf391607b))
|
||||
* 优化选择任务时手机版展示效果 ([d01004d](https://github.com/certd/certd/commit/d01004d53071a75ac91ee21cc96bde9369f77ff3))
|
||||
* 站点监控,手动测试也发通知 ([729b19c](https://github.com/certd/certd/commit/729b19c8da60d5efb5baef7cf8df0518e7f6b471))
|
||||
* 站点证书监控支持模糊查询 ([0069c0e](https://github.com/certd/certd/commit/0069c0e3992946a8dd6410f299d4fc974ef0e76b))
|
||||
* 支持飞书通知 ([b82e1dc](https://github.com/certd/certd/commit/b82e1dcd6217b09a7d7e21cd648bb31de320cadf))
|
||||
* 支持手动上传证书并部署 ([a9fffa5](https://github.com/certd/certd/commit/a9fffa5180c83da27b35886aa2e858a92a2c5f94))
|
||||
|
||||
## [1.31.3](https://github.com/certd/certd/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云fc获取不到列表的bug ([474b337](https://github.com/certd/certd/commit/474b3372d8ce98e6d45900bf8046bc0b3f220686))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 1panel支持 apikey方式授权 ([170b2af](https://github.com/certd/certd/commit/170b2afb0e3b125e4ed057f633fe895b5ac3ac22))
|
||||
* 套餐支持3天7天等选项 ([0d71a8e](https://github.com/certd/certd/commit/0d71a8ee501a0e5bb69decf07e8729026e9d85bf))
|
||||
* 证书仓库增加有效期显示 ([be87124](https://github.com/certd/certd/commit/be87124ada7a093f281ca29a45c86b4ea4644ead))
|
||||
* 支持部署到天翼云CDN ([82a72e0](https://github.com/certd/certd/commit/82a72e0b497efa043d342ad0e33c083a2de79a05))
|
||||
* 支持dns.la ([ee8af18](https://github.com/certd/certd/commit/ee8af18d0ac0af82544d6dda1e4b4c678b733041))
|
||||
* cf授权支持配置http代理 ([27386ea](https://github.com/certd/certd/commit/27386ea04d3c1a5aebe3cfdd7ac48185eaa76629))
|
||||
|
||||
## [1.31.2](https://github.com/certd/certd/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复cname记录查找bug ([95fb4e3](https://github.com/certd/certd/commit/95fb4e3e8be6ca13cc43b451f6141d62190ba453))
|
||||
|
||||
## [1.31.1](https://github.com/certd/certd/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 一些手机端适配优化 ([5b8d5dd](https://github.com/certd/certd/commit/5b8d5dd97536456a9d5d1384216eac1093b2dc3d))
|
||||
|
||||
# [1.31.0](https://github.com/certd/certd/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复CDN插件我爱云因更换接口导致部署失败的问题 ([5641c19](https://github.com/certd/certd/commit/5641c19502970f67af19709bddf8c781b1a25bdc))
|
||||
* 修复CDN插件我爱云因更换接口导致部署失败的问题 ([0110dfd](https://github.com/certd/certd/commit/0110dfdb70b12dfb0a7a067717f3773ed75aae7c))
|
||||
* 修复webhook headers value中带等号是解析错误的bug ([1fe3365](https://github.com/certd/certd/commit/1fe3365e10c464c4c60c82f424cf74fe35b883e0))
|
||||
* ProxmoxUploadCert 增加强制部署证书 ([441b15e](https://github.com/certd/certd/commit/441b15ed2fe5a143a5bd5508613b3816ddbff596))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 历史记录查看详情,可以切换到对应的历史记录日志上去 ([082802e](https://github.com/certd/certd/commit/082802e1197156837800f814728ee0f6b300b18c))
|
||||
* 流水线同一个阶段任务优化为并行执行 ([efa9c74](https://github.com/certd/certd/commit/efa9c748c5c07fc950af3db742ef9310f1ac9a4b))
|
||||
* 升级midwayjs版本 ([057b0b4](https://github.com/certd/certd/commit/057b0b4565e19bb93195633f767b2942e8e40e59))
|
||||
* 是否允许爬虫爬取增加ui设置选项 ([779db9d](https://github.com/certd/certd/commit/779db9da705d2dfef36fec21f52bd38af9fc5f2e))
|
||||
* 通知支持钉钉群聊机器人 ([fc8bef5](https://github.com/certd/certd/commit/fc8bef5aae522d75d408d8c3aa74543269da5398))
|
||||
* 易支付支持固定支付方式,适合没有收银台版本使用 ([81df96b](https://github.com/certd/certd/commit/81df96bf4542ce8d8ef4a428a4460dd554e4719a))
|
||||
* 支持易盾RCDN部署 ([065713c](https://github.com/certd/certd/commit/065713cdb6953d16df08585c316c1a7a8eaec437))
|
||||
|
||||
## [1.30.6](https://github.com/certd/certd/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 禁止爬虫爬取本网站 ([5164116](https://github.com/certd/certd/commit/5164116bde60dabac774cdf94f5317ff386e95ca))
|
||||
* 上传到阿里云证书名称后缀增加毫秒时间戳 ([9f0ee21](https://github.com/certd/certd/commit/9f0ee219d02907ffe128a5cf10173397d934ccd7))
|
||||
* 支持部署到阿里云FC3.0 ([bcaf54d](https://github.com/certd/certd/commit/bcaf54d4cb7bc469486aae6cdb127ae017eb3abb))
|
||||
* 支持新版本LeCDN ([44d43f4](https://github.com/certd/certd/commit/44d43f45cb9094619df7494c2a64a51ba77ad116))
|
||||
|
||||
## [1.30.5](https://github.com/certd/certd/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package root
|
||||
|
||||
## [1.30.4](https://github.com/certd/certd/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 适配最新版1panel密码编码方式 ([78044c0](https://github.com/certd/certd/commit/78044c062e20cdd04f08baef9fb6745bf25eddcf))
|
||||
|
||||
## [1.30.3](https://github.com/certd/certd/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复腾讯云CLB多域名同证书部署报错的bug ([c3a5542](https://github.com/certd/certd/commit/c3a55429357e78f4b78c9592d3e5897db2d4d549))
|
||||
* 修复新版本1panel密码需要加密,无法登录的问题 ([ada0b71](https://github.com/certd/certd/commit/ada0b7106e97e551783829e4e719f76793a7123d))
|
||||
|
||||
## [1.30.2](https://github.com/certd/certd/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 当前置任务被删除时进行校验 ([c89686a](https://github.com/certd/certd/commit/c89686a2fda251484930f0ae715417b618c21690))
|
||||
* 修复cloudflare删除解析记录报错的bug ([00c2da4](https://github.com/certd/certd/commit/00c2da444f84adb89f3f1226d03294d7c6e3e4f1))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 上传自定义证书 ([75a38d9](https://github.com/certd/certd/commit/75a38d95f305b4271d9106babe7cffc1c89ae8f3))
|
||||
|
||||
## [1.30.1](https://github.com/certd/certd/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复部署到阿里云ALB、NLB插件加载混乱的bug ([6ab83b6](https://github.com/certd/certd/commit/6ab83b662a2c5e715b9cb7eb1244de2ebb7f47b0))
|
||||
* 修复腾讯clb重复执行会报错的bug ([e95d29f](https://github.com/certd/certd/commit/e95d29f446d06eced315a3087fc9e105a30b20bd))
|
||||
* 修复tg消息内容中存在.和*就会发送失败的bug ([ae5dfc3](https://github.com/certd/certd/commit/ae5dfc3bee950267123ae2fbd1c11e7ce36626ea))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 创建流水线时,默认成功时也发送通知 ([52ae690](https://github.com/certd/certd/commit/52ae6902d203ca56e0312692b50c55cb6ddd3e39))
|
||||
* http方式校验,选择sftp时,支持修改文件访问权限比如777 ([15d6eaf](https://github.com/certd/certd/commit/15d6eaf5532ed25acd4f8d58c429353a2f44206c))
|
||||
|
||||
# [1.30.0](https://github.com/certd/certd/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复查看任务日志偶发性无法自动滚动底部的bug ([7e482f7](https://github.com/certd/certd/commit/7e482f798c0142bce1866f84676cb40210f9638a))
|
||||
* 修复namesilo ttl太短的问题 ([865f26d](https://github.com/certd/certd/commit/865f26d75c0d3dd4dc8b41448f8830068e45957c))
|
||||
|
||||
### Features
|
||||
|
||||
* 支持open api接口,根据域名获取证书 ([52a4fd3](https://github.com/certd/certd/commit/52a4fd33180e9b3f71b8dc9f7671d7cd8e448c3b))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书仓库 ([91e7f45](https://github.com/certd/certd/commit/91e7f45a1c5ea1e0ec0aa3236b80028f03a6d0aa))
|
||||
* 支持部署到阿里云ALB ([653940a](https://github.com/certd/certd/commit/653940a0ca64fc380178c1b0b58ae0af64dfaf07))
|
||||
* 支持部署到阿里云NLB、SLB ([c085bac](https://github.com/certd/certd/commit/c085bac5d877c4250a8a79e17eb8673b8e4fc89c))
|
||||
* 支持部署到腾讯云直播 ([417d37b](https://github.com/certd/certd/commit/417d37b199b79a42f790f9edab8f178eedf8fbf7))
|
||||
* 支持部署证书到proxmox ([d10795e](https://github.com/certd/certd/commit/d10795ecd97eb8cf2ffa46aabfdbfc6812636396))
|
||||
|
||||
## [1.29.5](https://github.com/certd/certd/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复复制到本机插件,pfx格式复制时报错的bug ([f57116d](https://github.com/certd/certd/commit/f57116d2bebf33e47ad93e0b39c4efe8e4aea25c))
|
||||
* 修复授权管理,点击了查看原文按钮后,无法修改值的bug ([85c99f7](https://github.com/certd/certd/commit/85c99f7f80761ac6efaf3255c03b933442db1686))
|
||||
|
||||
## [1.29.4](https://github.com/certd/certd/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复站点监控域名校验无法通过的bug ([1cb4a53](https://github.com/certd/certd/commit/1cb4a539cc523721ffd4b22d40d0e3d2d68cd915))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化腾讯云CLB插件,支持非sni情况,sni情况支持填写多个域名 ([635b042](https://github.com/certd/certd/commit/635b042690637bff85e97e07c7aac4b87a8a124b))
|
||||
|
||||
## [1.29.3](https://github.com/certd/certd/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复系统级授权无法查看密钥的bug ([8644348](https://github.com/certd/certd/commit/8644348fc41ae2e1672f946ca37e5d3a674e0218))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化站点证书检查页面,检查增加3次重试 ([e6dd7cd](https://github.com/certd/certd/commit/e6dd7cd54a3e23897031b5df6e0c3cdc0545d35a))
|
||||
* 优化acme sdk ([54db744](https://github.com/certd/certd/commit/54db74428259de64d12230c2ab7353ae11197bbc))
|
||||
* 支持http校验方式申请证书 ([405591c](https://github.com/certd/certd/commit/405591c5d08fa1a3b228ee3980199e7731cfec4a))
|
||||
* http校验方式,支持七牛云oss、阿里云oss、腾讯云cos ([3f74d4d](https://github.com/certd/certd/commit/3f74d4d9e5f5d0e629b44cff1895b3f7a8fbcafc))
|
||||
|
||||
## [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
|
||||
|
||||
@@ -28,7 +28,7 @@ packages:
|
||||
### 安装依赖和初始化:
|
||||
```shell
|
||||
# 安装pnpm,如果提示npm命令不存在,就需要先安装nodejs
|
||||
npm install -g pnpm@8.15.7 --registry=https://registry.npmmirror.com
|
||||
npm install -g pnpm--registry=https://registry.npmmirror.com
|
||||
|
||||
# 使用国内镜像源,如果有代理,就不需要
|
||||
pnpm config set registry https://registry.npmmirror.com
|
||||
@@ -36,19 +36,19 @@ pnpm config set registry https://registry.npmmirror.com
|
||||
pnpm install
|
||||
|
||||
# 初始化构建
|
||||
npm run init
|
||||
pnpm init
|
||||
```
|
||||
|
||||
### 启动 server:
|
||||
```shell
|
||||
cd packages/ui/certd-server
|
||||
npm run dev
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### 启动 client:
|
||||
```shell
|
||||
cd packages/ui/certd-client
|
||||
npm run dev
|
||||
pnpm dev
|
||||
|
||||
# 会自动打开浏览器,确认正常运行
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
* 全自动申请证书(支持所有注册商注册的域名)
|
||||
* 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等,目前已支持30+部署插件)
|
||||
* 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等,目前已支持60+部署插件)
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上
|
||||
* 邮件通知
|
||||
* 私有化部署,保障数据安全
|
||||
|
||||
@@ -19,7 +19,8 @@ https://1panel.cn/docs/installation/online_installation/
|
||||
3. 点击确定,启动容器
|
||||

|
||||
|
||||
> 默认数据保存在`/data/certd`目录下,可以手动备份
|
||||
> 默认使用sqlite数据库,数据保存在`/data/certd`目录下,您可以手动备份该目录
|
||||
> certd还支持`mysql`和`postgresql`数据库,[点我了解如何切换其他数据库](../database)
|
||||
|
||||
3. 访问测试
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
点击确定,等待启动完成
|
||||

|
||||
|
||||
> certd默认使用sqlite数据库,另外支持`mysql`和`postgresql`数据库,[点我了解如何切换其他数据库](../database)
|
||||
|
||||
|
||||
## 二、访问应用
|
||||
|
||||
http://ip:7001
|
||||
@@ -59,6 +62,7 @@ admin/123456
|
||||
数据默认保存在`/data/certd`目录下,可以手动备份
|
||||
|
||||
|
||||
|
||||
### 4.3 自动备份
|
||||
|
||||
> 建议配置一条 [数据库备份流水线](../../use/backup/),自动备份
|
||||
|
||||
73
docs/guide/install/database.md
Normal file
73
docs/guide/install/database.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# 切换数据库
|
||||
|
||||
certd支持如下几种数据库:
|
||||
1. sqlite3 (默认)
|
||||
2. mysql
|
||||
3. postgresql
|
||||
|
||||
您可以按如下两种方式切换数据库
|
||||
|
||||
|
||||
## 一、全新安装
|
||||
::: tip
|
||||
以下按照`docker-compose`安装方式介绍如何使用mysql或postgresql数据库
|
||||
如果您使用其他方式部署,请自行修改对应的环境变量即可。
|
||||
:::
|
||||
|
||||
### 1.1、使用mysql数据库
|
||||
|
||||
1. 安装mysql,创建数据库 `(注意:charset=utf8mb4, collation=utf8mb4_bin)`
|
||||
2. 下载最新的docker-compose.yaml
|
||||
3. 修改环境变量配置
|
||||
```yaml
|
||||
services:
|
||||
certd:
|
||||
environment:
|
||||
# 使用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 # 数据库名
|
||||
|
||||
```
|
||||
4. 启动certd
|
||||
```shell
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
|
||||
### 1.2、使用Postgresql数据库
|
||||
|
||||
1. 安装postgresql,创建数据库
|
||||
2. 下载最新的docker-compose.yaml
|
||||
3. 修改环境变量配置
|
||||
```yaml
|
||||
services:
|
||||
certd:
|
||||
environment:
|
||||
# 使用postgresql数据库,需要提前创建数据库
|
||||
- certd_flyway_scriptDir=./db/migration-pg # 升级脚本目录 【照抄】
|
||||
- certd_typeorm_dataSource_default_type=postgres # 数据库类型 【照抄】
|
||||
- certd_typeorm_dataSource_default_host=localhost # 数据库地址
|
||||
- certd_typeorm_dataSource_default_port=5433 # 数据库端口
|
||||
- certd_typeorm_dataSource_default_username=postgres # 用户名
|
||||
- certd_typeorm_dataSource_default_password=yourpasswd # 密码
|
||||
- certd_typeorm_dataSource_default_database=certd # 数据库名
|
||||
|
||||
```
|
||||
4. 启动certd
|
||||
```shell
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## 二、从旧版的sqlite切换数据库
|
||||
|
||||
1. 先将`旧certd`升级到最新版 (`建议:备份sqlite数据库` )
|
||||
2. 按照上面全新安装方式部署一套`新的certd` (`注意:新旧版本的certd要一致`)
|
||||
3. 使用数据库工具将数据从sqlite导入到mysql或postgresql (`注意:flyway_history数据表不要导入`)
|
||||
4. 重启新certd
|
||||
5. 确认没有问题之后,删除旧版certd
|
||||
|
||||
@@ -42,6 +42,8 @@ docker compose up -d
|
||||
> 如果提示 没有docker compose命令,请安装docker-compose
|
||||
> https://docs.docker.com/compose/install/linux/
|
||||
|
||||
> certd默认使用sqlite数据库,另外还支持`mysql`和`postgresql`数据库,[点我了解如何切换其他数据库](../database)
|
||||
|
||||
|
||||
### 3. 访问测试
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 源码部署
|
||||
不推荐
|
||||
如果没有`git`和`nodejs`基础,则不推荐
|
||||
## 一、源码安装
|
||||
|
||||
### 环境要求
|
||||
@@ -7,7 +7,7 @@
|
||||
### 源码启动
|
||||
```shell
|
||||
# 克隆代码
|
||||
git clone https://github.com/certd/certd
|
||||
git clone https://github.com/certd/certd --depth=1
|
||||
# git checkout v1.x.x # 当v2主干分支代码无法正常启动时,可以尝试此命令,1.x.x换成最新版本号
|
||||
cd certd
|
||||
# 启动服务
|
||||
|
||||
BIN
docs/guide/open/images/1.png
Normal file
BIN
docs/guide/open/images/1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
21
docs/guide/open/index.md
Normal file
21
docs/guide/open/index.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# 开放接口
|
||||
被动方式对第三方提供证书, 支持根据域名或证书id获取证书。
|
||||
|
||||
## 获取keyId和KeySecret
|
||||
|
||||

|
||||
|
||||
## 接口文档
|
||||
|
||||
https://apifox.com/apidoc/shared-2e76f8c4-7c58-413b-a32d-a1316529af44/254949529e0
|
||||
|
||||
## Token生成方法
|
||||
|
||||
header中传入x-certd-token即可调用开放接口
|
||||
1、首先从OpenKey页面生成keyId,keySecret;
|
||||
2、准备一个content( json字符串): content={"keyId":keyId, t:时间戳秒数, encrypt:false, signType:"md5"} `// encrypt返回结果是否加密`
|
||||
3、将content加上keySecret进行签名: sign = md5(content + keySecret)
|
||||
4、然后将content和sign分别base64后用.号连接: x-certd-token = base64(content) +"."+base64(sign)
|
||||
|
||||
## SDK
|
||||
待开发
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
## 2. 使用示例
|
||||
```js
|
||||
|
||||
// 如果需要引用第三方库,必须使用import语法
|
||||
// const thirdSdk = await import("third-sdk-name")
|
||||
|
||||
const certPem = ctx.self.cert.crt
|
||||
const certKey = ctx.self.cert.key
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 51 KiB |
@@ -24,7 +24,7 @@ features:
|
||||
- title: 全自动申请证书
|
||||
details: 支持所有注册商注册的域名
|
||||
- title: 全自动部署证书
|
||||
details: 支持部署到主机、阿里云、腾讯云等,目前已支持30+部署插件
|
||||
details: 支持部署到主机、阿里云、腾讯云等,目前已支持60+部署插件
|
||||
- title: 多域名、泛域名打到一个证书上
|
||||
details: 支持通配符域名/泛域名,支持多个域名打到一个证书上
|
||||
- title: 多证书格式支持
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.29.2"
|
||||
"version": "1.31.5"
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"@lerna-lite/run": "^3.9.3",
|
||||
"@lerna-lite/version": "^3.9.3",
|
||||
"medium-zoom": "^1.1.0",
|
||||
"vitepress": "^1.4.1",
|
||||
"vitepress": "^2.0.0-alpha.4",
|
||||
"vitepress-plugin-lightbox": "^1.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -41,5 +41,8 @@
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/**"
|
||||
]
|
||||
],
|
||||
"pnpm": {
|
||||
"neverBuiltDependencies": []
|
||||
}
|
||||
}
|
||||
|
||||
7
packages/core/acme-client/.prettierrc
Normal file
7
packages/core/acme-client/.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"printWidth": 220,
|
||||
"bracketSpacing": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
@@ -3,6 +3,74 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/publishlab/node-acme-client/compare/v1.31.4...v1.31.5) (2025-03-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.31.4](https://github.com/publishlab/node-acme-client/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.31.3](https://github.com/publishlab/node-acme-client/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.31.2](https://github.com/publishlab/node-acme-client/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.31.1](https://github.com/publishlab/node-acme-client/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
# [1.31.0](https://github.com/publishlab/node-acme-client/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.30.6](https://github.com/publishlab/node-acme-client/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.30.5](https://github.com/publishlab/node-acme-client/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.30.4](https://github.com/publishlab/node-acme-client/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.30.3](https://github.com/publishlab/node-acme-client/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.30.2](https://github.com/publishlab/node-acme-client/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.30.1](https://github.com/publishlab/node-acme-client/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
# [1.30.0](https://github.com/publishlab/node-acme-client/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复查看任务日志偶发性无法自动滚动底部的bug ([7e482f7](https://github.com/publishlab/node-acme-client/commit/7e482f798c0142bce1866f84676cb40210f9638a))
|
||||
|
||||
## [1.29.5](https://github.com/publishlab/node-acme-client/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.29.4](https://github.com/publishlab/node-acme-client/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.29.3](https://github.com/publishlab/node-acme-client/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化acme sdk ([54db744](https://github.com/publishlab/node-acme-client/commit/54db74428259de64d12230c2ab7353ae11197bbc))
|
||||
|
||||
## [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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.29.2",
|
||||
"version": "1.31.5",
|
||||
"type": "module",
|
||||
"module": "scr/index.js",
|
||||
"main": "src/index.js",
|
||||
@@ -18,7 +18,7 @@
|
||||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.29.2",
|
||||
"@certd/basic": "^1.31.5",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
@@ -30,6 +30,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.14.10",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"chai": "^4.4.1",
|
||||
"chai-as-promised": "^7.1.2",
|
||||
"eslint": "^8.57.0",
|
||||
@@ -65,5 +67,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||
"gitHead": "b649617e0457b4e177bacb173dc1aa67eb84d7cf"
|
||||
}
|
||||
|
||||
@@ -99,31 +99,14 @@ export default async (client, userOpts) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const keyAuthorizationGetter = async (challenge) => {
|
||||
return await client.getChallengeKeyAuthorization(challenge);
|
||||
}
|
||||
|
||||
try {
|
||||
/* Select challenge based on priority */
|
||||
const challenge = authz.challenges.sort((a, b) => {
|
||||
const aidx = opts.challengePriority.indexOf(a.type);
|
||||
const bidx = opts.challengePriority.indexOf(b.type);
|
||||
|
||||
if (aidx === -1) return 1;
|
||||
if (bidx === -1) return -1;
|
||||
return aidx - bidx;
|
||||
}).slice(0, 1)[0];
|
||||
|
||||
if (!challenge) {
|
||||
throw new Error(`Unable to select challenge for ${d}, no challenge found`);
|
||||
}
|
||||
|
||||
log(`[auto] [${d}] Found ${authz.challenges.length} challenges, selected type: ${challenge.type}`);
|
||||
|
||||
/* Trigger challengeCreateFn() */
|
||||
log(`[auto] [${d}] Trigger challengeCreateFn()`);
|
||||
const keyAuthorization = await client.getChallengeKeyAuthorization(challenge);
|
||||
|
||||
try {
|
||||
const { recordReq, recordRes, dnsProvider } = await opts.challengeCreateFn(authz, challenge, keyAuthorization);
|
||||
log(`[auto] [${d}] challengeCreateFn success`);
|
||||
log(`[auto] [${d}] add challengeRemoveFn()`);
|
||||
const { recordReq, recordRes, dnsProvider,challenge ,keyAuthorization} = await opts.challengeCreateFn(authz, keyAuthorizationGetter);
|
||||
clearTasks.push(async () => {
|
||||
/* Trigger challengeRemoveFn(), suppress errors */
|
||||
log(`[auto] [${d}] Trigger challengeRemoveFn()`);
|
||||
@@ -141,7 +124,7 @@ export default async (client, userOpts) => {
|
||||
await wait(60 * 1000);
|
||||
}
|
||||
else {
|
||||
log(`[auto] [${d}] Running challenge verification`);
|
||||
log(`[auto] [${d}] Running challenge verification, type = ${challenge.type}`);
|
||||
try {
|
||||
await client.verifyChallenge(authz, challenge);
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ instance.interceptors.response.use(null, async (error) => {
|
||||
|
||||
/* Wait and retry the request */
|
||||
await new Promise((resolve) => { setTimeout(resolve, (retryAfter * 1000)); });
|
||||
log(`Retrying request to URL ${config.url}`);
|
||||
return instance(config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,3 +5,5 @@ export class CancelError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
6
packages/core/acme-client/types/index.d.ts
vendored
6
packages/core/acme-client/types/index.d.ts
vendored
@@ -4,6 +4,8 @@
|
||||
|
||||
import { AxiosInstance } from 'axios';
|
||||
import * as rfc8555 from './rfc8555';
|
||||
import {CancelError} from '../src/error.js'
|
||||
export * from '../src/error.js'
|
||||
|
||||
export type PrivateKeyBuffer = Buffer;
|
||||
export type PublicKeyBuffer = Buffer;
|
||||
@@ -56,7 +58,7 @@ export interface ClientExternalAccountBindingOptions {
|
||||
|
||||
export interface ClientAutoOptions {
|
||||
csr: CsrBuffer | CsrString;
|
||||
challengeCreateFn: (authz: Authorization, challenge: rfc8555.Challenge, keyAuthorization: string) => Promise<{recordReq:any,recordRes:any,dnsProvider:any}>;
|
||||
challengeCreateFn: (authz: Authorization, keyAuthorization: (challenge:rfc8555.Challenge)=>Promise<string>) => Promise<{recordReq?:any,recordRes?:any,dnsProvider?:any,challenge: rfc8555.Challenge,keyAuthorization:string}>;
|
||||
challengeRemoveFn: (authz: Authorization, challenge: rfc8555.Challenge, keyAuthorization: string,recordReq:any, recordRes:any,dnsProvider:any) => Promise<any>;
|
||||
email?: string;
|
||||
termsOfServiceAgreed?: boolean;
|
||||
@@ -202,4 +204,4 @@ export function setLogger(fn: (message: any, ...args: any[]) => void): void;
|
||||
|
||||
export function walkTxtRecord(record: any): Promise<string[]>;
|
||||
|
||||
export const CancelError: Error;
|
||||
export const CancelError: typeof CancelError;
|
||||
@@ -16,7 +16,7 @@
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// "no-unused-expressions": "off",
|
||||
"max-len": [0, 160, 2, { "ignoreUrls": true }]
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
|
||||
7
packages/core/basic/.prettierrc
Normal file
7
packages/core/basic/.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"printWidth": 220,
|
||||
"bracketSpacing": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
@@ -3,6 +3,77 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/certd/certd/compare/v1.31.4...v1.31.5) (2025-03-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.31.4](https://github.com/certd/certd/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.31.3](https://github.com/certd/certd/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持部署到天翼云CDN ([82a72e0](https://github.com/certd/certd/commit/82a72e0b497efa043d342ad0e33c083a2de79a05))
|
||||
|
||||
## [1.31.2](https://github.com/certd/certd/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.31.1](https://github.com/certd/certd/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
# [1.31.0](https://github.com/certd/certd/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 流水线同一个阶段任务优化为并行执行 ([efa9c74](https://github.com/certd/certd/commit/efa9c748c5c07fc950af3db742ef9310f1ac9a4b))
|
||||
* 支持易盾RCDN部署 ([065713c](https://github.com/certd/certd/commit/065713cdb6953d16df08585c316c1a7a8eaec437))
|
||||
|
||||
## [1.30.6](https://github.com/certd/certd/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持新版本LeCDN ([44d43f4](https://github.com/certd/certd/commit/44d43f45cb9094619df7494c2a64a51ba77ad116))
|
||||
|
||||
## [1.30.5](https://github.com/certd/certd/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.30.4](https://github.com/certd/certd/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.30.3](https://github.com/certd/certd/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.30.2](https://github.com/certd/certd/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.30.1](https://github.com/certd/certd/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
# [1.30.0](https://github.com/certd/certd/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.29.5](https://github.com/certd/certd/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.29.4](https://github.com/certd/certd/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.29.3](https://github.com/certd/certd/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [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 +1 @@
|
||||
01:51
|
||||
15:01
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.29.2",
|
||||
"version": "1.31.5",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -33,8 +33,8 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/node-forge": "^1.3.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.7",
|
||||
"@typescript-eslint/parser": "^5.59.7",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"chai": "4.3.10",
|
||||
"eslint": "^8.41.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
@@ -44,5 +44,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||
"gitHead": "b649617e0457b4e177bacb173dc1aa67eb84d7cf"
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ import { nanoid } from 'nanoid';
|
||||
import * as id from './util.id.js';
|
||||
import { locker } from './util.lock.js';
|
||||
import { mitter } from './util.mitter.js';
|
||||
|
||||
import * as request from './util.request.js';
|
||||
export const utils = {
|
||||
sleep,
|
||||
http,
|
||||
@@ -52,4 +54,5 @@ export const utils = {
|
||||
locker,
|
||||
mitter,
|
||||
amount: amountUtils,
|
||||
request,
|
||||
};
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
import crypto from 'crypto';
|
||||
import crypto, { BinaryToTextEncoding } from 'crypto';
|
||||
|
||||
function md5(data: string) {
|
||||
return crypto.createHash('md5').update(data).digest('hex');
|
||||
function md5(data: string, digest: BinaryToTextEncoding = 'hex') {
|
||||
return crypto.createHash('md5').update(data).digest(digest);
|
||||
}
|
||||
function sha256(data: string) {
|
||||
return crypto.createHash('sha256').update(data).digest('hex');
|
||||
function sha256(data: string, digest: BinaryToTextEncoding = 'hex') {
|
||||
return crypto.createHash('sha256').update(data).digest(digest);
|
||||
}
|
||||
|
||||
function hmacSha256(data: string, digest: BinaryToTextEncoding = 'base64') {
|
||||
return crypto.createHmac('sha256', data).update(Buffer.alloc(0)).digest(digest);
|
||||
}
|
||||
|
||||
function base64(data: string) {
|
||||
return Buffer.from(data).toString('base64');
|
||||
}
|
||||
export const hashUtils = {
|
||||
md5,
|
||||
sha256,
|
||||
base64,
|
||||
hmacSha256,
|
||||
};
|
||||
|
||||
@@ -310,3 +310,14 @@ export async function download(req: { http: HttpClient; config: HttpRequestConfi
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function getCookie(response: any, name: string) {
|
||||
const cookies = response.headers['set-cookie'];
|
||||
//根据name 返回对应的cookie
|
||||
const found = cookies.find((cookie: any) => cookie.includes(name));
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
const cookie = found.split(';')[0];
|
||||
return cookie.substring(cookie.indexOf('=') + 1);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// "no-unused-expressions": "off",
|
||||
"max-len": [0, 160, 2, { "ignoreUrls": true }]
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
{
|
||||
"printWidth": 160
|
||||
"printWidth": 220,
|
||||
"bracketSpacing": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
@@ -3,6 +3,88 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/certd/certd/compare/v1.31.4...v1.31.5) (2025-03-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.31.4](https://github.com/certd/certd/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复站点监控通知通过webhook发送失败的bug ([9be1ecc](https://github.com/certd/certd/commit/9be1ecc8aab3ea23dd0dc2dab3688f4edb90ef2c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 流水线增加上传证书快捷方式 ([425bba6](https://github.com/certd/certd/commit/425bba67c539b734e2a85a83a4f9ecc9b2434fb4))
|
||||
* 支持飞书通知 ([b82e1dc](https://github.com/certd/certd/commit/b82e1dcd6217b09a7d7e21cd648bb31de320cadf))
|
||||
* 支持手动上传证书并部署 ([a9fffa5](https://github.com/certd/certd/commit/a9fffa5180c83da27b35886aa2e858a92a2c5f94))
|
||||
|
||||
## [1.31.3](https://github.com/certd/certd/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.31.2](https://github.com/certd/certd/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.31.1](https://github.com/certd/certd/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
# [1.31.0](https://github.com/certd/certd/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 流水线同一个阶段任务优化为并行执行 ([efa9c74](https://github.com/certd/certd/commit/efa9c748c5c07fc950af3db742ef9310f1ac9a4b))
|
||||
|
||||
## [1.30.6](https://github.com/certd/certd/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 上传到阿里云证书名称后缀增加毫秒时间戳 ([9f0ee21](https://github.com/certd/certd/commit/9f0ee219d02907ffe128a5cf10173397d934ccd7))
|
||||
|
||||
## [1.30.5](https://github.com/certd/certd/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.30.4](https://github.com/certd/certd/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.30.3](https://github.com/certd/certd/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.30.2](https://github.com/certd/certd/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.30.1](https://github.com/certd/certd/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复tg消息内容中存在.和*就会发送失败的bug ([ae5dfc3](https://github.com/certd/certd/commit/ae5dfc3bee950267123ae2fbd1c11e7ce36626ea))
|
||||
|
||||
# [1.30.0](https://github.com/certd/certd/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书仓库 ([91e7f45](https://github.com/certd/certd/commit/91e7f45a1c5ea1e0ec0aa3236b80028f03a6d0aa))
|
||||
|
||||
## [1.29.5](https://github.com/certd/certd/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.29.4](https://github.com/certd/certd/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.29.3](https://github.com/certd/certd/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持http校验方式申请证书 ([405591c](https://github.com/certd/certd/commit/405591c5d08fa1a3b228ee3980199e7731cfec4a))
|
||||
|
||||
## [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,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.29.2",
|
||||
"version": "1.31.5",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -16,8 +16,8 @@
|
||||
"test": "mocha --loader=ts-node/esm"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.29.2",
|
||||
"@certd/plus-core": "^1.29.2",
|
||||
"@certd/basic": "^1.31.5",
|
||||
"@certd/plus-core": "^1.31.5",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
@@ -31,8 +31,8 @@
|
||||
"@types/chai": "^4.3.10",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.7",
|
||||
"@typescript-eslint/parser": "^5.59.7",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"chai": "4.3.10",
|
||||
"eslint": "^8.41.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
@@ -43,5 +43,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||
"gitHead": "b649617e0457b4e177bacb173dc1aa67eb84d7cf"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import type { ResultError } from "../dt/index.js";
|
||||
|
||||
export class CancelError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
export class RunnableError extends Error {
|
||||
errors: ResultError[];
|
||||
constructor(message: string, errors: ResultError[]) {
|
||||
super(message);
|
||||
this.errors = errors;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ConcurrencyStrategy, NotificationWhen, Pipeline, ResultType, Runnable, RunStrategy, Stage, Step, Task } from "../dt/index.js";
|
||||
import { ConcurrencyStrategy, NotificationWhen, Pipeline, ResultType, Runnable, RunStrategy, Stage, Step, Task, ResultError } from "../dt/index.js";
|
||||
import { RunHistory, RunnableCollection } from "./run-history.js";
|
||||
import { AbstractTaskPlugin, PluginDefine, pluginRegistry, TaskInstanceContext, UserInfo } from "../plugin/index.js";
|
||||
import { ContextFactory, IContext } from "./context.js";
|
||||
@@ -7,10 +7,12 @@ import { createAxiosService, hashUtils, HttpRequestConfig, ILogger, logger, util
|
||||
import { IAccessService } from "../access/index.js";
|
||||
import { RegistryItem } from "../registry/index.js";
|
||||
import { Decorator } from "../decorator/index.js";
|
||||
import { ICnameProxyService, IEmailService, IPluginConfigService, IUrlService } from "../service/index.js";
|
||||
import { ICnameProxyService, IEmailService, IPluginConfigService, IServiceGetter, IUrlService } from "../service/index.js";
|
||||
import { FileStore } from "./file-store.js";
|
||||
import { cloneDeep, forEach, merge } from "lodash-es";
|
||||
import { INotificationService } from "../notification/index.js";
|
||||
import { taskEmitterCreate } from "../service/emit.js";
|
||||
import { RunnableError } from "./exceptions.js";
|
||||
|
||||
export type SysInfo = {
|
||||
//系统标题
|
||||
@@ -31,6 +33,7 @@ export type ExecutorOptions = {
|
||||
user: UserInfo;
|
||||
baseURL?: string;
|
||||
sysInfo?: SysInfo;
|
||||
serviceGetter: IServiceGetter;
|
||||
};
|
||||
|
||||
export class Executor {
|
||||
@@ -109,7 +112,13 @@ export class Executor {
|
||||
} finally {
|
||||
clearInterval(intervalFlushLogId);
|
||||
await this.onChanged(this.runtime);
|
||||
await this.pipelineContext.setObj("lastRuntime", this.runtime);
|
||||
//保存之前移除logs
|
||||
const lastRuntime: any = {
|
||||
...this.runtime,
|
||||
};
|
||||
delete lastRuntime.logs;
|
||||
delete lastRuntime._loggers;
|
||||
await this.pipelineContext.setObj("lastRuntime", lastRuntime);
|
||||
this.logger.info(`pipeline.${this.pipeline.id} end`);
|
||||
}
|
||||
}
|
||||
@@ -185,6 +194,8 @@ export class Executor {
|
||||
}
|
||||
|
||||
let resList: ResultType[] = [];
|
||||
const errorList: ResultError[] = [];
|
||||
let errorMessage = "";
|
||||
if (stage.concurrency === ConcurrencyStrategy.Parallel) {
|
||||
//并行
|
||||
const pList = [];
|
||||
@@ -193,10 +204,25 @@ export class Executor {
|
||||
}
|
||||
resList = await Promise.all(pList);
|
||||
} else {
|
||||
//串行
|
||||
//串行且报错继续
|
||||
for (let i = 0; i < runnerList.length; i++) {
|
||||
const runner = runnerList[i];
|
||||
resList[i] = await runner();
|
||||
try {
|
||||
resList[i] = await runner();
|
||||
} catch (e: any) {
|
||||
const t = stage.tasks[i];
|
||||
this.logger.error(`任务 ${t.title} 执行异常:`, e.message);
|
||||
resList[i] = ResultType.error;
|
||||
errorList.push({
|
||||
e,
|
||||
returnType: ResultType.error,
|
||||
runnable: t,
|
||||
});
|
||||
errorMessage += `任务${t.title}执行失败,错误详情:${e.message};`;
|
||||
}
|
||||
}
|
||||
if (errorList.length > 0) {
|
||||
throw new RunnableError(errorMessage, errorList);
|
||||
}
|
||||
}
|
||||
return this.compositionResultType(resList);
|
||||
@@ -336,6 +362,11 @@ export class Executor {
|
||||
signal: this.abort.signal,
|
||||
utils,
|
||||
user: this.options.user,
|
||||
emitter: taskEmitterCreate({
|
||||
step,
|
||||
pipeline: this.pipeline,
|
||||
}),
|
||||
serviceGetter: this.options.serviceGetter,
|
||||
};
|
||||
instance.setCtx(taskCtx);
|
||||
|
||||
@@ -391,7 +422,16 @@ export class Executor {
|
||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`;
|
||||
} else if (when === "error") {
|
||||
subject = `执行失败,${this.pipeline.title}【${this.pipeline.id}】`;
|
||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}\n\n${this.currentStatusMap?.currentStep?.title} 执行失败\n\n错误详情:${error.message}`;
|
||||
|
||||
if (error instanceof RunnableError) {
|
||||
const runnableError = error as RunnableError;
|
||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}\n\n`;
|
||||
for (const re of runnableError.errors) {
|
||||
content += ` - ${re.runnable.title} 执行失败\n 错误详情:${re.e.message}\n\n`;
|
||||
}
|
||||
} else {
|
||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}\n\n${this.currentStatusMap?.currentStep?.title} 执行失败\n\n错误详情:${error.message}`;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -424,7 +464,7 @@ export class Executor {
|
||||
content,
|
||||
userId: this.pipeline.userId,
|
||||
pipeline: this.pipeline,
|
||||
result: this.lastRuntime.pipeline.status,
|
||||
result: this.lastRuntime?.pipeline?.status,
|
||||
pipelineId: this.pipeline.id,
|
||||
historyId: this.runtime.id,
|
||||
errorMessage,
|
||||
|
||||
@@ -11,11 +11,13 @@ function attachProperty(target: any, propertyKey: string | symbol) {
|
||||
}
|
||||
|
||||
function getClassProperties(target: any) {
|
||||
//获取父类
|
||||
//获取父类, 向上追溯三层
|
||||
const parent = Object.getPrototypeOf(target);
|
||||
const pParent = Object.getPrototypeOf(parent);
|
||||
const pParentMap = propertyMap[pParent] || {};
|
||||
const parentMap = propertyMap[parent] || {};
|
||||
const current = propertyMap[target] || {};
|
||||
return _.merge({}, parentMap, current);
|
||||
return _.merge({}, pParentMap, parentMap, current);
|
||||
}
|
||||
|
||||
function target(target: any, propertyKey?: string | symbol) {
|
||||
|
||||
@@ -107,6 +107,12 @@ export type Log = {
|
||||
text: string;
|
||||
};
|
||||
|
||||
export type ResultError = {
|
||||
e: any;
|
||||
returnType: ResultType;
|
||||
runnable: Runnable;
|
||||
};
|
||||
|
||||
export enum ResultType {
|
||||
start = "start",
|
||||
success = "success",
|
||||
|
||||
@@ -119,13 +119,15 @@ export abstract class BaseNotification implements INotification {
|
||||
}
|
||||
|
||||
async onTestRequest() {
|
||||
await this.doSend({
|
||||
return await this.doSend({
|
||||
userId: 0,
|
||||
title: "【Certd】测试通知,标题长度测试、测试、测试",
|
||||
content: "测试通知",
|
||||
title: "【Certd】测试通知【*.foo.com】,标题长度测试、测试、测试",
|
||||
content: `测试通知,*.foo.com
|
||||
换行测试
|
||||
`,
|
||||
pipeline: {
|
||||
id: 1,
|
||||
title: "测试流水线",
|
||||
title: "证书申请成功【测试流水线】",
|
||||
} as any,
|
||||
pipelineId: 1,
|
||||
historyId: 1,
|
||||
|
||||
@@ -2,14 +2,15 @@ import { Registrable } from "../registry/index.js";
|
||||
import { FileItem, FormItemProps, Pipeline, Runnable, Step } from "../dt/index.js";
|
||||
import { FileStore } from "../core/file-store.js";
|
||||
import { IAccessService } from "../access/index.js";
|
||||
import { ICnameProxyService, IEmailService, IUrlService } from "../service/index.js";
|
||||
import { ICnameProxyService, IEmailService, IServiceGetter, IUrlService } from "../service/index.js";
|
||||
import { CancelError, IContext, RunHistory, RunnableCollection } from "../core/index.js";
|
||||
import { HttpRequestConfig, ILogger, logger, utils } from "@certd/basic";
|
||||
import { HttpClient } from "@certd/basic";
|
||||
import dayjs from "dayjs";
|
||||
import { IPluginConfigService } from "../service/config";
|
||||
import { IPluginConfigService } from "../service/config.js";
|
||||
import { upperFirst } from "lodash-es";
|
||||
import { INotificationService } from "../notification";
|
||||
import { INotificationService } from "../notification/index.js";
|
||||
import { TaskEmitter } from "../service/emit.js";
|
||||
|
||||
export type PluginRequestHandleReq<T = any> = {
|
||||
typeName: string;
|
||||
@@ -54,6 +55,14 @@ export type PluginDefine = Registrable & {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
shortcut?: {
|
||||
[key: string]: {
|
||||
title: string;
|
||||
icon: string;
|
||||
action: string;
|
||||
form: any;
|
||||
};
|
||||
};
|
||||
needPlus?: boolean;
|
||||
};
|
||||
|
||||
@@ -111,6 +120,11 @@ export type TaskInstanceContext = {
|
||||
utils: typeof utils;
|
||||
//用户信息
|
||||
user: UserInfo;
|
||||
|
||||
emitter: TaskEmitter;
|
||||
|
||||
//service 容器
|
||||
serviceGetter?: IServiceGetter;
|
||||
};
|
||||
|
||||
export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||
@@ -190,7 +204,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||
if (name == null) {
|
||||
name = "certd";
|
||||
}
|
||||
return name + "_" + dayjs().format("YYYYMMDDHHmmss");
|
||||
return name + "_" + dayjs().format("YYYYMMDDHHmmssSSS");
|
||||
}
|
||||
|
||||
async onRequest(req: PluginRequestHandleReq<any>) {
|
||||
@@ -218,7 +232,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||
|
||||
getStepFromPipeline(stepId: string) {
|
||||
let found: any = null;
|
||||
RunnableCollection.each(this.ctx.pipeline.stages, (step) => {
|
||||
RunnableCollection.each(this.ctx.pipeline.stages, step => {
|
||||
if (step.id === stepId) {
|
||||
found = step;
|
||||
return;
|
||||
|
||||
@@ -18,6 +18,7 @@ export type CnameRecord = {
|
||||
status: string;
|
||||
commonDnsProvider?: any;
|
||||
};
|
||||
|
||||
export type ICnameProxyService = {
|
||||
getByDomain: (domain: string) => Promise<CnameRecord>;
|
||||
};
|
||||
|
||||
68
packages/core/pipeline/src/service/emit.ts
Normal file
68
packages/core/pipeline/src/service/emit.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { logger } from "@certd/basic";
|
||||
import { Pipeline, Runnable } from "../dt";
|
||||
|
||||
export type PipelineEventListener = (...args: any[]) => Promise<void>;
|
||||
export type PipelineEvent<T> = {
|
||||
pipeline: Pipeline;
|
||||
step: Runnable;
|
||||
event: T;
|
||||
};
|
||||
export class PipelineEmitter {
|
||||
events: Record<string, PipelineEventListener[]>;
|
||||
constructor() {
|
||||
this.events = {};
|
||||
}
|
||||
on(event: string, listener: PipelineEventListener) {
|
||||
if (!this.events[event]) {
|
||||
this.events[event] = [];
|
||||
}
|
||||
this.events[event].push(listener);
|
||||
}
|
||||
async emit<T>(name: string, event: PipelineEvent<T>) {
|
||||
const listeners = this.events[name];
|
||||
if (listeners) {
|
||||
for (const listener of listeners) {
|
||||
try {
|
||||
await listener(event);
|
||||
} catch (e) {
|
||||
logger.error(`事件<${name}>监听器执行失败:`, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
off(event: string, listener: PipelineEventListener) {
|
||||
if (this.events[event]) {
|
||||
this.events[event] = this.events[event].filter((l) => l !== listener);
|
||||
}
|
||||
}
|
||||
once(event: string, listener: PipelineEventListener) {
|
||||
const onceListener = async (...args: any[]) => {
|
||||
this.off(event, onceListener);
|
||||
await listener(...args);
|
||||
};
|
||||
this.on(event, onceListener);
|
||||
}
|
||||
}
|
||||
|
||||
export const pipelineEmitter = new PipelineEmitter();
|
||||
|
||||
export type TaskEmitterCreateReq = {
|
||||
step: Runnable;
|
||||
pipeline: Pipeline;
|
||||
};
|
||||
|
||||
export type TaskEmitter = {
|
||||
emit: <T>(name: string, event: T) => Promise<void>;
|
||||
};
|
||||
|
||||
export function taskEmitterCreate(req: TaskEmitterCreateReq) {
|
||||
return {
|
||||
emit: async <T>(name: string, event: T) => {
|
||||
await pipelineEmitter.emit(name, {
|
||||
pipeline: req.pipeline,
|
||||
step: req.step,
|
||||
event,
|
||||
});
|
||||
},
|
||||
} as TaskEmitter;
|
||||
}
|
||||
@@ -2,3 +2,7 @@ export * from "./email.js";
|
||||
export * from "./cname.js";
|
||||
export * from "./config.js";
|
||||
export * from "./url.js";
|
||||
export * from "./emit.js";
|
||||
export type IServiceGetter = {
|
||||
get: (name: string) => Promise<any>;
|
||||
};
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
// "no-unused-expressions": "off",
|
||||
"max-len": [0, 160, 2, { "ignoreUrls": true }]
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
{
|
||||
"printWidth": 160
|
||||
"printWidth": 220,
|
||||
"bracketSpacing": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
@@ -3,6 +3,70 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/certd/certd/compare/v1.31.4...v1.31.5) (2025-03-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.31.4](https://github.com/certd/certd/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.31.3](https://github.com/certd/certd/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.31.2](https://github.com/certd/certd/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.31.1](https://github.com/certd/certd/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
# [1.31.0](https://github.com/certd/certd/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.30.6](https://github.com/certd/certd/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.30.5](https://github.com/certd/certd/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.30.4](https://github.com/certd/certd/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.30.3](https://github.com/certd/certd/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.30.2](https://github.com/certd/certd/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.30.1](https://github.com/certd/certd/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
# [1.30.0](https://github.com/certd/certd/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.29.5](https://github.com/certd/certd/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.29.4](https://github.com/certd/certd/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.29.3](https://github.com/certd/certd/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [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,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.29.2",
|
||||
"version": "1.31.5",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -18,8 +18,10 @@
|
||||
"rollup": "^3.7.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||
"gitHead": "b649617e0457b4e177bacb173dc1aa67eb84d7cf"
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
// "no-unused-expressions": "off",
|
||||
"max-len": [0, 160, 2, { "ignoreUrls": true }]
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"printWidth": 160,
|
||||
"printWidth": 220,
|
||||
"bracketSpacing": true,
|
||||
"singleQuote": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,70 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/certd/certd/compare/v1.31.4...v1.31.5) (2025-03-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.31.4](https://github.com/certd/certd/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.31.3](https://github.com/certd/certd/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.31.2](https://github.com/certd/certd/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.31.1](https://github.com/certd/certd/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
# [1.31.0](https://github.com/certd/certd/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.30.6](https://github.com/certd/certd/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.30.5](https://github.com/certd/certd/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.30.4](https://github.com/certd/certd/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.30.3](https://github.com/certd/certd/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.30.2](https://github.com/certd/certd/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.30.1](https://github.com/certd/certd/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
# [1.30.0](https://github.com/certd/certd/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.29.5](https://github.com/certd/certd/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.29.4](https://github.com/certd/certd/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.29.3](https://github.com/certd/certd/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [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,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.29.2",
|
||||
"version": "1.31.5",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -20,8 +20,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.38.1",
|
||||
"@typescript-eslint/parser": "^5.38.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
@@ -30,5 +30,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||
"gitHead": "b649617e0457b4e177bacb173dc1aa67eb84d7cf"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"printWidth": 160,
|
||||
"printWidth": 220,
|
||||
"bracketSpacing": true,
|
||||
"singleQuote": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,70 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/certd/certd/compare/v1.31.4...v1.31.5) (2025-03-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.31.4](https://github.com/certd/certd/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.31.3](https://github.com/certd/certd/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.31.2](https://github.com/certd/certd/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.31.1](https://github.com/certd/certd/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
# [1.31.0](https://github.com/certd/certd/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.30.6](https://github.com/certd/certd/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.30.5](https://github.com/certd/certd/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.30.4](https://github.com/certd/certd/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.30.3](https://github.com/certd/certd/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.30.2](https://github.com/certd/certd/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.30.1](https://github.com/certd/certd/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
# [1.30.0](https://github.com/certd/certd/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.29.5](https://github.com/certd/certd/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.29.4](https://github.com/certd/certd/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.29.3](https://github.com/certd/certd/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [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,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.29.2",
|
||||
"version": "1.31.5",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -16,13 +16,13 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.29.2",
|
||||
"@certd/basic": "^1.31.5",
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.38.1",
|
||||
"@typescript-eslint/parser": "^5.38.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
@@ -31,5 +31,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||
"gitHead": "b649617e0457b4e177bacb173dc1aa67eb84d7cf"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"printWidth": 160,
|
||||
"printWidth": 220,
|
||||
"bracketSpacing": true,
|
||||
"singleQuote": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,77 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/certd/certd/compare/v1.31.4...v1.31.5) (2025-03-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.31.4](https://github.com/certd/certd/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.31.3](https://github.com/certd/certd/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.31.2](https://github.com/certd/certd/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.31.1](https://github.com/certd/certd/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
# [1.31.0](https://github.com/certd/certd/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 升级midwayjs版本 ([057b0b4](https://github.com/certd/certd/commit/057b0b4565e19bb93195633f767b2942e8e40e59))
|
||||
* 是否允许爬虫爬取增加ui设置选项 ([779db9d](https://github.com/certd/certd/commit/779db9da705d2dfef36fec21f52bd38af9fc5f2e))
|
||||
|
||||
## [1.30.6](https://github.com/certd/certd/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.30.5](https://github.com/certd/certd/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.30.4](https://github.com/certd/certd/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.30.3](https://github.com/certd/certd/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.30.2](https://github.com/certd/certd/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.30.1](https://github.com/certd/certd/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
# [1.30.0](https://github.com/certd/certd/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
### Features
|
||||
|
||||
* 支持open api接口,根据域名获取证书 ([52a4fd3](https://github.com/certd/certd/commit/52a4fd33180e9b3f71b8dc9f7671d7cd8e448c3b))
|
||||
|
||||
## [1.29.5](https://github.com/certd/certd/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.29.4](https://github.com/certd/certd/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.29.3](https://github.com/certd/certd/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复系统级授权无法查看密钥的bug ([8644348](https://github.com/certd/certd/commit/8644348fc41ae2e1672f946ca37e5d3a674e0218))
|
||||
|
||||
## [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,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.29.2",
|
||||
"version": "1.31.5",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -27,18 +27,18 @@
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.29.2",
|
||||
"@certd/basic": "^1.29.2",
|
||||
"@certd/pipeline": "^1.29.2",
|
||||
"@certd/plus-core": "^1.29.2",
|
||||
"@certd/acme-client": "^1.31.5",
|
||||
"@certd/basic": "^1.31.5",
|
||||
"@certd/pipeline": "^1.31.5",
|
||||
"@certd/plus-core": "^1.31.5",
|
||||
"@midwayjs/cache": "~3.14.0",
|
||||
"@midwayjs/core": "~3.17.1",
|
||||
"@midwayjs/i18n": "~3.17.3",
|
||||
"@midwayjs/info": "~3.17.3",
|
||||
"@midwayjs/koa": "~3.17.1",
|
||||
"@midwayjs/core": "~3.20.3",
|
||||
"@midwayjs/i18n": "~3.20.3",
|
||||
"@midwayjs/info": "~3.20.3",
|
||||
"@midwayjs/koa": "~3.20.3",
|
||||
"@midwayjs/logger": "~3.4.2",
|
||||
"@midwayjs/typeorm": "~3.17.1",
|
||||
"@midwayjs/upload": "^3.17.3",
|
||||
"@midwayjs/typeorm": "~3.20.3",
|
||||
"@midwayjs/upload": "^3.20.3",
|
||||
"better-sqlite3": "^11.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"dayjs": "^1.11.7",
|
||||
@@ -50,8 +50,8 @@
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.3",
|
||||
"@types/node": "^18",
|
||||
"@typescript-eslint/eslint-plugin": "^5.38.1",
|
||||
"@typescript-eslint/parser": "^5.38.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
@@ -61,5 +61,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||
"gitHead": "b649617e0457b4e177bacb173dc1aa67eb84d7cf"
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export abstract class BaseService<T> {
|
||||
|
||||
async transaction(callback: (entityManager: EntityManager) => Promise<any>) {
|
||||
const dataSource = this.dataSourceManager.getDataSource('default');
|
||||
await dataSource.transaction(callback as any);
|
||||
return await dataSource.transaction(callback as any);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,8 @@ export const Constants = {
|
||||
authOnly: '_authOnly_',
|
||||
//仅需要登录
|
||||
loginOnly: '_authOnly_',
|
||||
|
||||
open: '_open_',
|
||||
},
|
||||
res: {
|
||||
serverError(message: string) {
|
||||
@@ -68,5 +70,33 @@ export const Constants = {
|
||||
code: 10001,
|
||||
message: '对不起,预览环境不允许修改此数据',
|
||||
},
|
||||
openKeyError: {
|
||||
code: 20000,
|
||||
message: 'ApiToken错误',
|
||||
},
|
||||
openKeySignError: {
|
||||
code: 20001,
|
||||
message: 'ApiToken签名错误',
|
||||
},
|
||||
openKeyExpiresError: {
|
||||
code: 20002,
|
||||
message: 'ApiToken时间戳错误',
|
||||
},
|
||||
openKeySignTypeError: {
|
||||
code: 20003,
|
||||
message: 'ApiToken签名类型不支持',
|
||||
},
|
||||
openParamError: {
|
||||
code: 20010,
|
||||
message: '请求参数错误',
|
||||
},
|
||||
openCertNotFound: {
|
||||
code: 20011,
|
||||
message: '证书不存在',
|
||||
},
|
||||
openCertNotReady: {
|
||||
code: 20012,
|
||||
message: '证书还未生成',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -5,10 +5,6 @@ import { BaseException } from './base-exception.js';
|
||||
*/
|
||||
export class AuthException extends BaseException {
|
||||
constructor(message) {
|
||||
super(
|
||||
'AuthException',
|
||||
Constants.res.auth.code,
|
||||
message ? message : Constants.res.auth.message
|
||||
);
|
||||
super('AuthException', Constants.res.auth.code, message ? message : Constants.res.auth.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
* 异常基类
|
||||
*/
|
||||
export class BaseException extends Error {
|
||||
status: number;
|
||||
code: number;
|
||||
constructor(name, code, message) {
|
||||
super(message);
|
||||
this.name = name;
|
||||
this.status = code;
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,3 +8,9 @@ export class CommonException extends BaseException {
|
||||
super('CommonException', Constants.res.error.code, message ? message : Constants.res.error.message);
|
||||
}
|
||||
}
|
||||
|
||||
export class CodeException extends BaseException {
|
||||
constructor(res: { code: number; message: string }) {
|
||||
super('CodeException', res.code, res.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export class Result<T> {
|
||||
}
|
||||
|
||||
static error(code = 1, msg) {
|
||||
return new Result(code, msg, null);
|
||||
return new Result(code, msg);
|
||||
}
|
||||
|
||||
static success(msg, data?) {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './service/plus-service.js';
|
||||
export * from './service/file-service.js';
|
||||
export * from './service/encryptor.js';
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import crypto from 'crypto';
|
||||
|
||||
export class Encryptor {
|
||||
secretKey: Buffer;
|
||||
constructor(encryptSecret: string, encoding: BufferEncoding = 'base64') {
|
||||
this.secretKey = Buffer.from(encryptSecret, encoding);
|
||||
}
|
||||
// 加密函数
|
||||
encrypt(text: string) {
|
||||
const iv = crypto.randomBytes(16); // 初始化向量
|
||||
// const secretKey = crypto.randomBytes(32);
|
||||
// const key = Buffer.from(secretKey);
|
||||
const cipher = crypto.createCipheriv('aes-256-cbc', this.secretKey, iv);
|
||||
let encrypted = cipher.update(text);
|
||||
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
||||
return iv.toString('hex') + ':' + encrypted.toString('hex');
|
||||
}
|
||||
|
||||
// 解密函数
|
||||
decrypt(encryptedText: string) {
|
||||
const textParts = encryptedText.split(':');
|
||||
const iv = Buffer.from(textParts.shift(), 'hex');
|
||||
const encrypted = Buffer.from(textParts.join(':'), 'hex');
|
||||
const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(this.secretKey), iv);
|
||||
let decrypted = decipher.update(encrypted);
|
||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||
return decrypted.toString();
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ export class SysPublicSettings extends BaseSettings {
|
||||
limitUserPipelineCount = 0;
|
||||
managerOtherUserPipeline = false;
|
||||
icpNo?: string;
|
||||
robots?: boolean = true;
|
||||
}
|
||||
|
||||
export class SysPrivateSettings extends BaseSettings {
|
||||
@@ -112,6 +113,17 @@ export class SysSecretBackup extends BaseSettings {
|
||||
encryptSecret?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 不要修改
|
||||
*/
|
||||
export class SysSecret extends BaseSettings {
|
||||
static __title__ = '密钥信息';
|
||||
static __key__ = 'sys.secret';
|
||||
static __access__ = 'private';
|
||||
siteId?: string;
|
||||
encryptSecret?: string;
|
||||
}
|
||||
|
||||
export class SysSiteEnv {
|
||||
agent?: {
|
||||
enabled?: boolean;
|
||||
|
||||
@@ -1,25 +1,22 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { SysSettingsEntity } from '../entity/sys-settings.js';
|
||||
import { CacheManager } from '@midwayjs/cache';
|
||||
import { BaseSettings, SysInstallInfo, SysPrivateSettings, SysPublicSettings, SysSecretBackup } from './models.js';
|
||||
import { BaseSettings, SysInstallInfo, SysPrivateSettings, SysPublicSettings, SysSecret, SysSecretBackup } from './models.js';
|
||||
import * as _ from 'lodash-es';
|
||||
import { BaseService } from '../../../basic/index.js';
|
||||
import { logger, setGlobalProxy } from '@certd/basic';
|
||||
import { cache, logger, setGlobalProxy } from '@certd/basic';
|
||||
import * as dns from 'node:dns';
|
||||
|
||||
/**
|
||||
* 设置
|
||||
*/
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||
@Scope(ScopeEnum.Singleton)
|
||||
export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
@InjectEntityModel(SysSettingsEntity)
|
||||
repository: Repository<SysSettingsEntity>;
|
||||
|
||||
@Inject()
|
||||
cache: CacheManager; // 依赖注入CacheManager
|
||||
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
@@ -72,7 +69,7 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
async getSetting<T>(type: any): Promise<T> {
|
||||
const key = type.__key__;
|
||||
const cacheKey = type.getCacheKey();
|
||||
const settings: T = await this.cache.get(cacheKey);
|
||||
const settings: T = cache.get(cacheKey);
|
||||
if (settings) {
|
||||
return settings;
|
||||
}
|
||||
@@ -80,7 +77,7 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
const savedSettings = await this.getSettingByKey(key);
|
||||
newSetting = _.merge(newSetting, savedSettings);
|
||||
await this.saveSetting(newSetting);
|
||||
await this.cache.set(cacheKey, newSetting);
|
||||
cache.set(cacheKey, newSetting);
|
||||
return newSetting;
|
||||
}
|
||||
|
||||
@@ -93,6 +90,12 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
if (entity) {
|
||||
entity.setting = JSON.stringify(bean);
|
||||
entity.access = type.__access__;
|
||||
|
||||
if (key === SysSecretBackup.__key__) {
|
||||
//备份密钥不允许更新
|
||||
return;
|
||||
}
|
||||
|
||||
await this.repository.save(entity);
|
||||
} else {
|
||||
const newEntity = new SysSettingsEntity();
|
||||
@@ -103,7 +106,7 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
await this.repository.save(newEntity);
|
||||
}
|
||||
|
||||
await this.cache.set(cacheKey, bean);
|
||||
cache.set(cacheKey, bean);
|
||||
}
|
||||
|
||||
async getPublicSettings(): Promise<SysPublicSettings> {
|
||||
@@ -146,7 +149,7 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
} else {
|
||||
throw new Error('该设置不存在');
|
||||
}
|
||||
await this.cache.del(`settings.${key}`);
|
||||
cache.delete(`settings.${key}`);
|
||||
}
|
||||
|
||||
async backupSecret() {
|
||||
@@ -173,4 +176,20 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
}
|
||||
}
|
||||
}
|
||||
async getSecret() {
|
||||
const sysSecret = await this.getSetting<SysSecret>(SysSecret);
|
||||
if (sysSecret.encryptSecret) {
|
||||
return sysSecret;
|
||||
}
|
||||
//从备份中读取
|
||||
const settings = await this.getSettingByKey(SysSecretBackup.__key__);
|
||||
if (settings == null || !settings.encryptSecret) {
|
||||
throw new Error('密钥备份不存在');
|
||||
}
|
||||
sysSecret.siteId = settings.siteId;
|
||||
sysSecret.encryptSecret = settings.encryptSecret;
|
||||
await this.saveSetting(sysSecret);
|
||||
logger.info('密钥恢复成功');
|
||||
return sysSecret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Init, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import crypto from 'crypto';
|
||||
import { SysPrivateSettings, SysSettingsService } from '../../../system/index.js';
|
||||
import { Encryptor, SysSecret, SysSettingsService } from '../../../system/index.js';
|
||||
|
||||
/**
|
||||
* 授权
|
||||
@@ -8,36 +7,24 @@ import { SysPrivateSettings, SysSettingsService } from '../../../system/index.js
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Singleton)
|
||||
export class EncryptService {
|
||||
secretKey: Buffer;
|
||||
encryptor: Encryptor;
|
||||
|
||||
@Inject()
|
||||
sysSettingService: SysSettingsService;
|
||||
|
||||
@Init()
|
||||
async init() {
|
||||
const privateInfo: SysPrivateSettings = await this.sysSettingService.getSetting(SysPrivateSettings);
|
||||
this.secretKey = Buffer.from(privateInfo.encryptSecret, 'base64');
|
||||
const secret: SysSecret = await this.sysSettingService.getSecret();
|
||||
this.encryptor = new Encryptor(secret.encryptSecret);
|
||||
}
|
||||
|
||||
// 加密函数
|
||||
encrypt(text: string) {
|
||||
const iv = crypto.randomBytes(16); // 初始化向量
|
||||
// const secretKey = crypto.randomBytes(32);
|
||||
// const key = Buffer.from(secretKey);
|
||||
const cipher = crypto.createCipheriv('aes-256-cbc', this.secretKey, iv);
|
||||
let encrypted = cipher.update(text);
|
||||
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
||||
return iv.toString('hex') + ':' + encrypted.toString('hex');
|
||||
return this.encryptor.encrypt(text);
|
||||
}
|
||||
|
||||
// 解密函数
|
||||
decrypt(encryptedText: string) {
|
||||
const textParts = encryptedText.split(':');
|
||||
const iv = Buffer.from(textParts.shift(), 'hex');
|
||||
const encrypted = Buffer.from(textParts.join(':'), 'hex');
|
||||
const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(this.secretKey), iv);
|
||||
let decrypted = decipher.update(encrypted);
|
||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||
return decrypted.toString();
|
||||
return this.encryptor.decrypt(encryptedText);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"printWidth": 160,
|
||||
"printWidth": 220,
|
||||
"bracketSpacing": true,
|
||||
"singleQuote": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,72 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/certd/certd/compare/v1.31.4...v1.31.5) (2025-03-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.31.4](https://github.com/certd/certd/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.31.3](https://github.com/certd/certd/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.31.2](https://github.com/certd/certd/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.31.1](https://github.com/certd/certd/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
# [1.31.0](https://github.com/certd/certd/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 升级midwayjs版本 ([057b0b4](https://github.com/certd/certd/commit/057b0b4565e19bb93195633f767b2942e8e40e59))
|
||||
|
||||
## [1.30.6](https://github.com/certd/certd/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.30.5](https://github.com/certd/certd/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.30.4](https://github.com/certd/certd/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.30.3](https://github.com/certd/certd/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.30.2](https://github.com/certd/certd/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.30.1](https://github.com/certd/certd/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
# [1.30.0](https://github.com/certd/certd/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.29.5](https://github.com/certd/certd/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.29.4](https://github.com/certd/certd/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.29.3](https://github.com/certd/certd/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [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,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.29.2",
|
||||
"version": "1.31.5",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -25,16 +25,16 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@midwayjs/core": "~3.17.1",
|
||||
"@midwayjs/core": "~3.20.3",
|
||||
"@midwayjs/logger": "~3.4.2",
|
||||
"@midwayjs/typeorm": "~3.17.1",
|
||||
"@midwayjs/typeorm": "~3.20.3",
|
||||
"better-sqlite3": "^11.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.3",
|
||||
"@types/node": "^18",
|
||||
"@typescript-eslint/eslint-plugin": "^5.38.1",
|
||||
"@typescript-eslint/parser": "^5.38.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
@@ -46,5 +46,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||
"gitHead": "b649617e0457b4e177bacb173dc1aa67eb84d7cf"
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
// "no-unused-expressions": "off",
|
||||
"max-len": [0, 160, 2, { "ignoreUrls": true }]
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
{
|
||||
"printWidth": 160
|
||||
"printWidth": 220,
|
||||
"bracketSpacing": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
@@ -3,6 +3,96 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/certd/certd/compare/v1.31.4...v1.31.5) (2025-03-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.31.4](https://github.com/certd/certd/compare/v1.31.3...v1.31.4) (2025-03-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复dns.la域名申请失败的bug ([1de8eee](https://github.com/certd/certd/commit/1de8eee6ea8307f3c11626af75303d3cc104bb95))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 流水线增加上传证书快捷方式 ([425bba6](https://github.com/certd/certd/commit/425bba67c539b734e2a85a83a4f9ecc9b2434fb4))
|
||||
* 手动上传证书部署流水线 ([fbb66f3](https://github.com/certd/certd/commit/fbb66f3c4389489aa8a43b194d82bc8cf391607b))
|
||||
* 支持手动上传证书并部署 ([a9fffa5](https://github.com/certd/certd/commit/a9fffa5180c83da27b35886aa2e858a92a2c5f94))
|
||||
|
||||
## [1.31.3](https://github.com/certd/certd/compare/v1.31.2...v1.31.3) (2025-03-13)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 1panel支持 apikey方式授权 ([170b2af](https://github.com/certd/certd/commit/170b2afb0e3b125e4ed057f633fe895b5ac3ac22))
|
||||
|
||||
## [1.31.2](https://github.com/certd/certd/compare/v1.31.1...v1.31.2) (2025-03-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复cname记录查找bug ([95fb4e3](https://github.com/certd/certd/commit/95fb4e3e8be6ca13cc43b451f6141d62190ba453))
|
||||
|
||||
## [1.31.1](https://github.com/certd/certd/compare/v1.31.0...v1.31.1) (2025-03-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
# [1.31.0](https://github.com/certd/certd/compare/v1.30.6...v1.31.0) (2025-03-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.30.6](https://github.com/certd/certd/compare/v1.30.5...v1.30.6) (2025-02-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.30.5](https://github.com/certd/certd/compare/v1.30.4...v1.30.5) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.30.4](https://github.com/certd/certd/compare/v1.30.3...v1.30.4) (2025-02-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.30.3](https://github.com/certd/certd/compare/v1.30.2...v1.30.3) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.30.2](https://github.com/certd/certd/compare/v1.30.1...v1.30.2) (2025-02-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.30.1](https://github.com/certd/certd/compare/v1.30.0...v1.30.1) (2025-01-20)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* http方式校验,选择sftp时,支持修改文件访问权限比如777 ([15d6eaf](https://github.com/certd/certd/commit/15d6eaf5532ed25acd4f8d58c429353a2f44206c))
|
||||
|
||||
# [1.30.0](https://github.com/certd/certd/compare/v1.29.5...v1.30.0) (2025-01-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复namesilo ttl太短的问题 ([865f26d](https://github.com/certd/certd/commit/865f26d75c0d3dd4dc8b41448f8830068e45957c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 证书仓库 ([91e7f45](https://github.com/certd/certd/commit/91e7f45a1c5ea1e0ec0aa3236b80028f03a6d0aa))
|
||||
|
||||
## [1.29.5](https://github.com/certd/certd/compare/v1.29.4...v1.29.5) (2025-01-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复复制到本机插件,pfx格式复制时报错的bug ([f57116d](https://github.com/certd/certd/commit/f57116d2bebf33e47ad93e0b39c4efe8e4aea25c))
|
||||
|
||||
## [1.29.4](https://github.com/certd/certd/compare/v1.29.3...v1.29.4) (2025-01-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.29.3](https://github.com/certd/certd/compare/v1.29.2...v1.29.3) (2025-01-04)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化acme sdk ([54db744](https://github.com/certd/certd/commit/54db74428259de64d12230c2ab7353ae11197bbc))
|
||||
* 支持http校验方式申请证书 ([405591c](https://github.com/certd/certd/commit/405591c5d08fa1a3b228ee3980199e7731cfec4a))
|
||||
* http校验方式,支持七牛云oss、阿里云oss、腾讯云cos ([3f74d4d](https://github.com/certd/certd/commit/3f74d4d9e5f5d0e629b44cff1895b3f7a8fbcafc))
|
||||
|
||||
## [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,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.29.2",
|
||||
"version": "1.31.5",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -15,9 +15,10 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.29.2",
|
||||
"@certd/basic": "^1.29.2",
|
||||
"@certd/pipeline": "^1.29.2",
|
||||
"@certd/acme-client": "^1.31.5",
|
||||
"@certd/basic": "^1.31.5",
|
||||
"@certd/pipeline": "^1.31.5",
|
||||
"@certd/plugin-lib": "^1.31.5",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jszip": "^3.10.1",
|
||||
@@ -29,8 +30,8 @@
|
||||
"@types/chai": "^4.3.3",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/psl": "^1.1.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.38.1",
|
||||
"@typescript-eslint/parser": "^5.38.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"chai": "^4.3.6",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
@@ -40,5 +41,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f9128d4d452e344b6990c117a5d647add226437b"
|
||||
"gitHead": "b649617e0457b4e177bacb173dc1aa67eb84d7cf"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { CreateRecordOptions, DnsProviderContext, DnsProviderDefine, IDnsProvider, RemoveRecordOptions } from "./api.js";
|
||||
//@ts-ignore
|
||||
import psl from "psl";
|
||||
import { dnsProviderRegistry } from "./registry.js";
|
||||
import { Decorator } from "@certd/pipeline";
|
||||
|
||||
@@ -6,23 +6,37 @@ import { Challenge } from "@certd/acme-client/types/rfc8555";
|
||||
import { IContext } from "@certd/pipeline";
|
||||
import { ILogger, utils } from "@certd/basic";
|
||||
import { IDnsProvider, parseDomain } from "../../dns-provider/index.js";
|
||||
|
||||
import { HttpChallengeUploader } from "./uploads/api.js";
|
||||
export type CnameVerifyPlan = {
|
||||
type?: string;
|
||||
domain: string;
|
||||
fullRecord: string;
|
||||
dnsProvider: IDnsProvider;
|
||||
};
|
||||
|
||||
export type HttpVerifyPlan = {
|
||||
type: string;
|
||||
domain: string;
|
||||
httpUploader: HttpChallengeUploader;
|
||||
};
|
||||
|
||||
export type DomainVerifyPlan = {
|
||||
domain: string;
|
||||
type: "cname" | "dns";
|
||||
type: "cname" | "dns" | "http";
|
||||
dnsProvider?: IDnsProvider;
|
||||
cnameVerifyPlan?: Record<string, CnameVerifyPlan>;
|
||||
httpVerifyPlan?: Record<string, HttpVerifyPlan>;
|
||||
};
|
||||
export type DomainsVerifyPlan = {
|
||||
[key: string]: DomainVerifyPlan;
|
||||
};
|
||||
|
||||
export type Providers = {
|
||||
dnsProvider?: IDnsProvider;
|
||||
domainsVerifyPlan?: DomainsVerifyPlan;
|
||||
httpUploader?: HttpChallengeUploader;
|
||||
};
|
||||
|
||||
export type CertInfo = {
|
||||
crt: string; //fullchain证书
|
||||
key: string; //私钥
|
||||
@@ -46,6 +60,7 @@ type AcmeServiceOptions = {
|
||||
reverseProxy?: string;
|
||||
privateKeyType?: PrivateKeyType;
|
||||
signal?: AbortSignal;
|
||||
maxCheckRetryCount?: number;
|
||||
};
|
||||
|
||||
export class AcmeService {
|
||||
@@ -130,7 +145,7 @@ export class AcmeService {
|
||||
accountKey: conf.key,
|
||||
accountUrl: conf.accountUrl,
|
||||
externalAccountBinding: this.eab,
|
||||
backoffAttempts: 15,
|
||||
backoffAttempts: this.options.maxCheckRetryCount || 20,
|
||||
backoffMin: 5000,
|
||||
backoffMax: 10000,
|
||||
urlMapping,
|
||||
@@ -155,58 +170,37 @@ export class AcmeService {
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
async challengeCreateFn(authz: any, challenge: any, keyAuthorization: string, dnsProvider: IDnsProvider, domainsVerifyPlan: DomainsVerifyPlan) {
|
||||
async challengeCreateFn(authz: any, keyAuthorizationGetter: (challenge: Challenge) => Promise<string>, providers: Providers) {
|
||||
this.logger.info("Triggered challengeCreateFn()");
|
||||
|
||||
/* http-01 */
|
||||
const fullDomain = authz.identifier.value;
|
||||
if (challenge.type === "http-01") {
|
||||
const filePath = `/var/www/html/.well-known/acme-challenge/${challenge.token}`;
|
||||
let domain = parseDomain(fullDomain);
|
||||
this.logger.info("主域名为:" + domain);
|
||||
|
||||
const getChallenge = (type: string) => {
|
||||
return authz.challenges.find((c: any) => c.type === type);
|
||||
};
|
||||
|
||||
const doHttpVerify = async (challenge: any, httpUploader: HttpChallengeUploader) => {
|
||||
const keyAuthorization = await keyAuthorizationGetter(challenge);
|
||||
this.logger.info("http校验");
|
||||
const filePath = `.well-known/acme-challenge/${challenge.token}`;
|
||||
const fileContents = keyAuthorization;
|
||||
this.logger.info(`校验 ${fullDomain} ,准备上传文件:${filePath}`);
|
||||
await httpUploader.upload(filePath, Buffer.from(fileContents));
|
||||
this.logger.info(`上传文件【${filePath}】成功`);
|
||||
return {
|
||||
challenge,
|
||||
keyAuthorization,
|
||||
httpUploader,
|
||||
};
|
||||
};
|
||||
|
||||
this.logger.info(`Creating challenge response for ${fullDomain} at path: ${filePath}`);
|
||||
const doDnsVerify = async (challenge: any, fullRecord: string, dnsProvider: IDnsProvider) => {
|
||||
this.logger.info("dns校验");
|
||||
const keyAuthorization = await keyAuthorizationGetter(challenge);
|
||||
|
||||
/* Replace this */
|
||||
this.logger.info(`Would write "${fileContents}" to path "${filePath}"`);
|
||||
// await fs.writeFileAsync(filePath, fileContents);
|
||||
} else if (challenge.type === "dns-01") {
|
||||
/* dns-01 */
|
||||
let fullRecord = `_acme-challenge.${fullDomain}`;
|
||||
const recordValue = keyAuthorization;
|
||||
|
||||
this.logger.info(`Creating TXT record for ${fullDomain}: ${fullRecord}`);
|
||||
/* Replace this */
|
||||
this.logger.info(`Would create TXT record "${fullRecord}" with value "${recordValue}"`);
|
||||
|
||||
let domain = parseDomain(fullDomain);
|
||||
this.logger.info("解析到域名domain=" + domain);
|
||||
|
||||
if (domainsVerifyPlan) {
|
||||
//按照计划执行
|
||||
const domainVerifyPlan = domainsVerifyPlan[domain];
|
||||
if (domainVerifyPlan) {
|
||||
if (domainVerifyPlan.type === "dns") {
|
||||
dnsProvider = domainVerifyPlan.dnsProvider;
|
||||
} else if (domainVerifyPlan.type === "cname") {
|
||||
const cnameVerifyPlan = domainVerifyPlan.cnameVerifyPlan;
|
||||
if (cnameVerifyPlan) {
|
||||
const cname = cnameVerifyPlan[fullDomain];
|
||||
if (cname) {
|
||||
dnsProvider = cname.dnsProvider;
|
||||
domain = parseDomain(cname.domain);
|
||||
fullRecord = cname.fullRecord;
|
||||
}
|
||||
} else {
|
||||
this.logger.error("未找到域名Cname校验计划,使用默认的dnsProvider");
|
||||
}
|
||||
} else {
|
||||
this.logger.error("不支持的校验类型", domainVerifyPlan.type);
|
||||
}
|
||||
} else {
|
||||
this.logger.info("未找到域名校验计划,使用默认的dnsProvider");
|
||||
}
|
||||
}
|
||||
|
||||
let hostRecord = fullRecord.replace(`${domain}`, "");
|
||||
if (hostRecord.endsWith(".")) {
|
||||
hostRecord = hostRecord.substring(0, hostRecord.length - 1);
|
||||
@@ -226,8 +220,54 @@ export class AcmeService {
|
||||
recordReq,
|
||||
recordRes,
|
||||
dnsProvider,
|
||||
challenge,
|
||||
keyAuthorization,
|
||||
};
|
||||
};
|
||||
|
||||
let dnsProvider = providers.dnsProvider;
|
||||
let fullRecord = `_acme-challenge.${fullDomain}`;
|
||||
|
||||
if (providers.domainsVerifyPlan) {
|
||||
//按照计划执行
|
||||
const domainVerifyPlan = providers.domainsVerifyPlan[domain];
|
||||
if (domainVerifyPlan) {
|
||||
if (domainVerifyPlan.type === "dns") {
|
||||
dnsProvider = domainVerifyPlan.dnsProvider;
|
||||
} else if (domainVerifyPlan.type === "cname") {
|
||||
const cnameVerifyPlan = domainVerifyPlan.cnameVerifyPlan;
|
||||
if (cnameVerifyPlan) {
|
||||
const cname = cnameVerifyPlan[fullDomain];
|
||||
if (cname) {
|
||||
dnsProvider = cname.dnsProvider;
|
||||
domain = parseDomain(cname.domain);
|
||||
fullRecord = cname.fullRecord;
|
||||
}
|
||||
} else {
|
||||
this.logger.error("未找到域名Cname校验计划,使用默认的dnsProvider");
|
||||
}
|
||||
} else if (domainVerifyPlan.type === "http") {
|
||||
const httpVerifyPlan = domainVerifyPlan.httpVerifyPlan;
|
||||
if (httpVerifyPlan) {
|
||||
const httpChallenge = getChallenge("http-01");
|
||||
if (httpChallenge == null) {
|
||||
throw new Error("该域名不支持http-01方式校验");
|
||||
}
|
||||
const plan = httpVerifyPlan[fullDomain];
|
||||
return await doHttpVerify(httpChallenge, plan.httpUploader);
|
||||
} else {
|
||||
throw new Error("未找到域名【" + fullDomain + "】的http校验配置");
|
||||
}
|
||||
} else {
|
||||
throw new Error("不支持的校验类型", domainVerifyPlan.type);
|
||||
}
|
||||
} else {
|
||||
this.logger.info("未找到域名校验计划,使用默认的dnsProvider");
|
||||
}
|
||||
}
|
||||
|
||||
const dnsChallenge = getChallenge("dns-01");
|
||||
return await doDnsVerify(dnsChallenge, fullRecord, dnsProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,22 +279,20 @@ export class AcmeService {
|
||||
* @param recordReq
|
||||
* @param recordRes
|
||||
* @param dnsProvider dnsProvider
|
||||
* @param httpUploader
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
async challengeRemoveFn(authz: any, challenge: any, keyAuthorization: string, recordReq: any, recordRes: any, dnsProvider: IDnsProvider) {
|
||||
this.logger.info("Triggered challengeRemoveFn()");
|
||||
async challengeRemoveFn(authz: any, challenge: any, keyAuthorization: string, recordReq: any, recordRes: any, dnsProvider?: IDnsProvider, httpUploader?: HttpChallengeUploader) {
|
||||
this.logger.info("执行清理");
|
||||
|
||||
/* http-01 */
|
||||
const fullDomain = authz.identifier.value;
|
||||
if (challenge.type === "http-01") {
|
||||
const filePath = `/var/www/html/.well-known/acme-challenge/${challenge.token}`;
|
||||
|
||||
this.logger.info(`Removing challenge response for ${fullDomain} at path: ${filePath}`);
|
||||
|
||||
/* Replace this */
|
||||
this.logger.info(`Would remove file on path "${filePath}"`);
|
||||
// await fs.unlinkAsync(filePath);
|
||||
const filePath = `.well-known/acme-challenge/${challenge.token}`;
|
||||
this.logger.info(`Removing challenge response for ${fullDomain} at file: ${filePath}`);
|
||||
await httpUploader.remove(filePath);
|
||||
this.logger.info(`删除文件【${filePath}】成功`);
|
||||
} else if (challenge.type === "dns-01") {
|
||||
this.logger.info(`删除 TXT 解析记录:${JSON.stringify(recordReq)} ,recordRes = ${JSON.stringify(recordRes)}`);
|
||||
try {
|
||||
@@ -275,11 +313,12 @@ export class AcmeService {
|
||||
domains: string | string[];
|
||||
dnsProvider?: any;
|
||||
domainsVerifyPlan?: DomainsVerifyPlan;
|
||||
httpUploader?: any;
|
||||
csrInfo: any;
|
||||
isTest?: boolean;
|
||||
privateKeyType?: string;
|
||||
}): Promise<CertInfo> {
|
||||
const { email, isTest, domains, csrInfo, dnsProvider, domainsVerifyPlan } = options;
|
||||
const { email, isTest, domains, csrInfo, dnsProvider, domainsVerifyPlan, httpUploader } = options;
|
||||
const client: acme.Client = await this.getAcmeClient(email, isTest);
|
||||
|
||||
/* Create CSR */
|
||||
@@ -319,32 +358,30 @@ export class AcmeService {
|
||||
privateKey
|
||||
);
|
||||
|
||||
if (dnsProvider == null && domainsVerifyPlan == null) {
|
||||
throw new Error("dnsProvider 、 domainsVerifyPlan 不能都为空");
|
||||
if (dnsProvider == null && domainsVerifyPlan == null && httpUploader == null) {
|
||||
throw new Error("dnsProvider 、 domainsVerifyPlan 、 httpUploader不能都为空");
|
||||
}
|
||||
|
||||
const providers: Providers = {
|
||||
dnsProvider,
|
||||
domainsVerifyPlan,
|
||||
httpUploader,
|
||||
};
|
||||
/* 自动申请证书 */
|
||||
const crt = await client.auto({
|
||||
csr,
|
||||
email: email,
|
||||
termsOfServiceAgreed: true,
|
||||
skipChallengeVerification: this.skipLocalVerify,
|
||||
challengePriority: ["dns-01"],
|
||||
challengePriority: ["dns-01", "http-01"],
|
||||
challengeCreateFn: async (
|
||||
authz: acme.Authorization,
|
||||
challenge: Challenge,
|
||||
keyAuthorization: string
|
||||
): Promise<{ recordReq: any; recordRes: any; dnsProvider: any }> => {
|
||||
return await this.challengeCreateFn(authz, challenge, keyAuthorization, dnsProvider, domainsVerifyPlan);
|
||||
keyAuthorizationGetter: (challenge: Challenge) => Promise<string>
|
||||
): Promise<{ recordReq?: any; recordRes?: any; dnsProvider?: any; challenge: Challenge; keyAuthorization: string }> => {
|
||||
return await this.challengeCreateFn(authz, keyAuthorizationGetter, providers);
|
||||
},
|
||||
challengeRemoveFn: async (
|
||||
authz: acme.Authorization,
|
||||
challenge: Challenge,
|
||||
keyAuthorization: string,
|
||||
recordReq: any,
|
||||
recordRes: any,
|
||||
dnsProvider: IDnsProvider
|
||||
): Promise<any> => {
|
||||
return await this.challengeRemoveFn(authz, challenge, keyAuthorization, recordReq, recordRes, dnsProvider);
|
||||
challengeRemoveFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string, recordReq: any, recordRes: any, dnsProvider: IDnsProvider): Promise<any> => {
|
||||
return await this.challengeRemoveFn(authz, challenge, keyAuthorization, recordReq, recordRes, dnsProvider, httpUploader);
|
||||
},
|
||||
signal: this.options.signal,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
import { AbstractTaskPlugin, IContext, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import dayjs from "dayjs";
|
||||
import type { CertInfo } from "./acme.js";
|
||||
import { CertReader } from "./cert-reader.js";
|
||||
import JSZip from "jszip";
|
||||
import { CertConverter } from "./convert.js";
|
||||
export const EVENT_CERT_APPLY_SUCCESS = "CertApply.success";
|
||||
|
||||
export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: "域名",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
open: false,
|
||||
placeholder: "foo.com / *.foo.com / *.bar.com",
|
||||
tokenSeparators: [",", " ", ",", "、", "|"],
|
||||
},
|
||||
rules: [{ type: "domains" }],
|
||||
required: true,
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
order: -999,
|
||||
helper:
|
||||
"1、支持多个域名打到一个证书上,例如: foo.com,*.foo.com,*.bar.com\n" +
|
||||
"2、子域名被通配符包含的不要填写,例如:www.foo.com已经被*.foo.com包含,不要填写www.foo.com\n" +
|
||||
"3、泛域名只能通配*号那一级(*.foo.com的证书不能用于xxx.yyy.foo.com、不能用于foo.com)\n" +
|
||||
"4、输入一个,空格之后,再输入下一个",
|
||||
})
|
||||
domains!: string[];
|
||||
|
||||
@TaskInput({
|
||||
title: "证书加密密码",
|
||||
component: {
|
||||
name: "input-password",
|
||||
vModel: "value",
|
||||
},
|
||||
required: false,
|
||||
order: 100,
|
||||
helper: "转换成PFX、jks格式证书是否需要加密\njks必须设置密码,不传则默认123456\npfx不传则为空密码",
|
||||
})
|
||||
pfxPassword!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "PFX证书转换参数",
|
||||
value: "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES",
|
||||
component: {
|
||||
name: "a-auto-complete",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ value: "", label: "兼容 Windows Server 最新" },
|
||||
{ value: "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES", label: "兼容 Windows Server 2016" },
|
||||
{ value: "-nomac -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES", label: "兼容 Windows Server 2008" },
|
||||
],
|
||||
},
|
||||
required: false,
|
||||
order: 100,
|
||||
helper: "兼容Windows Server各个版本",
|
||||
})
|
||||
pfxArgs = "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES";
|
||||
|
||||
userContext!: IContext;
|
||||
lastStatus!: Step;
|
||||
|
||||
@TaskOutput({
|
||||
title: "域名证书",
|
||||
})
|
||||
cert?: CertInfo;
|
||||
|
||||
async onInstance() {
|
||||
this.userContext = this.ctx.userContext;
|
||||
this.lastStatus = this.ctx.lastStatus as Step;
|
||||
await this.onInit();
|
||||
}
|
||||
|
||||
abstract onInit(): Promise<void>;
|
||||
|
||||
//必须output之后执行
|
||||
async emitCertApplySuccess() {
|
||||
const emitter = this.ctx.emitter;
|
||||
const value = {
|
||||
cert: this.cert,
|
||||
file: this._result.files[0].path,
|
||||
};
|
||||
await emitter.emit(EVENT_CERT_APPLY_SUCCESS, value);
|
||||
}
|
||||
|
||||
async output(certReader: CertReader, isNew: boolean) {
|
||||
const cert: CertInfo = certReader.toCertInfo();
|
||||
this.cert = cert;
|
||||
|
||||
this._result.pipelineVars.certExpiresTime = dayjs(certReader.detail.notAfter).valueOf();
|
||||
if (!this._result.pipelinePrivateVars) {
|
||||
this._result.pipelinePrivateVars = {};
|
||||
}
|
||||
this._result.pipelinePrivateVars.cert = cert;
|
||||
|
||||
if (isNew) {
|
||||
try {
|
||||
const converter = new CertConverter({ logger: this.logger });
|
||||
const res = await converter.convert({
|
||||
cert,
|
||||
pfxPassword: this.pfxPassword,
|
||||
pfxArgs: this.pfxArgs,
|
||||
});
|
||||
if (cert.pfx == null && res.pfx) {
|
||||
cert.pfx = res.pfx;
|
||||
}
|
||||
|
||||
if (cert.der == null && res.der) {
|
||||
cert.der = res.der;
|
||||
}
|
||||
|
||||
if (cert.jks == null && res.jks) {
|
||||
cert.jks = res.jks;
|
||||
}
|
||||
|
||||
this.logger.info("转换证书格式成功");
|
||||
} catch (e) {
|
||||
this.logger.error("转换证书格式失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (isNew) {
|
||||
const zipFileName = certReader.buildCertFileName("zip", certReader.detail.notBefore);
|
||||
await this.zipCert(cert, zipFileName);
|
||||
} else {
|
||||
this.extendsFiles();
|
||||
}
|
||||
}
|
||||
|
||||
async zipCert(cert: CertInfo, filename: string) {
|
||||
const zip = new JSZip();
|
||||
zip.file("证书.pem", cert.crt);
|
||||
zip.file("私钥.pem", cert.key);
|
||||
zip.file("中间证书.pem", cert.ic);
|
||||
zip.file("cert.crt", cert.crt);
|
||||
zip.file("cert.key", cert.key);
|
||||
zip.file("intermediate.crt", cert.ic);
|
||||
zip.file("origin.crt", cert.oc);
|
||||
zip.file("one.pem", cert.one);
|
||||
if (cert.pfx) {
|
||||
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
|
||||
}
|
||||
if (cert.der) {
|
||||
zip.file("cert.der", Buffer.from(cert.der, "base64"));
|
||||
}
|
||||
if (cert.jks) {
|
||||
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" });
|
||||
this.saveFile(filename, content);
|
||||
this.logger.info(`已保存文件:${filename}`);
|
||||
}
|
||||
|
||||
formatCert(pem: string) {
|
||||
pem = pem.replace(/\r/g, "");
|
||||
pem = pem.replace(/\n\n/g, "\n");
|
||||
pem = pem.replace(/\n$/g, "");
|
||||
return pem;
|
||||
}
|
||||
|
||||
formatCerts(cert: { crt: string; key: string; csr: string }) {
|
||||
const newCert: CertInfo = {
|
||||
crt: this.formatCert(cert.crt),
|
||||
key: this.formatCert(cert.key),
|
||||
csr: this.formatCert(cert.csr),
|
||||
};
|
||||
return newCert;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,10 @@
|
||||
import { AbstractTaskPlugin, IContext, NotificationBody, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import { NotificationBody, Step, TaskInput } from "@certd/pipeline";
|
||||
import dayjs from "dayjs";
|
||||
import type { CertInfo } from "./acme.js";
|
||||
import { CertReader } from "./cert-reader.js";
|
||||
import JSZip from "jszip";
|
||||
import { CertConverter } from "./convert.js";
|
||||
import { pick } from "lodash-es";
|
||||
import { CertApplyBaseConvertPlugin } from "./base-convert.js";
|
||||
|
||||
export { CertReader };
|
||||
export type { CertInfo };
|
||||
|
||||
export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: "域名",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
open: false,
|
||||
tokenSeparators: [",", " ", ",", "、", "|"],
|
||||
},
|
||||
rules: [{ type: "domains" }],
|
||||
required: true,
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
order: -999,
|
||||
helper:
|
||||
"1、支持通配符域名,例如: *.foo.com、foo.com、*.test.handsfree.work\n" +
|
||||
"2、支持多个域名、多个子域名、多个通配符域名打到一个证书上(域名必须是在同一个DNS提供商解析)\n" +
|
||||
"3、多级子域名要分成多个域名输入(*.foo.com的证书不能用于xxx.yyy.foo.com、foo.com)\n" +
|
||||
"4、输入一个,空格之后,再输入下一个",
|
||||
})
|
||||
domains!: string[];
|
||||
|
||||
export abstract class CertApplyBasePlugin extends CertApplyBaseConvertPlugin {
|
||||
@TaskInput({
|
||||
title: "邮箱",
|
||||
component: {
|
||||
@@ -46,31 +18,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
})
|
||||
email!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "证书密码",
|
||||
component: {
|
||||
name: "input-password",
|
||||
vModel: "value",
|
||||
},
|
||||
required: false,
|
||||
order: 100,
|
||||
helper: "PFX、jks格式证书是否加密;jks必须设置密码,不传则默认123456",
|
||||
})
|
||||
pfxPassword!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "PFX证书转换参数",
|
||||
value: "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES",
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value",
|
||||
},
|
||||
required: false,
|
||||
order: 100,
|
||||
helper: "兼容Server 2016,如果导入证书失败,请删除此参数",
|
||||
})
|
||||
pfxArgs = "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES";
|
||||
|
||||
@TaskInput({
|
||||
title: "更新天数",
|
||||
value: 35,
|
||||
@@ -102,14 +49,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
// })
|
||||
csrInfo!: string;
|
||||
|
||||
userContext!: IContext;
|
||||
lastStatus!: Step;
|
||||
|
||||
@TaskOutput({
|
||||
title: "域名证书",
|
||||
})
|
||||
cert?: CertInfo;
|
||||
|
||||
async onInstance() {
|
||||
this.userContext = this.ctx.userContext;
|
||||
this.lastStatus = this.ctx.lastStatus as Step;
|
||||
@@ -118,7 +57,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
|
||||
abstract onInit(): Promise<void>;
|
||||
|
||||
abstract doCertApply(): Promise<any>;
|
||||
abstract doCertApply(): Promise<CertReader>;
|
||||
|
||||
async execute(): Promise<string | void> {
|
||||
const oldCert = await this.condition();
|
||||
@@ -129,6 +68,8 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
const cert = await this.doCertApply();
|
||||
if (cert != null) {
|
||||
await this.output(cert, true);
|
||||
|
||||
await this.emitCertApplySuccess();
|
||||
//清空后续任务的状态,让后续任务能够重新执行
|
||||
this.clearLastStatus();
|
||||
|
||||
@@ -140,89 +81,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
async output(certReader: CertReader, isNew: boolean) {
|
||||
const cert: CertInfo = certReader.toCertInfo();
|
||||
this.cert = cert;
|
||||
|
||||
this._result.pipelineVars.certExpiresTime = dayjs(certReader.detail.notAfter).valueOf();
|
||||
if (!this._result.pipelinePrivateVars) {
|
||||
this._result.pipelinePrivateVars = {};
|
||||
}
|
||||
this._result.pipelinePrivateVars.cert = cert;
|
||||
|
||||
if (isNew) {
|
||||
try {
|
||||
const converter = new CertConverter({ logger: this.logger });
|
||||
const res = await converter.convert({
|
||||
cert,
|
||||
pfxPassword: this.pfxPassword,
|
||||
pfxArgs: this.pfxArgs,
|
||||
});
|
||||
if (cert.pfx == null && res.pfx) {
|
||||
cert.pfx = res.pfx;
|
||||
}
|
||||
|
||||
if (cert.der == null && res.der) {
|
||||
cert.der = res.der;
|
||||
}
|
||||
|
||||
if (cert.jks == null && res.jks) {
|
||||
cert.jks = res.jks;
|
||||
}
|
||||
|
||||
this.logger.info("转换证书格式成功");
|
||||
} catch (e) {
|
||||
this.logger.error("转换证书格式失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (isNew) {
|
||||
const zipFileName = certReader.buildCertFileName("zip", certReader.detail.notBefore);
|
||||
await this.zipCert(cert, zipFileName);
|
||||
} else {
|
||||
this.extendsFiles();
|
||||
}
|
||||
}
|
||||
|
||||
async zipCert(cert: CertInfo, filename: string) {
|
||||
const zip = new JSZip();
|
||||
zip.file("证书.pem", cert.crt);
|
||||
zip.file("私钥.pem", cert.key);
|
||||
zip.file("中间证书.pem", cert.ic);
|
||||
zip.file("cert.crt", cert.crt);
|
||||
zip.file("cert.key", cert.key);
|
||||
zip.file("intermediate.crt", cert.ic);
|
||||
zip.file("origin.crt", cert.oc);
|
||||
zip.file("one.pem", cert.one);
|
||||
if (cert.pfx) {
|
||||
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
|
||||
}
|
||||
if (cert.der) {
|
||||
zip.file("cert.der", Buffer.from(cert.der, "base64"));
|
||||
}
|
||||
if (cert.jks) {
|
||||
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" });
|
||||
this.saveFile(filename, content);
|
||||
this.logger.info(`已保存文件:${filename}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否更新证书
|
||||
*/
|
||||
@@ -233,28 +91,10 @@ cert.jks:jks格式证书文件,java服务器使用
|
||||
// return null;
|
||||
// }
|
||||
|
||||
let inputChanged = false;
|
||||
//判断域名有没有变更
|
||||
/**
|
||||
* "renewDays": 35,
|
||||
* "certApplyPlugin": "CertApply",
|
||||
* "sslProvider": "letsencrypt",
|
||||
* "privateKeyType": "rsa_2048_pkcs1",
|
||||
* "dnsProviderType": "aliyun",
|
||||
* "domains": [
|
||||
* "*.handsfree.work"
|
||||
* ],
|
||||
* "email": "xiaojunnuo@qq.com",
|
||||
* "dnsProviderAccess": 3,
|
||||
* "useProxy": false,
|
||||
* "skipLocalVerify": false,
|
||||
* "successNotify": true,
|
||||
* "pfxPassword": "123456"
|
||||
*/
|
||||
const checkInputChanges = ["domains", "sslProvider", "privateKeyType", "dnsProviderType", "pfxPassword"];
|
||||
const oldInput = JSON.stringify(pick(this.lastStatus?.input, checkInputChanges));
|
||||
const thisInput = JSON.stringify(pick(this, checkInputChanges));
|
||||
inputChanged = oldInput !== thisInput;
|
||||
const inputChanged = oldInput !== thisInput;
|
||||
|
||||
this.logger.info(`旧参数:${oldInput}`);
|
||||
this.logger.info(`新参数:${thisInput}`);
|
||||
@@ -262,11 +102,12 @@ cert.jks:jks格式证书文件,java服务器使用
|
||||
this.logger.info("输入参数变更,准备申请新证书");
|
||||
return null;
|
||||
} else {
|
||||
this.logger.info("输入参数未变更,不需要更新证书");
|
||||
this.logger.info("输入参数未变更,检查证书是否过期");
|
||||
}
|
||||
|
||||
let oldCert: CertReader | undefined = undefined;
|
||||
try {
|
||||
this.logger.info("读取上次证书");
|
||||
oldCert = await this.readLastCert();
|
||||
} catch (e) {
|
||||
this.logger.warn("读取cert失败:", e);
|
||||
@@ -285,25 +126,10 @@ cert.jks:jks格式证书文件,java服务器使用
|
||||
return null;
|
||||
}
|
||||
|
||||
formatCert(pem: string) {
|
||||
pem = pem.replace(/\r/g, "");
|
||||
pem = pem.replace(/\n\n/g, "\n");
|
||||
pem = pem.replace(/\n$/g, "");
|
||||
return pem;
|
||||
}
|
||||
|
||||
formatCerts(cert: { crt: string; key: string; csr: string }) {
|
||||
const newCert: CertInfo = {
|
||||
crt: this.formatCert(cert.crt),
|
||||
key: this.formatCert(cert.key),
|
||||
csr: this.formatCert(cert.csr),
|
||||
};
|
||||
return newCert;
|
||||
}
|
||||
|
||||
async readLastCert(): Promise<CertReader | undefined> {
|
||||
const cert = this.lastStatus?.status?.output?.cert;
|
||||
if (cert == null) {
|
||||
this.logger.info("没有找到上次的证书");
|
||||
return undefined;
|
||||
}
|
||||
return new CertReader(cert);
|
||||
@@ -321,7 +147,7 @@ cert.jks:jks格式证书文件,java服务器使用
|
||||
// 检查有效期
|
||||
const leftDays = dayjs(expires).diff(dayjs(), "day");
|
||||
return {
|
||||
isWillExpire: leftDays < maxDays,
|
||||
isWillExpire: leftDays <= maxDays,
|
||||
leftDays,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CertInfo } from "./acme.js";
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import { crypto } from "@certd/acme-client";
|
||||
import { CertificateInfo, crypto } from "@certd/acme-client";
|
||||
import { ILogger } from "@certd/basic";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
@@ -21,61 +21,54 @@ export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise<void>;
|
||||
export type HandleOpts = { logger: ILogger; handle: CertReaderHandle };
|
||||
export class CertReader {
|
||||
cert: CertInfo;
|
||||
oc: string; //仅证书,非fullchain证书
|
||||
crt: string;
|
||||
key: string;
|
||||
csr: string;
|
||||
ic: string; //中间证书
|
||||
one: string; //crt + key 合成一个pem文件
|
||||
|
||||
detail: any;
|
||||
detail: CertificateInfo;
|
||||
//毫秒时间戳
|
||||
expires: number;
|
||||
constructor(certInfo: CertInfo) {
|
||||
this.cert = certInfo;
|
||||
this.crt = certInfo.crt;
|
||||
this.key = certInfo.key;
|
||||
this.csr = certInfo.csr;
|
||||
|
||||
this.ic = certInfo.ic;
|
||||
if (!this.ic) {
|
||||
this.ic = this.getIc();
|
||||
this.cert.ic = this.ic;
|
||||
if (!certInfo.ic) {
|
||||
this.cert.ic = this.getIc();
|
||||
}
|
||||
|
||||
this.oc = certInfo.oc;
|
||||
if (!this.oc) {
|
||||
this.oc = this.getOc();
|
||||
this.cert.oc = this.oc;
|
||||
if (!certInfo.oc) {
|
||||
this.cert.oc = this.getOc();
|
||||
}
|
||||
|
||||
this.one = certInfo.one;
|
||||
if (!this.one) {
|
||||
this.one = this.crt + "\n" + this.key;
|
||||
this.cert.one = this.one;
|
||||
if (!certInfo.one) {
|
||||
this.cert.one = this.cert.crt + "\n" + this.cert.key;
|
||||
}
|
||||
|
||||
const { detail, expires } = this.getCrtDetail(this.cert.crt);
|
||||
this.detail = detail;
|
||||
this.expires = expires.getTime();
|
||||
try {
|
||||
const { detail, expires } = this.getCrtDetail(this.cert.crt);
|
||||
this.detail = detail;
|
||||
this.expires = expires.getTime();
|
||||
} catch (e) {
|
||||
throw new Error("证书解析失败:" + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
getIc() {
|
||||
//中间证书ic, 就是crt的第一个 -----END CERTIFICATE----- 之后的内容
|
||||
const endStr = "-----END CERTIFICATE-----";
|
||||
const firstBlockEndIndex = this.crt.indexOf(endStr);
|
||||
const firstBlockEndIndex = this.cert.crt.indexOf(endStr);
|
||||
|
||||
const start = firstBlockEndIndex + endStr.length + 1;
|
||||
if (this.crt.length <= start) {
|
||||
if (this.cert.crt.length <= start) {
|
||||
return "";
|
||||
}
|
||||
const ic = this.crt.substring(start);
|
||||
return ic.trim();
|
||||
const ic = this.cert.crt.substring(start);
|
||||
if (ic == null) {
|
||||
return "";
|
||||
}
|
||||
return ic?.trim();
|
||||
}
|
||||
|
||||
getOc() {
|
||||
//原始证书 就是crt的第一个 -----END CERTIFICATE----- 之前的内容
|
||||
const endStr = "-----END CERTIFICATE-----";
|
||||
const arr = this.crt.split(endStr);
|
||||
const arr = this.cert.crt.split(endStr);
|
||||
return arr[0] + endStr;
|
||||
}
|
||||
|
||||
@@ -147,10 +140,11 @@ export class CertReader {
|
||||
tmpOnePath,
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error("处理失败", err);
|
||||
throw err;
|
||||
} finally {
|
||||
//删除临时文件
|
||||
logger.info("删除临时文件");
|
||||
logger.info("清理临时文件");
|
||||
function removeFile(filepath?: string) {
|
||||
if (filepath) {
|
||||
fs.unlinkSync(filepath);
|
||||
@@ -167,7 +161,7 @@ export class CertReader {
|
||||
}
|
||||
}
|
||||
|
||||
buildCertFileName(suffix: string, applyTime: number, prefix = "cert") {
|
||||
buildCertFileName(suffix: string, applyTime: any, prefix = "cert") {
|
||||
const detail = this.getCrtDetail();
|
||||
let domain = detail.detail.domains.commonName;
|
||||
domain = domain.replace(".", "_").replace("*", "_");
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import type { CertInfo } from "../acme.js";
|
||||
import { CertReader } from "../cert-reader.js";
|
||||
import { CertApplyBaseConvertPlugin } from "../base-convert.js";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export { CertReader };
|
||||
export type { CertInfo };
|
||||
@IsTaskPlugin({
|
||||
name: "CertApplyUpload",
|
||||
icon: "ph:certificate",
|
||||
title: "证书手动上传",
|
||||
group: pluginGroups.cert.key,
|
||||
desc: "在证书仓库手动上传后触发部署证书",
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.AlwaysRun,
|
||||
},
|
||||
},
|
||||
shortcut: {
|
||||
certUpdate: {
|
||||
title: "更新证书",
|
||||
icon: "ion:upload",
|
||||
action: "onCertUpdate",
|
||||
form: {
|
||||
columns: {
|
||||
crt: {
|
||||
title: "证书",
|
||||
type: "text",
|
||||
form: {
|
||||
component: {
|
||||
name: "pem-input",
|
||||
vModel: "modelValue",
|
||||
textarea: {
|
||||
rows: 4,
|
||||
placeholder: "-----BEGIN CERTIFICATE-----\n...\n...\n-----END CERTIFICATE-----",
|
||||
},
|
||||
},
|
||||
rules: [{ required: true, message: "此项必填" }],
|
||||
col: { span: 24 },
|
||||
},
|
||||
},
|
||||
key: {
|
||||
title: "私钥",
|
||||
type: "text",
|
||||
form: {
|
||||
component: {
|
||||
name: "pem-input",
|
||||
vModel: "modelValue",
|
||||
textarea: {
|
||||
rows: 4,
|
||||
placeholder: "-----BEGIN PRIVATE KEY-----\n...\n...\n-----END PRIVATE KEY----- ",
|
||||
},
|
||||
},
|
||||
rules: [{ required: true, message: "此项必填" }],
|
||||
col: { span: 24 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
export class CertApplyUploadPlugin extends CertApplyBaseConvertPlugin {
|
||||
@TaskInput({
|
||||
title: "手动上传证书",
|
||||
component: {
|
||||
name: "cert-info-updater",
|
||||
vModel: "modelValue",
|
||||
},
|
||||
helper: "手动上传证书",
|
||||
order: -9999,
|
||||
required: true,
|
||||
mergeScript: `
|
||||
return {
|
||||
component:{
|
||||
on:{
|
||||
updated(scope){
|
||||
scope.form.input.domains = scope.$event?.domains
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
})
|
||||
uploadCert!: CertInfo;
|
||||
|
||||
@TaskOutput({
|
||||
title: "证书MD5",
|
||||
})
|
||||
certMd5?: string;
|
||||
|
||||
async onInstance() {
|
||||
this.accessService = this.ctx.accessService;
|
||||
this.logger = this.ctx.logger;
|
||||
this.userContext = this.ctx.userContext;
|
||||
this.lastStatus = this.ctx.lastStatus as Step;
|
||||
}
|
||||
async onInit(): Promise<void> {}
|
||||
|
||||
async getCertFromStore() {
|
||||
const certReader = new CertReader(this.uploadCert);
|
||||
if (!certReader.expires && certReader.expires < new Date().getTime()) {
|
||||
throw new Error("证书已过期,停止部署,请重新上传证书");
|
||||
}
|
||||
|
||||
return certReader;
|
||||
}
|
||||
|
||||
async execute(): Promise<string | void> {
|
||||
const certReader = await this.getCertFromStore();
|
||||
const crtMd5 = this.ctx.utils.hash.md5(certReader.cert.crt);
|
||||
|
||||
const leftDays = dayjs(certReader.expires).diff(dayjs(), "day");
|
||||
this.logger.info(`证书过期时间${dayjs(certReader.expires).format("YYYY-MM-DD HH:mm:ss")},剩余${leftDays}天`);
|
||||
|
||||
if (!this.ctx.inputChanged) {
|
||||
this.logger.info("输入参数无变化");
|
||||
const lastCrtMd5 = this.lastStatus?.status?.output?.certMd5;
|
||||
this.logger.info("证书MD5", crtMd5);
|
||||
this.logger.info("上次证书MD5", lastCrtMd5);
|
||||
if (lastCrtMd5 === crtMd5) {
|
||||
this.logger.info("证书无变化,跳过");
|
||||
//输出证书MD5
|
||||
this.certMd5 = crtMd5;
|
||||
await this.output(certReader, false);
|
||||
return "skip";
|
||||
}
|
||||
this.logger.info("证书有变化,重新部署");
|
||||
} else {
|
||||
this.logger.info("输入参数有变化,重新部署");
|
||||
}
|
||||
|
||||
this.clearLastStatus();
|
||||
//输出证书MD5
|
||||
this.certMd5 = crtMd5;
|
||||
await this.output(certReader, true);
|
||||
|
||||
//必须output之后执行
|
||||
await this.emitCertApplySuccess();
|
||||
return;
|
||||
}
|
||||
|
||||
async onCertUpdate(data: any) {
|
||||
const certReader = new CertReader(data);
|
||||
return {
|
||||
input: {
|
||||
uploadCert: {
|
||||
crt: data.crt,
|
||||
key: data.key,
|
||||
},
|
||||
domains: certReader.getAllDomains(),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
new CertApplyUploadPlugin();
|
||||
@@ -1,7 +1,7 @@
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { CancelError, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { utils } from "@certd/basic";
|
||||
|
||||
import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js";
|
||||
import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, HttpVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js";
|
||||
import { AcmeService } from "./acme.js";
|
||||
import * as _ from "lodash-es";
|
||||
import { createDnsProvider, DnsProviderContext, IDnsProvider } from "../../dns-provider/index.js";
|
||||
@@ -9,20 +9,28 @@ import { CertReader } from "./cert-reader.js";
|
||||
import { CertApplyBasePlugin } from "./base.js";
|
||||
import { GoogleClient } from "../../libs/google.js";
|
||||
import { EabAccess } from "../../access";
|
||||
import { CancelError } from "@certd/pipeline";
|
||||
|
||||
import { httpChallengeUploaderFactory } from "./uploads/factory.js";
|
||||
export * from "./base.js";
|
||||
export type { CertInfo };
|
||||
export * from "./cert-reader.js";
|
||||
export type CnameRecordInput = {
|
||||
id: number;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type HttpRecordInput = {
|
||||
domain: string;
|
||||
httpUploaderType: string;
|
||||
httpUploaderAccess: number;
|
||||
httpUploadRootDir: string;
|
||||
};
|
||||
export type DomainVerifyPlanInput = {
|
||||
domain: string;
|
||||
type: "cname" | "dns";
|
||||
type: "cname" | "dns" | "http";
|
||||
dnsProviderType?: string;
|
||||
dnsProviderAccessId?: number;
|
||||
cnameVerifyPlan?: Record<string, CnameRecordInput>;
|
||||
httpVerifyPlan?: Record<string, HttpRecordInput>;
|
||||
};
|
||||
export type DomainsVerifyPlanInput = {
|
||||
[key: string]: DomainVerifyPlanInput;
|
||||
@@ -54,11 +62,13 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
options: [
|
||||
{ value: "dns", label: "DNS直接验证" },
|
||||
{ value: "cname", label: "CNAME代理验证" },
|
||||
{ value: "http", label: "HTTP文件验证" },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
helper:
|
||||
"DNS直接验证:域名是在阿里云、腾讯云、华为云、Cloudflare、NameSilo、西数注册的,选它。\nCNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录",
|
||||
helper: `DNS直接验证:域名是在阿里云、腾讯云、华为云、Cloudflare、NameSilo、西数、dns.la注册的,选它;
|
||||
CNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录;
|
||||
HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
})
|
||||
challengeType!: string;
|
||||
|
||||
@@ -122,9 +132,8 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
component: {
|
||||
name: "domains-verify-plan-editor",
|
||||
},
|
||||
rules: [{ type: "checkCnameVerifyPlan" }],
|
||||
rules: [{ type: "checkDomainVerifyPlan" }],
|
||||
required: true,
|
||||
helper: "如果选择CNAME方式,请按照上面的显示,给要申请证书的域名添加CNAME记录,添加后,点击验证,验证成功后不要删除记录,申请和续期证书会一直用它",
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
@@ -132,10 +141,20 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
component:{
|
||||
domains: ctx.compute(({form})=>{
|
||||
return form.domains
|
||||
}),
|
||||
defaultType: ctx.compute(({form})=>{
|
||||
return form.challengeType || 'cname'
|
||||
})
|
||||
},
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.challengeType === 'cname'
|
||||
return form.challengeType === 'cname' || form.challengeType === 'http'
|
||||
}),
|
||||
helper: ctx.compute(({form})=>{
|
||||
if(form.challengeType === 'cname' ){
|
||||
return '请按照上面的提示,给要申请证书的域名添加CNAME记录,添加后,点击验证,验证成功后不要删除记录,申请和续期证书会一直用它'
|
||||
}else if (form.challengeType === 'http'){
|
||||
return '请按照上面的提示,给每个域名设置文件上传配置,证书申请过程中会上传校验文件到网站根目录下'
|
||||
}
|
||||
})
|
||||
}
|
||||
`,
|
||||
@@ -184,8 +203,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
},
|
||||
maybeNeed: true,
|
||||
required: false,
|
||||
helper:
|
||||
"google服务账号授权与EAB授权选填其中一个,[服务账号授权获取方法](https://certd.docmirror.cn/guide/use/google/)\n服务账号授权需要配置代理或者服务器本身在海外",
|
||||
helper: "google服务账号授权与EAB授权选填其中一个,[服务账号授权获取方法](https://certd.docmirror.cn/guide/use/google/)\n服务账号授权需要配置代理或者服务器本身在海外",
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
@@ -213,7 +231,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
// { value: "ec_521", label: "EC 521" },
|
||||
],
|
||||
},
|
||||
helper: "如无特殊需求,默认即可",
|
||||
helper: "如无特殊需求,默认即可\n选择RSA 2048 pkcs1可以获得旧版RSA证书",
|
||||
required: true,
|
||||
})
|
||||
privateKeyType!: PrivateKeyType;
|
||||
@@ -249,6 +267,17 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
})
|
||||
skipLocalVerify = false;
|
||||
|
||||
@TaskInput({
|
||||
title: "检查解析重试次数",
|
||||
value: 35,
|
||||
component: {
|
||||
name: "a-input-number",
|
||||
vModel: "value",
|
||||
},
|
||||
helper: "检查域名验证解析记录重试次数,如果你的域名服务商解析生效速度慢,可以适当增加此值",
|
||||
})
|
||||
maxCheckRetryCount = 35;
|
||||
|
||||
acme!: AcmeService;
|
||||
|
||||
eab!: EabAccess;
|
||||
@@ -295,6 +324,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
reverseProxy: this.reverseProxy,
|
||||
privateKeyType: this.privateKeyType,
|
||||
signal: this.ctx.signal,
|
||||
maxCheckRetryCount: this.maxCheckRetryCount,
|
||||
// cnameProxyService: this.ctx.cnameProxyService,
|
||||
// dnsProviderCreator: this.createDnsProvider.bind(this),
|
||||
});
|
||||
@@ -320,9 +350,9 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
);
|
||||
this.logger.info("开始申请证书,", email, domains);
|
||||
|
||||
let dnsProvider: any = null;
|
||||
let dnsProvider: IDnsProvider = null;
|
||||
let domainsVerifyPlan: DomainsVerifyPlan = null;
|
||||
if (this.challengeType === "cname") {
|
||||
if (this.challengeType === "cname" || this.challengeType === "http") {
|
||||
domainsVerifyPlan = await this.createDomainsVerifyPlan();
|
||||
} else {
|
||||
const dnsProviderType = this.dnsProviderType;
|
||||
@@ -370,10 +400,11 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
const domainVerifyPlan = this.domainsVerifyPlan[domain];
|
||||
let dnsProvider = null;
|
||||
const cnameVerifyPlan: Record<string, CnameVerifyPlan> = {};
|
||||
const httpVerifyPlan: Record<string, HttpVerifyPlan> = {};
|
||||
if (domainVerifyPlan.type === "dns") {
|
||||
const access = await this.ctx.accessService.getById(domainVerifyPlan.dnsProviderAccessId);
|
||||
dnsProvider = await this.createDnsProvider(domainVerifyPlan.dnsProviderType, access);
|
||||
} else {
|
||||
} else if (domainVerifyPlan.type === "cname") {
|
||||
for (const key in domainVerifyPlan.cnameVerifyPlan) {
|
||||
const cnameRecord = await this.ctx.cnameProxyService.getByDomain(key);
|
||||
let dnsProvider = cnameRecord.commonDnsProvider;
|
||||
@@ -381,17 +412,44 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
dnsProvider = await this.createDnsProvider(cnameRecord.cnameProvider.dnsProviderType, cnameRecord.cnameProvider.access);
|
||||
}
|
||||
cnameVerifyPlan[key] = {
|
||||
type: "cname",
|
||||
domain: cnameRecord.cnameProvider.domain,
|
||||
fullRecord: cnameRecord.recordValue,
|
||||
dnsProvider,
|
||||
};
|
||||
}
|
||||
} else if (domainVerifyPlan.type === "http") {
|
||||
const httpUploaderContext = {
|
||||
accessService: this.ctx.accessService,
|
||||
logger: this.logger,
|
||||
utils,
|
||||
};
|
||||
for (const key in domainVerifyPlan.httpVerifyPlan) {
|
||||
const httpRecord = domainVerifyPlan.httpVerifyPlan[key];
|
||||
const access = await this.ctx.accessService.getById(httpRecord.httpUploaderAccess);
|
||||
let rootDir = httpRecord.httpUploadRootDir;
|
||||
if (!rootDir.endsWith("/") && !rootDir.endsWith("\\")) {
|
||||
rootDir = rootDir + "/";
|
||||
}
|
||||
this.logger.info("上传方式", httpRecord.httpUploaderType);
|
||||
const httpUploader = await httpChallengeUploaderFactory.createUploaderByType(httpRecord.httpUploaderType, {
|
||||
access,
|
||||
rootDir: rootDir,
|
||||
ctx: httpUploaderContext,
|
||||
});
|
||||
httpVerifyPlan[key] = {
|
||||
type: "http",
|
||||
domain: key,
|
||||
httpUploader,
|
||||
};
|
||||
}
|
||||
}
|
||||
plan[domain] = {
|
||||
domain,
|
||||
type: domainVerifyPlan.type,
|
||||
dnsProvider,
|
||||
cnameVerifyPlan,
|
||||
httpVerifyPlan,
|
||||
};
|
||||
}
|
||||
return plan;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { IAccessService } from "@certd/pipeline";
|
||||
import { ILogger, utils } from "@certd/basic";
|
||||
|
||||
export type HttpChallengeUploader = {
|
||||
upload: (fileName: string, fileContent: Buffer) => Promise<void>;
|
||||
remove: (fileName: string) => Promise<void>;
|
||||
};
|
||||
|
||||
export type HttpChallengeUploadContext = {
|
||||
accessService: IAccessService;
|
||||
logger: ILogger;
|
||||
utils: typeof utils;
|
||||
};
|
||||
|
||||
export abstract class BaseHttpChallengeUploader<A> implements HttpChallengeUploader {
|
||||
rootDir: string;
|
||||
access: A = null;
|
||||
logger: ILogger;
|
||||
utils: typeof utils;
|
||||
ctx: HttpChallengeUploadContext;
|
||||
protected constructor(opts: { rootDir: string; access: A }) {
|
||||
this.rootDir = opts.rootDir;
|
||||
this.access = opts.access;
|
||||
}
|
||||
|
||||
async setCtx(ctx: any) {
|
||||
// set context
|
||||
this.ctx = ctx;
|
||||
this.logger = ctx.logger;
|
||||
this.utils = ctx.utils;
|
||||
}
|
||||
|
||||
abstract remove(fileName: string): Promise<void>;
|
||||
abstract upload(fileName: string, fileContent: Buffer): Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { HttpChallengeUploadContext } from "./api";
|
||||
|
||||
export class HttpChallengeUploaderFactory {
|
||||
async getClassByType(type: string) {
|
||||
if (type === "alioss") {
|
||||
const module = await import("./impls/alioss.js");
|
||||
return module.AliossHttpChallengeUploader;
|
||||
} else if (type === "ssh") {
|
||||
const module = await import("./impls/ssh.js");
|
||||
return module.SshHttpChallengeUploader;
|
||||
} else if (type === "sftp") {
|
||||
const module = await import("./impls/sftp.js");
|
||||
return module.SftpHttpChallengeUploader;
|
||||
} else if (type === "ftp") {
|
||||
const module = await import("./impls/ftp.js");
|
||||
return module.FtpHttpChallengeUploader;
|
||||
} else if (type === "tencentcos") {
|
||||
const module = await import("./impls/tencentcos.js");
|
||||
return module.TencentCosHttpChallengeUploader;
|
||||
} else if (type === "qiniuoss") {
|
||||
const module = await import("./impls/qiniuoss.js");
|
||||
return module.QiniuOssHttpChallengeUploader;
|
||||
} else {
|
||||
throw new Error(`暂不支持此文件上传方式: ${type}`);
|
||||
}
|
||||
}
|
||||
async createUploaderByType(type: string, opts: { rootDir: string; access: any; ctx: HttpChallengeUploadContext }) {
|
||||
const cls = await this.getClassByType(type);
|
||||
if (cls) {
|
||||
// @ts-ignore
|
||||
const instance = new cls(opts);
|
||||
await instance.setCtx(opts.ctx);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const httpChallengeUploaderFactory = new HttpChallengeUploaderFactory();
|
||||
@@ -0,0 +1,39 @@
|
||||
import { BaseHttpChallengeUploader } from "../api.js";
|
||||
import { AliossAccess, AliyunAccess } from "@certd/plugin-lib";
|
||||
import { AliossClient } from "@certd/plugin-lib";
|
||||
|
||||
export class AliossHttpChallengeUploader extends BaseHttpChallengeUploader<AliossAccess> {
|
||||
async upload(filePath: string, fileContent: Buffer) {
|
||||
const aliyunAccess = await this.ctx.accessService.getById<AliyunAccess>(this.access.accessId);
|
||||
const client = new AliossClient({
|
||||
access: aliyunAccess,
|
||||
bucket: this.access.bucket,
|
||||
region: this.access.region,
|
||||
});
|
||||
|
||||
const key = this.rootDir + filePath;
|
||||
this.logger.info(`开始上传文件: ${key}`);
|
||||
await client.uploadFile(key, fileContent);
|
||||
|
||||
this.logger.info(`校验文件上传成功: ${filePath}`);
|
||||
}
|
||||
|
||||
async remove(filePath: string) {
|
||||
const key = this.rootDir + filePath;
|
||||
// remove file from alioss
|
||||
const client = await this.getAliossClient();
|
||||
await client.removeFile(key);
|
||||
this.logger.info(`文件删除成功: ${key}`);
|
||||
}
|
||||
|
||||
private async getAliossClient() {
|
||||
const aliyunAccess = await this.ctx.accessService.getById<AliyunAccess>(this.access.accessId);
|
||||
const client = new AliossClient({
|
||||
access: aliyunAccess,
|
||||
bucket: this.access.bucket,
|
||||
region: this.access.region,
|
||||
});
|
||||
await client.init();
|
||||
return client;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { BaseHttpChallengeUploader } from "../api.js";
|
||||
import { FtpAccess, FtpClient } from "@certd/plugin-lib";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import fs from "fs";
|
||||
|
||||
export class FtpHttpChallengeUploader extends BaseHttpChallengeUploader<FtpAccess> {
|
||||
async upload(filePath: string, fileContent: Buffer) {
|
||||
const client = new FtpClient({
|
||||
access: this.access,
|
||||
logger: this.logger,
|
||||
});
|
||||
await client.connect(async (client) => {
|
||||
const tmpFilePath = path.join(os.tmpdir(), "cert", "http", filePath);
|
||||
const dir = path.dirname(tmpFilePath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(tmpFilePath, fileContent);
|
||||
try {
|
||||
// Write file to temp path
|
||||
const path = this.rootDir + filePath;
|
||||
await client.upload(path, tmpFilePath);
|
||||
} finally {
|
||||
// Remove temp file
|
||||
fs.unlinkSync(tmpFilePath);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async remove(filePath: string) {
|
||||
const client = new FtpClient({
|
||||
access: this.access,
|
||||
logger: this.logger,
|
||||
});
|
||||
await client.connect(async (client) => {
|
||||
const path = this.rootDir + filePath;
|
||||
await client.client.remove(path);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { BaseHttpChallengeUploader } from "../api.js";
|
||||
import { QiniuOssAccess, QiniuClient, QiniuAccess } from "@certd/plugin-lib";
|
||||
|
||||
export class QiniuOssHttpChallengeUploader extends BaseHttpChallengeUploader<QiniuOssAccess> {
|
||||
async upload(filePath: string, fileContent: Buffer) {
|
||||
const qiniuAccess = await this.ctx.accessService.getById<QiniuAccess>(this.access.accessId);
|
||||
const client = new QiniuClient({
|
||||
access: qiniuAccess,
|
||||
logger: this.logger,
|
||||
http: this.ctx.utils.http,
|
||||
});
|
||||
if (this.rootDir.endsWith("/")) {
|
||||
this.rootDir = this.rootDir.slice(0, -1);
|
||||
}
|
||||
await client.uploadFile(this.access.bucket, this.rootDir + filePath, fileContent);
|
||||
}
|
||||
|
||||
async remove(filePath: string) {
|
||||
const qiniuAccess = await this.ctx.accessService.getById<QiniuAccess>(this.access.accessId);
|
||||
const client = new QiniuClient({
|
||||
access: qiniuAccess,
|
||||
logger: this.logger,
|
||||
http: this.ctx.utils.http,
|
||||
});
|
||||
|
||||
if (this.rootDir.endsWith("/")) {
|
||||
this.rootDir = this.rootDir.slice(0, -1);
|
||||
}
|
||||
await client.removeFile(this.access.bucket, this.rootDir + filePath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { BaseHttpChallengeUploader } from "../api.js";
|
||||
import { SshAccess, SshClient } from "@certd/plugin-lib";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import fs from "fs";
|
||||
import { SftpAccess } from "@certd/plugin-lib";
|
||||
|
||||
export class SftpHttpChallengeUploader extends BaseHttpChallengeUploader<SftpAccess> {
|
||||
async upload(filePath: string, fileContent: Buffer) {
|
||||
const tmpFilePath = path.join(os.tmpdir(), "cert", "http", filePath);
|
||||
|
||||
// Write file to temp path
|
||||
const dir = path.dirname(tmpFilePath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(tmpFilePath, fileContent);
|
||||
|
||||
const access = await this.ctx.accessService.getById<SshAccess>(this.access.sshAccess);
|
||||
const key = this.rootDir + filePath;
|
||||
try {
|
||||
const client = new SshClient(this.logger);
|
||||
await client.uploadFiles({
|
||||
connectConf: access,
|
||||
mkdirs: true,
|
||||
transports: [
|
||||
{
|
||||
localPath: tmpFilePath,
|
||||
remotePath: key,
|
||||
},
|
||||
],
|
||||
opts: {
|
||||
mode: this.access?.fileMode ?? undefined,
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
// Remove temp file
|
||||
fs.unlinkSync(tmpFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
async remove(filePath: string) {
|
||||
const access = await this.ctx.accessService.getById<SshAccess>(this.access.sshAccess);
|
||||
const client = new SshClient(this.logger);
|
||||
const key = this.rootDir + filePath;
|
||||
await client.removeFiles({
|
||||
connectConf: access,
|
||||
files: [key],
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { BaseHttpChallengeUploader } from "../api.js";
|
||||
import { SshAccess, SshClient } from "@certd/plugin-lib";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import fs from "fs";
|
||||
|
||||
export class SshHttpChallengeUploader extends BaseHttpChallengeUploader<SshAccess> {
|
||||
async upload(filePath: string, fileContent: Buffer) {
|
||||
const tmpFilePath = path.join(os.tmpdir(), "cert", "http", filePath);
|
||||
|
||||
// Write file to temp path
|
||||
const dir = path.dirname(tmpFilePath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(tmpFilePath, fileContent);
|
||||
|
||||
const key = this.rootDir + filePath;
|
||||
try {
|
||||
const client = new SshClient(this.logger);
|
||||
await client.uploadFiles({
|
||||
connectConf: this.access,
|
||||
mkdirs: true,
|
||||
transports: [
|
||||
{
|
||||
localPath: tmpFilePath,
|
||||
remotePath: key,
|
||||
},
|
||||
],
|
||||
});
|
||||
} finally {
|
||||
// Remove temp file
|
||||
fs.unlinkSync(tmpFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
async remove(filePath: string) {
|
||||
const client = new SshClient(this.logger);
|
||||
const key = this.rootDir + filePath;
|
||||
await client.removeFiles({
|
||||
connectConf: this.access,
|
||||
files: [key],
|
||||
});
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user