Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c98b974f7 | ||
|
|
e2aff952f9 | ||
|
|
9d9ae64aff | ||
|
|
22715a430e | ||
|
|
949a69f0dc | ||
|
|
53db97b6f2 | ||
|
|
cd2dcaa859 | ||
|
|
d0463abc26 | ||
|
|
8f1b38ad7d | ||
|
|
e11349b8cc | ||
|
|
2394cc6dd9 | ||
|
|
8209c3d6e1 | ||
|
|
3e001b8ba4 | ||
|
|
41ca198116 | ||
|
|
6eca5dad9b | ||
|
|
c285522500 | ||
|
|
b12f7c54d4 | ||
|
|
b055bbecfc | ||
|
|
a52a6ce8f6 | ||
|
|
fcbf1045fe | ||
|
|
f5cfe054b7 | ||
|
|
5ded5ff2b6 | ||
|
|
8d31346cd3 | ||
|
|
44b41b6a08 | ||
|
|
4420472f8f | ||
|
|
c4497a7018 | ||
|
|
03f1a7bd0e | ||
|
|
97d2b50074 | ||
|
|
2d0b85b305 | ||
|
|
28052c9387 | ||
|
|
c4277350bc | ||
|
|
97160373d6 | ||
|
|
0ce24618a1 | ||
|
|
f60e63fbaf | ||
|
|
2735feb330 | ||
|
|
b6381d79fc | ||
|
|
241b2e5584 | ||
|
|
bb1f232f41 | ||
|
|
f82d3a5fcc | ||
|
|
bbeaf617d1 | ||
|
|
ea7d14c289 | ||
|
|
3272a68ff6 | ||
|
|
b5715d99ff | ||
|
|
3f5ba14fde | ||
|
|
07f0d3b4d6 | ||
|
|
3dbbe72fc1 | ||
|
|
7f006d1359 | ||
|
|
d30f1c4785 | ||
|
|
96e0122b93 | ||
|
|
7786a87b21 | ||
|
|
34476ba14f | ||
|
|
4b942385a8 | ||
|
|
14809127d6 | ||
|
|
bd8b251d6e | ||
|
|
5563abb13a | ||
|
|
51e83e4c38 | ||
|
|
2b1a5296fe | ||
|
|
bded368cbb | ||
|
|
6a649aaca0 | ||
|
|
e971145686 | ||
|
|
bbca449f94 | ||
|
|
e6852c2715 | ||
|
|
47cb523307 | ||
|
|
cbf46b5c48 | ||
|
|
7ed3105d97 | ||
|
|
61b945c08f | ||
|
|
cc60cd4cd1 | ||
|
|
dade599acb | ||
|
|
1070417a36 | ||
|
|
81f676f1ca | ||
|
|
0cf0608d3f | ||
|
|
dac94b64f0 | ||
|
|
8c88092235 | ||
|
|
2a2e963914 | ||
|
|
1b882a2ca4 | ||
|
|
bd9433478a | ||
|
|
32ade8e4a3 | ||
|
|
f2bcdeeb33 | ||
|
|
4099af7f5d | ||
|
|
67f3daae62 | ||
|
|
c72fa68e4c | ||
|
|
1f5cda452c | ||
|
|
5a19d2513d | ||
|
|
c0f8145615 | ||
|
|
2ad14b82fa | ||
|
|
c8bdcdc778 | ||
|
|
15d2bd8484 | ||
|
|
7d4311115c | ||
|
|
3efa0582ef | ||
|
|
7624babc99 | ||
|
|
6cf8f350f5 | ||
|
|
0e08555220 | ||
|
|
fe738fa7d4 | ||
|
|
2439f4ab02 | ||
|
|
75b2b146ce | ||
|
|
1f3c096517 | ||
|
|
d264388c00 | ||
|
|
b8eaeeaa64 | ||
|
|
dba1a486cb | ||
|
|
5408ae6ad8 | ||
|
|
f5430a8925 | ||
|
|
9cc21204b1 | ||
|
|
f911e06a69 | ||
|
|
4a6eab0ce6 | ||
|
|
1d90fadd0c | ||
|
|
1b1a5ec94d | ||
|
|
d67379f297 | ||
|
|
249b98df66 | ||
|
|
aebbb5cc7d | ||
|
|
4f020aa8a5 | ||
|
|
02426c507a | ||
|
|
ffb7ae79eb | ||
|
|
f58f2f3cd6 | ||
|
|
794abc3d7a | ||
|
|
da406014ad | ||
|
|
9842a24a50 | ||
|
|
fb21ec04a6 | ||
|
|
15b74207dd | ||
|
|
6055e9b6ba | ||
|
|
df3e0814c4 | ||
|
|
81f660dc49 | ||
|
|
f56e2a07c6 | ||
|
|
a2fce6cf0b | ||
|
|
ccb5356bfa | ||
|
|
f44084dfd2 | ||
|
|
948d76f98f | ||
|
|
6606f32678 | ||
|
|
6af12d49fc | ||
|
|
9decb49d04 | ||
|
|
69466c1c41 | ||
|
|
adf5163a79 | ||
|
|
b40bc1b487 | ||
|
|
9d30ccf1f0 | ||
|
|
396810eddf | ||
|
|
5dbf6694b1 | ||
|
|
c2df8d3fa3 | ||
|
|
c149662d54 | ||
|
|
ae1c5e38d1 | ||
|
|
718b46141e | ||
|
|
9c8986be10 | ||
|
|
1d12ad73c6 | ||
|
|
30d4fc84a9 | ||
|
|
834e7750ce | ||
|
|
f38522ca0b | ||
|
|
d87821ee02 | ||
|
|
bd9e226c36 | ||
|
|
2809267d7a | ||
|
|
4de24da9d5 | ||
|
|
580981a468 | ||
|
|
5bff2c8fa5 | ||
|
|
338de1f04c | ||
|
|
5e867c86c3 | ||
|
|
07efe717d0 | ||
|
|
2b4c066a2e | ||
|
|
c03e82e4e7 | ||
|
|
a91d7c000a | ||
|
|
faf9828168 | ||
|
|
eadf10f287 | ||
|
|
ec980bf68a | ||
|
|
6f9dffe6e5 | ||
|
|
f61487284f | ||
|
|
483e7c5f51 | ||
|
|
be47d732e0 | ||
|
|
c57110e42a | ||
|
|
e8adaad01f | ||
|
|
4db0f83304 | ||
|
|
2ab23f50b2 | ||
|
|
4df94a4e2b | ||
|
|
97c417b1ad | ||
|
|
c0f194f443 | ||
|
|
e79660c5d1 | ||
|
|
deaf5b7398 | ||
|
|
e4041eabec | ||
|
|
7a1a642dc2 | ||
|
|
555f3a800b | ||
|
|
145784e73c | ||
|
|
f8e492d6cb | ||
|
|
49e04784af | ||
|
|
f843e69a1b | ||
|
|
232ac4317b | ||
|
|
b9dc03cd85 | ||
|
|
1ad7750d8b | ||
|
|
b6c772a326 | ||
|
|
ac5bb63214 | ||
|
|
4d580deeb0 | ||
|
|
cbf337a002 | ||
|
|
15ee6ead49 | ||
|
|
1cc9641f56 | ||
|
|
0cfc3b7ae9 | ||
|
|
fbfe1256a5 | ||
|
|
5074572694 | ||
|
|
e004c34ae3 | ||
|
|
5c0e5c347d | ||
|
|
2935111c6b | ||
|
|
71155eeec5 | ||
|
|
135acb5240 | ||
|
|
5558376bae | ||
|
|
2da560a21f | ||
|
|
bc9a0988a7 | ||
|
|
6a731f986e | ||
|
|
2cb4e551fa | ||
|
|
e5a1844852 | ||
|
|
b8f82ecb5e | ||
|
|
18583f6ce0 | ||
|
|
1468eb1ef2 | ||
|
|
8ab699a910 | ||
|
|
b173311468 | ||
|
|
522dcd8ffb | ||
|
|
6809a35177 | ||
|
|
bd82147496 | ||
|
|
a4224ab1df | ||
|
|
4c4dc8ca46 | ||
|
|
0afabd38c6 | ||
|
|
cacd108802 | ||
|
|
7138243c63 | ||
|
|
73b096a6e5 | ||
|
|
8165a5ff89 | ||
|
|
1017a38eb4 | ||
|
|
80374cae8a | ||
|
|
6339cdffa9 | ||
|
|
96a33bd387 | ||
|
|
1042e599d9 | ||
|
|
1a4f1cb07d | ||
|
|
edb249c2ad | ||
|
|
e9921928df | ||
|
|
fa0c87dec3 | ||
|
|
ba64c2d147 | ||
|
|
cf008b9cff | ||
|
|
3a9069f6e6 | ||
|
|
01abf348d2 | ||
|
|
eae7edbda0 | ||
|
|
d7c6a06b61 | ||
|
|
9d6f7ef0f2 | ||
|
|
0ddb1f69d2 | ||
|
|
4091abdfd7 | ||
|
|
27008cb44a | ||
|
|
b84825eae5 | ||
|
|
1c6ffe8ac6 | ||
|
|
dc0845b2d2 | ||
|
|
7ab502991e | ||
|
|
319f555569 | ||
|
|
0bf323ab97 | ||
|
|
255960d434 | ||
|
|
83a6aed625 | ||
|
|
f1b67049d1 | ||
|
|
8cbca5761e | ||
|
|
a237179a72 | ||
|
|
967846bef5 | ||
|
|
0bf9a2d3da | ||
|
|
18b2d3ac20 | ||
|
|
7d22fe3d7d | ||
|
|
ee67b6c042 | ||
|
|
1cfa76683b | ||
|
|
4662e45e58 | ||
|
|
1fefbdc9ab | ||
|
|
1cb2a57c55 | ||
|
|
246ee83015 | ||
|
|
335ddfc7a5 | ||
|
|
5b500830a1 | ||
|
|
ce4839bd80 | ||
|
|
eee22154e3 | ||
|
|
49007d3915 | ||
|
|
f9b453ca8c | ||
|
|
5f53b81c75 | ||
|
|
9d83adaac8 | ||
|
|
c8c269f612 | ||
|
|
15740904e5 | ||
|
|
85e9ff7a96 | ||
|
|
743617dbda | ||
|
|
89806b828a | ||
|
|
2e530bfdb0 | ||
|
|
83495b3213 | ||
|
|
5108416904 | ||
|
|
5589da1822 | ||
|
|
21e5aed3f3 | ||
|
|
4a88f795e1 | ||
|
|
604fa5be63 | ||
|
|
7ed1be994f | ||
|
|
6cc74a1c0a | ||
|
|
167b303fae | ||
|
|
b91c9e4ea6 | ||
|
|
947fe729cb | ||
|
|
bfb3ee4c43 | ||
|
|
bab1df2c78 | ||
|
|
00eabec771 | ||
|
|
584b7b6f45 | ||
|
|
2312c444ef | ||
|
|
0373d019f8 | ||
|
|
fe09e75b80 | ||
|
|
432c9c6cc1 | ||
|
|
5fc1d55879 | ||
|
|
268cd6cc9c | ||
|
|
20ffe31638 | ||
|
|
02d30067ea | ||
|
|
0ce7808e08 | ||
|
|
d609ee2b7a | ||
|
|
083df61fcc | ||
|
|
a524988be6 | ||
|
|
f2855d6dac | ||
|
|
8517a0b564 | ||
|
|
ec69b8f11b | ||
|
|
4250d0e266 | ||
|
|
edda1b57f3 | ||
|
|
5a7766992d | ||
|
|
02dabe11db | ||
|
|
58024128d8 | ||
|
|
e44bf9d773 | ||
|
|
1114223bda | ||
|
|
55022e5fa6 | ||
|
|
ae732fb298 | ||
|
|
a6ef6996c3 | ||
|
|
97cf5e127b | ||
|
|
690df7373c | ||
|
|
9cc01e5da1 | ||
|
|
0a068a2746 | ||
|
|
85a239ff8c | ||
|
|
a545a28dfb | ||
|
|
ac876a980c | ||
|
|
4b555e8a56 | ||
|
|
1a8d14dc44 | ||
|
|
83263a72d2 | ||
|
|
76f3ba8691 | ||
|
|
072edd7aff | ||
|
|
c0be4d702c | ||
|
|
c3d6db3f1e | ||
|
|
e05ec53eb5 | ||
|
|
8d9dad9c82 | ||
|
|
0071bcb0e4 | ||
|
|
dbdc1ccd1b | ||
|
|
2a606fdb1d | ||
|
|
3b86f30bcf | ||
|
|
7808d028e9 | ||
|
|
04bcf73b8b | ||
|
|
1f8179d519 | ||
|
|
3ffd8946f8 | ||
|
|
c78898e4c1 | ||
|
|
d3e4677ea4 | ||
|
|
d176f9cc0e | ||
|
|
a65366bbe1 | ||
|
|
20cfe74b17 | ||
|
|
b74db81304 | ||
|
|
a8adbda04a | ||
|
|
3e80d30ca6 | ||
|
|
2eb54d50a5 | ||
|
|
6995308c17 | ||
|
|
0738d120ae | ||
|
|
bad6879589 | ||
|
|
b46948c0ba | ||
|
|
3024720fc2 | ||
|
|
cf854c9278 | ||
|
|
608cc2a81f | ||
|
|
396670dc8f | ||
|
|
79f65868ca | ||
|
|
56e5524a0f | ||
|
|
1ae185d0bc | ||
|
|
82276b53a8 | ||
|
|
d5882f16be | ||
|
|
b35e7b0702 | ||
|
|
bce7d95838 | ||
|
|
4d490d0add | ||
|
|
7cff1a9842 | ||
|
|
cfba7b4daa | ||
|
|
4dff48e807 | ||
|
|
8abe0daf20 | ||
|
|
635f069012 | ||
|
|
eeb83f9024 | ||
|
|
b48831e60b | ||
|
|
095791cdc2 | ||
|
|
3e304c497e | ||
|
|
9ffea32176 | ||
|
|
f32c99d4a1 | ||
|
|
1f1b1858c7 | ||
|
|
42fcb91f2e | ||
|
|
01568ca148 | ||
|
|
0d97ad67c5 | ||
|
|
c94a5537a3 | ||
|
|
d88dfc197e | ||
|
|
f709c05c0d | ||
|
|
2c609da7a1 | ||
|
|
d770c7bd08 | ||
|
|
b9ccd4a8a0 | ||
|
|
8875e8059f | ||
|
|
6490366c68 | ||
|
|
c278946771 | ||
|
|
1562d9de36 | ||
|
|
5bb0990abb | ||
|
|
bfd3cacc68 | ||
|
|
c7e1163d59 | ||
|
|
fba7aeb71b | ||
|
|
c66a2bd77a | ||
|
|
ed58ae3c53 | ||
|
|
194463bea9 | ||
|
|
260f5ae777 | ||
|
|
e85d824337 | ||
|
|
e17fc39709 | ||
|
|
da9b297b12 | ||
|
|
807dfcd57a | ||
|
|
0a410db52a | ||
|
|
4501095106 | ||
|
|
bc731e4fb1 | ||
|
|
53561d2755 | ||
|
|
e913fe509c | ||
|
|
a3a215b7ae | ||
|
|
56f2949ac5 | ||
|
|
c1b5a35f90 | ||
|
|
48ab1fbffe | ||
|
|
5f078273b3 | ||
|
|
636338f9ed | ||
|
|
6cbd629777 | ||
|
|
5a07dce759 | ||
|
|
15484bc119 | ||
|
|
d6cd9d136d | ||
|
|
c76815756b | ||
|
|
eef93250ac | ||
|
|
a1c6cf0477 | ||
|
|
14a0ccac93 | ||
|
|
9439743b7e | ||
|
|
acbac6a9c3 | ||
|
|
cc38ccd0e9 | ||
|
|
7d0cf846ac | ||
|
|
f9541fab70 | ||
|
|
8d9870e9c6 | ||
|
|
0f3f8519e0 | ||
|
|
016ae865b1 | ||
|
|
3e9953a74a | ||
|
|
1fc80d2b93 | ||
|
|
b55fe2ef19 | ||
|
|
71030b7e27 | ||
|
|
5e8bdac008 | ||
|
|
56b8c689ec | ||
|
|
454912d314 | ||
|
|
61e3f5761c | ||
|
|
2908569841 | ||
|
|
775226b49f | ||
|
|
e3dacb5b3f | ||
|
|
cdea411136 | ||
|
|
fdb000ee7c | ||
|
|
4a0be1c29d | ||
|
|
892d22e225 | ||
|
|
4958a48b92 | ||
|
|
28bbea85f0 | ||
|
|
73b3a29cfc | ||
|
|
77b8024453 | ||
|
|
1175e1164b | ||
|
|
5546af518e | ||
|
|
99fd3083f2 | ||
|
|
c0df8be832 | ||
|
|
73cab6a6ee | ||
|
|
7a71e45799 | ||
|
|
fdb1d1e6dd | ||
|
|
6dd4d6adeb | ||
|
|
d368f9666a | ||
|
|
ee50458333 | ||
|
|
9792c616b5 | ||
|
|
205a7d134e | ||
|
|
2cbacb4338 | ||
|
|
cdb812ef63 | ||
|
|
ea010f8c9b | ||
|
|
362bbc5f32 | ||
|
|
2e19dda72e | ||
|
|
021155278e | ||
|
|
3db87218ee | ||
|
|
91d5c90eb0 | ||
|
|
f8b71a0e61 | ||
|
|
3e4b7f30ac | ||
|
|
c637985575 | ||
|
|
2960e2459b | ||
|
|
81d6289a86 | ||
|
|
dc1507a5ea | ||
|
|
3d960c3869 | ||
|
|
5d60e6191f | ||
|
|
4b49f8a5a6 | ||
|
|
94459fe922 | ||
|
|
e834e31510 | ||
|
|
4b57a0d729 | ||
|
|
acd440106b | ||
|
|
5096df5cc0 | ||
|
|
3c2d450aa8 | ||
|
|
b083b3cc41 | ||
|
|
6624769032 | ||
|
|
55f75c6051 | ||
|
|
42d9c3ef14 | ||
|
|
c7a9363422 | ||
|
|
969b6e3288 | ||
|
|
03ce030754 | ||
|
|
f2c1e362a0 | ||
|
|
6426aa57a2 | ||
|
|
7ceb0f6306 | ||
|
|
b26a1944c6 | ||
|
|
235aec3e42 | ||
|
|
346fb730a3 | ||
|
|
c87bc22a5f | ||
|
|
7198e24945 | ||
|
|
1a08bd340e | ||
|
|
af9047bf3c | ||
|
|
9566fc4e03 | ||
|
|
41254d10b7 | ||
|
|
ed97f41884 | ||
|
|
02b83ce0ad | ||
|
|
f1d2a1033a | ||
|
|
ba1fe54ef8 | ||
|
|
deac92faf8 | ||
|
|
1c36a79162 | ||
|
|
b6f7042adc | ||
|
|
f721cefb4a | ||
|
|
fc2c947afe | ||
|
|
d0272095cc | ||
|
|
4a09cf289d | ||
|
|
89c23fef35 | ||
|
|
5e59651d45 | ||
|
|
5e72f75395 | ||
|
|
0a77fe0169 | ||
|
|
961abb0f80 | ||
|
|
4efe12d2d3 | ||
|
|
67b05e2d75 | ||
|
|
8edb6f8727 | ||
|
|
b30f02a1fb | ||
|
|
7e2333a63a | ||
|
|
0be66cccbc | ||
|
|
ed26ed196d | ||
|
|
a204f270dd | ||
|
|
7585d7bbd0 | ||
|
|
2981f086c8 | ||
|
|
784ef8a6a4 | ||
|
|
f4bb459b5e | ||
|
|
83a5a21f95 | ||
|
|
85c633fddf | ||
|
|
f9a310b6c3 | ||
|
|
1bdcfe646f |
@@ -1,36 +1,29 @@
|
||||
---
|
||||
name: Plugin Apply
|
||||
about: 部署插件申请支持
|
||||
title: "[Plugin] "
|
||||
title: '[Plugin] '
|
||||
labels: feature
|
||||
---
|
||||
|
||||
> > 感谢您支持certd,请按如下规范提交issue
|
||||
> 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||
> > 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||
|
||||
# 新部署插件申请支持
|
||||
|
||||
## 1. 需求描述
|
||||
`请在此处简要描述你的需求`
|
||||
|
||||
`请在此处简要描述你的需求`
|
||||
|
||||
## 2. 要部署证书应用的信息
|
||||
|
||||
1. 应用名称:
|
||||
|
||||
|
||||
2. 应用网址/项目地址/官方网站:
|
||||
|
||||
|
||||
3. 管理证书界面截图(或者手动部署证书方式介绍及截图):
|
||||
|
||||
|
||||
4. 是否有API接口,接口地址:
|
||||
|
||||
|
||||
5. 如果没有API接口,网页登录是否需要验证码:
|
||||
|
||||
|
||||
6. 是否可以提供测试账号?(如果可以请留下联系方式或者加作者好友)
|
||||
|
||||
|
||||
|
||||
@@ -1,36 +1,29 @@
|
||||
---
|
||||
name: DNS Provider Apply
|
||||
about: 域名提供商申请支持
|
||||
title: "[DNS] "
|
||||
title: '[DNS] '
|
||||
labels: feature
|
||||
---
|
||||
|
||||
|
||||
> 感谢您支持certd,请按如下规范提交issue
|
||||
> 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||
|
||||
# 新域名提供商支持申请
|
||||
|
||||
## 1. 基本信息
|
||||
|
||||
请填写如下内容:
|
||||
|
||||
1. 域名提供商名称:
|
||||
|
||||
|
||||
2. 管理页面地址:
|
||||
|
||||
|
||||
3. 是否有API接口,接口地址:
|
||||
|
||||
|
||||
4. 如果没有API接口,网页登录是否有验证码:
|
||||
|
||||
|
||||
5. 是否可以提供测试账号?(如果可以请留下联系方式或者加作者好友)
|
||||
|
||||
|
||||
|
||||
## 2. 截图
|
||||
|
||||
`域名管理页面截图`
|
||||
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: 错误或问题报告
|
||||
title: "[BUG] "
|
||||
title: '[BUG] '
|
||||
labels: bug
|
||||
---
|
||||
|
||||
|
||||
> 感谢您支持certd,请按如下规范提交issue
|
||||
> 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||
|
||||
# bug提交
|
||||
|
||||
## 1、问题描述
|
||||
|
||||
`请在此处简要描述你所遇到的问题,必要时请贴出相关截图辅助理解和定位`
|
||||
|
||||
### 2、复现步骤
|
||||
|
||||
`请描述复现问题的详细步骤`
|
||||
`如果非示例页面的问题,最好能提供最小复现示例的代码、或者仓库链接`
|
||||
|
||||
|
||||
### 3.报错截图
|
||||
|
||||
`请贴出报错日志截图`
|
||||
|
||||
### 4、效果截图
|
||||
|
||||
`请贴出效果截图`
|
||||
|
||||
#### 4.1. 期望效果
|
||||
|
||||
#### 4.2. 实际效果
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: 新需求、新特性申请支持
|
||||
title: "[Feature] "
|
||||
title: '[Feature] '
|
||||
labels: feature
|
||||
---
|
||||
|
||||
> > 感谢您支持certd,请按如下规范提交issue
|
||||
> 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||
|
||||
> > 如果有条件,请尽量在[github上提交](https://github.com/certd/certd/issues)
|
||||
|
||||
# 新特性申请
|
||||
>注意:这里仅供如果是要申请新的部署插件,请提交插件申请
|
||||
|
||||
> 注意:这里仅供如果是要申请新的部署插件,请提交插件申请
|
||||
|
||||
## 1. 需求描述,需求背景
|
||||
|
||||
`请在此处简要描述你所遇到的问题,必要时请贴出相关截图辅助理解`
|
||||
|
||||
|
||||
## 2. 期望效果
|
||||
|
||||
`必要时可以截图描述你的期望效果`
|
||||
|
||||
|
||||
## 3. 你的解决方案
|
||||
|
||||
`如果你有解决方案,请描述你的方案`
|
||||
|
||||
@@ -3,8 +3,8 @@ on:
|
||||
push:
|
||||
branches: ['v2-dev']
|
||||
paths:
|
||||
- "trigger/build.trigger"
|
||||
workflow_dispatch: # 添加手动触发
|
||||
- 'trigger/build.trigger'
|
||||
workflow_dispatch: # 添加手动触发
|
||||
# schedule:
|
||||
# - # 国际时间 19:17 执行,北京时间3:17 ↙↙↙ 改成你想要每天自动执行的时间
|
||||
# - cron: '17 19 * * *'
|
||||
@@ -37,14 +37,14 @@ jobs:
|
||||
const pkg = JSON.parse(jsonContent)
|
||||
console.log("certd_version:",pkg.version);
|
||||
return pkg.version
|
||||
# - name: Use Node.js
|
||||
# uses: actions/setup-node@v4
|
||||
# with:
|
||||
# node-version: 18
|
||||
# cache: 'npm'
|
||||
# working-directory: ./packages/ui/certd-client
|
||||
# - name: Use Node.js
|
||||
# uses: actions/setup-node@v4
|
||||
# with:
|
||||
# node-version: 18
|
||||
# cache: 'npm'
|
||||
# working-directory: ./packages/ui/certd-client
|
||||
- run: |
|
||||
npm install -g pnpm
|
||||
npm install -g pnpm@10.33.4
|
||||
pnpm install
|
||||
npm run build
|
||||
working-directory: ./packages/ui/certd-client
|
||||
@@ -80,6 +80,8 @@ jobs:
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
provenance: false
|
||||
sbom: false
|
||||
context: ./packages/ui/
|
||||
tags: |
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${{steps.get_certd_version.outputs.result}}
|
||||
|
||||
@@ -3,14 +3,12 @@ on:
|
||||
push:
|
||||
branches: ['v2-dev']
|
||||
paths:
|
||||
- "trigger/deploy.trigger"
|
||||
- 'trigger/deploy.trigger'
|
||||
workflow_run:
|
||||
workflows: [ "build-image" ]
|
||||
workflows: ['build-image']
|
||||
types:
|
||||
- completed
|
||||
workflow_dispatch: # 添加手动触发
|
||||
|
||||
|
||||
workflow_dispatch: # 添加手动触发
|
||||
|
||||
# schedule:
|
||||
# - # 国际时间 19:17 执行,北京时间3:17 ↙↙↙ 改成你想要每天自动执行的时间
|
||||
@@ -28,7 +26,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: v2-dev
|
||||
|
||||
|
||||
- name: get_certd_version
|
||||
id: get_certd_version
|
||||
uses: actions/github-script@v6
|
||||
|
||||
@@ -3,12 +3,12 @@ on:
|
||||
push:
|
||||
branches: ['v2-dev']
|
||||
paths:
|
||||
- "trigger/publish.trigger"
|
||||
- 'trigger/publish.trigger'
|
||||
workflow_run:
|
||||
workflows: [ "build-image-for-release" ]
|
||||
workflows: ['build-image-for-release']
|
||||
types:
|
||||
- completed
|
||||
workflow_dispatch: # 添加手动触发
|
||||
workflow_dispatch: # 添加手动触发
|
||||
# schedule:
|
||||
# - # 国际时间 19:17 执行,北京时间3:17 ↙↙↙ 改成你想要每天自动执行的时间
|
||||
# - cron: '17 19 * * *'
|
||||
@@ -46,11 +46,11 @@ jobs:
|
||||
console.log("certd_version:",pkg.version);
|
||||
return pkg.version
|
||||
- run: |
|
||||
npm install -g pnpm
|
||||
npm install -g pnpm@10.33.4
|
||||
pnpm install
|
||||
npm run build
|
||||
working-directory: ./packages/ui/certd-client
|
||||
|
||||
|
||||
- name: publish_to_atomgit
|
||||
id: publish_to_atomgit
|
||||
run: |
|
||||
@@ -62,4 +62,3 @@ jobs:
|
||||
pnpm install
|
||||
npm run publish_to_atomgit
|
||||
working-directory: ./
|
||||
|
||||
@@ -3,12 +3,12 @@ on:
|
||||
push:
|
||||
branches: ['v2-dev']
|
||||
paths:
|
||||
- "trigger/publish.trigger"
|
||||
- 'trigger/publish.trigger'
|
||||
workflow_run:
|
||||
workflows: [ "build-image-for-release" ]
|
||||
workflows: ['build-image-for-release']
|
||||
types:
|
||||
- completed
|
||||
workflow_dispatch: # 添加手动触发
|
||||
workflow_dispatch: # 添加手动触发
|
||||
# schedule:
|
||||
# - # 国际时间 19:17 执行,北京时间3:17 ↙↙↙ 改成你想要每天自动执行的时间
|
||||
# - cron: '17 19 * * *'
|
||||
@@ -29,14 +29,13 @@ jobs:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
ref: 'v2-dev'
|
||||
|
||||
|
||||
- name: publish_to_gitee
|
||||
id: publish_to_gitee
|
||||
run: |
|
||||
export GITEE_TOKEN=${{ secrets.GITEE_TOKEN }}
|
||||
rm -rf ./pnpm*.yaml
|
||||
npm install -g pnpm
|
||||
npm install -g pnpm@10.33.4
|
||||
pnpm install
|
||||
npm run publish_to_gitee
|
||||
working-directory: ./
|
||||
|
||||
@@ -3,12 +3,12 @@ on:
|
||||
push:
|
||||
branches: ['v2-dev']
|
||||
paths:
|
||||
- "trigger/publish.trigger"
|
||||
- 'trigger/publish.trigger'
|
||||
workflow_run:
|
||||
workflows: [ "build-image-for-release" ]
|
||||
workflows: ['build-image-for-release']
|
||||
types:
|
||||
- completed
|
||||
workflow_dispatch: # 添加手动触发
|
||||
workflow_dispatch: # 添加手动触发
|
||||
# schedule:
|
||||
# - # 国际时间 19:17 执行,北京时间3:17 ↙↙↙ 改成你想要每天自动执行的时间
|
||||
# - cron: '17 19 * * *'
|
||||
@@ -29,14 +29,13 @@ jobs:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
ref: 'v2-dev'
|
||||
|
||||
|
||||
- name: publish_to_github
|
||||
id: publish_to_github
|
||||
run: |
|
||||
export GITHUB_TOKEN=${{ secrets.GH_TOKEN }}
|
||||
rm -rf ./pnpm*.yaml
|
||||
npm install -g pnpm
|
||||
npm install -g pnpm@10.33.4
|
||||
pnpm install
|
||||
npm run publish_to_github
|
||||
working-directory: ./
|
||||
|
||||
@@ -3,8 +3,8 @@ on:
|
||||
push:
|
||||
branches: ['v2-dev']
|
||||
paths:
|
||||
- "trigger/release.trigger"
|
||||
workflow_dispatch: # 添加手动触发
|
||||
- 'trigger/release.trigger'
|
||||
workflow_dispatch: # 添加手动触发
|
||||
# workflow_run:
|
||||
# workflows: [ "deploy-demo" ]
|
||||
# types:
|
||||
@@ -43,14 +43,14 @@ jobs:
|
||||
const pkg = JSON.parse(jsonContent)
|
||||
console.log("certd_version:",pkg.version);
|
||||
return pkg.version
|
||||
# - name: Use Node.js
|
||||
# uses: actions/setup-node@v4
|
||||
# with:
|
||||
# node-version: 18
|
||||
# cache: 'npm'
|
||||
# working-directory: ./packages/ui/certd-client
|
||||
# - name: Use Node.js
|
||||
# uses: actions/setup-node@v4
|
||||
# with:
|
||||
# node-version: 18
|
||||
# cache: 'npm'
|
||||
# working-directory: ./packages/ui/certd-client
|
||||
- run: |
|
||||
npm install -g pnpm
|
||||
npm install -g pnpm@10.33.4
|
||||
pnpm install
|
||||
npm run build
|
||||
working-directory: ./packages/ui/certd-client
|
||||
@@ -86,39 +86,71 @@ jobs:
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
provenance: false
|
||||
sbom: false
|
||||
context: ./packages/ui/
|
||||
tags: |
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${{steps.get_certd_version.outputs.result}}
|
||||
registry.cn-shenzhen.aliyuncs.com/certd/certd:latest
|
||||
registry.cn-shenzhen.aliyuncs.com/certd/certd:${{steps.get_certd_version.outputs.result}}
|
||||
greper/certd:latest
|
||||
greper/certd:${{steps.get_certd_version.outputs.result}}
|
||||
ghcr.io/${{ github.repository }}:latest
|
||||
ghcr.io/${{ github.repository }}:${{steps.get_certd_version.outputs.result}}
|
||||
- name: Build slim
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
provenance: false
|
||||
sbom: false
|
||||
context: ./packages/ui/
|
||||
build-args: |
|
||||
base_type=slim
|
||||
tags: |
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:slim
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${{steps.get_certd_version.outputs.result}}-slim
|
||||
registry.cn-shenzhen.aliyuncs.com/certd/certd:slim
|
||||
registry.cn-shenzhen.aliyuncs.com/certd/certd:${{steps.get_certd_version.outputs.result}}-slim
|
||||
greper/certd:slim
|
||||
greper/certd:${{steps.get_certd_version.outputs.result}}-slim
|
||||
ghcr.io/${{ github.repository }}:slim
|
||||
ghcr.io/${{ github.repository }}:${{steps.get_certd_version.outputs.result}}-slim
|
||||
|
||||
- name: Build armv7
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/arm/v7
|
||||
push: true
|
||||
provenance: false
|
||||
sbom: false
|
||||
context: ./packages/ui/
|
||||
tags: |
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:armv7
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
registry.cn-shenzhen.aliyuncs.com/certd/certd:armv7
|
||||
registry.cn-shenzhen.aliyuncs.com/certd/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
greper/certd:armv7
|
||||
greper/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
ghcr.io/${{ github.repository }}:armv7
|
||||
ghcr.io/${{ github.repository }}:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
|
||||
# - name: Build agent
|
||||
# uses: docker/build-push-action@v6
|
||||
# with:
|
||||
# platforms: linux/amd64,linux/arm64
|
||||
# push: true
|
||||
# context: ./packages/ui/agent/
|
||||
# tags: |
|
||||
# registry.cn-shenzhen.aliyuncs.com/handsfree/certd-agent:latest
|
||||
# registry.cn-shenzhen.aliyuncs.com/handsfree/certd-agent:${{steps.get_certd_version.outputs.result}}
|
||||
# greper/certd-agent:latest
|
||||
# greper/certd-agent:${{steps.get_certd_version.outputs.result}}
|
||||
- name: Login to Certd Docker Hub account
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.dockerhub_username2 }}
|
||||
password: ${{ secrets.dockerhub_password2 }}
|
||||
|
||||
- name: Publish to certd Docker Hub repository
|
||||
run: |
|
||||
docker buildx imagetools create --tag certd/certd:latest greper/certd:latest
|
||||
docker buildx imagetools create --tag certd/certd:${{ steps.get_certd_version.outputs.result }} greper/certd:${{ steps.get_certd_version.outputs.result }}
|
||||
docker buildx imagetools create --tag certd/certd:slim greper/certd:slim
|
||||
docker buildx imagetools create --tag certd/certd:${{ steps.get_certd_version.outputs.result }}-slim greper/certd:${{ steps.get_certd_version.outputs.result }}-slim
|
||||
docker buildx imagetools create --tag certd/certd:armv7 greper/certd:armv7
|
||||
docker buildx imagetools create --tag certd/certd:${{ steps.get_certd_version.outputs.result }}-armv7 greper/certd:${{ steps.get_certd_version.outputs.result }}-armv7
|
||||
|
||||
- name: deploy-certd-doc
|
||||
uses: tyrrrz/action-http-request@prime
|
||||
with:
|
||||
@@ -132,4 +164,3 @@ jobs:
|
||||
Content-Type: application/json
|
||||
retry-count: 3
|
||||
retry-delay: 5000
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
name: stable-release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "版本号(如 1.42.5)"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
make-stable:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to aliyun container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.cn-shenzhen.aliyuncs.com
|
||||
username: ${{ secrets.aliyun_cs_username }}
|
||||
password: ${{ secrets.aliyun_cs_password }}
|
||||
|
||||
- name: Login to GitHub Packages
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.dockerhub_username2 }}
|
||||
password: ${{ secrets.dockerhub_password2 }}
|
||||
|
||||
# stable 镜像:叠加 ENV 层
|
||||
- name: Build and push stable images
|
||||
run: |
|
||||
echo "FROM greper/certd:${{ inputs.version }}
|
||||
ENV certd_release_mode=stable" > Dockerfile.stable
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--provenance=false \
|
||||
--sbom=false \
|
||||
--push \
|
||||
-f Dockerfile.stable \
|
||||
-t registry.cn-shenzhen.aliyuncs.com/handsfree/certd:stable \
|
||||
-t registry.cn-shenzhen.aliyuncs.com/certd/certd:stable \
|
||||
-t certd/certd:stable \
|
||||
-t ghcr.io/${{ github.repository }}:stable \
|
||||
.
|
||||
|
||||
# slim-stable 镜像
|
||||
- name: Build and push slim-stable images
|
||||
run: |
|
||||
echo "FROM greper/certd:${{ inputs.version }}-slim
|
||||
ENV certd_release_mode=stable" > Dockerfile.slim-stable
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--provenance=false \
|
||||
--sbom=false \
|
||||
--push \
|
||||
-f Dockerfile.slim-stable \
|
||||
-t registry.cn-shenzhen.aliyuncs.com/handsfree/certd:slim-stable \
|
||||
-t registry.cn-shenzhen.aliyuncs.com/certd/certd:slim-stable \
|
||||
-t certd/certd:slim-stable \
|
||||
-t ghcr.io/${{ github.repository }}:slim-stable \
|
||||
.
|
||||
|
||||
- name: Set AtomGit release as stable
|
||||
run: |
|
||||
export ATOMGIT_TOKEN=${{ secrets.ATOMGIT_TOKEN }}
|
||||
export VERSION=${{ inputs.version }}
|
||||
node ./scripts/set-release-stable-fetch.js
|
||||
@@ -12,24 +12,23 @@ jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
ref: v2-dev
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
run: |
|
||||
git config --global user.name "xiaojunnuo"
|
||||
git config --global user.email "xiaojunnuo@qq.com"
|
||||
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
uses: de-vri-es/setup-git-credentials@v2
|
||||
with: # token 格式为: username:password
|
||||
with: # token 格式为: username:password
|
||||
credentials: https://greper:${{secrets.ATOMGIT_TOKEN}}@atomgit.com
|
||||
|
||||
- name: push to atomgit # 4. 执行同步
|
||||
- name: push to atomgit # 4. 执行同步
|
||||
run: |
|
||||
git remote add upstream https://atomgit.com/certd/certd
|
||||
git push --set-upstream upstream v2-dev
|
||||
|
||||
|
||||
@@ -12,24 +12,23 @@ jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
ref: v2
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
run: |
|
||||
git config --global user.name "xiaojunnuo"
|
||||
git config --global user.email "xiaojunnuo@qq.com"
|
||||
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
uses: de-vri-es/setup-git-credentials@v2
|
||||
with: # token 格式为: username:password
|
||||
with: # token 格式为: username:password
|
||||
credentials: https://greper:${{secrets.ATOMGIT_TOKEN}}@atomgit.com
|
||||
|
||||
- name: push to atomgit # 4. 执行同步
|
||||
- name: push to atomgit # 4. 执行同步
|
||||
run: |
|
||||
git remote add upstream https://atomgit.com/certd/certd
|
||||
git push --set-upstream upstream v2
|
||||
|
||||
|
||||
@@ -12,24 +12,23 @@ jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
ref: v2-dev
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
run: |
|
||||
git config --global user.name "xiaojunnuo"
|
||||
git config --global user.email "xiaojunnuo@qq.com"
|
||||
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
uses: de-vri-es/setup-git-credentials@v2
|
||||
with: # token 格式为: username:password
|
||||
with: # token 格式为: username:password
|
||||
credentials: https://cnb:${{secrets.CNB_TOKEN}}@cnb.cool
|
||||
|
||||
- name: push to cnb # 4. 执行同步
|
||||
- name: push to cnb # 4. 执行同步
|
||||
run: |
|
||||
git remote add upstream https://cnb.cool/certd/certd.git
|
||||
git push --set-upstream upstream v2-dev
|
||||
|
||||
|
||||
@@ -12,23 +12,22 @@ jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
run: |
|
||||
git config --global user.name "xiaojunnuo"
|
||||
git config --global user.email "xiaojunnuo@qq.com"
|
||||
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
uses: de-vri-es/setup-git-credentials@v2
|
||||
with: # token 格式为: username:password
|
||||
with: # token 格式为: username:password
|
||||
credentials: https://cnb:${{secrets.CNB_TOKEN}}@cnb.cool
|
||||
|
||||
- name: push to cnb # 4. 执行同步
|
||||
- name: push to cnb # 4. 执行同步
|
||||
run: |
|
||||
git remote add upstream https://cnb.cool/certd/certd.git
|
||||
git push --set-upstream upstream v2
|
||||
|
||||
|
||||
@@ -12,24 +12,23 @@ jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
ref: v2-dev
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
run: |
|
||||
git config --global user.name "xiaojunnuo"
|
||||
git config --global user.email "xiaojunnuo@qq.com"
|
||||
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
uses: de-vri-es/setup-git-credentials@v2
|
||||
with: # token 格式为: username:password
|
||||
with: # token 格式为: username:password
|
||||
credentials: https://${{secrets.PUSH_TOKEN_GITEE}}@gitee.com
|
||||
|
||||
- name: push to gitee # 4. 执行同步
|
||||
- name: push to gitee # 4. 执行同步
|
||||
run: |
|
||||
git remote add upstream https://gitee.com/certd/certd
|
||||
git push --set-upstream upstream v2-dev
|
||||
|
||||
|
||||
@@ -12,23 +12,22 @@ jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
- name: Checkout work repo # 1. 检出当前仓库(certd-sync-work)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
run: |
|
||||
git config --global user.name "xiaojunnuo"
|
||||
git config --global user.email "xiaojunnuo@qq.com"
|
||||
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
- name: Set git token # 3. 给git命令设置token,用于push到目标仓库
|
||||
uses: de-vri-es/setup-git-credentials@v2
|
||||
with: # token 格式为: username:password
|
||||
with: # token 格式为: username:password
|
||||
credentials: https://${{secrets.PUSH_TOKEN_GITEE}}@gitee.com
|
||||
|
||||
- name: push to gitee # 4. 执行同步
|
||||
- name: push to gitee # 4. 执行同步
|
||||
run: |
|
||||
git remote add upstream https://gitee.com/certd/certd
|
||||
git push --set-upstream upstream v2
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
./packages/core/lego
|
||||
./packages/core/lego
|
||||
# IntelliJ project files
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
@@ -32,4 +32,15 @@ test/**/*.js
|
||||
test.js
|
||||
.history
|
||||
/logs
|
||||
.pnpm-lock.yaml
|
||||
.pnpm-lock.yaml
|
||||
pnpm-lock.yaml
|
||||
.studio/
|
||||
|
||||
# Certd 推广报告,仅本地使用
|
||||
/popularize/reports/
|
||||
output/
|
||||
.uploads/
|
||||
.certd-plugin-history/
|
||||
.tmp
|
||||
.plugin-dev/
|
||||
.tmp_chunks/
|
||||
@@ -7,29 +7,38 @@ version: 1.0.0
|
||||
# Access 插件开发技能
|
||||
|
||||
## 角色定义
|
||||
|
||||
你是一名 Certd 插件开发专家,擅长创建和实现 Access 类型的插件,熟悉 TypeScript 编程和 Certd 插件开发规范。
|
||||
|
||||
## 核心指令
|
||||
|
||||
请严格按照以下步骤执行任务:
|
||||
|
||||
1. **导入必要的依赖**
|
||||
|
||||
- 导入 `AccessInput`, `BaseAccess`, `IsAccess`, `Pager`, `PageRes`, `PageSearch` 等必要的类型和装饰器
|
||||
- 导入 `DomainRecord` 等相关类型
|
||||
|
||||
2. **使用 @IsAccess 注解注册插件**
|
||||
|
||||
- 配置插件的唯一标识、标题、图标和描述
|
||||
- 继承 `BaseAccess` 类
|
||||
- 插件默认文案使用中文;需要英文时,在注解参数对象中添加同级 `i18n: { "en-US": { ... } }`,不要写成 `metadata.i18n`。`define` 本身就是插件 metadata。
|
||||
- `i18n["en-US"]` 仅配置要翻译的展示字段,如 `title`、`desc`、`input`;输入字段可翻译 `title`、`helper`、组件展示文案和 `optionsMapping`。缺少英文翻译时回退默认中文。
|
||||
|
||||
3. **定义授权属性**
|
||||
|
||||
- 使用 `@AccessInput` 注解定义授权属性
|
||||
- 配置属性的标题、默认值、组件类型和验证规则
|
||||
- 对于敏感信息,设置 `encrypt: true` 进行加密
|
||||
|
||||
4. **实现测试方法**
|
||||
|
||||
- 添加测试按钮配置
|
||||
- 实现 `onTestRequest` 方法,用于测试接口调用是否正常
|
||||
|
||||
5. **实现 API 方法**
|
||||
|
||||
- 实现必要的 API 方法,如 `GetDomainList`
|
||||
- 封装统一的 API 请求方法 `doRequest`,处理错误和日志
|
||||
|
||||
@@ -39,6 +48,7 @@ version: 1.0.0
|
||||
- 实现代码复用,避免重复逻辑
|
||||
|
||||
## 输出规范
|
||||
|
||||
- 必须包含完整的插件实现代码,包括所有必要的导入语句
|
||||
- 代码必须包含详细的注释说明,解释每个步骤的目的和实现细节
|
||||
- 提供完整的示例代码,展示插件的使用方法,包括不同类型的授权方式
|
||||
@@ -51,6 +61,7 @@ version: 1.0.0
|
||||
### 示例 1: 基本 Access 插件
|
||||
|
||||
#### 用户输入
|
||||
|
||||
创建一个 Access 插件,用于存储第三方应用的授权信息并提供 API 接口。
|
||||
|
||||
#### 你的回答
|
||||
@@ -70,7 +81,6 @@ import { DomainRecord } from '@certd/plugin-lib';
|
||||
desc: '这是一个示例授权插件,用于演示如何实现一个授权插件',
|
||||
})
|
||||
export class DemoAccess extends BaseAccess {
|
||||
|
||||
/**
|
||||
* 授权属性配置
|
||||
*/
|
||||
@@ -78,16 +88,17 @@ export class DemoAccess extends BaseAccess {
|
||||
title: '授权方式',
|
||||
value: 'apiKey', //默认值
|
||||
component: {
|
||||
name: "a-select", //基于antdv的输入组件
|
||||
vModel: "value", // v-model绑定的属性名
|
||||
options: [ //组件参数
|
||||
name: 'a-select', //基于antdv的输入组件
|
||||
vModel: 'value', // v-model绑定的属性名
|
||||
options: [
|
||||
//组件参数
|
||||
{
|
||||
label: "API密钥(推荐)",
|
||||
value: "apiKey"
|
||||
label: 'API密钥(推荐)',
|
||||
value: 'apiKey',
|
||||
},
|
||||
{
|
||||
label: "账号密码",
|
||||
value: "account"
|
||||
label: '账号密码',
|
||||
value: 'account',
|
||||
},
|
||||
],
|
||||
placeholder: 'demoKeyId',
|
||||
@@ -102,7 +113,7 @@ export class DemoAccess extends BaseAccess {
|
||||
@AccessInput({
|
||||
title: '密钥Id',
|
||||
component: {
|
||||
name:"a-input",
|
||||
name: 'a-input',
|
||||
allowClear: true,
|
||||
placeholder: 'demoKeyId',
|
||||
},
|
||||
@@ -111,19 +122,19 @@ export class DemoAccess extends BaseAccess {
|
||||
demoKeyId = '';
|
||||
|
||||
@AccessInput({
|
||||
title: '密钥',//标题
|
||||
required: true, //text组件可以省略
|
||||
title: '密钥', //标题
|
||||
required: true, //text组件可以省略
|
||||
encrypt: true, //该属性是否需要加密
|
||||
})
|
||||
demoKeySecret = '';
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
title: '测试',
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest"
|
||||
name: 'api-test',
|
||||
action: 'TestRequest',
|
||||
},
|
||||
helper: "点击测试接口是否正常"
|
||||
helper: '点击测试接口是否正常',
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
@@ -132,7 +143,7 @@ export class DemoAccess extends BaseAccess {
|
||||
*/
|
||||
async onTestRequest() {
|
||||
await this.GetDomainList({});
|
||||
return "ok"
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,41 +154,41 @@ export class DemoAccess extends BaseAccess {
|
||||
this.ctx.logger.info(`获取域名列表,req:${JSON.stringify(req)}`);
|
||||
const pager = new Pager(req);
|
||||
const resp = await this.doRequest({
|
||||
action: "ListDomains",
|
||||
action: 'ListDomains',
|
||||
data: {
|
||||
domain: req.searchKey,
|
||||
offset: pager.getOffset(),
|
||||
limit: pager.pageSize,
|
||||
}
|
||||
},
|
||||
});
|
||||
const total = resp?.TotalCount || 0;
|
||||
let list = resp?.DomainList?.map((item) => {
|
||||
let list = resp?.DomainList?.map(item => {
|
||||
item.domain = item.Domain;
|
||||
item.id = item.DomainId;
|
||||
return item;
|
||||
})
|
||||
});
|
||||
return {
|
||||
total,
|
||||
list
|
||||
list,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用api调用方法, 具体如何构造请求体,需参考对应应用的API文档
|
||||
*/
|
||||
async doRequest(req: { action: string, data?: any }) {
|
||||
async doRequest(req: { action: string; data?: any }) {
|
||||
const res = await this.ctx.http.request({
|
||||
url: "https://api.demo.cn/api/",
|
||||
method: "POST",
|
||||
url: 'https://api.demo.cn/api/',
|
||||
method: 'POST',
|
||||
data: {
|
||||
Action: req.action,
|
||||
Body: req.data
|
||||
}
|
||||
Body: req.data,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.Code !== 0) {
|
||||
//异常处理
|
||||
throw new Error(res.Message || "请求失败");
|
||||
//异常处理
|
||||
throw new Error(res.Message || '请求失败');
|
||||
}
|
||||
return res.Resp;
|
||||
}
|
||||
@@ -187,6 +198,7 @@ export class DemoAccess extends BaseAccess {
|
||||
### 示例 2: 支持 OAuth 授权的 Access 插件
|
||||
|
||||
#### 用户输入
|
||||
|
||||
创建一个支持 OAuth 授权方式的 Access 插件。
|
||||
|
||||
#### 你的回答
|
||||
@@ -205,21 +217,20 @@ import { DomainRecord } from '@certd/plugin-lib';
|
||||
desc: '这是一个支持OAuth授权的插件示例',
|
||||
})
|
||||
export class OAuthDemoAccess extends BaseAccess {
|
||||
|
||||
@AccessInput({
|
||||
title: '授权方式',
|
||||
value: 'oauth',
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
name: 'a-select',
|
||||
vModel: 'value',
|
||||
options: [
|
||||
{
|
||||
label: "OAuth授权",
|
||||
value: "oauth"
|
||||
label: 'OAuth授权',
|
||||
value: 'oauth',
|
||||
},
|
||||
{
|
||||
label: "API密钥",
|
||||
value: "apiKey"
|
||||
label: 'API密钥',
|
||||
value: 'apiKey',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -230,7 +241,7 @@ export class OAuthDemoAccess extends BaseAccess {
|
||||
@AccessInput({
|
||||
title: '客户端ID',
|
||||
component: {
|
||||
name:"a-input",
|
||||
name: 'a-input',
|
||||
placeholder: 'Client ID',
|
||||
},
|
||||
required: true,
|
||||
@@ -247,7 +258,7 @@ export class OAuthDemoAccess extends BaseAccess {
|
||||
@AccessInput({
|
||||
title: '授权回调地址',
|
||||
component: {
|
||||
name:"a-input",
|
||||
name: 'a-input',
|
||||
placeholder: 'https://your-domain.com/callback',
|
||||
},
|
||||
required: true,
|
||||
@@ -268,12 +279,12 @@ export class OAuthDemoAccess extends BaseAccess {
|
||||
refreshToken = '';
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
title: '测试',
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestOAuth"
|
||||
name: 'api-test',
|
||||
action: 'TestOAuth',
|
||||
},
|
||||
helper: "点击测试OAuth授权是否正常"
|
||||
helper: '点击测试OAuth授权是否正常',
|
||||
})
|
||||
testOAuth = true;
|
||||
|
||||
@@ -285,7 +296,7 @@ export class OAuthDemoAccess extends BaseAccess {
|
||||
// 测试AccessToken是否有效
|
||||
const result = await this.doOAuthRequest('GET', '/api/user/profile');
|
||||
this.ctx.logger.info('OAuth测试成功:', result);
|
||||
return "OAuth授权测试成功";
|
||||
return 'OAuth授权测试成功';
|
||||
} catch (error) {
|
||||
this.ctx.logger.error('OAuth测试失败:', error);
|
||||
throw new Error('OAuth授权测试失败');
|
||||
@@ -300,10 +311,10 @@ export class OAuthDemoAccess extends BaseAccess {
|
||||
url: `https://api.oauth-demo.com${endpoint}`,
|
||||
method,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${this.accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
Authorization: `Bearer ${this.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data
|
||||
data,
|
||||
});
|
||||
|
||||
if (res.status !== 200) {
|
||||
@@ -327,8 +338,8 @@ export class OAuthDemoAccess extends BaseAccess {
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: this.refreshToken,
|
||||
client_id: this.clientId,
|
||||
client_secret: this.clientSecret
|
||||
}
|
||||
client_secret: this.clientSecret,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data.access_token) {
|
||||
@@ -349,15 +360,15 @@ export class OAuthDemoAccess extends BaseAccess {
|
||||
const res = await this.doOAuthRequest('GET', '/api/domains', {
|
||||
search: req.searchKey,
|
||||
page: req.page,
|
||||
pageSize: req.pageSize
|
||||
pageSize: req.pageSize,
|
||||
});
|
||||
|
||||
return {
|
||||
total: res.total,
|
||||
list: res.items.map((item: any) => ({
|
||||
id: item.id,
|
||||
domain: item.domain
|
||||
}))
|
||||
domain: item.domain,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
// 尝试刷新AccessToken并重试
|
||||
@@ -366,15 +377,15 @@ export class OAuthDemoAccess extends BaseAccess {
|
||||
const res = await this.doOAuthRequest('GET', '/api/domains', {
|
||||
search: req.searchKey,
|
||||
page: req.page,
|
||||
pageSize: req.pageSize
|
||||
pageSize: req.pageSize,
|
||||
});
|
||||
|
||||
return {
|
||||
total: res.total,
|
||||
list: res.items.map((item: any) => ({
|
||||
id: item.id,
|
||||
domain: item.domain
|
||||
}))
|
||||
domain: item.domain,
|
||||
})),
|
||||
};
|
||||
}
|
||||
throw error;
|
||||
@@ -383,6 +394,66 @@ export class OAuthDemoAccess extends BaseAccess {
|
||||
}
|
||||
```
|
||||
|
||||
## 字段动态显隐(mergeScript)
|
||||
|
||||
多种鉴权方式共用一个授权时,用 `@AccessInput` 上的 `mergeScript` 按所选方式显隐字段:
|
||||
|
||||
```typescript
|
||||
@AccessInput({
|
||||
title: '鉴权方式',
|
||||
value: 'apikey',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
vModel: 'value',
|
||||
options: [
|
||||
{ label: 'AccessKey签名', value: 'aksk' },
|
||||
{ label: 'ApiKey', value: 'apikey' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
authType = 'apikey';
|
||||
|
||||
@AccessInput({
|
||||
title: 'accessKeyId',
|
||||
component: { name: 'a-input', vModel: 'value' },
|
||||
required: true,
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return !form.access.authType || form.access.authType === 'aksk';
|
||||
})
|
||||
}
|
||||
`,
|
||||
})
|
||||
accessKeyId = '';
|
||||
```
|
||||
|
||||
要点:
|
||||
|
||||
- `mergeScript` 返回的对象会深合并进本字段定义,可动态化的属性有 `show`、`required`、`helper`、
|
||||
`component` 下的属性(`options`、`placeholder` 等)以及 `component.on` 事件。
|
||||
- **动态判断必须写在 `ctx.compute(({form})=>{ ... })` 回调里**。`mergeScript` 本身在插件类
|
||||
定义阶段就被拼成字符串,那时表单还没打开,用参数在服务端判断字段值没有意义。
|
||||
- 授权表单字段值在 `form.access.xxx`(任务表单才是 `form.xxx`)。
|
||||
- 历史授权没有新字段,条件里要用 `!form.access.authType || ...` 兜底走旧逻辑,保证老授权还能编辑保存。
|
||||
- 联动其他字段用 `component.on` 事件回调,回调参数是 `{ form }`:
|
||||
|
||||
```typescript
|
||||
mergeScript: `
|
||||
return {
|
||||
component: {
|
||||
on: {
|
||||
selectedChange: (scope) => {
|
||||
const form = scope.form;
|
||||
form.acmeAccountAccessId = null;
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`,
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **插件命名**:插件名称应简洁明了,反映其功能。
|
||||
@@ -391,15 +462,20 @@ export class OAuthDemoAccess extends BaseAccess {
|
||||
4. **错误处理**:API 调用失败时应抛出明确的错误信息。
|
||||
5. **测试方法**:实现 `onTestRequest` 方法,以便用户可以测试授权是否正常。
|
||||
6. **统一接口调用**:封装统一的 API 请求方法,避免重复编写错误处理逻辑。
|
||||
7. **旧版数据兼容**: 新增注解的插件参数,必须要考虑旧版数据兼容,比如新增一个deployType参数,有两种值:`default`和`custom`,需要在使用时判空,走旧版逻辑。
|
||||
|
||||
## 开发技巧
|
||||
|
||||
### 实现统一的 API 请求封装
|
||||
|
||||
**好处:**
|
||||
|
||||
- **代码复用**:避免在每个 API 方法中重复编写相同的 header 设置和错误处理逻辑
|
||||
- **错误处理一致**:统一捕获和处理各种错误情况,确保错误信息格式统一
|
||||
- **日志记录完善**:集中记录详细的错误信息,便于调试和问题排查
|
||||
- **接口调用简化**:调用方只需关注业务逻辑,无需关心底层请求细节
|
||||
- **易于维护**:统一修改 API 调用方式时,只需修改一处代码
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
@@ -1 +1 @@
|
||||
我需要开发一个 Access 插件,用于存储和管理第三方应用的授权信息。请指导我如何实现。
|
||||
我需要开发一个 Access 插件,用于存储和管理第三方应用的授权信息。请指导我如何实现。
|
||||
|
||||
@@ -129,7 +129,7 @@ async doRequest(req: { action: string, data?: any }) {
|
||||
});
|
||||
|
||||
if (res.Code !== 0) {
|
||||
//异常处理
|
||||
//异常处理
|
||||
throw new Error(res.Message || "请求失败");
|
||||
}
|
||||
return res.Resp;
|
||||
@@ -142,4 +142,4 @@ async doRequest(req: { action: string, data?: any }) {
|
||||
2. **属性加密**:对于敏感信息(如密钥),应设置 `encrypt: true`。
|
||||
3. **日志输出**:必须使用 `this.ctx.logger` 输出日志,而不是 `console`。
|
||||
4. **错误处理**:API 调用失败时应抛出明确的错误信息。
|
||||
5. **测试方法**:实现 `onTestRequest` 方法,以便用户可以测试授权是否正常。
|
||||
5. **测试方法**:实现 `onTestRequest` 方法,以便用户可以测试授权是否正常。
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
你是一名资深nodejs工程师,擅长开发Certd开源系统的任务插件。
|
||||
certd是一款全自动证书申请部署管理工具,基于流水线的方式,通过里面申请证书插件申请证书,然后将证书传递给下一个部署任务插件,不同的部署任务插件将证书部署到用户的各个应用系统当中。
|
||||
|
||||
certd插件分成以下几种类型:
|
||||
Access:存储用户的第三放应用的授权数据,比如用户名密码,accessSecret 或 accessToken等。同时它里面的方法还负责对接第三方的api接口
|
||||
Task: 部署任务插件,它继承AbstractTaskPlugin类,被流水线调用execute方法,将证书部署到对应的应用上
|
||||
DnsProvider: DNS提供商插件,它用于在ACME申请证书时给域名添加txt解析记录。
|
||||
|
||||
注意事项:
|
||||
1、使用技能:在开始工作前,请阅读并加载.trae/skills下面的技能,根据skills进行相应的插件开发
|
||||
2、迭代技能:当开发过程用户提醒你更好的做法时,你需要总结经验,更新相应的skills,让skills越来越完善,能够在以后得新插件开发中具备指导意义。
|
||||
3、一般调用的api接口文档会比较复杂,你不知道接口是什么时,请务必询问用户,让用户提供API接口文档
|
||||
4、完成开发后无需测试,通知用户自己去测试
|
||||
@@ -0,0 +1,184 @@
|
||||
---
|
||||
name: certd-online-plugin-dev
|
||||
description: 用于通过 Certd API 开发、修改、读取、保存和恢复在线插件。当用户要求使用 Codex 或 Trae 创建 Task、DNS Provider、Access 插件,或优化已有 Certd 插件时使用。
|
||||
---
|
||||
|
||||
# Certd 在线插件开发 Skill
|
||||
|
||||
## 开发方式
|
||||
|
||||
本 Skill 使用 Certd HTTP API,不使用 WebSocket,也不依赖浏览器传递代码草稿。
|
||||
|
||||
- 前端只生成包含需求、插件作者、API 地址和认证 Token 的启动提示词。
|
||||
- Agent 直接调用 Certd API 读取和保存插件 YAML。
|
||||
- Agent 的进度、日志和代码修改在 Codex/Trae 中查看。
|
||||
- 插件开发临时文件和修改历史统一保存在 Agent 工作区的 `.plugin-dev/` 下,不保存到浏览器或 Certd 后端。
|
||||
|
||||
## 启动检查
|
||||
|
||||
开始开发前先确认当前工作目录是否已经在 Certd 项目内:
|
||||
|
||||
- 应存在 `package.json`。
|
||||
- 应存在 `packages/ui/certd-server/src/plugins/`。
|
||||
- 应存在 `.trae/skills/`。
|
||||
- 应存在 `.trae/skills/certd-online-plugin-dev/SKILL.md`。
|
||||
|
||||
如果当前目录不是 Certd 项目,或缺少 `certd-online-plugin-dev` Skill,先拉取 Certd 仓库代码并切换到仓库内工作( --depth 1 拉取第一层即可):
|
||||
|
||||
1. 优先使用 `https://atomgit.com/certd/certd/`。
|
||||
2. 如果 AtomGit 拉取失败,再使用 `https://github.com/certd/certd`。
|
||||
3. 拉取后重新检查上述特征,并读取 `.trae/skills/certd-online-plugin-dev/SKILL.md`。
|
||||
|
||||
开发插件时,参考 Certd 项目下已有内置插件实现:`packages/ui/certd-server/src/plugins/`。
|
||||
|
||||
## 插件来源
|
||||
|
||||
Certd 插件按来源分为三类:
|
||||
|
||||
- 内置插件:`type: "builtIn"`,随 Certd 安装包提供。可读取并在流水线中使用,不应通过本 Skill 修改或覆盖。
|
||||
- 市场插件:`type: "store"`,且存在 `appId` 或 `developerId`。它来自在线插件市场,可能尚未安装到本地;是否可修改只能以接口返回的 `editable` 为准。
|
||||
- 本地插件:`type: "store"`,但没有 `appId` 和 `developerId`。它是当前 Certd 实例本地创建、导入或复制的插件,可直接保存;发布到市场后会带上市场归属信息。
|
||||
|
||||
不要只根据 `type: "store"` 判断插件是否来自市场,也不要自行推断编辑权限;始终使用列表结果中的 `editable` 字段。
|
||||
|
||||
## API 认证
|
||||
|
||||
提示词会提供 Certd API 地址和仅限 AI 插件开发接口的受限的短时效的 Token。调用 API 时使用:
|
||||
|
||||
```http
|
||||
Authorization: <token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
所有 Certd API 请求统一使用 Node.js 的 `fetch`。不要使用 PowerShell 的 `Invoke-RestMethod`、`Invoke-WebRequest` 或 .NET HTTP 客户端发送插件 YAML/JSON;它们在 Windows 上可能造成中文乱码或使完整 YAML 导入请求长时间无响应。
|
||||
|
||||
Node 请求须直接读取 UTF-8 文件或在 Node 内构造 JSON,并使用 `JSON.stringify`:
|
||||
|
||||
```javascript
|
||||
const response = await fetch(`${apiBase}/scoped/sys/ai/plugin/find`, {
|
||||
method: "POST",
|
||||
headers: { Authorization: token, "Content-Type": "application/json; charset=utf-8" },
|
||||
body: JSON.stringify({ keywords: ["nginx"], includeBuiltIn: true, includeStore: true }),
|
||||
})
|
||||
```
|
||||
|
||||
## UTF-8 保存
|
||||
|
||||
在 Windows 上,Node 直接以 UTF-8 读取 YAML 并用 `JSON.stringify` 发送;不要让 PowerShell 转发含中文的 YAML/JSON。保存后检查中文字段不含 `?`,再调用 `/scoped/sys/ai/plugin/find` 或 `/scoped/sys/ai/plugin/info` 验证。
|
||||
|
||||
## API 工作流
|
||||
|
||||
1. 使用 `/scoped/sys/ai/plugin/find` 查询插件和 Access,可通过 `keywords` 数组传递多个关键词。
|
||||
2. 查询结果包含 `editable`:
|
||||
- `editable: true`:允许当前 Agent 修改并保存。
|
||||
- `editable: false`:只能读取和使用,不能修改。
|
||||
3. 读取完整 YAML 时调用 `/scoped/sys/ai/plugin/export`。
|
||||
4. 所有插件保存统一调用 `/scoped/sys/ai/plugin/import`,并始终传递完整 YAML:
|
||||
- 新插件使用 `override: false`。
|
||||
- 已有插件使用 `override: true`;导入接口根据 `author` 和 `name` 定位并覆盖已有记录。
|
||||
5. 不使用 `/sys/plugin/add` 或 `/sys/plugin/update` 保存插件,避免保存路径分叉、字段丢失和 Windows 请求兼容性问题。
|
||||
6. 保存完成后重新调用 `/scoped/sys/ai/plugin/find` 或 `/scoped/sys/ai/plugin/info` 验证结果。
|
||||
|
||||
`/scoped/sys/ai/plugin/find` 会在一次请求中分别查询内置插件和 `store` 插件,再合并返回;`store` 插件需按上述字段区分市场插件与本地插件。
|
||||
|
||||
详细请求字段见 `references/certd-api.md`。
|
||||
|
||||
## Access 协作
|
||||
|
||||
开发 Task 或 DNS Provider 前,先用 `/scoped/sys/ai/plugin/find` 查询对应 Access:
|
||||
|
||||
1. 如果没有对应 Access,先创建 Access 插件,再创建业务插件。
|
||||
2. 如果已有 Access,先读取它的完整 YAML 和 `content`。
|
||||
3. 如果 Access 已提供所需 API/SDK,业务插件优先复用。
|
||||
4. 如果缺少能力:
|
||||
- `editable: true`:优先修改 Access,并先保存历史。
|
||||
- `editable: false`:在当前业务插件中实现必要的 API 调用。
|
||||
5. 业务插件通过 `dependPlugins` 声明 Access 依赖。
|
||||
|
||||
详细规则见 `references/access-development.md`。
|
||||
|
||||
## 本地历史
|
||||
|
||||
开发插件时,必须在当前工作区创建并使用 `.plugin-dev/{plugin-name}` 作为插件开发目录。历史记录、临时 YAML、脚本草稿和调试记录都放在该目录下。
|
||||
|
||||
每次修改插件前,必须将完整 YAML 保存到 `.plugin-dev/{plugin-name}/history/`:
|
||||
|
||||
```text
|
||||
.plugin-dev/{plugin-name}/xxxxx.yaml
|
||||
.plugin-dev/{plugin-name}/history/
|
||||
2026-08-02T12-30-00-before-edit.yaml
|
||||
2026-08-02T12-30-00-change.md
|
||||
```
|
||||
|
||||
保存要求:
|
||||
|
||||
- 修改前保存完整 YAML。
|
||||
- 修改后保存修改摘要。
|
||||
- 恢复前再次备份当前版本。
|
||||
- 不上传历史文件,不保存 Token、证书、私钥或真实授权值。
|
||||
- 修改完一版后立即提交更新到certd,但不要发布到市场。
|
||||
|
||||
详细格式见 `references/local-history.md`。
|
||||
|
||||
## YAML 和脚本规范
|
||||
|
||||
插件始终以完整 YAML 传递和保存,脚本源码放在顶层 `content` 字段。
|
||||
|
||||
- 新插件的 `author` 必须使用启动提示词中给出的插件作者,不要自行编造作者名;修改已有插件时保留原 `author`,不要改成其他作者。
|
||||
- 统一使用 `await _ctx.import(...)` 引用模块。
|
||||
- `"/@/..."` 表示以绝对路径引用 `server/src/` 下的模块。
|
||||
- 最后返回继承目标基类的 class。
|
||||
- 不使用 `import`、`export`、装饰器或独立源码文件语法。
|
||||
- 使用 `this.logger` 打印插件执行日志。
|
||||
- 使用 `this.ctx.http` 访问 HTTP 能力。
|
||||
- 失败时抛出 `Error`。
|
||||
|
||||
需要字段格式时读取 `references/online-yaml-format.md`。
|
||||
需要组件示例时读取 `references/component-examples.md`。
|
||||
需要按其他字段动态显隐/必填/联动时读取 `references/merge-script.md`。
|
||||
|
||||
### 字段动态显隐(mergeScript)
|
||||
|
||||
字段定义支持 `mergeScript`:脚本 `return` 的对象会合并进本字段,用来做「选了 A 才显示 B」这类联动。
|
||||
|
||||
```yaml
|
||||
mergeScript: |2-
|
||||
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.access.authType === 'apikey';
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
- 动态逻辑必须写在 `ctx.compute(({form})=>{ ... })` 回调里;`mergeScript` 本身在插件类定义阶段就
|
||||
被拼成字符串,那时表单还没打开,用参数在 node 侧判断字段值没有任何意义。
|
||||
- 授权表单字段值在 `form.access.xxx`,任务表单字段值在 `form.xxx`。
|
||||
- 新增可选字段时要给历史数据兜底,例如 `!form.access.authType || form.access.authType === 'aksk'`。
|
||||
|
||||
完整用法(能力、可动态化的属性、事件联动、常见错误、验证方式)见 `references/merge-script.md`。
|
||||
|
||||
## 示例插件
|
||||
|
||||
开发对应类型插件前,先读取 `examples/` 下的示例:
|
||||
|
||||
- Access:`examples/DemoAccess.yaml`
|
||||
- 部署/Task:`examples/DemoDeploy.yaml`
|
||||
- DNS Provider:`examples/DemoDnsProvider.yaml`
|
||||
|
||||
示例是完整在线插件 YAML,重点参考 `input` 配置、依赖声明和 `content` 脚本结构。
|
||||
|
||||
## 子 Skill
|
||||
|
||||
- Task:`skills/task-plugin-dev/SKILL.md`
|
||||
- DNS Provider:`skills/dns-provider-dev/SKILL.md`
|
||||
- Access:`skills/access-plugin-dev/SKILL.md`
|
||||
|
||||
## 安全边界
|
||||
|
||||
Certd 会保存证书、私钥、API Token、云厂商密钥、SSH 凭据和其他敏感授权。
|
||||
|
||||
- 禁止读取、打印或上传真实授权值。
|
||||
- 禁止把认证 Token 写入插件、历史、日志或摘要。
|
||||
- 禁止读取无关的证书、私钥、Cookie、环境变量和系统设置。
|
||||
- 只使用脱敏示例数据和公开文档。
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Certd 在线插件开发"
|
||||
short_description: "通过 Certd API 使用 Codex 或 Trae 开发在线插件"
|
||||
default_prompt: "读取在线插件 YAML 和对应类型规范,按需求修改 content,保存历史记录后通过 Certd API 写回。"
|
||||
@@ -0,0 +1,37 @@
|
||||
name: DemoAccess
|
||||
icon: logos:airflow-icon
|
||||
title: Demo-授权插件示例 # 格式:平台-功能 ,例如: 网宿-授权 ; 阿里云-授权 ; 天翼云-授权
|
||||
group: null
|
||||
desc: 这只是一个示例
|
||||
version: 1.0.0
|
||||
pluginType: access
|
||||
author: greper
|
||||
input:
|
||||
username:
|
||||
title: 用户名
|
||||
required: true
|
||||
encrypt: false
|
||||
component:
|
||||
name: a-input
|
||||
allowClear: true
|
||||
password:
|
||||
title: 密码
|
||||
required: true
|
||||
encrypt: true
|
||||
component:
|
||||
name: a-input
|
||||
allowClear: true
|
||||
showRunStrategy: false
|
||||
default:
|
||||
strategy:
|
||||
runStrategy: 1
|
||||
content: |
|
||||
|
||||
// 必须使用 await import 来引入模块
|
||||
const { BaseAccess } = await import("@certd/pipeline")
|
||||
// 需要返回一个继承BaseAccess的类
|
||||
return class DemoAccess extends BaseAccess {
|
||||
// 授权的字段,跟左边input一一对应
|
||||
username;
|
||||
password;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
name: DemoDeploy
|
||||
icon: logos:amp-icon
|
||||
title: Demo-部署插件示例 # 格式:平台-功能 ,例如: 网宿-更新CDNpro证书 ; 阿里云-上传到CAS证书管理服务 ; 天翼云-更新CDN证书
|
||||
group: cdn
|
||||
desc: 这仅仅是一个示例
|
||||
version: 1.0.0
|
||||
pluginType: deploy
|
||||
author: greper
|
||||
input:
|
||||
cert:
|
||||
title: 前置任务证书
|
||||
helper: 请选择前置任务产生的证书
|
||||
component:
|
||||
name: output-selector # 前置任务输出选择组件
|
||||
vModel: modelValue
|
||||
from:
|
||||
- ':cert:' # 前置任务输出作为输入的筛选条件 , 格式 pluginType:valueType:keyName , 为空表示任意匹配
|
||||
required: true
|
||||
certDomains:
|
||||
title: 当前证书域名
|
||||
component:
|
||||
name: cert-domains-getter
|
||||
mergeScript: |
|
||||
return {
|
||||
component:{
|
||||
inputKey: ctx.compute(({form})=>{
|
||||
return form.cert
|
||||
}),
|
||||
}
|
||||
}
|
||||
required: true
|
||||
accessId:
|
||||
title: Access授权
|
||||
helper: xxxx的授权
|
||||
component:
|
||||
name: access-selector
|
||||
type: aliyun
|
||||
required: true
|
||||
key1:
|
||||
title: 输入示例1
|
||||
required: false
|
||||
key2:
|
||||
title: 可选项
|
||||
component:
|
||||
name: a-select
|
||||
vMode: value
|
||||
options:
|
||||
- value: '1'
|
||||
label: 选项1
|
||||
- value: '2'
|
||||
label: 选项2
|
||||
required: false
|
||||
showRunStrategy: false # 用户是否可以选择运行策略, 【默认不显示】
|
||||
default:
|
||||
strategy:
|
||||
runStrategy: 0 # 运行策略, 0 = 成功后跳过,1 = 正常运行
|
||||
content: >
|
||||
|
||||
// 要用await来import模块
|
||||
|
||||
const { AbstractTaskPlugin } = await _ctx.import("@certd/pipeline")
|
||||
|
||||
// 使用_ctx.import("/@/xxx.js") 以绝对路径引用模块,/@相当于根路径
|
||||
|
||||
const {AliyunAccess} = await _ctx.import("/@/plugins/plugin-lib/aliyun/access/index.js")
|
||||
|
||||
_ctx.logger.info("AliyunAccess:",AliyunAccess)
|
||||
|
||||
// 要返回一个继承AbstractTaskPlugin的class
|
||||
|
||||
return class DemoTask extends AbstractTaskPlugin {
|
||||
// 这里是插件的输入参数,对应左边的input配置
|
||||
cert;
|
||||
certDomains;
|
||||
accessId;
|
||||
key1;
|
||||
key2;
|
||||
// 编写执行方法
|
||||
async execute(){
|
||||
// 根据accessId获取授权配置
|
||||
const access = await this.getAccess(this.accessId)
|
||||
|
||||
//必须使用this.logger打印日志
|
||||
// this.logger.info("cert:",this.cert);
|
||||
this.logger.info("certDomains:",this.certDomains);
|
||||
this.logger.info("access:",access);
|
||||
this.logger.info("key1:",this.key1);
|
||||
this.logger.info("key2:",this.key2);
|
||||
this.logger.info("开始xxx部署任务")
|
||||
// 你的部署任务代码 【必须实现】
|
||||
// this.ctx里面有一些常用的方法类,比如utils、http、logger等
|
||||
const res = await this.ctx.http.request({url:"https://www.baidu.com"})
|
||||
if(res.error){
|
||||
//抛出异常,终止任务,否则将被判定为执行成功
|
||||
throw new Error("部署失败:"+res.message)
|
||||
}
|
||||
this.logger.info("执行成功")
|
||||
// this.outputName = xxxx //设置输出参数,可以被其他插件选择使用
|
||||
|
||||
// 此处可以返回 "skip" , 表示本次任务没有做任何操作和改变 , 配合runStrategy=1使用
|
||||
// return "skip"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
name: DemoDnsProvider
|
||||
icon: fa-solid:frog
|
||||
title: Demo-Dns提供商插件示例 # 格式:平台-功能 ,例如: 阿里云-DNS提供商 ;腾讯云-DNS提供商
|
||||
desc: 这只是一个示例
|
||||
type: custom
|
||||
version: 1.0.0
|
||||
pluginType: dnsProvider
|
||||
author: greper
|
||||
accessType: aliyun # 需要的授权类型
|
||||
showRunStrategy: false
|
||||
default:
|
||||
strategy:
|
||||
runStrategy: 1
|
||||
content: |+
|
||||
|
||||
const { AbstractDnsProvider } = await _ctx.import("@certd/pipeline")
|
||||
return class DemoDnsProvider extends AbstractDnsProvider {
|
||||
// 创建dns解析记录,用于验证域名所有权 【必须实现】
|
||||
async createRecord(options) {
|
||||
/**
|
||||
* fullRecord: '_acme-challenge.test.example.com',
|
||||
* value: 一串uuid
|
||||
* type: 'TXT',
|
||||
* domain: 'example.com'
|
||||
*/
|
||||
const { fullRecord, value, type, domain } = options;
|
||||
const access = this.ctx.access
|
||||
this.logger.info('添加域名解析:', fullRecord, value, type, domain);
|
||||
// const record = await sdk.createRecord() // 调用对应的接口创建解析记录
|
||||
|
||||
//返回解析记录,用于后面清理
|
||||
return record
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除dns解析记录,清理申请痕迹【必须实现】
|
||||
* @param options
|
||||
*/
|
||||
async removeRecord(options) {
|
||||
const { fullRecord, value } = options.recordReq;
|
||||
const record = options.recordRes; // createRecord接口返回的record
|
||||
const access = this.ctx.access
|
||||
this.logger.info('删除域名解析:', fullRecord, value);
|
||||
if (!record) {
|
||||
this.logger.info('record为空,不执行删除');
|
||||
return;
|
||||
}
|
||||
const recordId = record.id;
|
||||
// 这里调用删除txt dns解析记录接口
|
||||
// sdk.removeRecord(recordId)
|
||||
this.logger.info("删除域名解析成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取域名列表 【可选,没有实现的话,不支持在certd域名管理中导入域名列表,不影响证书申请】
|
||||
* @param req
|
||||
* @returns
|
||||
*/
|
||||
async getDomainListPage(req: PageSearch): Promise<PageRes<DomainRecord>> {
|
||||
const pager = new Pager(req);
|
||||
const params = {
|
||||
RegionId: "cn-hangzhou",
|
||||
PageSize: pager.pageSize,
|
||||
PageNumber: pager.pageNo,
|
||||
};
|
||||
|
||||
const requestOption = {
|
||||
method: "POST",
|
||||
};
|
||||
|
||||
const ret = await this.client.request("DescribeDomains", params, requestOption);
|
||||
const list =
|
||||
ret.Domains?.Domain?.map(item => ({
|
||||
id: item.DomainId,
|
||||
domain: item.DomainName,
|
||||
})) || [];
|
||||
|
||||
return {
|
||||
list,
|
||||
total: ret.TotalCount,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取域名解析记录列表 【可选,没有实现的话,不支持在站点监控里面导入网址,不影响证书申请】
|
||||
* @param domain
|
||||
* @param req
|
||||
* @returns
|
||||
*/
|
||||
async getRecordListPage(domain: string, req: PageSearch): Promise<PageRes<DnsResolveRecord>> {
|
||||
const pager = new Pager(req);
|
||||
const params = {
|
||||
RegionId: "cn-hangzhou",
|
||||
DomainName: domain,
|
||||
PageSize: pager.pageSize,
|
||||
PageNumber: pager.pageNo,
|
||||
};
|
||||
|
||||
const requestOption = {
|
||||
method: "POST",
|
||||
};
|
||||
|
||||
const ret = await this.client.request("DescribeDomainRecords", params, requestOption);
|
||||
const rawList = ret.DomainRecords?.Record || [];
|
||||
const list = rawList.map(item => ({
|
||||
id: item.RecordId,
|
||||
hostRecord: item.RR,
|
||||
fullRecord: item.RR === "@" ? domain : `${item.RR}.${domain}`,
|
||||
type: item.Type,
|
||||
value: item.Value,
|
||||
}));
|
||||
|
||||
return {
|
||||
list,
|
||||
total: ret.TotalCount,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Access 开发规范
|
||||
|
||||
Access 插件负责保存授权配置,也负责封装平台 API/SDK,供 Task 和 DNS Provider 复用。
|
||||
|
||||
## 查询顺序
|
||||
|
||||
1. 调用 `/scoped/sys/ai/plugin/find`,使用 `pluginType: access`。
|
||||
2. 根据 `name`、`author`、`fullName` 识别目标 Access。
|
||||
3. 使用 `/scoped/sys/ai/plugin/export` 读取完整 YAML。
|
||||
4. 检查 `content` 中已经提供的方法。
|
||||
|
||||
## 修改规则
|
||||
|
||||
- Access 的 `editable: true` 时才允许修改。
|
||||
- 修改前先保存本地历史。
|
||||
- 优先把通用 API/SDK 能力放入 Access。
|
||||
- 业务插件通过 `dependPlugins` 依赖 Access。
|
||||
- `editable: false` 时不要尝试修改 Access,在业务插件内部实现必要的调用。
|
||||
- 不要在日志中打印完整授权配置。
|
||||
@@ -0,0 +1,70 @@
|
||||
# Certd API
|
||||
|
||||
以下接口都以前端生成提示词中的 API 地址为基础地址,并使用 `Authorization` 请求头。
|
||||
|
||||
## 查询插件
|
||||
|
||||
```http
|
||||
POST /scoped/sys/ai/plugin/find
|
||||
Content-Type: application/json
|
||||
Authorization: <token>
|
||||
```
|
||||
|
||||
请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"keywords": ["aliyun", "dns"],
|
||||
"pluginType": "access",
|
||||
"includeBuiltIn": true,
|
||||
"includeStore": true
|
||||
}
|
||||
```
|
||||
|
||||
接口会分别查询内置插件和 `store` 插件,再合并返回:
|
||||
|
||||
- `type: "builtIn"`:内置插件,不通过在线开发 API 修改。
|
||||
- `type: "store"` 且有 `appId` 或 `developerId`:市场插件。
|
||||
- `type: "store"` 且没有 `appId`、`developerId`:本地插件。
|
||||
|
||||
结果中的 `editable` 是唯一的编辑权限依据;不能只按插件来源判断是否可修改。
|
||||
列表结果只返回插件基础信息,不返回 `content`、`setting`、`sysSetting`、`metadata` 或 `extra`。需要完整 YAML 时再调用 `/scoped/sys/ai/plugin/export`。
|
||||
|
||||
## 读取插件信息
|
||||
|
||||
```http
|
||||
POST /scoped/sys/ai/plugin/info?id=12
|
||||
Authorization: <token>
|
||||
```
|
||||
|
||||
## 导出完整 YAML
|
||||
|
||||
```http
|
||||
POST /scoped/sys/ai/plugin/export
|
||||
Content-Type: application/json
|
||||
Authorization: <token>
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 12
|
||||
}
|
||||
```
|
||||
|
||||
## 保存插件
|
||||
|
||||
使用完整 YAML 导入:
|
||||
|
||||
```http
|
||||
POST /scoped/sys/ai/plugin/import
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"content": "完整 YAML",
|
||||
"override": true,
|
||||
"type": "store"
|
||||
}
|
||||
```
|
||||
|
||||
保存后重新调用 `/scoped/sys/ai/plugin/find` 或 `/scoped/sys/ai/plugin/info` 验证。
|
||||
@@ -0,0 +1,423 @@
|
||||
# Component Examples
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins`.
|
||||
Detected **30** distinct component names.
|
||||
|
||||
These snippets are extracted from existing Certd plugins. For online plugins, place the object under `input.<field>.component` in the YAML document.
|
||||
|
||||
## `EmailSelector`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-other/plugins/plugin-deploy-to-mail.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "EmailSelector",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
}
|
||||
```
|
||||
|
||||
## `ParamsShow`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-template/email/plugin-common.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "ParamsShow",
|
||||
params: [
|
||||
{ label: "标题", value: "title" },
|
||||
{ label: "内容", value: "content" },
|
||||
{ label: "URL", value: "url" },
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
## `RemoteSelect`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/getter/aliyun.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "RemoteSelect",
|
||||
vModel: "value",
|
||||
pager: true,
|
||||
single: true,
|
||||
}
|
||||
```
|
||||
|
||||
## `a-alert`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-template/email/plugin-base.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "a-alert",
|
||||
props: {
|
||||
type: "info",
|
||||
message: "在标题和内容模版中,通过${name}引用参数,例如: 感谢注册,您的注册验证码为:${code}",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## `a-auto-complete`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack/index.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "a-auto-complete",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ value: "cn-qingdao", label: "华北1(青岛)" },
|
||||
{ value: "cn-beijing", label: "华北2(北京)" },
|
||||
{ value: "cn-zhangjiakou", label: "华北3(张家口)" },
|
||||
{ value: "cn-huhehaote", label: "华北5(呼和浩特)" },
|
||||
{ value: "cn-wulanchabu", label: "华北6(乌兰察布)" },
|
||||
{ value: "cn-hangzhou", label: "华东1(杭州)" },
|
||||
{ value: "cn-shanghai", label: "华东2(上海)" },
|
||||
{ value: "cn-shenzhen", label: "华南1(深圳)" },
|
||||
{ value: "cn-guangzhou", label: "华南3(广州)" },
|
||||
{ value: "ap-southeast-2", label: "澳大利亚(悉尼)" },
|
||||
{ value: "ap-southeast-3", label: "马来西亚(吉隆坡)" },
|
||||
{ value: "ap-northeast-1", label: "日本(东京)" },
|
||||
{ value: "cn-chengdu", label: "西南1(成都)" },
|
||||
{ value: "ap-southeast-1", label: "新加坡" },
|
||||
{ value: "ap-southeast-5", label: "印度尼西亚(雅加达)" },
|
||||
{ value: "cn-hongkong", label: "中国香港" },
|
||||
{ value: "eu-central-1", label: "德国(法兰克福)" },
|
||||
{ value: "us-east-1", label: "美国(弗吉尼亚)" },
|
||||
{ value: "us-west-1", label: "美国(硅谷)" },
|
||||
{ value: "eu-west-1", label: "英国(伦敦)" },
|
||||
{ value: "me-east-1", label: "阿联酋(迪拜)" },
|
||||
//金融云
|
||||
{ value: "cn-beijing-finance-1", label: "华北2 金融云(邀测)" },
|
||||
{ value: "cn-hangzhou-finance", label: "华东1 金融云" },
|
||||
{ value: "cn-shanghai-finance-1", label: "华东2 金融云" },
|
||||
{ value: "cn-shenzhen-finance-1", label: "华南1 金融云" },
|
||||
],
|
||||
placeholder: "集群所属大区",
|
||||
}
|
||||
```
|
||||
|
||||
## `a-input`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-admin/plugin-db-backup.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "a-input",
|
||||
type: "value",
|
||||
placeholder: `默认${defaultBackupDir}`,
|
||||
}
|
||||
```
|
||||
|
||||
## `a-input-number`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-acepanel/access.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "a-input-number",
|
||||
vModel: "value",
|
||||
}
|
||||
```
|
||||
|
||||
## `a-input-password`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-51dns/access.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "a-input-password",
|
||||
vModel: "value",
|
||||
placeholder: "密码",
|
||||
}
|
||||
```
|
||||
|
||||
## `a-radio-group`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-esa/index.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "a-radio-group",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ label: "边缘证书", value: "edge" },
|
||||
{ label: "SaaS证书", value: "saas" },
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
## `a-select`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-admin/plugin-db-backup.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "a-select",
|
||||
options: [
|
||||
{ label: "本地复制", value: "local" },
|
||||
{ label: "oss上传(推荐)", value: "oss" },
|
||||
{ label: "ssh上传(请使用oss上传方式)", value: "ssh", disabled: true },
|
||||
],
|
||||
placeholder: "",
|
||||
}
|
||||
```
|
||||
|
||||
## `a-switch`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-acepanel/access.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "a-switch",
|
||||
vModel: "checked",
|
||||
}
|
||||
```
|
||||
|
||||
## `a-textarea`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-admin/plugin-script.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "a-textarea",
|
||||
vModel: "value",
|
||||
rows: 10,
|
||||
style: "background-color: #000c17;color: #fafafa;",
|
||||
}
|
||||
```
|
||||
|
||||
## `access-selector`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-acepanel/plugins/plugin-deploy-to-website.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "acepanel",
|
||||
}
|
||||
```
|
||||
|
||||
## `api-test`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-51dns/access.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest",
|
||||
}
|
||||
```
|
||||
|
||||
## `cert-info-updater`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/custom/index.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "cert-info-updater",
|
||||
vModel: "modelValue",
|
||||
}
|
||||
```
|
||||
|
||||
## `dns-provider-selector`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/apply.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "dns-provider-selector",
|
||||
}
|
||||
```
|
||||
|
||||
## `domain-selector`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/base-convert.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "domain-selector",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
// open: false,
|
||||
placeholder: "请输入证书域名/IP,比如:foo.com , *.foo.com , *.sub.foo.com , *.bar.com , 123.123.123.123",
|
||||
tokenSeparators: [",", " ", ",", "、", "|"],
|
||||
search: true,
|
||||
pager: true,
|
||||
}
|
||||
```
|
||||
|
||||
## `domains-verify-plan-editor`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/apply.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "domains-verify-plan-editor",
|
||||
}
|
||||
```
|
||||
|
||||
## `email-selector`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/base.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "email-selector",
|
||||
vModel: "value",
|
||||
}
|
||||
```
|
||||
|
||||
## `fs-icon-selector`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-oauth/oidc/plugin-oidc.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "fs-icon-selector",
|
||||
vModel: "modelValue",
|
||||
iconSets: IconSets,
|
||||
}
|
||||
```
|
||||
|
||||
## `icon-select`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/apply.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "icon-select",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ value: "letsencrypt", label: "Let's Encrypt(免费,新手推荐,支持IP证书)", icon: "simple-icons:letsencrypt" },
|
||||
{ value: "google", label: "Google(免费)", icon: "flat-color-icons:google" },
|
||||
{ value: "zerossl", label: "ZeroSSL(免费)", icon: "emojione:digit-zero" },
|
||||
{ value: "litessl", label: "litessl(免费)", icon: "roentgen:free" },
|
||||
{ value: "sslcom", label: "SSL.com(仅主域名和www免费)", icon: "la:expeditedssl" },
|
||||
{ value: "letsencrypt_staging", label: "Let's Encrypt测试环境(仅供测试)", icon: "simple-icons:letsencrypt" },
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
## `input-password`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/base-convert.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "input-password",
|
||||
vModel: "value",
|
||||
}
|
||||
```
|
||||
|
||||
## `notification-selector`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-github/plugins/plugin-check-release.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "notification-selector",
|
||||
select: {
|
||||
mode: "tags",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## `output-selector`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-acepanel/plugins/plugin-deploy-to-website.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames],
|
||||
}
|
||||
```
|
||||
|
||||
## `pem-input`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/custom/index.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "pem-input",
|
||||
vModel: "modelValue",
|
||||
textarea: {
|
||||
rows: 4,
|
||||
placeholder: "-----BEGIN CERTIFICATE-----\n...\n...\n-----END CERTIFICATE-----",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## `refresh-input`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-cert/access/acme-account-access.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "refresh-input",
|
||||
action: "GenerateAccount",
|
||||
buttonText: "生成ACME账号",
|
||||
successMessage: "ACME账号已生成,请保存授权配置",
|
||||
type: "textarea",
|
||||
rows: 4,
|
||||
}
|
||||
```
|
||||
|
||||
## `remote-auto-complete`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-apig/index.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "remote-auto-complete",
|
||||
}
|
||||
```
|
||||
|
||||
## `remote-select`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-nginx-proxy-manager/plugins/plugin-deploy-to-proxy-hosts.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "remote-select",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
type: "plugin",
|
||||
action: "onGetProxyHostOptions",
|
||||
search: true,
|
||||
pager: false,
|
||||
single: false,
|
||||
watches: ["certDomains", "accessId"],
|
||||
}
|
||||
```
|
||||
|
||||
## `remote-tree-select`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-tencent/plugin/refresh-cert/index.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
name: "remote-tree-select",
|
||||
vModel: "value",
|
||||
action: TencentRefreshCert.prototype.onGetRegionsTree.name,
|
||||
pager: false,
|
||||
search: false,
|
||||
watches: ["certList"],
|
||||
}
|
||||
```
|
||||
|
||||
## `synology-device-id-getter`
|
||||
|
||||
Source: `packages/ui/certd-server/src/plugins/plugin-plus/synology/access.ts`
|
||||
|
||||
```ts
|
||||
component: {
|
||||
placeholder: "设备ID",
|
||||
name: "synology-device-id-getter",
|
||||
type: "access",
|
||||
typeName: "synology",
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,25 @@
|
||||
# 本地历史记录
|
||||
|
||||
历史记录和开发临时文件只保存在 Codex/Trae 当前工作区的 `.tmp/online-plugin-dev/` 下,不调用 Certd 后端历史接口。
|
||||
|
||||
目录格式:
|
||||
|
||||
```text
|
||||
.tmp/online-plugin-dev/
|
||||
history/
|
||||
plugin-12/
|
||||
2026-08-02T12-30-00-before-edit.yaml
|
||||
2026-08-02T12-30-00-change.md
|
||||
work/
|
||||
plugin-12.yaml
|
||||
plugin-12-content.js
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 修改前保存完整 YAML。
|
||||
- 临时 YAML、脚本草稿、调试记录都放到 `.tmp/online-plugin-dev/` 下,不散落到项目目录。
|
||||
- `change.md` 只记录插件 ID、版本、时间和脱敏修改摘要。
|
||||
- 不保存 Token、证书、私钥、Cookie、环境变量和真实授权值。
|
||||
- 恢复历史版本前先备份当前 YAML。
|
||||
- 恢复后通过 `/scoped/sys/ai/plugin/import` 写回 Certd。
|
||||
@@ -0,0 +1,181 @@
|
||||
# mergeScript 用法
|
||||
|
||||
来源:前端 `packages/ui/certd-client/src/use/use-refrence.tsx`,类型定义来自 `@fast-crud/fast-crud`。
|
||||
|
||||
`mergeScript` 用来让输入字段的定义**依赖当前表单里的其他字段值动态变化**,例如:
|
||||
选了某个鉴权方式才显示对应字段、切换类型后清空已选值、下拉选项跟着另一个字段变。
|
||||
|
||||
它写成字符串放在字段定义上(内置插件放在 `@AccessInput` / `@TaskInput` 里,在线插件放在 `input.<字段>` 下):
|
||||
|
||||
```ts
|
||||
@AccessInput({
|
||||
title: "API Key",
|
||||
component: { name: "a-input", vModel: "value" },
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
//access里面 要用 form.access.[字段名]
|
||||
return form.access.authType === 'apikey';
|
||||
//deploy插件里面要用form.[字段名]
|
||||
return form.authType === 'apikey';
|
||||
})
|
||||
}
|
||||
`,
|
||||
})
|
||||
apiKey = "";
|
||||
```
|
||||
|
||||
## 执行时机
|
||||
|
||||
字段定义被前端加载时,对**每一个字段**执行一次:
|
||||
|
||||
```js
|
||||
const func = new Function('ctx', formItem.mergeScript);
|
||||
const merged = func(ctx); // 字段脚本只执行这一次
|
||||
merge(formItem, merged); // 返回值深合并进该字段的定义
|
||||
delete formItem.mergeScript; // 执行完就删掉,最终定义里不再有 mergeScript
|
||||
```
|
||||
|
||||
要点:
|
||||
|
||||
- 脚本体内**必须 `return` 一个对象**,返回的对象会深合并到本字段的定义上。
|
||||
- 脚本本身只在加载字段时跑一次,**拿不到、也不应该判断用户填了什么值**。
|
||||
- 真正的动态逻辑写在返回对象里的 `ctx.compute(...)` 回调中,由 fast-crud 在渲染时求值。
|
||||
|
||||
## ctx 提供的能力
|
||||
|
||||
| 能力 | 说明 |
|
||||
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `ctx.compute(fn)` | 最常用。返回一个响应式的计算值:`fn` 里读到的表单字段会被自动追踪,字段变化时重新计算,视图跟着刷新 |
|
||||
|
||||
`ctx.compute` 的回调参数是一个 context 对象,常用字段:
|
||||
|
||||
- `form`:当前表单数据。**这是唯一常用的一个**。
|
||||
- `row`:行数据。
|
||||
- `mode`:表单模式 `add` / `edit` / `view`。
|
||||
- `getComponentRef(key)`:取其他字段组件的 ref。
|
||||
|
||||
注意:Certd 在把 `form` 传进回调前做过一次兼容处理(`form.input || form.body || form`),
|
||||
所以两种表单取值路径不同:
|
||||
|
||||
- **授权(Access)表单**:字段值在 `form.access.xxx`(字段 key 会被加上 `access.` 前缀)。
|
||||
- **任务(Task)表单**:字段值直接是 `form.xxx`。
|
||||
|
||||
## 可以动态化的属性
|
||||
|
||||
返回的对象里,任何字段定义属性都可以用 `ctx.compute`,常用的有:
|
||||
|
||||
| 属性 | 用途 |
|
||||
| -------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| `show` | 显隐(最常用) |
|
||||
| `required` | 动态必填,例如 `required: ctx.compute(({form}) => form.targetType === 'ingress')` |
|
||||
| `disabled` | 动态禁用,例如账号已创建后不允许再改:`disabled: ctx.compute(({form}) => !!form.access?.account)` |
|
||||
| `helper` | 动态帮助文案,回调里按条件 `return` 不同字符串 |
|
||||
| `value` | 动态默认值 |
|
||||
| `component` 下的属性 | 动态 `options`、`placeholder`、`inputKey`、`type`、`disabled` 等 |
|
||||
| `component.on` | 事件处理,见下面「联动」 |
|
||||
| `col` / `order` | 布局与排序 |
|
||||
|
||||
只写了一层 `show` 时最简形式就是本文开头的例子。
|
||||
|
||||
## 联动(监听事件并改动其他字段)
|
||||
|
||||
`component.on` 的事件回调**不**用 `ctx.compute` 包,它本身就是回调,参数是
|
||||
`{ form, $event, ... }`;`form` 同样做过 `form.input || form.body || form` 的兼容处理。
|
||||
事件名按组件而定,例如 `selectedChange`。
|
||||
|
||||
```ts
|
||||
mergeScript: `
|
||||
return {
|
||||
component: {
|
||||
on: {
|
||||
selectedChange: (scope) => {
|
||||
const form = scope.form;
|
||||
// 切换颁发机构后清空 ACME 账号,避免账号与机构不匹配
|
||||
form.acmeAccountAccessId = null;
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`,
|
||||
```
|
||||
|
||||
另一种写法是把回调也做成计算值(需要用到组件上配置的 `onSelectedChange` / `onChange` 属性):
|
||||
|
||||
```ts
|
||||
mergeScript: `
|
||||
return {
|
||||
component: {
|
||||
onSelectedChange: ctx.compute(({form}) => {
|
||||
return ($event) => {
|
||||
form.dnsProviderAccessType = $event.accessType;
|
||||
};
|
||||
}),
|
||||
},
|
||||
}
|
||||
`,
|
||||
```
|
||||
|
||||
两种写法都能用,优先参考同目录已有插件的写法,保持一致。
|
||||
|
||||
## 常见错误
|
||||
|
||||
- **不要用 node 侧变量决定条件**。`mergeScript` 是在插件类定义阶段(node 侧)拼出来的字符串,
|
||||
此时表单还没打开,拿不到任何用户输入;用参数拼条件等于把逻辑写死在服务端。
|
||||
条件必须原样落到 `ctx.compute` 回调里。
|
||||
- **不要用 `if` 直接判断字段值**。回调必须 `return` 一个值,写成
|
||||
`show: ctx.compute(({form}) => { if (...) { return true } })` 也可以,但不要漏掉 `return`。
|
||||
- **不要漏掉历史数据兼容**。新增可选字段时,历史数据里没有这个字段(值为 `undefined`),
|
||||
条件要按旧行为兜底,例如 `!form.access.authType || form.access.authType === 'aksk'`。
|
||||
- **不要访问 `form.access` 以外的路径**去读授权字段,也不要在授权表单里按任务表单的路径取值。
|
||||
- **不要依赖脚本执行时的副作用**(打印日志、改全局状态),它在每次打开表单时都会重新执行。
|
||||
|
||||
## YAML 写法(在线插件)
|
||||
|
||||
`mergeScript` 是含换行的脚本字符串,必须用 YAML 块标量:
|
||||
|
||||
```yaml
|
||||
input:
|
||||
apiKey:
|
||||
title: API Key
|
||||
component:
|
||||
name: a-input
|
||||
vModel: value
|
||||
mergeScript: |2-
|
||||
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.access.authType === 'apikey';
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
导出生成的缩进比较特殊(块标量内容统一缩进),**不要手工调整缩进**:
|
||||
用脚本生成 YAML,并保证导出后再导入内容一致。转换成 block scalar 时注意:
|
||||
|
||||
- `|` / `|2-` 等块标量不需要转义换行,不要把脚本写成带 `\n` 的单行。
|
||||
- 脚本里不要出现 `??` 这类容易被误判为乱码的写法,用显式 `if (x == null)` 代替。
|
||||
|
||||
## 验证方式
|
||||
|
||||
前端表单没法在插件开发流程里直接断言,可以在后端加一个 `src/**/*.test.ts`,
|
||||
按前端 `useReference` 的路径执行字段上的 `mergeScript`:
|
||||
|
||||
```ts
|
||||
const computedGetters = [];
|
||||
const ctx = {
|
||||
compute: getter => {
|
||||
computedGetters.push(getter);
|
||||
return getter;
|
||||
},
|
||||
asyncCompute: () => undefined,
|
||||
computed: () => undefined,
|
||||
};
|
||||
new Function('ctx', mergeScript)(ctx);
|
||||
// 用假的 form 求值,断言显隐结果
|
||||
const show = computedGetters[0]({ form: { access: { authType: 'apikey' } } });
|
||||
```
|
||||
|
||||
参考实现:`packages/ui/certd-server/src/plugins/plugin-wangsu/access-input.test.ts`。
|
||||
要点是断言「同一个 show 函数换 `authType` 结果会变」,证明显隐确实是运行时算的,
|
||||
而不是在 node 侧定死的。
|
||||
@@ -0,0 +1,68 @@
|
||||
## 在线插件 YAML
|
||||
|
||||
在线插件始终以一个完整 YAML 文档传递、编辑、导入和导出。脚本源码必须放在顶层 `content` 字段中,不要输出独立的 `.ts` 文件,也不要使用 JSON Patch。
|
||||
|
||||
常用字段:
|
||||
|
||||
```yaml
|
||||
name: DemoTask
|
||||
author: demo
|
||||
title: Demo-插件名称 # 格式:平台-功能 ,例如: 网宿-更新CDNpro证书 ; 阿里云-上传到CAS证书管理服务 ; 天翼云-更新CDN证书
|
||||
desc: 插件说明
|
||||
icon: clarity:plugin-line
|
||||
pluginType: task
|
||||
group: other
|
||||
version: 1.0.0
|
||||
input:
|
||||
cert: # 输入字段定义
|
||||
title: 域名证书
|
||||
required: true # 是否必填
|
||||
component: # 输入字段组件
|
||||
name: cert-select # 前端vue组件名称
|
||||
output: # 【可选】输出字段定义
|
||||
cert:
|
||||
title: 证书 #输出字段标题
|
||||
type: "cert" # 输出字段类型
|
||||
dependPlugins: # 依赖的插件
|
||||
# - access:certd/DemoAccess: *
|
||||
dependPackages: # 依赖的nodejs包
|
||||
# xxx: ^1.0.0
|
||||
vip: "free" # 默认免费,plus 需要专业版
|
||||
showRunStrategy: false # 【默认不显示】
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: 0, # 运行策略, 0 = 成功后跳过,1 = 正常运行
|
||||
},
|
||||
}
|
||||
content: |
|
||||
const { AbstractTaskPlugin } = await _ctx.import("@certd/pipeline")
|
||||
const { DemoAccess } = await _ctx.import("/@/plugins/plugin-lib/demo/access/index.js")
|
||||
_ctx.logger.info("DemoAccess:", DemoAccess)
|
||||
return class DemoTask extends AbstractTaskPlugin {
|
||||
async execute() {
|
||||
this.logger.info("执行成功")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `content` 规则
|
||||
|
||||
- 统一使用 `await _ctx.import(...)` 加载模块。
|
||||
- 使用 `_ctx.import("/@/...")` 以绝对路径加载 `certd-server/src/` 下的模块,`/@` 代表 `certd-server/src` 根路径。
|
||||
- 需要确认模块时使用 `_ctx.logger`,插件执行过程使用 `this.logger`。
|
||||
- 最后返回继承目标基类的 class。
|
||||
- 不使用 `import`、`export`、装饰器或独立源码文件语法。
|
||||
- 输入字段在 class 中声明为同名属性,并与 YAML 的 `input` 配置保持一致。
|
||||
- HTTP 使用 `this.ctx.http`;
|
||||
- 不要使用 `console.log`。
|
||||
- 读取授权使用 `await this.getAccess(accessId)` 或目标基类规定的授权方式。
|
||||
- 失败时抛出 `Error`,不要吞掉错误。
|
||||
|
||||
### 编辑规则
|
||||
|
||||
- 修改已有插件时保留 `name`、`author`、`pluginType` 和已有兼容字段。
|
||||
- 新插件的 `author` 使用启动提示词中给出的插件作者,不要自行编造作者名;启动提示词未给出作者时先向用户确认。
|
||||
- `fullName` 由 `author/name` 组成,作者变化会导致插件身份变化,不要随意修改。
|
||||
- 只修改需求涉及的字段,避免删除未知的 YAML 字段。
|
||||
- 脚本过长时仍放在同一个 `content` block scalar 中。
|
||||
- 提交前检查 YAML 可解析、`content` 非空、版本和插件类型没有被意外修改。
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
name: certd-online-access-plugin-dev
|
||||
description: 用于开发 Certd 在线 Access 插件。输出完整 YAML,content 中返回继承 BaseAccess 的 class,并在 input 中声明授权字段。
|
||||
---
|
||||
|
||||
# 在线 Access 插件
|
||||
|
||||
读取父 Skill 的 `references/online-yaml-format.md`。不要沿用代码版 `@IsAccess`、`@AccessInput` 装饰器和独立 TypeScript 文件。
|
||||
|
||||
## 输出结构
|
||||
|
||||
- `pluginType` 使用 `access`。
|
||||
- `input` 中声明用户需要填写的授权字段。
|
||||
- 敏感字段在 input 中设置加密或密码类组件。
|
||||
- `content` 中实现授权 class 和 API 方法。
|
||||
|
||||
## `content` 模板
|
||||
|
||||
```javascript
|
||||
const { BaseAccess } = await _ctx.import("@certd/pipeline")
|
||||
|
||||
return class DemoAccess extends BaseAccess {
|
||||
demoKeyId
|
||||
demoKeySecret
|
||||
|
||||
async onTestRequest() {
|
||||
await this.getDomainList({ searchKey: "" })
|
||||
return "ok"
|
||||
}
|
||||
|
||||
async getDomainList(req) {
|
||||
this.logger.info("获取域名列表", { searchKey: req.searchKey })
|
||||
const res = await this.ctx.http.request({
|
||||
url: "https://api.example.com/domains",
|
||||
method: "GET",
|
||||
params: { keyword: req.searchKey },
|
||||
})
|
||||
if (res.error) {
|
||||
throw new Error(`获取域名列表失败: ${res.message}`)
|
||||
}
|
||||
return {
|
||||
total: res.data?.total || 0,
|
||||
list: res.data?.list || [],
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 编写要求
|
||||
|
||||
- 统一使用 `await _ctx.import(...)` 加载模块。
|
||||
- 使用 `_ctx.import("/@/...")` 通过绝对路径加载 `server/src/` 下的模块,`/@` 代表 `server/src` 根路径。
|
||||
- 需要记录模块加载信息时使用 `_ctx.logger`,访问执行日志使用 `this.logger`。
|
||||
- 返回继承 `BaseAccess` 的 class,不使用装饰器。
|
||||
- class 属性名必须与 YAML `input` 字段一致。
|
||||
- 所有敏感授权值只通过 `this` 和 Certd 授权上下文使用,不打印真实值。
|
||||
- `onTestRequest` 应调用实际 API 方法并在失败时抛出异常。
|
||||
- 对外 API 方法应统一处理分页、错误和返回字段。
|
||||
- 使用 `this.logger` 或框架提供的 logger,禁止 `console.log`。
|
||||
- 一般将API接口方法封装到Access中,其他plugin调用access的方法当做client sdk使用
|
||||
|
||||
## 字段动态显隐
|
||||
|
||||
多种鉴权方式(例如「ApiKey」和「AccessKey签名」)共用一个授权时,
|
||||
用字段上的 `mergeScript` 按所选方式显隐对应字段,只让用户看到当前方式需要的字段:
|
||||
|
||||
```yaml
|
||||
input:
|
||||
authType:
|
||||
title: 鉴权方式
|
||||
value: apikey
|
||||
component:
|
||||
name: a-select
|
||||
vModel: value
|
||||
options:
|
||||
- { label: AccessKey签名, value: aksk }
|
||||
- { label: ApiKey, value: apikey }
|
||||
accessKeyId:
|
||||
title: accessKeyId
|
||||
component:
|
||||
name: a-input
|
||||
vModel: value
|
||||
mergeScript: |2-
|
||||
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return !form.access.authType || form.access.authType === 'aksk';
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
- 判断必须写在 `ctx.compute(({form})=>{ ... })` 回调里;脚本本身在插件定义阶段就拼好了,
|
||||
那时表单还没打开,用参数在服务端判断字段值没有意义。
|
||||
- 授权表单的字段值在 `form.access.xxx`(任务表单才是 `form.xxx`)。
|
||||
- 历史授权没有 `authType` 字段,条件里要用 `!form.access.authType || ...` 兜底走旧逻辑。
|
||||
|
||||
完整用法见父 Skill 的 `references/merge-script.md`。
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
name: certd-online-dns-provider-dev
|
||||
description: 用于开发 Certd 在线 DNS Provider 插件。输出完整 YAML,content 中返回继承 AbstractDnsProvider 的 class。
|
||||
---
|
||||
|
||||
# 在线 DNS Provider 插件
|
||||
|
||||
读取父 Skill 的 `references/online-yaml-format.md`。不要沿用旧版 `@IsDnsProvider` 装饰器和独立 TypeScript 文件。
|
||||
|
||||
## 输出结构
|
||||
|
||||
- `pluginType` 使用 `dnsProvider`。
|
||||
- `input` 中配置授权选择、域名或平台所需的参数。
|
||||
- `content` 中实现创建和删除 DNS 记录的 class。
|
||||
|
||||
## `content` 模板
|
||||
|
||||
```javascript
|
||||
const { AbstractDnsProvider } = await _ctx.import("@certd/pipeline")
|
||||
const { DemoAccess } = await _ctx.import("/@/plugins/plugin-lib/demo/access/index.js")
|
||||
_ctx.logger.info("DemoAccess:", DemoAccess)
|
||||
|
||||
return class DemoDnsProvider extends AbstractDnsProvider {
|
||||
accessId
|
||||
|
||||
async onInstance() {
|
||||
this.access = await this.getAccess(this.accessId)
|
||||
}
|
||||
|
||||
async createRecord(options) {
|
||||
const { fullRecord, value, type, domain } = options
|
||||
this.logger.info("添加 DNS 记录", { fullRecord, type, domain })
|
||||
const res = await this.ctx.http.request({
|
||||
url: "https://api.example.com/dns/records",
|
||||
method: "POST",
|
||||
data: { fullRecord, value, type, domain },
|
||||
})
|
||||
if (res.error) {
|
||||
throw new Error(`创建 DNS 记录失败: ${res.message}`)
|
||||
}
|
||||
return res.data
|
||||
}
|
||||
|
||||
async removeRecord(options) {
|
||||
const { fullRecord, value, domain } = options.recordReq
|
||||
const res = await this.ctx.http.request({
|
||||
url: "https://api.example.com/dns/records",
|
||||
method: "DELETE",
|
||||
data: { fullRecord, value, domain },
|
||||
})
|
||||
if (res.error) {
|
||||
this.logger.warn("删除 DNS 记录失败", res.message)
|
||||
return
|
||||
}
|
||||
this.logger.info("删除 DNS 记录成功", fullRecord)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 编写要求
|
||||
|
||||
- 统一使用 `await _ctx.import(...)` 加载模块。
|
||||
- 使用 `_ctx.import("/@/...")` 通过绝对路径加载 `server/src/` 下的模块,`/@` 代表 `server/src` 根路径。
|
||||
- 需要记录模块加载信息时使用 `_ctx.logger`。
|
||||
- 返回继承 `AbstractDnsProvider` 的 class。
|
||||
- `createRecord` 必须返回删除时需要的记录信息。
|
||||
- `removeRecord` 使用 `options.recordReq` 和 `options.recordRes`。
|
||||
- 只处理业务 API 所需的 TXT 记录参数,不在日志中输出授权密钥。
|
||||
- 网络失败、授权失败和 API 业务失败要有明确日志;创建失败必须抛出异常。
|
||||
- 保持创建和删除幂等,避免清理失败阻断无关流程。
|
||||
- 一般将API接口方法封装到Access中,其他plugin使用access当做client sdk使用
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
name: certd-online-task-plugin-dev
|
||||
description: 用于开发 Certd 在线 Task 插件。输出完整 YAML,脚本源码放在 content 字段中,继承 AbstractTaskPlugin 并返回插件 class。
|
||||
---
|
||||
|
||||
# 在线 Task 插件
|
||||
|
||||
读取父 Skill 的 `references/online-yaml-format.md`。在线插件不是原来的装饰器源码文件模式。
|
||||
|
||||
## 输出结构
|
||||
|
||||
- `pluginType` 使用 `task`。
|
||||
- 保留或填写 `name`、`author`、`title`、`desc`、`icon`、`group`、`version`。
|
||||
- 输入配置放在 YAML 的 `input` 字段。
|
||||
- 执行脚本放在 YAML 顶层 `content` 字段。
|
||||
|
||||
|
||||
## runStrategy
|
||||
|
||||
整个流水线每次运行,会记录每个任务的运行结果状态,如果上次任务执行成功,且 runStrategy 为成功后跳过,那么下次运行时会跳过该任务。
|
||||
|
||||
|
||||
- `showRunStrategy`: false 【默认不显示】
|
||||
- 任务配置时是否显示 runStrategy 字段,用于指定任务的执行策略。
|
||||
- `default.strategy.runStrategy`: 0 【默认成功后跳过】
|
||||
- 0 表示成功后跳过,1 表示正常运行。
|
||||
- 设置任务的默认运行策略runStrategy。
|
||||
|
||||
当证书申请任务,申请证书成功后,会清空后续任务状态。此时后续`runStrategy = 0` 的任务,会重新执行。
|
||||
这样可以保证相同的证书不会重复部署。
|
||||
|
||||
在其他场景的部署任务,可能希望每次运行都检查是否需要部署,如果即将过期就部署,没有过期就跳过。
|
||||
此时可以设置 `default.strategy.runStrategy = 1`,然后在`execute`方法中,如果没有过期,就返回 `"skip"`。
|
||||
|
||||
## `content` 模板
|
||||
|
||||
```javascript
|
||||
const { AbstractTaskPlugin } = await _ctx.import("@certd/pipeline")
|
||||
const { DemoAccess } = await _ctx.import("/@/plugins/plugin-lib/demo/access/index.js")
|
||||
_ctx.logger.info("DemoAccess:", DemoAccess)
|
||||
|
||||
return class DemoTask extends AbstractTaskPlugin {
|
||||
cert
|
||||
certDomains
|
||||
accessId
|
||||
|
||||
async execute() {
|
||||
const access = await this.getAccess(this.accessId)
|
||||
this.logger.info("开始执行任务", { access })
|
||||
const res = await this.ctx.http.request({
|
||||
url: "https://api.example.com",
|
||||
})
|
||||
if (res.error) {
|
||||
// 抛异常让任务执行失败
|
||||
throw new Error(`任务执行失败: ${res.message}`)
|
||||
}
|
||||
this.logger.info("执行成功")
|
||||
// 还可以返回 "skip" 表示当前任务没有执行任何操作
|
||||
// 一般与 runStrategy = 1 配合使用。 (1=正常运行,0表示成功后跳过)
|
||||
// 比如检查无需更新,时就 返回 "skip"
|
||||
// return "skip"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 编写要求
|
||||
|
||||
- 统一用 `await _ctx.import(...)` 加载模块。
|
||||
- 使用 `_ctx.import("/@/...")` 通过绝对路径加载 `server/src/` 下的模块,`/@` 代表 `server/src` 根路径。
|
||||
- 需要记录模块加载信息时使用 `_ctx.logger`。
|
||||
- 返回继承 `AbstractTaskPlugin` 的 class,不写 `export class`。
|
||||
- class 属性名必须对应 `input` 配置的字段名。
|
||||
- 用 `this.logger` 记录关键步骤。
|
||||
- 用 `this.ctx.http` 请求远程 API,用 `this.getAccess` 获取授权。
|
||||
- 外部 API 返回失败或业务失败时抛出异常。
|
||||
- 对重复执行保持幂等,避免把真实 Token、证书和私钥写入日志。
|
||||
- 修改完成后把整个 YAML 通过 Certd `/scoped/sys/ai/plugin/import` 保存。
|
||||
- 一般将API接口方法封装到Access中,其他plugin使用access当做client sdk使用
|
||||
@@ -7,30 +7,39 @@ version: 1.0.0
|
||||
# DNS Provider 插件开发技能
|
||||
|
||||
## 角色定义
|
||||
|
||||
你是一名 Certd 插件开发专家,擅长创建和实现 DNS Provider 类型的插件,熟悉 TypeScript 编程和 Certd 插件开发规范。
|
||||
|
||||
## 核心指令
|
||||
|
||||
请严格按照以下步骤执行任务:
|
||||
|
||||
1. **导入必要的依赖**
|
||||
|
||||
- 导入 `AbstractDnsProvider`, `CreateRecordOptions`, `IsDnsProvider`, `RemoveRecordOptions` 等必要的类型和装饰器
|
||||
- 导入对应的 Access 插件类型
|
||||
|
||||
2. **定义记录数据结构**
|
||||
|
||||
- 定义适合对应云平台的记录数据结构
|
||||
- 至少包含 id 字段,用于后续删除记录
|
||||
|
||||
3. **使用 @IsDnsProvider 注解注册插件**
|
||||
|
||||
- 配置插件的唯一标识、标题、描述、图标
|
||||
- 指定对应的云平台的 access 类型名称
|
||||
- 设置排序值(可选)
|
||||
- 继承 `AbstractDnsProvider` 类
|
||||
- 插件默认文案使用中文;需要英文时,在注解参数对象中添加同级 `i18n: { "en-US": { ... } }`,不要写成 `metadata.i18n`。`define` 本身就是插件 metadata。
|
||||
- `i18n["en-US"]` 仅配置要翻译的展示字段,如 `title`、`desc`、`input`;输入字段可翻译 `title`、`helper`、组件展示文案和 `optionsMapping`。缺少英文翻译时回退默认中文。
|
||||
|
||||
4. **实现 onInstance 方法**
|
||||
|
||||
- 获取并保存对应的 Access 实例
|
||||
- 执行初始化操作
|
||||
|
||||
5. **实现 createRecord 方法**
|
||||
|
||||
- 解析传入的参数(fullRecord, value, type, domain)
|
||||
- 记录操作开始日志
|
||||
- 调用云平台 API 创建 TXT 类型的 DNS 解析记录
|
||||
@@ -39,6 +48,7 @@ version: 1.0.0
|
||||
- 返回创建的记录信息,用于后续删除操作
|
||||
|
||||
6. **实现 removeRecord 方法**
|
||||
|
||||
- 解析传入的参数和之前创建的记录信息
|
||||
- 记录操作开始日志
|
||||
- 调用云平台 API 删除 TXT 类型的 DNS 解析记录
|
||||
@@ -46,6 +56,7 @@ version: 1.0.0
|
||||
- 记录操作结果日志
|
||||
|
||||
7. **实现 getDomainListPage 方法**
|
||||
|
||||
- 实现获取域名列表的方法
|
||||
- 支持分页查询
|
||||
- 处理可能的错误:网络错误、API调用失败、授权失败等
|
||||
@@ -55,6 +66,7 @@ version: 1.0.0
|
||||
- 实例化插件,确保插件被注册
|
||||
|
||||
## 输出规范
|
||||
|
||||
- 必须包含完整的插件实现代码
|
||||
- 代码必须包含详细的注释说明
|
||||
- 提供完整的示例代码,展示插件的使用方法
|
||||
@@ -65,12 +77,13 @@ version: 1.0.0
|
||||
### 示例 1: 基本 DNS Provider 插件
|
||||
|
||||
#### 用户输入
|
||||
|
||||
创建一个 DNS Provider 插件,用于在 ACME 申请证书时添加和删除 TXT 解析记录。
|
||||
|
||||
#### 你的回答
|
||||
|
||||
```typescript
|
||||
import { Pager, PageRes, PageSearch } from "@certd/pipeline";
|
||||
import { Pager, PageRes, PageSearch } from '@certd/pipeline';
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions, DomainRecord } from '@certd/plugin-cert';
|
||||
import { DemoAccess } from './access.js';
|
||||
|
||||
@@ -124,7 +137,7 @@ export class DemoDnsProvider extends AbstractDnsProvider<DemoRecord> {
|
||||
// })
|
||||
// // 返回本次创建的 dns 解析记录,这个记录会在删除的时候用到
|
||||
// return record
|
||||
|
||||
|
||||
// 模拟返回
|
||||
return { id: 'demo-record-id' };
|
||||
} catch (error) {
|
||||
@@ -141,7 +154,7 @@ export class DemoDnsProvider extends AbstractDnsProvider<DemoRecord> {
|
||||
const { fullRecord, value, domain } = options.recordReq;
|
||||
const record = options.recordRes;
|
||||
this.logger.info('删除域名解析:', domain, fullRecord, value, record);
|
||||
|
||||
|
||||
try {
|
||||
// 这里调用删除 txt dns 解析记录接口
|
||||
// 请根据实际接口情况调用,例如:
|
||||
@@ -150,7 +163,7 @@ export class DemoDnsProvider extends AbstractDnsProvider<DemoRecord> {
|
||||
// // 授权参数
|
||||
// // 删除 dns 解析记录的参数
|
||||
// })
|
||||
|
||||
|
||||
this.logger.info('删除域名解析成功:', fullRecord, value);
|
||||
} catch (error) {
|
||||
this.logger.error('删除DNS记录失败:', error);
|
||||
@@ -166,11 +179,12 @@ export class DemoDnsProvider extends AbstractDnsProvider<DemoRecord> {
|
||||
const pager = new Pager(req);
|
||||
const res = await this.http.request({
|
||||
// 请求接口获取域名列表
|
||||
})
|
||||
const list = res.Domains?.map(item => ({
|
||||
id: item.Id,
|
||||
domain: item.DomainName,
|
||||
})) || []
|
||||
});
|
||||
const list =
|
||||
res.Domains?.map(item => ({
|
||||
id: item.Id,
|
||||
domain: item.DomainName,
|
||||
})) || [];
|
||||
|
||||
return {
|
||||
list,
|
||||
@@ -190,6 +204,7 @@ new DemoDnsProvider();
|
||||
### 示例 2: 阿里云 DNS Provider 插件
|
||||
|
||||
#### 用户输入
|
||||
|
||||
创建一个阿里云 DNS Provider 插件,用于在 ACME 申请证书时添加和删除 TXT 解析记录。
|
||||
|
||||
#### 你的回答
|
||||
@@ -230,7 +245,7 @@ export class AliyunDnsProvider extends AbstractDnsProvider<AliyunRecord> {
|
||||
try {
|
||||
// 提取主机记录
|
||||
const hostRecord = fullRecord.replace(`.${domain}`, '');
|
||||
|
||||
|
||||
// 调用阿里云 API 创建解析记录
|
||||
const response = await this.access.doRequest({
|
||||
action: 'AddDomainRecord',
|
||||
@@ -240,7 +255,7 @@ export class AliyunDnsProvider extends AbstractDnsProvider<AliyunRecord> {
|
||||
Type: type,
|
||||
Value: value,
|
||||
TTL: 600, // 10分钟
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.info('阿里云DNS: 解析记录创建成功', { RecordId: response.RecordId });
|
||||
@@ -265,7 +280,7 @@ export class AliyunDnsProvider extends AbstractDnsProvider<AliyunRecord> {
|
||||
action: 'DeleteDomainRecord',
|
||||
data: {
|
||||
RecordId: record.RecordId,
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.info('阿里云DNS: 解析记录删除成功', { RecordId: record.RecordId });
|
||||
@@ -287,7 +302,7 @@ export class AliyunDnsProvider extends AbstractDnsProvider<AliyunRecord> {
|
||||
PageNumber: pager.page,
|
||||
PageSize: pager.pageSize,
|
||||
KeyWord: req.searchKey,
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const list = response.Domains.Domain.map((domain: any) => ({
|
||||
@@ -313,6 +328,7 @@ new AliyunDnsProvider();
|
||||
### 示例 3: 腾讯云 DNS Provider 插件
|
||||
|
||||
#### 用户输入
|
||||
|
||||
创建一个腾讯云 DNS Provider 插件,用于在 ACME 申请证书时添加和删除 TXT 解析记录。
|
||||
|
||||
#### 你的回答
|
||||
@@ -353,7 +369,7 @@ export class TencentDnsProvider extends AbstractDnsProvider<TencentRecord> {
|
||||
try {
|
||||
// 提取主机记录
|
||||
const hostRecord = fullRecord.replace(`.${domain}`, '');
|
||||
|
||||
|
||||
// 调用腾讯云 API 创建解析记录
|
||||
const response = await this.access.doRequest({
|
||||
action: 'CreateRecord',
|
||||
@@ -363,7 +379,7 @@ export class TencentDnsProvider extends AbstractDnsProvider<TencentRecord> {
|
||||
RecordType: type,
|
||||
RecordValue: value,
|
||||
TTL: 600, // 10分钟
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.info('腾讯云DNS: 解析记录创建成功', { RecordId: response.RecordId });
|
||||
@@ -388,7 +404,7 @@ export class TencentDnsProvider extends AbstractDnsProvider<TencentRecord> {
|
||||
action: 'DeleteRecord',
|
||||
data: {
|
||||
RecordId: record.RecordId,
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.info('腾讯云DNS: 解析记录删除成功', { RecordId: record.RecordId });
|
||||
@@ -410,7 +426,7 @@ export class TencentDnsProvider extends AbstractDnsProvider<TencentRecord> {
|
||||
Offset: (pager.page - 1) * pager.pageSize,
|
||||
Limit: pager.pageSize,
|
||||
Keyword: req.searchKey,
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const list = response.Domains.map((domain: any) => ({
|
||||
@@ -439,4 +455,5 @@ new TencentDnsProvider();
|
||||
2. **accessType**:必须指定对应的云平台的 access 类型名称。
|
||||
3. **记录结构**:定义适合对应云平台的记录数据结构,至少包含 id 字段用于删除记录。
|
||||
4. **日志输出**:使用 `this.logger` 输出日志,而不是 `console`,参数文本化,不要传对象,否则会输出`[object Object]}`。
|
||||
5. **错误处理**:API 调用失败时应抛出明确的错误信息。
|
||||
5. **错误处理**:API 调用失败时应抛出明确的错误信息。
|
||||
6. **旧版数据兼容**: 新增插件参数,必须要考虑旧版数据兼容,比如新增一个deployType参数,有两种值:`default`和`custom`,需要在使用时判空,走旧版逻辑。
|
||||
|
||||
@@ -1 +1 @@
|
||||
我需要开发一个 DNS Provider 插件,用于在 ACME 申请证书时添加 TXT 解析记录。请指导我如何实现。
|
||||
我需要开发一个 DNS Provider 插件,用于在 ACME 申请证书时添加 TXT 解析记录。请指导我如何实现。
|
||||
|
||||
@@ -118,4 +118,4 @@ if (isDev()) {
|
||||
3. **记录结构**:定义适合对应云平台的记录数据结构,至少包含 id 字段用于删除记录。
|
||||
4. **日志输出**:使用 `this.logger` 输出日志,而不是 `console`。
|
||||
5. **错误处理**:API 调用失败时应抛出明确的错误信息。
|
||||
6. **实例化**:生产环境中应移除 `if (isDev())` 条件,确保插件在生产环境中也能被注册。
|
||||
6. **实例化**:生产环境中应移除 `if (isDev())` 条件,确保插件在生产环境中也能被注册。
|
||||
|
||||
@@ -25,7 +25,7 @@ version: 1.0.0
|
||||
## 实现流程
|
||||
|
||||
1. 先在 `packages/ui/certd-client/src/views` 下找 1-2 个相近 Fast Crud 页面,沿用它们的导入、布局、命名和权限写法。
|
||||
2. 在 `index.vue` 中使用 `fs-crud ref="crudRef" v-bind="crudBinding"`,并在 `onMounted` / `onActivated` 时调用 `crudExpose.doRefresh()`。
|
||||
2. 在 `index.vue` 中使用 `fs-crud ref="crudRef" v-bind="crudBinding"`,并在 `onMounted` 或 `onActivated` 时调用 `crudExpose.doRefresh()`;两个生命周期同时存在时只保留一个刷新入口,避免首次进入页面请求两次。
|
||||
3. 在 `crud.tsx` 中配置 `request.pageRequest`、`columns`、`search`、`form`、`rowHandle`、`actionbar`、`toolbar` 等,接口分页参数和返回值按现有页面适配。
|
||||
4. 操作按钮优先放在 Fast Crud 的 `rowHandle.buttons` 或 `actionbar.buttons` 中;审核、保存设置、批量操作等复杂交互可通过 `context` 调用 `index.vue` 中的方法。
|
||||
5. 金额、状态、时间、枚举等字段优先复用项目已有组件、字典和格式化工具;避免在模板里重复堆格式化逻辑。
|
||||
@@ -33,42 +33,41 @@ version: 1.0.0
|
||||
7. 删除、审核通过、拒绝等危险操作必须保留确认弹窗和错误提示,成功后刷新当前 CRUD 列表。
|
||||
8. 对话框里只做纯确认时可以使用 `Modal.confirm`;只要需要字段输入、表单校验或提交字段,统一使用 `useFormDialog` / `openFormDialog`,不要在 `Modal.confirm` 的 `content` 里手写输入框。
|
||||
|
||||
|
||||
## crud 配置
|
||||
|
||||
const crudOptions ={
|
||||
id: string, //表格唯一标识,同一个页面的多个表格的列设置和字段设置会根据id进行区分保存
|
||||
request:{}, //http请求
|
||||
columns:{ //字段配置
|
||||
key:{ //字段key
|
||||
column:{}, //对应table-column配置
|
||||
form:{}, //表单中该字段的公共配置,viewForm、addForm、editForm、search会集成此配置,支持对应ui的form-item配置
|
||||
viewForm:{}, //查看表单中该字段的配置,支持对应ui的form-item配置
|
||||
addForm:{}, // 添加表单中该字段的配置,支持对应ui的form-item配置
|
||||
editForm:{}, //编辑表单中该字段的配置,支持对应ui的form-item配置
|
||||
search:{} //对应查询表单的form-item配置
|
||||
}
|
||||
},
|
||||
search:{ //查询框配置 ,对应fs-search组件
|
||||
options:{} //查询表单配置 ,对应el-from, a-form配置
|
||||
},
|
||||
actionbar:{}, //动作条,添加按钮,对应fs-actionbar组件
|
||||
toolbar:{}, //工具条 ,对应fs-toolbar组件
|
||||
table:{ //表格配置,对应fs-table
|
||||
// 对应 el-table / a-table的配置
|
||||
slots:{} // 对应el-table ,a-table的插槽
|
||||
},
|
||||
data:{}, //列表数据,无需配置,自动从pageRequest中获取
|
||||
// 如果你要手动改变表格数据,可以通过crudBinding.value.data直接赋值修改表格数据
|
||||
rowHandle:{}, //操作列配置,对应fs-row-handle
|
||||
form:{ //表单的公共配置,对应el-form,a-form配置
|
||||
wrapper:{} //表单外部容器(对话框)的配置,对应el-dialog,el-drawer,a-model,a-drawer的配置
|
||||
},
|
||||
viewForm:{}, //查看表单的独立配置
|
||||
editForm:{}, //编辑表单的独立配置
|
||||
addForm:{}, //添加表单的独立配置
|
||||
pagination:{}, //分页配置 ,对应el-pagination / a-pagination
|
||||
container:{}, //容器配置 ,对应fs-container
|
||||
id: string, //表格唯一标识,同一个页面的多个表格的列设置和字段设置会根据id进行区分保存
|
||||
request:{}, //http请求
|
||||
columns:{ //字段配置
|
||||
key:{ //字段key
|
||||
column:{}, //对应table-column配置
|
||||
form:{}, //表单中该字段的公共配置,viewForm、addForm、editForm、search会集成此配置,支持对应ui的form-item配置
|
||||
viewForm:{}, //查看表单中该字段的配置,支持对应ui的form-item配置
|
||||
addForm:{}, // 添加表单中该字段的配置,支持对应ui的form-item配置
|
||||
editForm:{}, //编辑表单中该字段的配置,支持对应ui的form-item配置
|
||||
search:{} //对应查询表单的form-item配置
|
||||
}
|
||||
},
|
||||
search:{ //查询框配置 ,对应fs-search组件
|
||||
options:{} //查询表单配置 ,对应el-from, a-form配置
|
||||
},
|
||||
actionbar:{}, //动作条,添加按钮,对应fs-actionbar组件
|
||||
toolbar:{}, //工具条 ,对应fs-toolbar组件
|
||||
table:{ //表格配置,对应fs-table
|
||||
// 对应 el-table / a-table的配置
|
||||
slots:{} // 对应el-table ,a-table的插槽
|
||||
},
|
||||
data:{}, //列表数据,无需配置,自动从pageRequest中获取
|
||||
// 如果你要手动改变表格数据,可以通过crudBinding.value.data直接赋值修改表格数据
|
||||
rowHandle:{}, //操作列配置,对应fs-row-handle
|
||||
form:{ //表单的公共配置,对应el-form,a-form配置
|
||||
wrapper:{} //表单外部容器(对话框)的配置,对应el-dialog,el-drawer,a-model,a-drawer的配置
|
||||
},
|
||||
viewForm:{}, //查看表单的独立配置
|
||||
editForm:{}, //编辑表单的独立配置
|
||||
addForm:{}, //添加表单的独立配置
|
||||
pagination:{}, //分页配置 ,对应el-pagination / a-pagination
|
||||
container:{}, //容器配置 ,对应fs-container
|
||||
}
|
||||
|
||||
## 布局高度
|
||||
@@ -78,6 +77,136 @@ const crudOptions ={
|
||||
- 有固定操作栏、统计区、说明区时,这些区域应 `flex: none`,把剩余空间交给表格区域。
|
||||
- 修改嵌入式 Fast Crud 页面后,要检查空数据、少量数据和多页数据时表格高度、分页器和空状态是否仍在预期区域内。
|
||||
|
||||
## 列表导出
|
||||
|
||||
- 列表需要导出时,优先使用 Fast Crud 工具栏导出能力,不要另写一套导出按钮或后端接口,除非数据必须跨权限、跨分页或异步生成文件。
|
||||
- 导出当前搜索条件下的数据时,在 `toolbar.export` 中设置 `dataFrom: "search"`,并显式打开导出按钮。
|
||||
- 导出列必须输出 Excel 可读的纯文本或数字;不要直接导出对象、数组、VNode、进度条组件、开关组件、时间戳毫秒值等。
|
||||
- 有隐藏但业务上需要导出的字段时,把字段定义为普通列并设置 `column.show: false`,再在 `columnFilter` 中对该字段返回 `true`。例如证书域名这类只用于导出的辅助列。
|
||||
- 嵌套字段可以使用 `lastVars.certDomains` 这类 key;导出格式化时用安全取值函数读取嵌套值。
|
||||
- `dataFormatter` 中统一格式化特殊字段:时间字段转 `YYYY-MM-DD HH:mm:ss`,日期类有效期转业务文案或 `YYYY-MM-DD`,枚举/开关转字典 label,数组转逗号分隔字符串,对象转明确的业务摘要。
|
||||
|
||||
```typescript
|
||||
import { ColumnProps, DataFormatterContext } from "@fast-crud/fast-crud";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
function getRecordValue(row: any, key: string) {
|
||||
return key.split(".").reduce((target, item) => target?.[item], row);
|
||||
}
|
||||
|
||||
function formatListValue(value: any) {
|
||||
if (Array.isArray(value)) {
|
||||
return value.join(",");
|
||||
}
|
||||
return value ?? "";
|
||||
}
|
||||
|
||||
function exportColumnFilter(col: ColumnProps) {
|
||||
if (!col.key || ["_index", "_selection", "rowHandle"].includes(col.key)) {
|
||||
return false;
|
||||
}
|
||||
if (col.key === "lastVars.certDomains") {
|
||||
return true;
|
||||
}
|
||||
return col.show !== false;
|
||||
}
|
||||
|
||||
function exportDataFormatter(opts: DataFormatterContext) {
|
||||
const { row, originalRow, col, exportCol } = opts;
|
||||
const key = col.key;
|
||||
const value = getRecordValue(originalRow, key);
|
||||
|
||||
if (key === "lastVars.certDomains") {
|
||||
row[key] = formatListValue(value);
|
||||
} else if (key.includes("Time") && value) {
|
||||
row[key] = dayjs(value).format("YYYY-MM-DD HH:mm:ss");
|
||||
}
|
||||
|
||||
if (col.width) {
|
||||
exportCol.width = col.width / 10;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
toolbar: {
|
||||
buttons: {
|
||||
export: { show: true },
|
||||
},
|
||||
export: {
|
||||
dataFrom: "search",
|
||||
columnFilter: exportColumnFilter,
|
||||
dataFormatter: exportDataFormatter,
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
"lastVars.certDomains": {
|
||||
title: "证书域名",
|
||||
type: "text",
|
||||
column: {
|
||||
show: false,
|
||||
width: 260,
|
||||
ellipsis: true,
|
||||
},
|
||||
form: { show: false },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## 内置 CRUD 按钮
|
||||
|
||||
只要在 `request` 中配置了 `addRequest`、`editRequest`、`delRequest`,Fast Crud 会自动在 `rowHandle` 渲染新增、编辑、删除按钮并完成对应操作,**不需要手写 `openDeleteConfirm`、`openEditDialog` 等方法**。
|
||||
|
||||
```typescript
|
||||
// crud.tsx
|
||||
const addRequest = async ({ form }: AddReq) => await api.AddObj(form);
|
||||
const editRequest = async ({ form, row }: EditReq) => {
|
||||
form.id = row.id;
|
||||
return await api.UpdateObj(form);
|
||||
};
|
||||
const delRequest = async ({ row }: DelReq) => await api.DelObj(row.id);
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
request: { pageRequest, addRequest, editRequest, delRequest },
|
||||
rowHandle: {
|
||||
buttons: {
|
||||
view: { show: false }, // 不需要查看就隐藏
|
||||
edit: {}, // 自动调用 editRequest
|
||||
remove: {}, // 自动调用 delRequest,自带确认弹窗和错误提示
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
- 删除按钮自带确认弹窗,不需要额外包装 `Modal.confirm`。
|
||||
- 只有**自定义操作**(如禁用、审核、生成激活码)才需要在 `rowHandle.buttons` 中手写 `click` 处理方法。
|
||||
- 如果不需要某列操作,直接把对应 key 去掉或设 `show: false`。
|
||||
|
||||
## compute 动态计算
|
||||
|
||||
当 `rowHandle.buttons` 的 `show`、`disabled` 等属性需要根据行数据动态决定时,**必须使用 `compute` 包裹**,不能直接传函数。
|
||||
|
||||
```typescript
|
||||
import { compute } from "@fast-crud/fast-crud";
|
||||
|
||||
// WRONG: 直接传函数
|
||||
show: ({ row }) => row.status === "unused"
|
||||
|
||||
// CORRECT: 用 compute 包裹
|
||||
show: compute(({ row }) => row.status === "unused")
|
||||
```
|
||||
|
||||
`compute` 基于 Vue 的 `computed`,但额外支持上下文参数。适用位置:
|
||||
- `rowHandle.buttons` 的 `show`、`disabled` 等属性
|
||||
- `columns.key.column` 的 `show`、`cellRender` 等
|
||||
- `columns.key.form` / `search` 的表单字段属性
|
||||
|
||||
参考文档:http://fast-crud.docmirror.cn/guide/advance/compute.html
|
||||
|
||||
## 代码习惯
|
||||
|
||||
- 页面命名、API 命名、权限标识和路由结构要贴近同目录已有页面。
|
||||
|
||||
@@ -7,15 +7,19 @@ version: 1.0.0
|
||||
# 插件转换工具技能
|
||||
|
||||
## 角色定义
|
||||
|
||||
你是一名 Certd 插件开发专家,擅长使用插件转换工具将 Certd 插件转换为 YAML 配置文件,熟悉命令行工具的使用和 Certd 插件开发规范。
|
||||
|
||||
## 核心指令
|
||||
|
||||
请严格按照以下步骤执行任务:
|
||||
|
||||
1. **定位工具位置**
|
||||
|
||||
- 工具位于 `trae/skills/convert-plugin-to-yaml.js`
|
||||
|
||||
2. **了解功能特性**
|
||||
|
||||
- 单个插件转换:支持指定单个插件文件进行转换
|
||||
- 批量插件转换:支持指定目录批量转换多个插件
|
||||
- 自动类型识别:自动识别插件类型(Access、Task、DNS Provider、Notification、Addon)
|
||||
@@ -27,6 +31,7 @@ version: 1.0.0
|
||||
- 可复用函数:导出了可复用的函数,便于其他模块调用
|
||||
|
||||
3. **使用工具**
|
||||
|
||||
- 基本用法:`node trae/skills/convert-plugin-to-yaml.js <插件文件路径>`
|
||||
- 批量转换:`node trae/skills/convert-plugin-to-yaml.js <目录路径>`
|
||||
- 自定义输出目录:`node trae/skills/convert-plugin-to-yaml.js <插件文件路径> --output <输出目录>`
|
||||
@@ -39,6 +44,7 @@ version: 1.0.0
|
||||
- 自定义输出目录:`node trae/skills/convert-plugin-to-yaml.js packages/ui/certd-server/src/plugins/plugin-demo/access.js --output ./configs`
|
||||
|
||||
4. **理解转换过程**
|
||||
|
||||
- 加载插件模块:使用 `import()` 动态加载指定的插件文件
|
||||
- 分析插件定义:检查模块导出的对象,寻找带有 `define` 属性的插件
|
||||
- 识别插件类型:根据插件的继承关系或属性识别插件类型
|
||||
@@ -46,10 +52,12 @@ version: 1.0.0
|
||||
- 保存配置文件:将生成的配置保存到 `./metadata` 目录
|
||||
|
||||
5. **了解输出说明**
|
||||
|
||||
- 命令行输出:插件加载状态、插件导出的对象列表、插件类型识别结果、生成的 YAML 配置内容、配置文件保存路径
|
||||
- 配置文件命名规则:`<插件类型>[_<子类型>]_<插件名称>.yaml`
|
||||
|
||||
6. **理解插件类型识别逻辑**
|
||||
|
||||
- DNS Provider:如果插件定义中包含 `accessType` 属性
|
||||
- Task:如果插件继承自 `AbstractTaskPlugin`
|
||||
- Notification:如果插件继承自 `BaseNotification`
|
||||
@@ -64,6 +72,7 @@ version: 1.0.0
|
||||
- 错误处理:如果插件加载失败或识别失败,工具会输出错误信息但不会终止执行
|
||||
|
||||
## 输出规范
|
||||
|
||||
- 必须包含工具的使用方法和示例
|
||||
- 必须包含转换过程的详细说明
|
||||
- 必须包含输出说明和配置文件命名规则
|
||||
@@ -75,6 +84,7 @@ version: 1.0.0
|
||||
### 示例 1: 转换单个 Access 插件
|
||||
|
||||
#### 用户输入
|
||||
|
||||
将 Access 插件转换为 YAML 配置文件。
|
||||
|
||||
#### 你的回答
|
||||
@@ -85,6 +95,7 @@ node trae/skills/convert-plugin-to-yaml.js packages/ui/certd-server/src/plugins/
|
||||
```
|
||||
|
||||
#### 输出
|
||||
|
||||
```bash
|
||||
$ node trae/skills/convert-plugin-to-yaml.js packages/ui/certd-server/src/plugins/plugin-demo/access.js
|
||||
开始转换插件: packages/ui/certd-server/src/plugins/plugin-demo/access.js
|
||||
@@ -109,6 +120,7 @@ YAML 配置已保存到: ./metadata/access_demo.yaml
|
||||
### 示例 2: 批量转换插件
|
||||
|
||||
#### 用户输入
|
||||
|
||||
批量转换目录中的所有插件为 YAML 配置文件。
|
||||
|
||||
#### 你的回答
|
||||
@@ -119,6 +131,7 @@ node trae/skills/convert-plugin-to-yaml.js packages/ui/certd-server/src/plugins/
|
||||
```
|
||||
|
||||
#### 输出
|
||||
|
||||
```bash
|
||||
$ node trae/skills/convert-plugin-to-yaml.js packages/ui/certd-server/src/plugins/
|
||||
开始转换目录: packages/ui/certd-server/src/plugins/
|
||||
@@ -189,6 +202,7 @@ YAML 配置已保存到: ./metadata/dns-provider_demo.yaml
|
||||
### 示例 3: 自定义输出目录
|
||||
|
||||
#### 用户输入
|
||||
|
||||
将插件转换为 YAML 配置文件,并保存到自定义目录。
|
||||
|
||||
#### 你的回答
|
||||
@@ -199,6 +213,7 @@ node trae/skills/convert-plugin-to-yaml.js packages/ui/certd-server/src/plugins/
|
||||
```
|
||||
|
||||
#### 输出
|
||||
|
||||
```bash
|
||||
$ node trae/skills/convert-plugin-to-yaml.js packages/ui/certd-server/src/plugins/plugin-demo/access.js --output ./configs
|
||||
开始转换插件: packages/ui/certd-server/src/plugins/plugin-demo/access.js
|
||||
@@ -225,14 +240,17 @@ YAML 配置已保存到: ./configs/access_demo.yaml
|
||||
### 常见问题
|
||||
|
||||
1. **模块加载失败**
|
||||
|
||||
- 原因:插件文件依赖未安装或路径错误
|
||||
- 解决:确保已安装所有依赖,检查文件路径是否正确
|
||||
|
||||
2. **插件类型识别失败**
|
||||
|
||||
- 原因:插件未正确继承基类或缺少必要的属性
|
||||
- 解决:检查插件代码,确保正确继承对应的基类
|
||||
|
||||
3. **YAML 配置生成失败**
|
||||
|
||||
- 原因:插件定义格式不正确
|
||||
- 解决:检查插件的 `define` 属性格式是否正确
|
||||
|
||||
@@ -262,9 +280,9 @@ YAML 配置已保存到: ./configs/access_demo.yaml
|
||||
|
||||
```javascript
|
||||
export {
|
||||
convertSinglePlugin, // 转换单个插件
|
||||
loadSingleModule, // 加载单个模块
|
||||
isPrototypeOf // 检查原型关系
|
||||
convertSinglePlugin, // 转换单个插件
|
||||
loadSingleModule, // 加载单个模块
|
||||
isPrototypeOf, // 检查原型关系
|
||||
};
|
||||
```
|
||||
|
||||
@@ -273,4 +291,4 @@ export {
|
||||
1. **插件开发**:在开发新插件时,快速生成配置文件
|
||||
2. **插件调试**:查看插件的内部定义和配置
|
||||
3. **插件管理**:批量转换现有插件为标准配置格式
|
||||
4. **自动化构建**:集成到构建流程中,自动生成插件配置
|
||||
4. **自动化构建**:集成到构建流程中,自动生成插件配置
|
||||
|
||||
@@ -1 +1 @@
|
||||
我需要将一个插件转换为 YAML 配置文件。请指导我如何使用插件转换工具。
|
||||
我需要将一个插件转换为 YAML 配置文件。请指导我如何使用插件转换工具。
|
||||
|
||||
@@ -65,6 +65,7 @@ node .trae/skills/plugin-converter/resources/convert-plugin-to-yaml.js packages/
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
- `access_demo.yaml`(Access 插件)
|
||||
- `deploy_DemoTest.yaml`(Task 插件)
|
||||
- `dnsProvider_demo.yaml`(DNS Provider 插件)
|
||||
@@ -92,4 +93,4 @@ scriptFilePath: packages/ui/certd-server/src/plugins/plugin-demo/access.js
|
||||
|
||||
YAML 配置已保存到: ./metadata/access_demo.yaml
|
||||
插件转换完成!
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// 转换单个插件为 YAML 配置的技能脚本
|
||||
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import * as yaml from "js-yaml";
|
||||
import { AbstractTaskPlugin, BaseAccess, BaseNotification} from "@certd/pipeline";
|
||||
import { BaseAddon} from "@certd/lib-server";
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import * as yaml from 'js-yaml';
|
||||
import { AbstractTaskPlugin, BaseAccess, BaseNotification } from '@certd/pipeline';
|
||||
import { BaseAddon } from '@certd/lib-server';
|
||||
|
||||
/**
|
||||
* 检查对象是否是指定类的原型
|
||||
@@ -34,23 +34,23 @@ async function loadSingleModule(filePath) {
|
||||
*/
|
||||
async function convertSinglePlugin(pluginPath) {
|
||||
console.log(`开始转换插件: ${pluginPath}`);
|
||||
|
||||
|
||||
// 加载插件模块
|
||||
const module = await loadSingleModule(pluginPath);
|
||||
if (!module) {
|
||||
console.error("加载插件失败,退出");
|
||||
console.error('加载插件失败,退出');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 处理模块中的所有导出
|
||||
const entry = Object.entries(module);
|
||||
if (entry.length === 0) {
|
||||
console.error("插件模块没有导出任何内容");
|
||||
console.error('插件模块没有导出任何内容');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`插件模块导出了 ${entry.length} 个对象: ${entry.map(([name]) => name).join(", ")}`);
|
||||
|
||||
|
||||
console.log(`插件模块导出了 ${entry.length} 个对象: ${entry.map(([name]) => name).join(', ')}`);
|
||||
|
||||
// 处理每个导出的对象
|
||||
for (const [name, value] of entry) {
|
||||
// 检查是否是插件(有 define 属性)
|
||||
@@ -58,64 +58,64 @@ async function convertSinglePlugin(pluginPath) {
|
||||
console.log(`跳过非插件对象: ${name}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
console.log(`处理插件: ${name}`);
|
||||
|
||||
|
||||
// 构建插件定义
|
||||
const pluginDefine = {
|
||||
...value.define
|
||||
...value.define,
|
||||
};
|
||||
|
||||
let subType = "";
|
||||
|
||||
|
||||
let subType = '';
|
||||
|
||||
// 确定插件类型
|
||||
if (pluginDefine.accessType) {
|
||||
pluginDefine.pluginType = "dnsProvider";
|
||||
pluginDefine.pluginType = 'dnsProvider';
|
||||
} else if (isPrototypeOf(value, AbstractTaskPlugin)) {
|
||||
pluginDefine.pluginType = "deploy";
|
||||
pluginDefine.pluginType = 'deploy';
|
||||
} else if (isPrototypeOf(value, BaseNotification)) {
|
||||
pluginDefine.pluginType = "notification";
|
||||
pluginDefine.pluginType = 'notification';
|
||||
} else if (isPrototypeOf(value, BaseAccess)) {
|
||||
pluginDefine.pluginType = "access";
|
||||
pluginDefine.pluginType = 'access';
|
||||
} else if (isPrototypeOf(value, BaseAddon)) {
|
||||
pluginDefine.pluginType = "addon";
|
||||
subType = "_" + (pluginDefine.addonType || "");
|
||||
pluginDefine.pluginType = 'addon';
|
||||
subType = '_' + (pluginDefine.addonType || '');
|
||||
} else {
|
||||
console.log(`[warning] 未知的插件类型:${pluginDefine.name}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
pluginDefine.type = "builtIn";
|
||||
|
||||
|
||||
pluginDefine.type = 'builtIn';
|
||||
|
||||
// 计算脚本文件路径
|
||||
const relativePath = path.relative(process.cwd(), pluginPath);
|
||||
const scriptFilePath = relativePath.replace(/\\/g, "/").replace(/\.js$/, ".js");
|
||||
const scriptFilePath = relativePath.replace(/\\/g, '/').replace(/\.js$/, '.js');
|
||||
pluginDefine.scriptFilePath = scriptFilePath;
|
||||
|
||||
|
||||
console.log(`插件类型: ${pluginDefine.pluginType}`);
|
||||
console.log(`脚本路径: ${scriptFilePath}`);
|
||||
|
||||
|
||||
// 生成 YAML 配置
|
||||
const yamlContent = yaml.dump(pluginDefine);
|
||||
console.log("\n生成的 YAML 配置:");
|
||||
console.log('\n生成的 YAML 配置:');
|
||||
console.log(yamlContent);
|
||||
|
||||
|
||||
// 可选:保存到文件
|
||||
const outputDir = "./metadata";
|
||||
const outputDir = './metadata';
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
}
|
||||
|
||||
|
||||
const outputFileName = `${pluginDefine.pluginType}${subType}_${pluginDefine.name}.yaml`;
|
||||
const outputPath = path.join(outputDir, outputFileName);
|
||||
|
||||
|
||||
fs.writeFileSync(outputPath, yamlContent, 'utf8');
|
||||
console.log(`\nYAML 配置已保存到: ${outputPath}`);
|
||||
|
||||
|
||||
return pluginDefine;
|
||||
}
|
||||
|
||||
console.error("未找到有效的插件定义");
|
||||
|
||||
console.error('未找到有效的插件定义');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,25 +123,25 @@ async function convertSinglePlugin(pluginPath) {
|
||||
*/
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
|
||||
if (args.length === 0) {
|
||||
console.error("请指定插件文件路径");
|
||||
console.log("用法: node convert-plugin-to-yaml.js <插件文件路径>");
|
||||
console.error('请指定插件文件路径');
|
||||
console.log('用法: node convert-plugin-to-yaml.js <插件文件路径>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
const pluginPath = args[0];
|
||||
|
||||
|
||||
if (!fs.existsSync(pluginPath)) {
|
||||
console.error(`插件文件不存在: ${pluginPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
await convertSinglePlugin(pluginPath);
|
||||
console.log("\n插件转换完成!");
|
||||
console.log('\n插件转换完成!');
|
||||
} catch (error) {
|
||||
console.error("转换过程中出错:", error);
|
||||
console.error('转换过程中出错:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -152,9 +152,4 @@ if (import.meta.url === pathToFileURL(process.argv[1]).href) {
|
||||
}
|
||||
|
||||
// 导出函数,以便其他模块使用
|
||||
export {
|
||||
convertSinglePlugin,
|
||||
loadSingleModule,
|
||||
isPrototypeOf
|
||||
};
|
||||
|
||||
export { convertSinglePlugin, loadSingleModule, isPrototypeOf };
|
||||
|
||||
@@ -7,12 +7,15 @@ version: 1.0.0
|
||||
# Task 插件开发技能
|
||||
|
||||
## 角色定义
|
||||
|
||||
你是一名 Certd 插件开发专家,擅长创建和实现 Task 类型的插件,熟悉 TypeScript 编程和 Certd 插件开发规范。
|
||||
|
||||
## 核心指令
|
||||
|
||||
请严格按照以下步骤执行任务:
|
||||
|
||||
1. **导入必要的依赖**
|
||||
|
||||
- 导入 `AbstractTaskPlugin`, `IsTaskPlugin`, `PageSearch`, `pluginGroups`, `RunStrategy`, `TaskInput` 等必要的类型和装饰器
|
||||
- 导入 `CertInfo`, `CertReader` 等证书相关类型
|
||||
- 导入 `createCertDomainGetterInputDefine`, `createRemoteSelectInputDefine` 等工具函数
|
||||
@@ -20,22 +23,28 @@ version: 1.0.0
|
||||
- 导入 `CertApplyPluginNames` 等常量
|
||||
|
||||
2. **使用 @IsTaskPlugin 注解注册插件**
|
||||
|
||||
- 配置插件的唯一标识、标题、图标
|
||||
- 设置插件分组
|
||||
- 配置默认策略(如 `SkipWhenSucceed`)
|
||||
- 确保类名与插件名称一致
|
||||
- 插件默认文案使用中文;需要英文时,在注解参数对象中添加同级 `i18n: { "en-US": { ... } }`,不要写成 `metadata.i18n`。`define` 本身就是插件 metadata。
|
||||
- `i18n["en-US"]` 仅配置要翻译的展示字段,如 `title`、`desc`、`group`、`input`、`output`;未配置的字段自动回退默认中文。不要翻译插件标识、组件类型、默认值或执行参数。
|
||||
|
||||
3. **定义任务输入参数**
|
||||
|
||||
- 使用 `@TaskInput` 注解定义各种输入参数
|
||||
- 必须包含证书选择参数,用于获取前置任务输出的域名证书
|
||||
- 可以添加授权选择框、文本输入、选择框等参数
|
||||
- 使用 `createCertDomainGetterInputDefine` 获取证书域名列表
|
||||
|
||||
4. **实现动态显隐配置**
|
||||
|
||||
- 使用 `mergeScript` 实现根据其他输入值动态控制输入项的显隐状态
|
||||
- 利用 `ctx.compute` 函数访问表单中的其他字段值
|
||||
|
||||
5. **实现插件方法**
|
||||
|
||||
- **onInstance 方法**:插件实例化时执行的初始化操作
|
||||
- **execute 方法**:插件的核心执行逻辑
|
||||
- 获取授权信息
|
||||
@@ -55,6 +64,7 @@ version: 1.0.0
|
||||
- 授权获取:使用 `this.getAccess(accessId)` 获取授权信息
|
||||
|
||||
## 输出规范
|
||||
|
||||
- 必须包含完整的插件实现代码
|
||||
- 代码必须包含详细的注释说明
|
||||
- 提供完整的示例代码,展示插件的使用方法
|
||||
@@ -65,6 +75,7 @@ version: 1.0.0
|
||||
### 示例 1: 基本 Task 插件
|
||||
|
||||
#### 用户输入
|
||||
|
||||
创建一个 Task 插件,用于将证书部署到对应的应用上。
|
||||
|
||||
#### 你的回答
|
||||
@@ -74,7 +85,7 @@ import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy
|
||||
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
|
||||
import { optionsUtils } from '@certd/basic';
|
||||
import { CertApplyPluginNames} from '@certd/plugin-cert';
|
||||
import { CertApplyPluginNames } from '@certd/plugin-cert';
|
||||
|
||||
@IsTaskPlugin({
|
||||
//命名规范,插件类型+功能,大写字母开头,驼峰命名
|
||||
@@ -202,6 +213,9 @@ export class DemoTest extends AbstractTaskPlugin {
|
||||
//当以下参数变化时,触发获取选项
|
||||
watches: ['certDomains', 'accessId'],
|
||||
required: true,
|
||||
single: false, // 是否单选
|
||||
pager: true, // 是否卡其分页查询
|
||||
search: true, // 是否开启搜索
|
||||
})
|
||||
)
|
||||
siteName!: string | string[];
|
||||
@@ -251,9 +265,12 @@ export class DemoTest extends AbstractTaskPlugin {
|
||||
throw new Error('请选择Access授权');
|
||||
}
|
||||
|
||||
const pager = new Pager(req);
|
||||
|
||||
// @ts-ignore
|
||||
const access = await this.getAccess(this.accessId);
|
||||
|
||||
//
|
||||
// 根据接口情况是否支持翻页查询,和关键字查询, 传递对应的参数,pager.pageNo,pager.pageSize, req.searchKey
|
||||
// const siteRes = await access.GetDomainList(req);
|
||||
//以下是模拟数据
|
||||
const siteRes = [
|
||||
@@ -266,12 +283,12 @@ export class DemoTest extends AbstractTaskPlugin {
|
||||
return {
|
||||
value: item.siteName,
|
||||
label: item.siteName,
|
||||
domain: item.siteName,
|
||||
domain: item.siteName, //这里必须要包含domain 否则后面分组时候全部分配到未匹配中
|
||||
};
|
||||
});
|
||||
//将站点域名名称根据证书域名进行匹配分组,分成匹配的和不匹配的两组选项,返回给前端,供用户选择
|
||||
return {
|
||||
list: optionsUtils.buildGroupOptions(options, this.certDomains),
|
||||
list: optionsUtils.buildGroupOptions(options, this.certDomains), //分组后的列表
|
||||
total: siteRes.length,
|
||||
};
|
||||
}
|
||||
@@ -281,6 +298,7 @@ export class DemoTest extends AbstractTaskPlugin {
|
||||
### 示例 2: Nginx 部署 Task 插件
|
||||
|
||||
#### 用户输入
|
||||
|
||||
创建一个 Task 插件,用于将证书部署到 Nginx 服务器上。
|
||||
|
||||
#### 你的回答
|
||||
@@ -459,6 +477,7 @@ new NginxDeploy();
|
||||
### 示例 3: 阿里云 OSS 部署 Task 插件
|
||||
|
||||
#### 用户输入
|
||||
|
||||
创建一个 Task 插件,用于将证书部署到阿里云 OSS 上。
|
||||
|
||||
#### 你的回答
|
||||
@@ -624,10 +643,12 @@ new AliyunOSSDeploy();
|
||||
4. **日志输出**:使用 `this.logger` 输出日志,而不是 `console`,参数文本化,不要传对象,否则会输出`[object Object]}`。
|
||||
5. **错误处理**:执行过程中的错误应被捕获并记录。
|
||||
6. **授权获取**:使用 `this.getAccess(accessId)` 获取授权信息。
|
||||
7. **旧版数据兼容**: 新增@TaskInput注解的插件参数,必须要考虑旧版数据兼容,比如新增一个deployType参数,有两种值:`default`和`custom`,需要在使用时判空,走旧版逻辑。
|
||||
|
||||
## 部署逻辑注意事项
|
||||
|
||||
1. **部署接口逻辑**:
|
||||
|
||||
- 研究应用的部署接口逻辑,一般有两种:
|
||||
a. 用户选择网站ID,给网站部署新证书
|
||||
b. 用户选择证书ID,只需要更新证书即可
|
||||
@@ -635,6 +656,7 @@ new AliyunOSSDeploy();
|
||||
- 确保出错后重新运行能够回归到正常状态
|
||||
|
||||
2. **前置证书选择**:
|
||||
|
||||
- 前置证书可以是原始的 `certInfo` 类型,也可能是上传到平台之后返回的证书id
|
||||
- 根据接口要求选择合适的证书类型:
|
||||
a. 如果接口需要上传后的证书id,那么部署时要先将证书上传,再部署
|
||||
@@ -643,4 +665,7 @@ new AliyunOSSDeploy();
|
||||
|
||||
3. **证书清理**:
|
||||
- 如果是先上传再部署的,那么在部署完成后,可能需要考虑清理证书
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
@@ -1 +1 @@
|
||||
我需要开发一个 Task 插件,用于将申请的证书部署到指定的应用系统中。请指导我如何实现。
|
||||
我需要开发一个 Task 插件,用于将申请的证书部署到指定的应用系统中。请指导我如何实现。
|
||||
|
||||
@@ -9,7 +9,7 @@ import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy
|
||||
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
|
||||
import { optionsUtils } from '@certd/basic';
|
||||
import { CertApplyPluginNames} from '@certd/plugin-cert';
|
||||
import { CertApplyPluginNames } from '@certd/plugin-cert';
|
||||
```
|
||||
|
||||
### 2. 使用 @IsTaskPlugin 注解注册插件
|
||||
@@ -126,4 +126,4 @@ async execute(): Promise<void> {
|
||||
3. **证书选择**:必须包含证书选择参数,用于获取前置任务输出的域名证书。
|
||||
4. **日志输出**:使用 `this.logger` 输出日志,而不是 `console`。
|
||||
5. **错误处理**:执行过程中的错误应被捕获并记录。
|
||||
6. **授权获取**:使用 `this.getAccess(accessId)` 获取授权信息。
|
||||
6. **授权获取**:使用 `this.getAccess(accessId)` 获取授权信息。
|
||||
|
||||
@@ -1,103 +1,127 @@
|
||||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "client",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-client",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-mysql",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev-mysql"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-pg",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev-pg"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-pgpl",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev-pgpl"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-common",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev-commpro"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-new",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev-new"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-local-plus",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": ["run", "dev-localplus"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"env": {
|
||||
"plus_use_prod": "false",
|
||||
"PLUS_SERVER_BASE_URL": "http://127.0.0.1:11007"
|
||||
}
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "all",
|
||||
"configurations": [
|
||||
"server",
|
||||
"client",
|
||||
],
|
||||
"stopAll": false
|
||||
},
|
||||
]
|
||||
}
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "client",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-client",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-mysql",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev-mysql"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-pg",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev-pg"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-pgpl",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev-pgpl"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-common",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev-commpro"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-new",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["dev-new"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "server-local-plus",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": ["run", "dev-localplus"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"env": {
|
||||
"plus_use_prod": "false",
|
||||
"PLUS_SERVER_BASE_URL": "http://127.0.0.1:11007"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server-local-plus2",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": ["run", "dev-localplus2"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"env": {
|
||||
"plus_use_prod": "false",
|
||||
"PLUS_SERVER_BASE_URL": "http://127.0.0.1:11007"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server-local-comm",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": ["run", "dev-localcomm"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"env": {
|
||||
"plus_use_prod": "false",
|
||||
"PLUS_SERVER_BASE_URL": "http://127.0.0.1:11007"
|
||||
}
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "all",
|
||||
"configurations": ["server", "client"],
|
||||
"stopAll": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
{
|
||||
"eslint.debug": false,
|
||||
"eslint.format.enable": true,
|
||||
"typescript.tsc.autoDetect": "watch",
|
||||
"git.scanRepositories": [
|
||||
"./packages/pro"
|
||||
],
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
"editor.tabSize": 2,
|
||||
"explorer.autoReveal": false,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
"[less]": {
|
||||
"editor.defaultFormatter": "vscode.css-language-features"
|
||||
},
|
||||
"scm.repositories.visible": 9,
|
||||
"scm.repositories.explorer": false,
|
||||
"scm.repositories.selectionMode": "multiple",
|
||||
"scm.repositories.sortOrder": "discovery time"
|
||||
}
|
||||
"eslint.debug": false,
|
||||
"eslint.format.enable": true,
|
||||
"typescript.tsc.autoDetect": "watch",
|
||||
"git.scanRepositories": ["./packages/pro"],
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
"editor.tabSize": 2,
|
||||
"explorer.autoReveal": false,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
"[less]": {
|
||||
"editor.defaultFormatter": "vscode.css-language-features"
|
||||
},
|
||||
"scm.repositories.visible": 9,
|
||||
"scm.repositories.explorer": false,
|
||||
"scm.repositories.selectionMode": "multiple",
|
||||
"scm.repositories.sortOrder": "discovery time",
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "启动Client",
|
||||
"type": "shell",
|
||||
"command": "npm",
|
||||
"args": ["run", "dev"],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-client"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "shared"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "启动Server",
|
||||
"type": "shell",
|
||||
"command": "npm",
|
||||
"args": ["run", "dev"],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "shared"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "同时启动Client和Server",
|
||||
"dependsOn": ["启动Client", "启动Server"],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "启动Client",
|
||||
"type": "shell",
|
||||
"command": "npm",
|
||||
"args": ["run", "dev"],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-client"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "shared"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "启动Server",
|
||||
"type": "shell",
|
||||
"command": "npm",
|
||||
"args": ["run", "dev"],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/packages/ui/certd-server"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "shared"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "同时启动Client和Server",
|
||||
"dependsOn": ["启动Client", "启动Server"],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,220 +1,284 @@
|
||||
# Certd 开发 Agent 上下文
|
||||
|
||||
这个文件是给在本仓库工作的开发 agent 看的常驻项目说明。后续会话进入仓库后,应先读取它,再按任务需要查看具体代码,避免每次都重新全量扫描项目。
|
||||
进入仓库后先读本文。本文同时包含常驻规则、仓库地图、常用入口和验证命令;不要依赖分散规则文件。
|
||||
思考时也要使用中文。
|
||||
|
||||
## 项目用途
|
||||
## 项目定位
|
||||
|
||||
Certd 是一个支持私有化部署的 SSL/TLS 证书自动化管理平台。它提供 Web 管理台和后端服务,用于证书申请、续期、部署、监控、通知和开放 API 集成。
|
||||
Certd 是可私有化部署的 SSL/TLS 证书自动化管理平台,提供 Web 管理台和后端服务,用于证书申请、续期、部署、监控、通知和开放 API 集成。
|
||||
|
||||
它不只是一个简单的 ACME 客户端。项目的核心产品模型是“证书流水线”:
|
||||
核心模型是“证书流水线”:
|
||||
|
||||
- 通过 ACME 申请证书
|
||||
- 支持 DNS-01、HTTP-01、CNAME 代理以及各类服务商集成来完成域名验证
|
||||
- 支持将证书转换或导出为 pem、pfx、der、jks、p7b 等格式
|
||||
- 支持把证书部署到主机、Nginx、Kubernetes、CDN、云厂商、面板等目标
|
||||
- 支持通知用户,并监控站点证书过期时间
|
||||
- 通过 ACME 申请证书。
|
||||
- 完成 DNS-01、HTTP-01、CNAME 代理或服务商验证。
|
||||
- 导出 pem、pfx、der、jks、p7b 等证书格式。
|
||||
- 部署到主机、Nginx、Kubernetes、CDN、云厂商、面板等目标。
|
||||
- 通知用户,并监控站点证书过期时间。
|
||||
|
||||
由于系统会保存证书、云厂商凭据、SSH 信息、API Key 等敏感数据,产品定位上强烈建议私有化/本地部署。
|
||||
系统会保存证书、云厂商凭据、SSH 信息、API Key 等敏感数据。始终按私有化/本地部署产品处理,避免泄露本地数据和配置。
|
||||
|
||||
## 仓库结构
|
||||
## 仓库边界
|
||||
|
||||
这是一个 pnpm + lerna 的 monorepo。
|
||||
- 根仓库是 pnpm + lerna monorepo;不要引入 npm/yarn lockfile。
|
||||
- `packages/pro/` 是独立 Git 工作区;修改商业版代码后,必须在 `packages/pro` 内单独执行 `git status` / `git diff`。
|
||||
- 不要把 `packages/ui/certd-server/data/`、`logs/`、生成的 metadata/dist 等运行时或构建产物纳入改动,除非任务明确要求。
|
||||
- 例外:分析插件动态依赖时,可以只读查看后端数据目录下的 `./data/.runtime-deps`;该目录用于 runtime-deps 动态安装第三方 SDK,不应纳入提交。
|
||||
|
||||
- `package.json`:根脚本和 workspace 元信息
|
||||
- `pnpm-workspace.yaml`:workspace 包匹配规则
|
||||
- `lerna.json`:lerna-lite 配置
|
||||
- `docs/`:VitePress 文档站
|
||||
- `docker/`:Docker 安装和运行相关文件
|
||||
- `packages/core/acme-client/`:ACME 协议客户端,风格接近 node-acme-client
|
||||
- `packages/core/basic/`:共享基础工具和基础设施
|
||||
- `packages/core/pipeline/`:流水线核心、注册表、装饰器、插件模型、上下文、服务、通知等
|
||||
- `packages/libs/`:共享集成与辅助库,例如 server、Huawei、JDCloud、Kubernetes、iframe
|
||||
- `packages/plugins/plugin-lib/`:通用插件辅助能力和证书相关共享代码
|
||||
- `packages/plugins/plugin-cert/`:证书流水线插件包
|
||||
- `packages/pro/`:商业版/专业版相关包
|
||||
- `packages/ui/certd-server/`:后端服务
|
||||
- `packages/ui/certd-client/`:前端 Web 管理台
|
||||
核心包:
|
||||
|
||||
## 后端
|
||||
- `packages/ui/certd-server`:后端服务。
|
||||
- `packages/ui/certd-client`:前端 Web 管理台。
|
||||
- `packages/core/pipeline`:流水线核心。
|
||||
- `packages/core/acme-client`:ACME 客户端。
|
||||
- `packages/plugins/plugin-lib`:插件共享能力。
|
||||
|
||||
主要后端包:`packages/ui/certd-server`。
|
||||
## 仓库地图
|
||||
|
||||
技术栈:
|
||||
- `package.json`:根脚本与 workspace 元信息。
|
||||
- `pnpm-workspace.yaml`:workspace 匹配规则,包含 `packages/**`、`packages/ui/**`。
|
||||
- `lerna.json`:lerna-lite 配置。
|
||||
- `docs`:VitePress 文档站。
|
||||
- `docker`:Docker 安装和运行相关文件。
|
||||
- `packages/core/acme-client`:ACME 协议客户端。
|
||||
- `packages/core/basic`:共享基础工具。
|
||||
- `packages/core/pipeline`:流水线核心抽象、插件模型、执行上下文。
|
||||
- `packages/libs`:共享集成库。
|
||||
- `packages/plugins/plugin-lib`:证书、DNS Provider、格式转换等插件共享能力。
|
||||
- `packages/plugins/plugin-cert`:证书插件包入口。
|
||||
- `packages/ui/certd-server`:后端 Midway 服务。
|
||||
- `packages/ui/certd-client`:前端 Vue/Vite 管理台。
|
||||
- `packages/pro`:商业版独立 Git 工作区,需在该目录内单独检查状态。
|
||||
|
||||
- Node.js、ESM、TypeScript
|
||||
- MidwayJS 3
|
||||
- Koa
|
||||
- TypeORM
|
||||
- 默认使用 better-sqlite3,同时支持 PostgreSQL 和 MySQL
|
||||
- 通过 `@certd/midway-flyway-js` 使用类似 Flyway 的 SQL 迁移机制
|
||||
常见运行时或生成产物:
|
||||
|
||||
重要位置:
|
||||
- 根目录:`node_modules`、`logs`、`output`、`lerna-debug.log`、`tmp-certd-client-vite*.log`。
|
||||
- 后端:`packages/ui/certd-server/data`、`packages/ui/certd-server/logs`。
|
||||
- 后端动态依赖:`./data/.runtime-deps`,常见于阿里云 SDK、腾讯云 SDK 等插件第三方依赖。
|
||||
- 各包:`dist`。
|
||||
- 插件:metadata/yaml 导出结果。
|
||||
|
||||
- `packages/ui/certd-server/src/config/config.default.ts`:默认服务、静态文件、数据库、定时任务、认证、上传、Swagger 配置
|
||||
- `packages/ui/certd-server/src/config/`:环境与配置加载逻辑
|
||||
- `packages/ui/certd-server/src/configuration.ts`:Midway 应用配置、中间件注册、组件导入
|
||||
- `packages/ui/certd-server/src/modules/`:业务模块,例如 pipeline、cert、cron、monitor、login、open API、sys、plugin、cname、notification
|
||||
- `packages/ui/certd-server/src/controller/`:按 API 领域划分的控制器
|
||||
- `packages/ui/certd-server/src/plugins/`:后端内置的具体服务商、部署、通知等插件
|
||||
- `packages/ui/certd-server/db/migration/`:数据库迁移 SQL
|
||||
- `packages/ui/certd-server/data/`:本地运行数据,例如 SQLite 数据库和生成文件
|
||||
- `packages/ui/certd-server/logs/`:运行日志
|
||||
## 常用验证
|
||||
|
||||
已观察到的默认开发配置:
|
||||
- 前端改动文件格式化:`packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>`。
|
||||
- 前端改动文件 ESLint 修复:`packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`。
|
||||
- 后端单元测试:`cd packages\ui\certd-server && npm run unit`。
|
||||
- 后端改动文件 lint fix:`cd packages\ui\certd-server && npm run lint`(该脚本即 `mwts fix`,对改动文件执行 ESLint 自动修复)。
|
||||
- 其他package lint fix:`cd packages\xxx\xxxx && npm run lint`。
|
||||
|
||||
- HTTP 端口:`7001`
|
||||
- HTTPS 端口:`7002`
|
||||
- 默认 SQLite 数据库:`./data/db.sqlite`
|
||||
- 默认文件根目录:`./data/files`
|
||||
## 通用工作规则
|
||||
|
||||
常用脚本:
|
||||
- 先读本文,再按任务读取具体代码或技能文件。
|
||||
- 与用户沟通、代码注释、文档、日志和面向用户的界面文案,尽量使用中文;技术专有名词、代码标识符、第三方库名称和命令可保留英文。
|
||||
- PowerShell 读取中文、Markdown、locale、文档类文件时使用 `Get-Content -Raw -Encoding UTF8`;仍乱码时先执行 `[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()`。
|
||||
- PowerShell 中用 `rg` 搜索含引号、括号、反斜杠的 pattern 时,优先用单引号包裹整个 pattern,例如 `rg 'await import\("tencentcloud-sdk-nodejs' packages/ui/certd-server/src -g '*.ts'`。
|
||||
- 手工编辑或创建文件时优先使用 `apply_patch`。单个文件内有多处不连续改动时,拆成多个独立的 `*** Update File` 块,每块只改一处附近上下文;不要在同一个 update hunk 里强塞多个 `@@`。
|
||||
- 只有真正机械化的大批量替换、格式化或生成任务才考虑脚本/工具。若必须使用临时脚本,应放在临时目录并在同一个受控步骤内完成创建、执行、删除;不要把临时脚本落在仓库里跨多步工具调用执行。
|
||||
- 不要主动运行 `pnpm install`;缺依赖、TTY、网络导致安装或测试失败时,停止尝试并说明环境问题。
|
||||
- 优先沿用现有模块、插件、service、页面模式;不要为形式上的复用制造过度抽象。
|
||||
- 【重要重要重要】代码可读性优先于短写法。尽量少用三元表达式,优先使用完整的 `if/else`【其他技能与此条要求冲突的,以此条要求为准】;复杂条件、链式调用、内联对象和多层 helper 调用要拆成命名清晰的中间变量或小方法。
|
||||
- 方法调用链不要直接塞进另一个方法参数;先用有意义的局部变量承接返回值,再传入下一步。
|
||||
- 不要在单一表达式内嵌套分支、对象构造与方法调用。优先使用清晰的 `if/else` 分支;仅在确实能降低复杂度时才提取有意义的中间变量,避免为拆分而增加阅读跳转。
|
||||
- 注释优先使用中文,尤其是业务规则、兼容逻辑、协议细节和隐藏风险;文件已有英文风格或引用外部术语时可保持一致。
|
||||
- 遵守 DRY 和单一职责;第三次出现的业务规则、字段转换、权限判断、Repository 选择、事务传播、金额计算等逻辑,应优先抽成合适 helper 或 service 方法。
|
||||
- 如无明确复用价值,不要随意新增 `normalizeXxx` 等辅助方法;优先在现有业务方法中直接处理简单兼容或字段转换逻辑,避免增加不必要的抽象层。
|
||||
|
||||
- 根目录 `pnpm run start:server`:以生产模式启动后端包
|
||||
- 后端 `pnpm run dev`:启动 Midway watch/dev 服务
|
||||
- 后端 `pnpm run test`:运行后端 mocha 测试
|
||||
- 后端 `pnpm run build`:构建后端并导出插件元数据
|
||||
|
||||
## 前端
|
||||
## 测试与验证
|
||||
|
||||
主要前端包:`packages/ui/certd-client`。
|
||||
- 新功能、缺陷修复和重构遵循 TDD:先编写或更新测试,覆盖正常路径、边界条件和明确的错误处理;先运行测试确认 RED,再实现最小改动,最后运行聚焦测试确认 GREEN。
|
||||
- 单元测试应优先直接测试原始业务方法,不要为了方便测试而抽取没有业务价值的 helper;数据库、RPC 和其他外部依赖可以使用 mock 隔离。
|
||||
- 确实不适合先写测试时,在回复中说明原因和替代验证方式。
|
||||
- 后补单元测试时,按正确行为写预期;若红灯需要修改既有实现,先向用户确认这是 bug 还是既有需求,避免未经确认改变行为。
|
||||
- 后端纯单测放在 `src/**/*.test.ts`,尽量与被测文件相邻;`test:unit` 只跑这些文件,构建/打包应排除 `*.test.ts`。
|
||||
- 单测需要 mock ESM 静态 import(如 `@certd/plus-core` 的 `isPlus`、第三方包)时,**优先使用 `esmock`**,通过 `esmock(被测模块路径, { 依赖模块: { 导出: mock实现 } })` 加载被测模块并替换依赖;**不要为了测试给业务代码加注入点/改业务结构**(如不需要给类加 `isPlusFn` 之类的可注入属性)。
|
||||
- 各包 `test:unit` 脚本应显式设置 `NODE_ENV=unittest`。
|
||||
- 单包单测优先用 `cd <包目录> && npm run test:unit`,例如 `cd packages\ui\certd-server && npm run test:unit`。
|
||||
- 优先对改动包运行聚焦测试或格式化/ESLint;只有跨包影响明显时再考虑更大范围构建。
|
||||
|
||||
技术栈:
|
||||
## 规范回顾
|
||||
|
||||
- Vue 3
|
||||
- Vite
|
||||
- TypeScript
|
||||
- Ant Design Vue
|
||||
- Fast Crud
|
||||
- Pinia
|
||||
- vue-router
|
||||
- vue-i18n
|
||||
- Tailwind/Windi 相关样式工具
|
||||
- 每次任务收尾时,回顾用户提出的要求,识别其中可跨任务复用、稳定且不与既有规则冲突的约束。
|
||||
- 只将经过确认的共性要求精炼后写入本文;一次性任务细节、临时偏好和未经确认的推断不要写入长期规范。
|
||||
- 更新本文后检查规则是否清晰、可执行,并删除重复或互相矛盾的表述。
|
||||
|
||||
重要位置:
|
||||
|
||||
- `packages/ui/certd-client/src/main.ts`:前端启动入口
|
||||
- `packages/ui/certd-client/src/App.vue`:根组件
|
||||
- `packages/ui/certd-client/src/api/`:API 调用封装
|
||||
- `packages/ui/certd-client/src/router/`:路由
|
||||
- `packages/ui/certd-client/src/store/`:Pinia store
|
||||
- `packages/ui/certd-client/src/views/certd/`:核心产品页面,例如流水线、证书、授权、监控、通知、开放 API、项目、支付、插件
|
||||
- `packages/ui/certd-client/src/components/`:共享 UI 组件
|
||||
- `packages/ui/certd-client/src/locales/`:国际化
|
||||
## 后端规则
|
||||
|
||||
常用脚本:
|
||||
|
||||
- 前端 `pnpm dev`:启动 Vite 开发服务
|
||||
- 前端 `pnpm build`:生产构建
|
||||
- 不要运行前端 `pnpm tsc` / `vue-tsc`:当前依赖组合中 `vue-tsc@1.8.27` 会直接抛内部错误 `Search string not found: "/supportedTSExtensions = .*(?=;)/"`,不是有效的项目类型检查结果。
|
||||
- 前端暂不跑单元测试;当前 `test:unit` 只是占位脚本
|
||||
|
||||
## 流水线与插件模型
|
||||
|
||||
项目最关键的架构概念是证书流水线。
|
||||
|
||||
可以从 `packages/core/pipeline/src/index.ts` 入手,它导出:
|
||||
|
||||
- `core`
|
||||
- `dt`
|
||||
- `access`
|
||||
- `registry`
|
||||
- `plugin`
|
||||
- `context`
|
||||
- `decorator`
|
||||
- `service`
|
||||
- `notification`
|
||||
|
||||
插件是核心能力,不是边缘功能。新增服务商、DNS 验证、证书部署、通知方式等能力,通常应该放在插件包里,或放在 `packages/ui/certd-server/src/plugins/<plugin-name>/` 下。
|
||||
|
||||
后端已看到的插件类型包括:
|
||||
|
||||
- DNS 和注册商服务商:Aliyun、Tencent、Cloudflare、Huawei、JDCloud、AWS、Azure、Google、GoDaddy、Namesilo、Xinnet、West、UCloud、Qiniu、Upyun、Volcengine 等
|
||||
- 部署目标:host、Kubernetes、Nginx Proxy Manager、APISIX、Proxmox、QNAP、Dokploy、GoEdge、各类 CDN、各类面板
|
||||
- 系统/产品插件:notification、captcha、oauth、admin、plus/pro、demo/template
|
||||
|
||||
当修改证书申请、验证、部署或通知行为时,先判断改动属于哪里:
|
||||
|
||||
- ACME client 代码
|
||||
- pipeline 核心抽象
|
||||
- 后端 module/service/entity/controller
|
||||
- 某个具体插件实现
|
||||
- 前端 view/form/schema
|
||||
|
||||
如果只是某个服务商或部署目标的问题,不要轻易修改共享 pipeline/core 行为,除非确实是可复用的公共能力。
|
||||
|
||||
### ACME / EAB 注意事项
|
||||
|
||||
- 公共 EAB(尤其是 Google EAB)可能只能创建一次 ACME 账号。要跨用户复用公共 EAB,应保存并复用同一个 ACME account private key;`accountUrl` 如果存到 `userContext` 里,只能视为当前用户缓存,因为 `userContext` 跟用户 id 走。
|
||||
- ACME 协议的 `newAccount` 支持 `onlyReturnExisting`。使用同一个 account private key 调用 `newAccount({ onlyReturnExisting: true })` 可以取回已创建账号的 URL,且不会再次消费 EAB。
|
||||
- 修改 EAB 的 `kid` 后,应重新生成绑定该 `kid` 的 account private key;否则应阻止继续申请并提示用户刷新账号私钥。
|
||||
|
||||
## 数据与迁移
|
||||
|
||||
后端使用 TypeORM 实体加 SQL 迁移。
|
||||
|
||||
重点查看:
|
||||
|
||||
- `packages/ui/certd-server/src/modules/**/entity/*.ts`
|
||||
- `packages/ui/certd-server/db/migration/*.sql`
|
||||
|
||||
默认配置中 `synchronize: false`,所以涉及表结构变更时,通常应该添加或更新迁移脚本,而不是依赖 TypeORM 自动同步。
|
||||
|
||||
## 开发注意事项
|
||||
|
||||
- 中文 README 在部分 PowerShell 环境中可能显示乱码;`README_en.md` 可读性更好,且包含同样的高层项目说明。
|
||||
- 初次整理时观察到当前分支为 `v2-dev`。
|
||||
- 根包管理器是 pnpm,不要引入 npm/yarn lockfile。
|
||||
- 优先沿用现有模块、插件、服务模式,再考虑新增抽象。
|
||||
- `packages/ui/certd-server/data/`、`logs/`、生成的 metadata/dist 等通常视为运行时或构建产物,除非任务明确要求处理它们。
|
||||
- 注意本地数据和配置里可能包含凭据、证书材料等敏感信息。
|
||||
- 本仓库代码注释优先使用中文,尤其是解释业务规则、兼容逻辑、协议细节和隐藏风险时;除非文件已有明确英文注释风格或引用外部英文术语,否则不要新增英文说明性注释。
|
||||
|
||||
## 插件开发技能
|
||||
|
||||
仓库内置了 Certd 插件开发技能,供 Trae 和 Codex 共用:
|
||||
|
||||
- Trae 入口:`.trae/skills`
|
||||
- Codex 入口:`.codex/skills`
|
||||
|
||||
其中 `.codex/skills` 是指向 `.trae/skills` 的目录链接,不要复制出第二份技能内容。更新技能时只维护 `.trae/skills` 下的原始文件,Codex 会通过 `.codex/skills` 读取同一份内容。
|
||||
|
||||
当前技能包括:
|
||||
|
||||
- `access-plugin-dev`:开发 Access 授权插件
|
||||
- `dns-provider-dev`:开发 DNS Provider 插件
|
||||
- `task-plugin-dev`:开发 Task 部署任务插件
|
||||
- `plugin-converter`:将插件转换为 YAML 配置
|
||||
|
||||
做插件相关任务时,先读取对应技能目录下的 `SKILL.md`,再进入具体实现。若用户在插件开发中指出更好的做法,应总结并更新对应技能。
|
||||
|
||||
## 快速定向命令
|
||||
|
||||
进入项目后,优先使用这些有目标的读取命令,而不是立刻全仓库扫描:
|
||||
|
||||
```powershell
|
||||
Get-Content -Encoding utf8 package.json
|
||||
Get-Content -Encoding utf8 pnpm-workspace.yaml
|
||||
Get-Content -Encoding utf8 lerna.json
|
||||
Get-Content -Encoding utf8 README_en.md -TotalCount 180
|
||||
Get-Content -Encoding utf8 packages\ui\certd-server\package.json
|
||||
Get-Content -Encoding utf8 packages\ui\certd-client\package.json
|
||||
Get-ChildItem packages\ui\certd-server\src\modules
|
||||
Get-ChildItem packages\ui\certd-server\src\plugins
|
||||
Get-ChildItem packages\ui\certd-client\src\views\certd
|
||||
```
|
||||
|
||||
## 本仓库 Agent 工作方式
|
||||
|
||||
- 先读本文件,再按用户任务查看相关 package/module。
|
||||
- 在 PowerShell 中读取中文、Markdown、locale、文档类文件时,显式使用 `Get-Content -Encoding utf8`;如果仍然显示乱码,再先执行 `[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()` 后重试。
|
||||
- 后端主包是 `packages/ui/certd-server`,使用 Node.js、ESM、TypeScript、MidwayJS 3、Koa、TypeORM 和 SQL 迁移。
|
||||
- 做后端任务时,先定位 `packages/ui/certd-server/src/modules` 下的模块,以及相关 entity/service/controller。
|
||||
- 表结构变更必须添加或更新 `packages/ui/certd-server/db/migration/*.sql`;不要依赖 TypeORM 自动同步。
|
||||
- 文件上传接口 `/basic/file/upload` 返回临时 key;业务保存前必须调用 `FileService.saveFile(userId, key, "public" | "private")` 转成永久 key,不能直接保存 `tmpfile_key_...`。
|
||||
- 方法参数超过 3 个时,优先改为对象参数。
|
||||
- 事务链路方法统一用 `method(ctx, req)`,`ctx` 放第一位并承载 `manager?: EntityManager`,业务参数放 `req` 对象。
|
||||
- 只有需要事务传播时才定义 `ctx`;普通查询、纯函数和简单私有方法继续使用明确参数。
|
||||
- 需要按事务上下文取 Repository 时,用 `BaseService.getRepo(ctx, EntityClass)`。
|
||||
- 需要“有事务则复用、无事务则开启”时,用 `BaseService.transactionWithCtx(ctx, callback)`。
|
||||
- 基础 CRUD 数据访问优先复用 `BaseService` 的 `find`、`findOne`、`list`、`page`、`update`、`deleteWhere` 等方法;不要从 `repository.createQueryBuilder()` 开始重复实现完整查询或更新。仅将关键词组合筛选、联表、业务排序等基类无法表达的部分放入 `list/page` 的 `buildQuery`。
|
||||
- 拼接可选 `projectId` 查询条件时,**必须**使用 `BaseService.buildUserProjectQuery(userId, projectId)`,禁止直接写 `{ userId, projectId }`。因为 `projectId` 可能为 `null`/`undefined`,直接放入查询会生成错误的 `WHERE projectId = NULL` 条件。
|
||||
- `ctx` 类型复用 `BaseService` 导出的 `ServiceContext`。
|
||||
- 新增 service 方法避免与 `BaseService` 方法签名冲突,例如不要用 `delete(id)` 覆盖 `delete(ids, where?)`;改用 `deleteById` 等具体名称。
|
||||
|
||||
### 证书仓库(cd_cert_info)空证书记录【必须保留】
|
||||
|
||||
- 保存流水线时(`PipelineService.save`)会调用 `CertInfoService.updateDomains` 同步该流水线的 active 证书记录(占位记录,`certInfo` 为空)。**这些记录必须保留,不要删除**:开放接口(OpenAPI `autoApply`)触发申请证书前,会先查询证书仓库中是否有该流水线的记录——有记录(即使证书内容为空)说明该流水线已存在、证书正在申请中,直接复用/触发已有流水线;若删掉这些记录,在证书申请成功前的空窗期内,开放接口每次调用都会重复创建新流水线。
|
||||
- 同步规则(`updateDomains`,只处理 active 记录,inactive/revoked 历史保留):① 流水线中每个证书申请任务(CertApply 类步骤)对应仓库一条 active 记录(按 `task_id` 关联),没有则创建空证书记录;② 删除孤儿 active 记录(流水线中已不存在对应任务 id 的,含 `task_id` 为空的历史遗留);③ 一个流水线多个申请任务时维护多条记录,随时保持一致。
|
||||
- `updateCertByPipelineId`(申请证书成功后写入仓库)中同样**不得删除**该流水线的空证书记录;新证书总是新建一条 active 记录,并按相同 `task_id` 把同流水线其他 active 记录标记为 inactive,避免同一流水线出现多条 active。
|
||||
- 吊销旧证书(`CertRevokeOld` 后置任务)按证书申请任务 id(`task_id`)精确匹配:只吊销同一申请任务产出的 inactive 旧证书,不误伤其他任务仍在使用的证书。
|
||||
|
||||
### 后端地图
|
||||
|
||||
- `packages/ui/certd-server/bootstrap.js`:Midway 启动入口,使用 `@midwayjs/bootstrap`。
|
||||
- `packages/ui/certd-server/src/configuration.ts`:Midway 主配置,注册组件和全局中间件。
|
||||
- `packages/ui/certd-server/src/config/config.default.ts`:端口、HTTPS、静态文件、cron、TypeORM、Flyway、上传、JWT、Swagger 默认配置。
|
||||
- `packages/ui/certd-server/src/config/loader.ts`:读取 `.env`、`.env.<env>.yaml`,支持 `certd_` 前缀环境变量覆盖嵌套配置。
|
||||
- `packages/ui/certd-server/src/modules`:业务模块根目录,常见模块包括:
|
||||
- `basic`
|
||||
- `cert`
|
||||
- `cname`
|
||||
- `cron`
|
||||
- `login`
|
||||
- `monitor`
|
||||
- `open`
|
||||
- `pipeline`
|
||||
- `plugin`
|
||||
- `suite`
|
||||
- `sys`
|
||||
- `packages/ui/certd-server/src/controller`:API 入口,按 `basic`、`user`、`sys`、`openapi` 分组。
|
||||
- `packages/ui/certd-server/db/migration`:SQL 迁移目录;TypeORM `synchronize: false`,表结构变更必须配套迁移 SQL。
|
||||
- 后端测试使用 Mocha + Node `assert/strict`;纯单测放在 `src/**/*.test.ts`,可参考 `src/utils/random.test.ts`、`src/controller/basic/app-controller.test.ts`、`src/modules/pipeline/service/pipeline-service.test.ts`。
|
||||
|
||||
## 前端规则
|
||||
|
||||
- 前端主包是 `packages/ui/certd-client`,使用 Vue 3、Vite、TypeScript、Ant Design Vue、Fast Crud、Pinia、vue-router、vue-i18n。
|
||||
- 做前端任务时,先定位 `packages/ui/certd-client/src/views/certd` 下的页面,再找对应 `src/api`。
|
||||
- 做服务商、DNS、部署、通知相关任务时,先看 `packages/ui/certd-server/src/plugins`,再看 `packages/plugins/plugin-lib` 里的共享辅助能力。
|
||||
- 做数据库结构变更时,添加或更新迁移脚本,不要依赖 TypeORM 自动同步。
|
||||
- 实现新功能或修复行为缺陷前,先补对应单元测试,并先运行测试确认它处于失败状态;再实现功能或修复代码,反复运行聚焦单元测试直到通过。若某项改动确实不适合先写单元测试,应在回复中说明原因和替代验证方式。
|
||||
- 后补单元测试时,应先基于对正确行为的实际预期编写测试,而不是为了迎合现有实现改写预期;如果运行后出现红灯,且通过测试需要修改已有实现,应先向用户确认这是确实的 bug,还是原本需求/既有行为就是如此;确认后再修改原始实现,避免把测试补充变成未经确认的行为改动。
|
||||
- 后端纯单元测试用例放在 `src` 目录内,并尽量与被测文件相邻,例如 `src/utils/random.test.ts`;对应 `test:unit` 只跑 `src/**/*.test.ts`,构建/打包配置应排除这些 `*.test.ts` 文件。
|
||||
- 单元测试需要 mock ESM 静态 import 时,优先使用 `esmock`,不要为了测试把业务代码改成构造函数注入或把逻辑挪到调用方;各包 `test:unit` 脚本应显式设置 `NODE_ENV=unittest`。
|
||||
- 单个 monorepo 包运行单元测试时,优先使用 `corepack pnpm --dir <包目录> test:unit`,例如 `corepack pnpm --dir packages\ui\certd-server test:unit`、`corepack pnpm --dir packages\core\basic test:unit`、`corepack pnpm --dir packages\plugins\plugin-lib test:unit`;也可以用包名过滤,例如 `corepack pnpm --filter @certd/ui-server test:unit`。前端 `packages\ui\certd-client` 暂时不跑单元测试。
|
||||
- 前端 TS/Vue/locale 等文件改动后,优先只对本次改动文件运行项目现有自动格式化/修复;Windows/PowerShell 下 Prettier 已验证可用命令为 `packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>`,ESLint 可用命令为 `packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`;不要运行 `vue-tsc` / `pnpm tsc`;不要为了格式化无关文件而扩大 diff。项目保留了 `tslint` 依赖,但当前主要使用 ESLint + Prettier。
|
||||
- 优先对改动包运行聚焦的测试;后端可按包运行单元测试,前端优先使用 Prettier/ESLint 做改动文件验证。只有跨包影响明显时再考虑全 monorepo 构建。
|
||||
- 前端用户提示**统一使用 `notification`**(ant-design-vue 的 `notification.success({ message: X })` / `.error` / `.warning` / `.info`),**不要使用 `message` API**;`src/vben/` 目录(vben 框架内置布局/组件)保持原样不动。
|
||||
- 不要运行前端 `pnpm tsc` / `vue-tsc`;当前 `vue-tsc@1.8.27` 会抛无效内部错误。前端 `test:unit` 只是占位脚本,也不要跑。
|
||||
- 前端 TS/Vue/locale 改动后,只对本次改动文件运行现有 Prettier / ESLint:`packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>` 和 `packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`。
|
||||
- 需要手写 render 的地方(如 `Modal.confirm` 的 `content`、`useFormDialog` 的 `body`、动态插槽等),一律用 JSX 编写,禁止使用 `h()` 创建 VNode:
|
||||
- `.vue` 组件:把 `<script lang="ts" setup>` 改为 `<script lang="tsx" setup>`,然后在 JSX 中直接写元素(如 `content: () => (<div class="xxx">...</div>)`)。
|
||||
- `.ts` 文件:直接把文件后缀改为 `.tsx`,再写 JSX render。
|
||||
- 列表管理、后台管理、记录查询、CRUD 表格页面优先使用 Fast Crud;开发或重构前读 `.trae/skills/fast-crud-page-dev/SKILL.md`。
|
||||
- 只有轻量只读展示、强交互自定义界面或既有页面模式明显不适合 Fast Crud 时,才手写 `a-table` / 自定义列表,并在回复中说明。
|
||||
- 内嵌 Fast Crud 时,外层必须有稳定高度或完整 `flex: 1; min-height: 0` 链路。
|
||||
- 前端组件样式统一写在 `<style>` / Less / CSS 文件里,通过样式名映射到元素;尽量不要在元素上直接写 `style`。
|
||||
- 每个组件都要有一个稳定的根样式名,并把组件下方样式全部包在该根样式名内;尽量不要使用 `scoped`。
|
||||
- 可复用的公共样式名放在 `packages/ui/certd-client/src/style` 下维护,优先使用 `cd-` 前缀,避免散落在业务组件里重复定义。
|
||||
- 后台管理列表展示或筛选用户字段时,优先参考 `packages/ui/certd-client/src/views/sys/suite/user-suite/crud.tsx` 的 `userId` 字段模式,用 `table-select` + `/sys/authority/user/getSimpleUserByIds` 字典回显和搜索。
|
||||
- 对话框里只做确认可用 `Modal.confirm`;有字段输入、表单校验或提交字段时,必须用 `useFormDialog` / `openFormDialog`。
|
||||
- 使用 `table-select` / `fs-table-select` 时,`dict` 必须配置 `getNodesByValues`,支持根据已选 ID 批量懒加载选项,确保编辑回显和异步数据场景正常工作。
|
||||
|
||||
### 前端地图
|
||||
|
||||
- `packages/ui/certd-client/vite.config.ts`:Vite 配置。
|
||||
- dev 端口:`3008`
|
||||
- 代理路径:`/api`、`/certd/api`
|
||||
- 代理目标:`127.0.0.1:7001`
|
||||
- `packages/ui/certd-client/src/main.ts`:Vue 启动入口,注册 AntDV、Vben、router、全局组件、插件和偏好设置。
|
||||
- `packages/ui/certd-client/src/App.vue`:根组件,包含 `AConfigProvider`、`FsFormProvider`、`router-view`。
|
||||
- `packages/ui/certd-client/src/router/index.ts`、`src/router/resolve.ts`:路由入口,使用 `createWebHashHistory`。
|
||||
- `packages/ui/certd-client/src/router/source/modules/certd.ts`:Certd 主业务路由。
|
||||
- `packages/ui/certd-client/src/store`:Pinia store,主要包括:
|
||||
- `user`
|
||||
- `project`
|
||||
- `settings`
|
||||
- `plugin`
|
||||
- `packages/ui/certd-client/src/api/service.ts`:Axios 封装。
|
||||
- `packages/ui/certd-client/src/api/tools.ts`:错误与响应工具。
|
||||
- `packages/ui/certd-client/src/views/certd`:核心业务视图,常见目录包括:
|
||||
- `pipeline`
|
||||
- `cert`
|
||||
- `monitor`
|
||||
- `access`
|
||||
- `notification`
|
||||
- `open`
|
||||
- `project`
|
||||
- `suite`
|
||||
- `wallet`
|
||||
- `packages/ui/certd-client/src/locales`:国际化入口与语言包。
|
||||
- Fast Crud 页面常见拆分是 `api.ts`、`crud.tsx`、`index.vue`;可参考 `src/views/certd/access`、`src/views/sys/suite/user-suite/crud.tsx`、`src/views/certd/wallet/index.vue`。
|
||||
|
||||
## 流水线与插件规则
|
||||
|
||||
- 插件是核心能力。新增服务商、DNS 验证、证书部署、通知方式,通常放到插件包或 `packages/ui/certd-server/src/plugins/<plugin-name>/`。
|
||||
- 做服务商、DNS、部署、通知相关任务时,先看 `packages/ui/certd-server/src/plugins`,再看 `packages/plugins/plugin-lib`。
|
||||
- 插件依赖的第三方 SDK 可能通过 runtime-deps 动态安装到后端运行目录 `./data/.runtime-deps`。分析阿里云、腾讯云等 SDK 行为时,需要进入该目录阅读实际安装版本代码。
|
||||
- 修改证书申请、验证、部署或通知行为时,先判断归属:ACME client、pipeline 核心、后端 module/service/entity/controller、具体插件、前端 view/form/schema。
|
||||
- 单个服务商或部署目标的问题,不要轻易修改共享 pipeline/core;只有可复用公共语义或跨插件一致行为才上移到 `packages/core/pipeline` 或 `packages/plugins/plugin-lib`。
|
||||
- `newAccount({ onlyReturnExisting: true })` 可用同一个 account private key 取回已创建账号 URL,且不会再次消费 EAB。
|
||||
- 修改 EAB `kid` 后,应重新生成绑定该 `kid` 的 account private key;否则应阻止继续申请并提示刷新账号私钥。
|
||||
- 插件开发前先读对应技能:`.trae/skills/dns-provider-dev/SKILL.md`、`.trae/skills/task-plugin-dev/SKILL.md`、`.trae/skills/access-plugin-dev/SKILL.md`、`.trae/skills/plugin-converter/SKILL.md`。
|
||||
- `.codex/skills` 是指向 `.trae/skills` 的目录链接;更新技能只维护 `.trae/skills`,不要复制第二份。
|
||||
|
||||
### 插件市场身份与卡片操作
|
||||
|
||||
- 插件唯一身份是 `fullName`:有作者时为 `author/name`,内置插件为其 `name`。数据库判重、同步/安装匹配、前端列表 `key` 和 Fast Crud `rowKey` 都必须使用 `fullName`,不得退回仅按 `name` 匹配。
|
||||
- 新增或导入本地插件必须生成 `fullName`;旧插件若缺失 `fullName`,应在迁移或兼容更新时按作者和名称补齐,避免同名不同作者的插件互相覆盖或误判已安装。
|
||||
- 插件分为四类:内置插件(无作者,需通过内置插件接口获取)、导入/自开发插件(无 `developerId`)、云端同步未安装插件(有 `developerId` 且 `installed=false`)、云端已安装插件(有 `developerId` 且 `installed=true`)。
|
||||
- 云端插件是否属于当前用户,只能以当前站点绑定账号的 `userId === developerId` 判断;不要以 `localEditable` 或插件名称、作者名称等字段代替。
|
||||
- 插件管理卡片所有类型都必须有“配置”入口。导入/自开发插件应显示编辑、复制、发布、删除;当前用户自己的已安装云端插件应显示编辑、复制、发布,但云端插件一律不显示删除。云端插件按 `installed` 显示安装或卸载,且管理操作和卸载入口可同时存在,不能互相覆盖。
|
||||
|
||||
### 后置任务(AfterTask)机制
|
||||
|
||||
- 概念:流水线主体运行结束后,按触发条件执行的任务;插件声明 `supportAfterTask: true` 后即可在后置任务中复用(如吊销旧证书 `CertRevokeOld`)。触发条件 `when`:`success`(主体执行成功)、`error`(主体失败)、`turnToSuccess`(主体被手动标记成功)。
|
||||
- 实现位置:`packages/core/pipeline/src/core/executor.ts`(`runAfterTasks` / `runOneAfterTask` / `executeAfterTaskPlugin`)与 `plugin/api.ts`。
|
||||
- **后置任务与普通任务步骤的执行链路完全一致**:`executeAfterTaskPlugin` 构造无 strategy 的伪 Step 后调用共用 `executePlugin`;不要给 executePlugin 增加差异化参数——后置任务与普通插件唯一区别是触发时机判断(`matchAfterTaskWhen`)。
|
||||
- 后置任务失败:`runAfterTasks` 聚合错误(格式 `后置任务[标题]执行失败:...`)并 throw → `runWithHistory` 将流水线整体标记为失败 → 统一走 error 通知;不再单独发送后置任务失败通知。
|
||||
- 后置任务没有内置等待时长:需要等待时由插件自身处理(`AbstractTaskPlugin.sleep(ms)` + `checkSignal()`)。
|
||||
- 未触发/禁用:写日志并标记 skip/disabled(与任务同语义),状态存 `afterTask.status`,日志 key 为 `afterTask.{id}`。
|
||||
- 通知在流水线整体(主体 + 后置任务)执行完成后发送,内容附加后置任务执行结果摘要。
|
||||
|
||||
### 流水线执行与状态写入规则
|
||||
|
||||
- `run()` 时序:`notification("start")` → `runtime.start(pipeline)` → `runtime.clearNotificationStatus()`(start 时机状态不参与显示)→ `runWithHistory(主体 + 后置任务)` → 成功/失败通知。`clearNotificationStatus` 不得移到 `notification("start")` 之前。
|
||||
- **插件主动返回 "skip" 时,runStep 仍必须执行结果处理**(把实例输出属性写回 `step.status.output` / files 等):否则保存的 lastRuntime 缺少输出,下次运行按上次结果做判断时(如 SkipWhenSucceed、证书未过期判断 `readLastCert`)会读不到上次证书,导致不跳过、重新申请(曾出 bug:第二次运行状态丢失)。SkipWhenSucceed 策略跳过的步骤,输出/files 直接从 lastStatus 拷贝(executePlugin 返回 `skipped: true`),此时可跳过结果处理。
|
||||
- 事件机制:`emit.ts` 为泛型 `PipelineEmitter<T> implements TaskEmitter<T>`,`emit(name, event)` 直接传事件对象,不再包装 `{pipeline, step, event}`;`PipelineEvent<T> = { cert: T; runnableId: string; pipelineId: number }`(`plugin/api.ts`)。
|
||||
- 证书申请成功事件:`base-convert.ts` `emitCertApplySuccess` 发 `{ cert, pipelineId: ctx.pipeline.id, runnableId: ctx.step.id }`;后端监听在 `auto-pipeline-emitter-register.ts`,写入证书仓库(`updateCertByPipelineId(pipelineId, cert, fromType, taskId)`,userId/projectId 从 pipeline 实体读取)。
|
||||
|
||||
### 流水线与插件地图
|
||||
|
||||
- `packages/core/pipeline/src/index.ts`:核心导出入口,导出 `core`、`dt`、`access`、`registry`、`plugin`、`context`、`decorator`、`service`、`notification`。
|
||||
- `packages/core/pipeline/src/plugin`:任务插件抽象,主要包括:
|
||||
- `AbstractTaskPlugin`
|
||||
- `IsTaskPlugin`
|
||||
- `TaskInput`
|
||||
- `pluginRegistry`
|
||||
- `packages/core/pipeline/src/access`:授权插件抽象,主要包括:
|
||||
- `BaseAccess`
|
||||
- `IsAccess`
|
||||
- `AccessInput`
|
||||
- `accessRegistry`
|
||||
- `packages/core/pipeline/src/dt/pipeline.ts`:`Pipeline`、`Stage`、`Task`、`RunStrategy` 等流水线数据结构。
|
||||
- `packages/core/pipeline/src/core`:执行器、上下文、运行历史、文件存储等。
|
||||
- `packages/core/pipeline/src/service`:CNAME、事件、配置、邮件、URL 等 pipeline service 接口。
|
||||
- `packages/ui/certd-server/src/plugins`:后端内置服务商、DNS、部署、通知等插件。
|
||||
- `packages/ui/certd-server/src/plugins/plugin-cert`:证书申请核心插件。
|
||||
- `packages/ui/certd-server/src/plugins/plugin-lib`:后端插件 helper/access。
|
||||
- `packages/plugins/plugin-lib/src/cert`:`CertReader`、`CertConverter`、DNS Provider 公共能力。
|
||||
- `packages/plugins/plugin-lib/src/cert/dns-provider`:`AbstractDnsProvider`、`dnsProviderRegistry`、`DomainParser`。
|
||||
- ACME 协议、EAB、账号、订单、挑战流程:优先看 `packages/core/acme-client` 或 `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts`。
|
||||
- 流水线执行、任务生命周期、输入输出、注册机制:看 `packages/core/pipeline`。
|
||||
- 单个云厂商 DNS 验证、证书部署、API 调用失败:改对应 `packages/ui/certd-server/src/plugins/plugin-xxx`。
|
||||
- 通用证书读取、DNS Provider 公共能力、格式转换:改 `packages/plugins/plugin-lib`。
|
||||
- 后端业务数据、接口、实体、权限、迁移:改 `packages/ui/certd-server/src/modules` 与 `src/controller`。
|
||||
- 表单、列表、插件配置 UI:改 `packages/ui/certd-client/src/views/certd` 及对应 `src/api`。
|
||||
|
||||
## 其他注意事项
|
||||
|
||||
### 旧版数据兼容
|
||||
|
||||
- 新增插件参数时,必须要考虑旧版数据兼容,比如新增一个deployType参数,有两种值:`default`和`custom`,需要在使用时判空,走旧版逻辑。
|
||||
|
||||
## 前端路由与国际化
|
||||
|
||||
- 路由 `meta.title` 是 **i18n 国际化 key**,必须在 `src/locales/langs/zh-CN/` 和 `src/locales/langs/en-US/` 对应的模块文件中添加翻译。
|
||||
- 示例:路由 `title: "certd.auditLog"` 需要在中英 locales 文件中有对应 key(`"certd.auditLog": "操作日志"` / `"certd.auditLog": "Audit Log"`)。
|
||||
- 菜单通过路由自动生成,需设置 `meta.isMenu: true` 才会出现在左侧菜单。
|
||||
- Plus 版功能菜单需设置 `meta.show: () => { const settingStore = useSettingStore(); return settingStore.isPlus; }`。
|
||||
|
||||
## 审计日志
|
||||
|
||||
- 审计日志是 Plus 版功能,非 Plus 版不会写入。
|
||||
- Controller 继承 `BaseController`,通过 `this.auditLog({ content: "xxx" })` 记录日志。
|
||||
- Controller 中的 `@Post("/add", { summary: "xxxx" })`, 这个summary是必须要的,他是日志action字段的来源
|
||||
- `getAuditType()` 返回类型常量,中间件自动从 ctx.path 判定 scope(`/api/sys/` → system,其他 → user)。
|
||||
- 操作日志有系统级(scope=system)和用户级(scope=user)区分。
|
||||
|
||||
@@ -3,6 +3,322 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.45.0](https://github.com/certd/certd/compare/v1.44.4...v1.45.0) (2026-10-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* [BUG]使用天翼云CDN部署证书时无法匹配域名 ([bb1f232](https://github.com/certd/certd/commit/bb1f232f415c522851dede979f5d609dda844fd3))
|
||||
* 缺失运行时嵌套依赖时添加清除缓存提示 ([2d0b85b](https://github.com/certd/certd/commit/2d0b85b3054fc1aa82b3ab5db34a2a56308f71f2))
|
||||
* 支持google persist校验方式 ([97d2b50](https://github.com/certd/certd/commit/97d2b5007409ec79ea864d437c473a2f9b5dfae4))
|
||||
* **config:** 修复环境变量加载逻辑并更新配置文件 ([07f0d3b](https://github.com/certd/certd/commit/07f0d3b4d626628a0e3dfc7e5c52e8c4a98bad47))
|
||||
* **ctyun-cdn:** 修复天翼云CDN部署插件的域名选择问题 ([ea7d14c](https://github.com/certd/certd/commit/ea7d14c289b8720781bf101bfef59eac7bb03765))
|
||||
* **webhook:** 修复模版转义换行符,避免手动上传的证书报错 ([2735feb](https://github.com/certd/certd/commit/2735feb3302f8308708dafc8b295adcd4b91d7f0))
|
||||
|
||||
### Features
|
||||
|
||||
* **client:** 新增客户端管理功能 ([3dbbe72](https://github.com/certd/certd/commit/3dbbe72fc15c114ca6b5e8ff45cb21f258b80650))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 宝塔站点列表支持搜索和排序 ([4420472](https://github.com/certd/certd/commit/4420472f8fac272d30fb8ccb1cc2ee9763989001))
|
||||
* 网宿插件双鉴权支持 ([241b2e5](https://github.com/certd/certd/commit/241b2e55848471e61b5d2be0c87a7dc9a0d29557))
|
||||
* **monitor:** 站点证书监控支持手动选中触发检查 ([f60e63f](https://github.com/certd/certd/commit/f60e63fbaf00460d5050cd7705bd75d57dec202d))
|
||||
* **open-api:** openkey增加用途备注 ([bbeaf61](https://github.com/certd/certd/commit/bbeaf617d19750515f6eca51863e74e23bc1de50))
|
||||
* **tencent clb:** 修改所有CLB地域的endpoint为就近接入 ([c427735](https://github.com/certd/certd/commit/c4277350bcc8cf034cf4e76db2a6daa1842bc5d7))
|
||||
|
||||
## [1.44.4](https://github.com/certd/certd/compare/v1.44.3...v1.44.4) (2026-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复添加步骤会修改所有步骤标题的bug ([51e83e4](https://github.com/certd/certd/commit/51e83e4c38f7f319314fdc38ef33cf5720b2dde0))
|
||||
* 修复证书插件配置无法打开的bug ([5563abb](https://github.com/certd/certd/commit/5563abb13a62140f4dee668ab768cf4ff9371ddb))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 新增余额管理,管理员充值功能 ([bded368](https://github.com/certd/certd/commit/bded368cbb8974b6937ae260e448c25fae5c33ad))
|
||||
* **acme-account-access:** AcmeAccount授权允许修改eab,重新生成account ([6a649aa](https://github.com/certd/certd/commit/6a649aaca083ccd3b517f7d676a58220aa33b37d))
|
||||
* **ui:** 商业版套餐购买不要求设置支付方式 ([e971145](https://github.com/certd/certd/commit/e9711456860d7db40914a0c295534f7bca56f83c))
|
||||
|
||||
## [1.44.3](https://github.com/certd/certd/compare/v1.44.2...v1.44.3) (2026-09-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **plugin-service:** 修复同步自己开发的云端插件不显示已安装状态问题 ([dac94b6](https://github.com/certd/certd/commit/dac94b64f0ceb7176e2cf07ce220be0aa5ed98d2))
|
||||
* **plugin:** 修复插件配置保存与加载的相关问题 ([bd94334](https://github.com/certd/certd/commit/bd9433478a43d5d64ce6370386d0fe0aaff07d2e))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **plugin:** add Fastly custom TLS certificates integration ([#797](https://github.com/certd/certd/issues/797)) [@szhu25](https://github.com/szhu25) ([2a2e963](https://github.com/certd/certd/commit/2a2e963914c4dfc192cbe0a4bbb9c115e626da01))
|
||||
|
||||
## [1.44.2](https://github.com/certd/certd/compare/v1.44.1...v1.44.2) (2026-09-03)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复插件市场插件安装无效的bug ([15d2bd8](https://github.com/certd/certd/commit/15d2bd8484a9ddd142bf4ef03d839c74405f9e6d))
|
||||
* preserve Route53 TXT record values ([#791](https://github.com/certd/certd/issues/791)) ([f5430a8](https://github.com/certd/certd/commit/f5430a8925cf6cf4e16c75f2358fbd78437e6705))
|
||||
|
||||
## [1.44.1](https://github.com/certd/certd/compare/v1.44.0...v1.44.1) (2026-09-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复编辑证书申请任务导致清空ACME账号的bug ([d67379f](https://github.com/certd/certd/commit/d67379f29725bbd6dcdefe97d101023c7fd11f03))
|
||||
* 修复大量问题 ([f911e06](https://github.com/certd/certd/commit/f911e06a698d568ae228880ec89b7e25fdd1305b))
|
||||
* 修复旧流水线保存时清空证书仓库证书内容的bug ([f58f2f3](https://github.com/certd/certd/commit/f58f2f3cd603c37e55ac5868fdd2ca99aa937e44))
|
||||
* **pipeline-controller:** 处理非编辑场景下保留id的问题 ([6606f32](https://github.com/certd/certd/commit/6606f3267868e3aadaca0092ef4c83198312553c))
|
||||
* **pipeline:** 修正流水线保存时的ID判断逻辑并增加参数校验 ([6af12d4](https://github.com/certd/certd/commit/6af12d49fce1144943dc37ba574b3c9356998dcd))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **dashboard:** 新增仪表盘站点监控和域名管理的统计卡片 ([9842a24](https://github.com/certd/certd/commit/9842a24a50a841f710ee7c8050a38e3334c58394))
|
||||
|
||||
# [1.44.0](https://github.com/certd/certd/compare/v1.43.0...v1.44.0) (2026-08-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复证书申请时EAB判断逻辑,已选择Acme账号的情况下不需要EAB ([d87821e](https://github.com/certd/certd/commit/d87821ee02b17136fc925df4547223332bf22823))
|
||||
* **pipeline:** 校验定时触发器cron表达式,拦截2月31号等无效日期 ([#785](https://github.com/certd/certd/issues/785)) [@yukaidi1220](https://github.com/yukaidi1220) ([f8e492d](https://github.com/certd/certd/commit/f8e492d6cb49257e56bbd06b28fd6eb32c923c28))
|
||||
* **plugin-ai-dev:** 优化AI插件测试流程并修复日志获取问题 ([faf9828](https://github.com/certd/certd/commit/faf9828168f6ce82adc530a65eaf313d6c9904b5))
|
||||
* **plugin-item-card:** 移除分数格式化时去掉.0的逻辑 ([a91d7c0](https://github.com/certd/certd/commit/a91d7c000a2aa6456a249433ff90a47787ec90f0))
|
||||
* **ssh:** 修复 keyboard-interactive 认证可能抛类型错误的问题 ([5e867c8](https://github.com/certd/certd/commit/5e867c86c30eb43f1e5aeee8c22d47596e173a8c))
|
||||
* **start.sh:** 优化前端zip包下载校验逻辑 ([15ee6ea](https://github.com/certd/certd/commit/15ee6ead49db3620d2ade641aadbfcb13ac3e6dc))
|
||||
* **tencent access:** 修复腾讯云国际站接口endpoint拼接问题 ([f614872](https://github.com/certd/certd/commit/f61487284f79d3f5a72c9f7eee04999a93728326))
|
||||
|
||||
### Features
|
||||
|
||||
* 实现自定义ACME证书颁发机构支持 ([97c417b](https://github.com/certd/certd/commit/97c417b1ad64b9a14bee8bfe98a2e789b9278820))
|
||||
* 新增证书吊销后置任务与证书状态管理 ([1cc9641](https://github.com/certd/certd/commit/1cc9641f5669710d1e5809995ad395c843855a12))
|
||||
* 新增AI插件开发全流程能力 ([6f9dffe](https://github.com/certd/certd/commit/6f9dffe6e59cc125bd394d7db6086d66a9c71e49))
|
||||
* 支持审计日志,操作日志 ([f2855d6](https://github.com/certd/certd/commit/f2855d6dac74c9db71d92f99601e35c360b10666))
|
||||
* 支持在线插件下载安装审核等 ([255960d](https://github.com/certd/certd/commit/255960d434eebb3d567a08f737f1642ab417b5d0))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 统一镜像地址格式 certd/certd ([49007d3](https://github.com/certd/certd/commit/49007d391565099d94dec375eb88e946856506b0))
|
||||
* 新增AI插件开发受限令牌与隔离API ([3a9069f](https://github.com/certd/certd/commit/3a9069f6e6242940229fd63c686f7e445408dbbb))
|
||||
* 优化源码启动脚本,增加快速启动 ([0cfc3b7](https://github.com/certd/certd/commit/0cfc3b7ae90fa031d75f0b395556a04d4efee76c))
|
||||
* 统一将路由前缀从/certd改为/cert ([4db0f83](https://github.com/certd/certd/commit/4db0f83304dc6fd9199673c48b1805421f024601))
|
||||
* 新增官方客户端Certd Client的多语言配置与页面入口 ([fbfe125](https://github.com/certd/certd/commit/fbfe1256a5c8be6dfb2fbae7e6130eb5f6c6d946))
|
||||
* 新增证书吊销功能,添加证书状态字段 ([5074572](https://github.com/certd/certd/commit/5074572694383c8e1bf2880e26827987683dc62c))
|
||||
* 新增自定义ACME管理功能,完善证书颁发机构适配 ([2ab23f5](https://github.com/certd/certd/commit/2ab23f50b216e27495fc823d2269ca0ba6366d15))
|
||||
* 移除全局反向代理配置,迁移到自定义ACME配置 ([c57110e](https://github.com/certd/certd/commit/c57110e42aada31dd0028b56b5baec1b19722525))
|
||||
* 在线插件支持通知类型 ([c0f194f](https://github.com/certd/certd/commit/c0f194f4438bd7ca3f52f63ca088543abde7428c))
|
||||
* 增加稳定版,预览版区分,预览版是最新版,稳定版在预览版验证稳定后,再将预览版转为稳定版 ([1574090](https://github.com/certd/certd/commit/15740904e5e97ee767c39e4401dbc1d645795c38))
|
||||
* 支持AI开发在线插件 ([eae7edb](https://github.com/certd/certd/commit/eae7edbda0fd7357163f33fb4084fcba21396f5f))
|
||||
* **domain:** 域名管理增加remark字段 ([e4041ea](https://github.com/certd/certd/commit/e4041eabece1bab2c1c4b955129cf7a7fe7302d0))
|
||||
* **login,settings:** 仅第三方登录开启后,在重启10分钟后将无法使用密码登录 ([1d12ad7](https://github.com/certd/certd/commit/1d12ad73c6ca827d2eb36bda867f9d9fe62dab48))
|
||||
* **plugin:** 插件安装支持检测依赖 ([e79660c](https://github.com/certd/certd/commit/e79660c5d17ed4049508a00a359950a54470332f))
|
||||
* **plugin:** 新增插件评分展示、排序与个人插件筛选功能 ([7ab5029](https://github.com/certd/certd/commit/7ab502991e0c001777b268b9f159311ef5e000a0))
|
||||
* **server:** response优化为gzip压缩 ([f38522c](https://github.com/certd/certd/commit/f38522ca0b2185f7f35538f53cb51dcf86d0bfc8))
|
||||
* **tencent-clb:** 重构腾讯云CLB部署插件的地域选择组件,改为远程下拉选择器 ([30d4fc8](https://github.com/certd/certd/commit/30d4fc84a9e940d1d07e1f25856eb6fa13da9ba1))
|
||||
|
||||
# [1.43.0](https://github.com/certd/certd/compare/v1.42.6...v1.43.0) (2026-08-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 优化火山引擎dcdn,单个单个部署,规避超时问题 ([cf008b9](https://github.com/certd/certd/commit/cf008b9cff54542dc551fb159578dbd49006229c))
|
||||
* **pipeline:** 修复过期/损坏的安装锁导致的依赖安装失败 ([1017a38](https://github.com/certd/certd/commit/1017a38eb48d6778745d4905d9ec4f6067a261d8))
|
||||
* **ui:** 修复oauth设置页保存后未正确刷新的问题 ([8ab699a](https://github.com/certd/certd/commit/8ab699a9104b47e02a88ad764e995a495deb775e))
|
||||
* **unicloud:** 修复unicloud登录接口改版后请求失败的问题 ([18583f6](https://github.com/certd/certd/commit/18583f6ce025fa8d365fad5a8c9c6020f3bcfbae))
|
||||
|
||||
### Features
|
||||
|
||||
* 优化开放接口证书自动申请功能 ([6339cdf](https://github.com/certd/certd/commit/6339cdffa9f79505dada5617d8c7fcfacc419a2e))
|
||||
* **pipeline:** 新增流水线批量编辑、阶段宽度调整功能 ([e5a1844](https://github.com/certd/certd/commit/e5a18448522be88bc504a45a46ad599f3c39ca30))
|
||||
* **ssh:** ssh连接支持跳板机 ([2cb4e55](https://github.com/certd/certd/commit/2cb4e551fa7616f587a2d907f9b513f7df3a9957))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 部署到京东云CDN支持设置跳转类型 ([e992192](https://github.com/certd/certd/commit/e9921928df011c2435af73b68ebc3d773f13c16a))
|
||||
* 统一通知类型常量管理,新增开放接口通知能力 ([edb249c](https://github.com/certd/certd/commit/edb249c2ad3c173dbfd04d8d156f895a6706ffd1))
|
||||
* 优化宝塔报错提示 ([1cfa766](https://github.com/certd/certd/commit/1cfa76683b40da9e9198552f2226419d4afa86a3))
|
||||
* 优化第三方登录设置提示 ([1468eb1](https://github.com/certd/certd/commit/1468eb1ef292a9e21a2a43131b86b8acb3688307))
|
||||
* 优化第三方依赖安装失败日志输出 ([18b2d3a](https://github.com/certd/certd/commit/18b2d3ac2078d0c6636af897f8f66e4eb5ff832c))
|
||||
* 优化SqliteError: disk I/O error报错修复提示 ([7d22fe3](https://github.com/certd/certd/commit/7d22fe3d7d0de97bae2ceedd051a0c16a1cd90e3))
|
||||
* 证书成功通知增加有效期显示 ([f1b6704](https://github.com/certd/certd/commit/f1b67049d16ebcabe6d6d9b6cb53a8a2b7a9265c))
|
||||
* **cert-plugin:** 证书申请支持失败重试 ([0ddb1f6](https://github.com/certd/certd/commit/0ddb1f69d2a46b993e792862ce9952336d532f5b))
|
||||
* Improve English localization coverage ([#778](https://github.com/certd/certd/issues/778)) @MephistoJB ([bd82147](https://github.com/certd/certd/commit/bd821474969a22078b9d2e73518e765b8c9a26c7))
|
||||
* **install:** 补充迁移到PostgreSQL后,表自增序列从1开始的修复SQL脚本和说明 ([80374ca](https://github.com/certd/certd/commit/80374cae8a43fd17eb180381a093267e466a0bc2))
|
||||
* **plugin-ucloud:** ucloud us3部署插件增加region选择 ([8165a5f](https://github.com/certd/certd/commit/8165a5ff8986e759948c06f924d12e605b2ec8f6))
|
||||
* **tencent-clb:** 为腾讯云CLB部署插件支持远程选择输入 ([967846b](https://github.com/certd/certd/commit/967846bef590b76d27e472180b96372ff55cfb6f))
|
||||
* **ui:** 域名选择器支持点击复制域名 ([b173311](https://github.com/certd/certd/commit/b173311468d2c1f318d1333257c3ebcf916da071))
|
||||
|
||||
## [1.42.6](https://github.com/certd/certd/compare/v1.42.5...v1.42.6) (2026-07-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复正常批量删除流水线报权限不足的bug ([5b50083](https://github.com/certd/certd/commit/5b500830a122c6c42dab054e57fed509050f94da))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化动态加载依赖镜像地址,多次重试 ([5f53b81](https://github.com/certd/certd/commit/5f53b81c75dd242b4260ac08cae14c6d1a08a883))
|
||||
|
||||
## [1.42.5](https://github.com/certd/certd/compare/v1.42.4...v1.42.5) (2026-07-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复上传到cos报runtimeDepsService未初始化的问题 ([167b303](https://github.com/certd/certd/commit/167b303faeca02cc11cf97e4be2a3df914852167))
|
||||
* 修复dingtalk通知格式没有换行的bug ([7ed1be9](https://github.com/certd/certd/commit/7ed1be994f8b4b74cdeb38743060c912c027248b))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 给SQLITE_IOERR_WRITE增加友好报错提示,将certd:latest镜像改为certd:slim ([b91c9e4](https://github.com/certd/certd/commit/b91c9e4ea671cb359ef164e27864de1d66cba9d3))
|
||||
* 优化vke keubconfig获取方式,改成先查询,如果没有再创建临时config ([604fa5b](https://github.com/certd/certd/commit/604fa5be634d099d797bfee5c2b0f26ce0ac8461))
|
||||
|
||||
## [1.42.4](https://github.com/certd/certd/compare/v1.42.3...v1.42.4) (2026-07-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复火山引擎查不到自定义源站域名的问题 ([02dabe1](https://github.com/certd/certd/commit/02dabe11db3e9b13ca4621ce9ddd2b808bfca390))
|
||||
* 修复火山引擎自定义源站域名查询不到的问题 ([e44bf9d](https://github.com/certd/certd/commit/e44bf9d77375d48ac7fd1582e69fae02dfd248fa))
|
||||
* **pipeline:** 重构运行时依赖加载逻辑,修复火山引擎DNS解析报runtimeDepsService未初始化的bug ([ec69b8f](https://github.com/certd/certd/commit/ec69b8f11bfd4b20991aef74a72a47182ca79a9d))
|
||||
|
||||
## [1.42.3](https://github.com/certd/certd/compare/v1.42.2...v1.42.3) (2026-07-08)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **volcengine-alb:** 修复火山引擎ALB 默认证书部署类型会部署到扩展证书的问题 ([0a068a2](https://github.com/certd/certd/commit/0a068a274673e9768954e9f7367c267d44f3b530))
|
||||
|
||||
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复火山视频点播源站选择不到自定义源站的bug ([0071bcb](https://github.com/certd/certd/commit/0071bcb0e4dd108c86d7ca01820a9f6e6960e440))
|
||||
* 修复企业模式下弹出邮箱绑定提醒的问题 ([8d9dad9](https://github.com/certd/certd/commit/8d9dad9c82f6f2fd3ab3040068946a33f37145b1))
|
||||
* 修复AsiaIsp CDN证书重复情况下部署失败的问题 ([c3d6db3](https://github.com/certd/certd/commit/c3d6db3f1ef2f1c897b7989521fe8809dffaded1))
|
||||
* 修复cname用阿里云校验时报找不到runtimeDepsService的错误 ([072edd7](https://github.com/certd/certd/commit/072edd7affee424ab3411f4d41d338f084d7cac6))
|
||||
|
||||
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复多域名无法使用passkey登录的bug ([d176f9c](https://github.com/certd/certd/commit/d176f9cc0ebd051a614bfac74d1616d1945fc9a3))
|
||||
* 修复企业模式下登录报projectId不能为空的问题 ([a65366b](https://github.com/certd/certd/commit/a65366bbe1aadea8baaffbdadab58a5b631d9417))
|
||||
* **login:** 修复输入法 composing 状态下回车触发提交的问题 ([b74db81](https://github.com/certd/certd/commit/b74db81304bbe68476bbec5ea4307a2264060e92))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **certd-server:** 使用 jks-go转换jks证书,大幅精简镜像大小 ([c78898e](https://github.com/certd/certd/commit/c78898e4c10dd1701467d2e42e3f72bd8f2a352f))
|
||||
* **pipeline:** 将默认历史保留条数从30调整为100 ([d3e4677](https://github.com/certd/certd/commit/d3e4677ea4fac8e7533749d7f4187e410489e536))
|
||||
|
||||
# [1.42.0](https://github.com/certd/certd/compare/v1.41.4...v1.42.0) (2026-07-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复jdk证书格式的问题 ([260f5ae](https://github.com/certd/certd/commit/260f5ae777b83493b0c578fe30fd00ec0c873226))
|
||||
* 修复telegram - 符号转义问题 ([d5882f1](https://github.com/certd/certd/commit/d5882f16bedb09baf09ace92049b02872620f5dc))
|
||||
* **aliyun:** 修复阿里云CDN/DCDN根据证书自动匹配不到证书的bug ([1ae185d](https://github.com/certd/certd/commit/1ae185d0bc356f4678bc38ca0582ce3396f82ebe))
|
||||
|
||||
### Features
|
||||
|
||||
* 通过插件配置懒加载依赖,动态加载第三方依赖包,精简安装镜像大小 ([01568ca](https://github.com/certd/certd/commit/01568ca1489069046b5a89ebdd4ced2f7f6ddf93))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 阿里云ESA证书部署支持SaaS模式 ([82276b5](https://github.com/certd/certd/commit/82276b53a8474a18a3d0237050907c994fc748f0))
|
||||
* 【破坏性更新】 证书压缩包不再生成文件存储,而是实时打包下载,证书申请插件不再输出certZip ([7cff1a9](https://github.com/certd/certd/commit/7cff1a98424120585205889874b3ef4956a30583))
|
||||
* 火山引擎点播插件支持部署到自定义源站域名 ([095791c](https://github.com/certd/certd/commit/095791cdc2b7c1f4b913b634643afec5e30fe9b0))
|
||||
* 基础镜像改成node:22-trixie-slim,对网络兼容性更好 ([c66a2bd](https://github.com/certd/certd/commit/c66a2bd77ab6dbb3e3fe2c00562b66287a9429ea))
|
||||
* 新增橙域网络(asia-isp) CDN证书部署插件 ([b48831e](https://github.com/certd/certd/commit/b48831e60b0059bef7ef9a34ab61c9dd2f684641))
|
||||
* 优化阿里云API网关增加翻页查询 ([ed58ae3](https://github.com/certd/certd/commit/ed58ae3c5339e4a0238a92acfe7ea6d2f566ea28))
|
||||
* 优化用户体验,首次访问时弹出邮箱账号绑定用以初始化账号 ([608cc2a](https://github.com/certd/certd/commit/608cc2a81ff0b4872c9fe11ed9c9c0b4b90a12a3))
|
||||
* 优化ACME账号字段的选择提示 ([bfd3cac](https://github.com/certd/certd/commit/bfd3cacc687fc5cbc3cb2ca3cadbc140de300dc2))
|
||||
* 支持全自动匹配部署宝塔网站证书 ([4dff48e](https://github.com/certd/certd/commit/4dff48e807c32a7623ec9206cf39c88e88f89f6a))
|
||||
* **cert-plugin:** 调整更新天数自动减半逻辑,仅7天ip证书生效,其他情况下不减半 ([56e5524](https://github.com/certd/certd/commit/56e5524a0f4af3645d70bc3b3ec750b45ba8de10))
|
||||
* dns默认ipv4first ([194463b](https://github.com/certd/certd/commit/194463bea9e797315aa7a724f4b2930701570419))
|
||||
* **passkey:** passkey支持多域名rpid ([79f6586](https://github.com/certd/certd/commit/79f65868ca0f5162bbc2f935ce89abc28011d816))
|
||||
* **plugin:** 在线插件编辑支持配置第三方依赖和插件依赖 ([635f069](https://github.com/certd/certd/commit/635f069012d4193cfb7cb051c96e28eec1247ca2))
|
||||
|
||||
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **plugin:** 增加 Dynadot DNS and access 插件 ([a3a215b](https://github.com/certd/certd/commit/a3a215b7ae2b90efcde91270ce4165bbfe77dc64))
|
||||
|
||||
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复litessl无法申请证书,报authorization must be pending 错误的问题 ([d6cd9d1](https://github.com/certd/certd/commit/d6cd9d136d2812b2335917305f36d6d9414507ad))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 首页夜间模式主图切换为黑色背景 ([15484bc](https://github.com/certd/certd/commit/15484bc119fef7a0ca7f3fdab01d665fde47e688))
|
||||
|
||||
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cert-plugin:** 修复DNS提供商授权无法回显的bug ([016ae86](https://github.com/certd/certd/commit/016ae865b1d914fe5792e77a08e3ab5358df5f89))
|
||||
* Parse PEM chain and import certificate chain ([#747](https://github.com/certd/certd/issues/747)) ([454912d](https://github.com/certd/certd/commit/454912d31407d350cbd170953ccbd0564e74fd6c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 添加AWS Rate Limit应对措施 ([#748](https://github.com/certd/certd/issues/748)) ([56b8c68](https://github.com/certd/certd/commit/56b8c689ec2b5cff49010a8c765483dd36803e9d))
|
||||
* 新增站点证书监控从DNS解析记录批量导入功能 ([f9541fa](https://github.com/certd/certd/commit/f9541fab701e01ba57af061da322204c894adfb8))
|
||||
* 优化 HiPM DNSMgr 插件,添加域名查询双层策略 ([#744](https://github.com/certd/certd/issues/744)) @WUHINS ([0f3f851](https://github.com/certd/certd/commit/0f3f8519e04d95cb848e28b98a3d4fcbed481fce))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "perf: 添加AWS Rate Limit应对措施 (#748)" (#749) ([5e8bdac](https://github.com/certd/certd/commit/5e8bdac00850bed4f5f2a272bee42c490730ec21)), closes [#748](https://github.com/certd/certd/issues/748) [#749](https://github.com/certd/certd/issues/749)
|
||||
|
||||
## [1.41.1](https://github.com/certd/certd/compare/v1.41.0...v1.41.1) (2026-06-05)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 流水线、监控站点支持导出 ([99fd308](https://github.com/certd/certd/commit/99fd3083f259cdb96fd656f04858dd708d1251c7))
|
||||
* 优化列表页面请求两次的问题 ([5546af5](https://github.com/certd/certd/commit/5546af518e92c765513787ccaf8e856be789bcf9))
|
||||
* 优化邀请注册流程 ([7a71e45](https://github.com/certd/certd/commit/7a71e45799d782d0691606fb42b4236f1d3009b0))
|
||||
* **settings:** 新增NO_PROXY代理排除配置 ([c0df8be](https://github.com/certd/certd/commit/c0df8be83237e323c2c9a5bd02507430a86a00cc))
|
||||
* **volcengine-vke:** 火山VKE集群证书支持两种类型的证书保密字典 ([77b8024](https://github.com/certd/certd/commit/77b802445322d576d54d194f7c505da49e0e824c))
|
||||
|
||||
# [1.41.0](https://github.com/certd/certd/compare/v1.40.5...v1.41.0) (2026-06-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云证书订单orderid 选择出错的问题 ([41254d1](https://github.com/certd/certd/commit/41254d10b748a2d3e6ba43c7e11411650c748d1b))
|
||||
* **monitor:** 修复开放接口自动创建证书流水线重复触发和等待时间不足的问题 ([91d5c90](https://github.com/certd/certd/commit/91d5c90eb0eaf65c81dddbd2d4d4b404cb8b4d07))
|
||||
* **pipeline:** 修复批量随机修改定时没有生效的bug ([2e19dda](https://github.com/certd/certd/commit/2e19dda72e70b525a7c269e18e963a5ee602f59f))
|
||||
|
||||
### Features
|
||||
|
||||
* 商业版支持邀请返佣功能 ([f9a310b](https://github.com/certd/certd/commit/f9a310b6c3bbf30f221482a0c59e9c30080bdfc8))
|
||||
* 商业版支持邀请推广功能 ([f1d2a10](https://github.com/certd/certd/commit/f1d2a1033a0f8d3dbd91fc9793e07bd0b858b539))
|
||||
* 新增管理员针对用户流水线和证书监控管理功能 ([0211552](https://github.com/certd/certd/commit/021155278e7375f8487b0531ed1b5ad52512f007))
|
||||
* 新增套餐激活码功能,通过CDK兑换套餐 ([81d6289](https://github.com/certd/certd/commit/81d6289a8631b073b49f24dee4b14bb1c8f31071))
|
||||
* 新增推广等级激励功能 ([5096df5](https://github.com/certd/certd/commit/5096df5cc0d8f0ad8aa327b8e2a900ba23714bd8))
|
||||
* 新增证书申请参数模版管理,开放接口支持使用证书参数模版和指定证书申请参数 ([f8b71a0](https://github.com/certd/certd/commit/f8b71a0e612fad527cf49136335e0b46f0f379cd))
|
||||
* 支持dns-persist-01持久化验证方式申请证书,优化Acme账号的存储方式 ([67b05e2](https://github.com/certd/certd/commit/67b05e2d75e96b9f855e1ca0b3d0d8d03b92d8e6))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 插件全局配置支持下拉选项自定义映射功能 ([c637985](https://github.com/certd/certd/commit/c637985575b09196b04cce37ac14fbe68c029bde))
|
||||
* 商业版提现增加收款二维码上传 ([83a5a21](https://github.com/certd/certd/commit/83a5a21f956e50942541f1532f3a8dcaa5821d34))
|
||||
* **aliyun-apig:** 优化阿里云API网关部署插件的查询及翻页 ([3e4b7f3](https://github.com/certd/certd/commit/3e4b7f30ac6f3c976c8274bdf256c69b8a2c46db))
|
||||
* **trade:** 优化商品购买页面的规格展示和折扣计算,支持订单取消 ([6624769](https://github.com/certd/certd/commit/66247690326ce2789900fc9110c08b3502cea655))
|
||||
|
||||
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 安装glibc,增加Alpine镜像下 dns解析结果的兼容性 ([1a08bd3](https://github.com/certd/certd/commit/1a08bd340e1e7d3f9acf5d40f7bba7998459b8fb))
|
||||
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/certd/certd/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
|
||||
* 修复查询阿里云cdn Dcdn 域名太多无法选择的bug ([346fb73](https://github.com/certd/certd/commit/346fb730a37e035576f5d9ea5c0d74c052b34aeb))
|
||||
|
||||
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **pipeline-service:** 修复流水线运行时超过套餐部署次数仍然能够正常运行的bug ([5e59651](https://github.com/certd/certd/commit/5e59651d45bc91919629e35995ff1b3cff6b87ea))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 商业版套餐只支持设置为可叠加 ([5e72f75](https://github.com/certd/certd/commit/5e72f75395fb632a30e80c07d35d8ba40ef631fa))
|
||||
* 新增阿里云直播证书部署插件 ([8edb6f8](https://github.com/certd/certd/commit/8edb6f8727bd148f106801bef25567880fd35e9e))
|
||||
|
||||
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
# 自定义 ACME 功能开发计划
|
||||
|
||||
## 一、背景与目标
|
||||
|
||||
Certd 目前仅支持内置 CA(Let's Encrypt / Google / ZeroSSL / SSL.com / litessl / LE 测试环境)。
|
||||
目标:支持用户**自定义 ACME 证书颁发机构**——用户可填写任意符合 RFC 8555 的 ACME Directory URL
|
||||
(内网 CA、企业 CA、其他公共 ACME 服务商),可选 EAB 授权,走完整的申请、续期、吊销流程。
|
||||
|
||||
## 二、需求确认(已与用户确认)
|
||||
|
||||
1. **Directory URL 填写位置**:在「ACME账号授权」中填写(账号与 CA 绑定,续期自动复用账号)。
|
||||
- 代码中 `directoryUrl` 字段、`caType === "custom"` 分支、`AcmeService.getAcmeClientByAccount()` 读取 `account.directoryUrl` 均已预留,架构改动最小。
|
||||
2. **不做系统级公共自定义 CA 账号**:仅用户自建自己的 ACME 账号。
|
||||
3. **自定义 CA 支持 EAB,选填**:填了就用,不填则跳过。
|
||||
4. **吊销链路改造**(用户追加要求):证书写入仓库时同时把 `acmeAccountAccessId` 记录到
|
||||
`cd_cert_info` 表,吊销时直接读表,**不再查询流水线**(旧数据回退兼容)。
|
||||
|
||||
## 三、现状分析
|
||||
|
||||
### 已有基础(无需改动或已预留)
|
||||
|
||||
| 位置 | 现状 |
|
||||
| --- | --- |
|
||||
| `@certd/acme-client` | 底层 `new Client({ directoryUrl })` 直接支持任意 URL,无需改动 |
|
||||
| `AcmeAccountAccess.directoryUrl` 字段 | 已定义,但 `mergeScript` 里 `show: false` 隐藏 |
|
||||
| `AcmeAccountAccess.getDirectoryUrl()` | 已有 `caType === "custom"` 分支:校验必填并返回 `directoryUrl` |
|
||||
| `AcmeAccountInfo` 类型 | 已含 `directoryUrl`、`eab` 字段 |
|
||||
| `AcmeService.getAcmeClientByAccount()` | 已支持 `account.directoryUrl \|\| acme.getDirectoryUrl(...)` |
|
||||
| `AcmeAccountAccess.createAccountInfo()` | EAB 已选填(`eabKid && eabHmacKey` 才构造),custom 不强制 EAB |
|
||||
| 前端 `Dicts.sslProviderDict` | 已含 `custom`("自定义ACME")选项 |
|
||||
|
||||
### 缺口(本次要开发)
|
||||
|
||||
1. `AcmeAccountAccess.caType` 下拉无 `custom` 选项;`directoryUrl` 被隐藏、无必填联动。
|
||||
2. `AcmeAccountAccess` EAB 字段 `show` 条件不含 custom;custom 下应为选填(内置 CA 保持必填)。
|
||||
3. `AcmeService.getAcmeClient()`(无账号临时建账号路径,生成账号时必走)用 `acme.getDirectoryUrl({ sslProvider: "custom" })` 会抛错,需要支持 `directoryUrl` 参数。
|
||||
4. `CertApplyPlugin.sslProvider` 下拉无 `custom` 选项;custom 时 ACME 账号必选、preferredChain/certProfile 显隐、DNS 持久验证限制。
|
||||
5. 吊销链路:`CertInfoService.revoke` 依赖 `resolveRevokeParams` 查流水线解析参数,需改为读表。
|
||||
6. 数据库迁移:`cd_cert_info` 新增 `acme_account_access_id` 列。
|
||||
|
||||
## 四、改动清单
|
||||
|
||||
### 4.1 数据层:cd_cert_info 新增 ACME 账号列
|
||||
|
||||
- **迁移 SQL**:`packages/ui/certd-server/db/migration/v10055__cert_info_acme_account.sql`
|
||||
|
||||
```sql
|
||||
-- 证书仓库记录增加ACME账号授权id:吊销旧证书时直接使用记录上的账号,无需再解析流水线配置
|
||||
ALTER TABLE cd_cert_info ADD COLUMN acme_account_access_id bigint NULL;
|
||||
```
|
||||
|
||||
- **Entity**:`packages/ui/certd-server/src/modules/monitor/entity/cert-info.ts`
|
||||
- 新增字段 `acmeAccountAccessId`(映射 `acme_account_access_id`,nullable)。
|
||||
|
||||
### 4.2 ACME账号授权:支持自定义CA(`access/acme-account-access.ts`)
|
||||
|
||||
1. `caType` 下拉 options 增加 `{ value: "custom", label: "自定义ACME" }`(放首位或末位均可,建议末位并注明"需自备 ACME 服务")。
|
||||
2. `directoryUrl`:
|
||||
- `mergeScript` 改为 `show: ctx.compute(({ form }) => form.access?.caType === "custom")`;
|
||||
- 动态 `required`(custom 时必填);
|
||||
- helper 说明:填写 `https://` 开头的 Directory URL,如内网 CA 端点。
|
||||
3. EAB 字段(`eabKid` / `eabHmacKey`):
|
||||
- `show` 条件增加 `custom`;
|
||||
- custom 下**选填**(mergeScript 动态 `required: false`),内置 CA 保持必填;
|
||||
- `onGenerateAccount()` 中 `needEab` 列表**不加** custom(已满足选填语义)。
|
||||
4. `getDirectoryUrl()` 已有 custom 分支,确认校验信息友好即可。
|
||||
|
||||
### 4.3 AcmeService 支持自定义 Directory URL(`plugin/cert-plugin/acme.ts`)
|
||||
|
||||
1. `AcmeServiceOptions` 增加 `directoryUrl?: string`。
|
||||
2. `getAcmeClient(email)`:
|
||||
- `const directoryUrl = this.options.directoryUrl || acme.getDirectoryUrl({ sslProvider: this.sslProvider, pkType: this.options.privateKeyType })`;
|
||||
- custom 时若未传 `directoryUrl` 给出明确报错("自定义ACME需要填写Directory URL")。
|
||||
3. `revokeCert` 方式二(证书私钥方式)同样优先用 `this.options.directoryUrl`。
|
||||
4. `buildUrlMapping`:自定义域名不在内置映射表,天然走直连/用户反代,无需改动。
|
||||
|
||||
### 4.4 证书申请任务支持自定义CA(`plugin/cert-plugin/apply.ts`)
|
||||
|
||||
1. `sslProvider` 下拉 options 增加 `{ value: "custom", label: "自定义ACME", icon: "..." }`。
|
||||
2. `onInit()` 构造 `AcmeService` 时:
|
||||
- 若 `sslProvider === "custom"`,读取 `this.acmeAccountAccessId` 对应 access 的 `account.directoryUrl`,传入 `AcmeServiceOptions.directoryUrl`;
|
||||
- custom 且未选 ACME 账号时直接报错("自定义ACME必须选择对应的ACME账号")。
|
||||
3. 校验:
|
||||
- `doCertApply()` 中 custom 时强制 `acmeAccount`(version 1 也强制,version 2 已有强制逻辑);
|
||||
- `sslProvider === "custom"` 且 `challengeType === "dns-persist"` 时提示不支持(dns-persist 是 Let's Encrypt 特有机制)。
|
||||
4. 表单显隐(现有 mergeScript 天然兼容,需回归确认):
|
||||
- `preferredChain`:custom 不在 `preferredChainSupportedProviders`,`show: false` ✓;
|
||||
- `certProfile`:仅 letsencrypt 显示 ✓;
|
||||
- `getCommonAcmeAccount()`:custom 时 `${sslProvider}CommonAcmeAccountAccessId` 不存在,返回 null ✓。
|
||||
5. `getCheckChangeInputKeys()` 已含 `sslProvider`,切换 CA 会触发重新申请 ✓。
|
||||
|
||||
### 4.5 吊销链路改造(核心,用户指定方案)
|
||||
|
||||
**写入侧**:`packages/ui/certd-server/src/modules/monitor/service/cert-info-service.ts`
|
||||
|
||||
1. `updateCertByPipelineId(pipelineId, cert, fromType, taskId)`:
|
||||
- 已查询 `pipeline` 实体,从 `pipeline.content` 解析证书申请任务输入(复用/提取 `parseCertApplyInput` 为模块内方法),取出 `acmeAccountAccessId`;
|
||||
- 传入 `updateCert()`,写入记录(含占位记录复用更新场景)。
|
||||
2. `UploadCertReq` 增加 `acmeAccountAccessId?: number`;`updateCert()` 落库该字段。
|
||||
|
||||
**吊销侧**:`CertInfoService.revoke(id, userId, projectId)`
|
||||
|
||||
1. 读 `entity.acmeAccountAccessId`:
|
||||
- **有值(新数据)**:`accessService.getAccessById(acmeAccountAccessId, true, userId, projectId)` → `access.getAccount()` 得到 `acmeAccount`,`sslProvider = acmeAccount.caType`,`useProxy/reverseProxy` 不传(`resolveUrlMapping` 有"直连失败自动启用代理"兜底)→ `acmeService.revokeCert({ cert, acmeAccount })`,**不再查流水线**;
|
||||
- **为空(旧数据 / upload 来源)**:回退现有 `resolveRevokeParams` 查流水线逻辑,保证旧版数据可吊销。
|
||||
2. `createAcmeService()` 不再需要从流水线取 `useProxy/reverseProxy`(保留参数兼容即可)。
|
||||
|
||||
**事件链路**:`modules/auto/auto-pipeline-emitter-register.ts` 无需改动
|
||||
(`updateCertByPipelineId` 内部自行解析流水线配置落库)。
|
||||
|
||||
### 4.6 前端
|
||||
|
||||
- `Dicts.sslProviderDict` 已有 `custom`,无需改;
|
||||
- ACME账号授权、证书申请任务的表单 schema 均来自后端插件定义(`@AccessInput` / `@TaskInput`),前端组件零改动;
|
||||
- 回归确认 `icon-select`(sslProvider)与 `a-select`(caType)能正常渲染新增选项。
|
||||
|
||||
## 五、实施顺序(TDD)
|
||||
|
||||
1. **写测试(RED)**:
|
||||
- `acme-account-access.test.ts`:custom + directoryUrl 生成账号(含 EAB 选填)、缺 directoryUrl 报错;
|
||||
- `acme.test.ts`:`AcmeService` 传/不传 `directoryUrl` 时 `getAcmeClient` 使用正确端点;
|
||||
- `apply.test.ts`:custom + ACME账号 申请链路(mock acme client)、custom 未选账号报错;
|
||||
- `cert-info-service.test.ts`:写入时 `acmeAccountAccessId` 落库;吊销读表(mock accessService)不再解析流水线;旧数据(列为空)回退旧逻辑。
|
||||
2. **4.1 数据层**(迁移 SQL + entity)。
|
||||
3. **4.3 AcmeService directoryUrl 支持**。
|
||||
4. **4.2 ACME账号授权 custom 支持**。
|
||||
5. **4.4 证书申请任务 custom 支持**。
|
||||
6. **4.5 吊销链路改造**。
|
||||
7. **4.6 前端回归验证**。
|
||||
8. 全量单测 + lint。
|
||||
|
||||
## 六、测试与验证
|
||||
|
||||
- 后端单测:`cd packages\ui\certd-server && npm run test:unit`(聚焦 `cert-info-service`、`acme-account-access`、`acme`、`apply` 相关测试);
|
||||
- 改动文件 lint:`cd packages\ui\certd-server && npm run lint`;
|
||||
- 手动验证:新建 caType=custom 的 ACME 账号(填 Directory URL,可选 EAB)→ 生成账号 → 证书申请任务选「自定义ACME」+ 该账号 → 申请成功 → 吊销旧证书(观察不再解析流水线)。
|
||||
|
||||
## 七、风险与兼容性
|
||||
|
||||
1. **旧版数据兼容**:`acme_account_access_id` 列可空,旧记录吊销回退查流水线逻辑,行为不变。
|
||||
2. **dns-persist 限制**:自定义 CA 不支持 DNS 持久验证(LE 特有 `_validation-persist` 机制),申请任务做显式校验提示。
|
||||
3. **代理/反代**:吊销时不再携带任务级 `useProxy/reverseProxy`,依赖 `resolveUrlMapping` 直连失败自动启用代理的兜底;自定义 CA 通常内网/直连可达,影响可接受。若后续需要可在表中再增列。
|
||||
4. **无数据库以外的结构变更**;`updateDomains` 占位记录不强制写账号列(申请成功更新时补齐)。
|
||||
5. 内置 CA 行为完全不变(`directoryUrl` 为空时走原逻辑)。
|
||||
@@ -1,56 +1,54 @@
|
||||
# Certd
|
||||
# Certd
|
||||
|
||||
中文 | [English](./README_en.md)
|
||||
|
||||
Certd® 是一个免费的全自动证书管理系统,让你的网站证书永不过期。
|
||||
Certd® 是一个免费的全自动证书管理系统,让你的网站证书永不过期。
|
||||
后缀d取自linux守护进程的命名风格,意为证书守护进程
|
||||
|
||||
|
||||
>首创流水线申请部署证书模式,已被多个项目“借鉴”,被抄也是一种成功。
|
||||
> 首创流水线申请部署证书模式,已被多个项目“借鉴”,被抄也是一种成功。
|
||||
|
||||
> 关于证书续期:
|
||||
>* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
>* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
>* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
|
||||
>
|
||||
> - 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
> - 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
> - 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
|
||||
> 流水线数量现已调整为无限制,欢迎大家使用
|
||||
|
||||
|
||||
|官方开源地址: | |
|
||||
| ---- | ---- |
|
||||
| [Github](https://github.com/certd/certd)|  |
|
||||
| [Gitee](https://gitee.com/certd/certd) |  |
|
||||
| [AtomGit](https://atomgit.com/certd/certd) | |
|
||||
|
||||
| 官方开源地址: | |
|
||||
| ------------------------------------------ | ---------------------------------------------------------------- |
|
||||
| [Github](https://github.com/certd/certd) |  |
|
||||
| [Gitee](https://gitee.com/certd/certd) |  |
|
||||
| [AtomGit](https://atomgit.com/certd/certd) |  |
|
||||
|
||||
## 一、特性
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
* **全自动申请证书**: 支持所有注册商注册的域名,支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式
|
||||
* **全自动部署更新证书**: 目前支持部署到主机、阿里云、腾讯云等110+部署插件
|
||||
* **多种证书格式**: 支持pem、pfx、der、jks、p7b
|
||||
* **免费通配符域名/泛域名证书**: 支持多个域名打到一个证书上
|
||||
* **多种通知方式**: 邮件通知、webhook通知、企微、钉钉、飞书、anpush等多种通知方式
|
||||
* **私有化部署**: 数据保存本地,安装简单快捷,镜像由Github Actions构建,过程公开透明
|
||||
* **多重安全保障**: 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障
|
||||
* **多数据库支持**:支持SQLite、PostgreSQL、MySQL、MariaDB
|
||||
* **开放接口支持**: 提供RESTful API接口,方便集成到其他系统
|
||||
* **站点证书监控**: 定时监控网站证书的过期时间
|
||||
* **多用户管理**: 用户可以管理自己的证书流水线
|
||||
* **项目管理**: 企业级项目管理模式
|
||||
* **多语言支持**: 中英双语切换
|
||||
* **无忧升级**: 版本向下兼容
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
- **全自动申请证书**: 支持所有注册商注册的域名,支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式
|
||||
- **全自动部署更新证书**: 目前支持部署到主机、阿里云、腾讯云等110+部署插件
|
||||
- **多种证书格式**: 支持pem、pfx、der、jks、p7b
|
||||
- **免费通配符域名/泛域名证书**: 支持多个域名打到一个证书上
|
||||
- **多种通知方式**: 邮件通知、webhook通知、企微、钉钉、飞书、anpush等多种通知方式
|
||||
- **私有化部署**: 数据保存本地,安装简单快捷,镜像由Github Actions构建,过程公开透明
|
||||
- **多重安全保障**: 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障
|
||||
- **多数据库支持**:支持SQLite、PostgreSQL、MySQL、MariaDB
|
||||
- **开放接口支持**: 提供RESTful API接口,方便集成到其他系统
|
||||
- **站点证书监控**: 定时监控网站证书的过期时间
|
||||
- **多用户管理**: 用户可以管理自己的证书流水线
|
||||
- **项目管理**: 企业级项目管理模式
|
||||
- **多语言支持**: 中英双语切换
|
||||
- **无忧升级**: 版本向下兼容
|
||||
|
||||

|
||||
|
||||
## 二、在线体验
|
||||
|
||||
官方Demo地址,自助注册后体验
|
||||
官方Demo地址,自助注册后体验
|
||||
|
||||
https://certd.handfree.work/
|
||||
|
||||
> 注意数据将不定期清理,不定期停止定时任务,生产使用请自行部署
|
||||
> 注意数据将不定期清理,不定期停止定时任务,生产使用请自行部署
|
||||
> 包含敏感信息,务必自己本地部署进行生产使用
|
||||
|
||||

|
||||
@@ -60,143 +58,184 @@ https://certd.handfree.work/
|
||||
仅需3步,让你的证书永不过期
|
||||
|
||||
### 1. 创建证书流水线
|
||||
|
||||

|
||||
|
||||
> 添加成功后,就可以直接运行流水线申请证书了
|
||||
|
||||
### 2. 添加部署任务
|
||||
|
||||
当然我们一般需要把证书部署到应用上,certd支持海量的部署插件,您可以根据自身实际情况进行选择,比如部署到Nginx、阿里云、腾讯云、K8S、CDN、宝塔、1Panel等等
|
||||
|
||||
此处演示部署证书到主机的nginx上
|
||||
此处演示部署证书到主机的nginx上
|
||||

|
||||
|
||||
如果目前的部署插件都无法满足,您也可以手动下载,然后自行部署
|
||||
如果目前的部署插件都无法满足,您也可以手动下载,然后自行部署
|
||||

|
||||
|
||||
### 3. 定时运行
|
||||
|
||||

|
||||
|
||||
|
||||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
||||
-------> [点我查看详细使用步骤演示](./step.md) <--------
|
||||
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
|
||||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
||||
-------> [点我查看详细使用步骤演示](./step.md) <--------
|
||||
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
|
||||
|
||||
更多教程请访问官方文档 [certd.docmirror.cn](https://certd.docmirror.cn/guide/)
|
||||
|
||||
|
||||
|
||||
## 四、私有化部署
|
||||
|
||||
由于证书、授权信息等属于高度敏感数据,请务必私有化部署,保障数据安全
|
||||
由于证书、授权信息等属于高度敏感数据,请务必私有化部署,保障数据安全
|
||||
|
||||
您可以根据实际情况从如下方式中选择一种方式进行私有化部署:
|
||||
|
||||
1. 【推荐】[Docker方式部署 ](https://certd.docmirror.cn/guide/install/docker/)
|
||||
2. 【推荐】[宝塔面板方式部署 ](https://certd.docmirror.cn/guide/install/docker/)
|
||||
3. 【推荐】[1Panel面板方式部署](https://certd.docmirror.cn/guide/install/1panel/)
|
||||
4. 【推荐】[雨云一键部署](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2) : 首充翻倍,每月仅需2.2元
|
||||
[<img src="https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-cn.svg">](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2)
|
||||
4. 【推荐】[雨云一键部署](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2) : 首充翻倍,每月仅需2.2元
|
||||
[<img src="https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-cn.svg">](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2)
|
||||
|
||||
5. 【推荐】[一键安装脚本](https://certd.docmirror.cn/guide/install/docker/)(自动安装 Docker,Certd):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://gitee.com/certd/certd/raw/v2/docker/run/install.sh | bash
|
||||
```
|
||||
|
||||
6. 【不推荐】[源码方式部署 ](https://certd.docmirror.cn/guide/install/source/)
|
||||
|
||||
|
||||
|
||||
#### Docker镜像说明:
|
||||
* 国内镜像地址:
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest`
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:armv7`、`[version]-armv7`
|
||||
* DockerHub地址:
|
||||
* `https://hub.docker.com/r/greper/certd`
|
||||
* `greper/certd:latest`
|
||||
* `greper/certd:armv7`、`greper/certd:[version]-armv7`
|
||||
* GitHub Packages地址:
|
||||
* `ghcr.io/certd/certd:latest`
|
||||
* `ghcr.io/certd/certd:armv7`、`ghcr.io/certd/certd:[version]-armv7`
|
||||
|
||||
* 镜像构建通过`Actions`自动执行,过程公开透明,请放心使用
|
||||
* [点我查看镜像构建日志](https://github.com/certd/certd/actions/workflows/build-image.yml)
|
||||
##### 1. 镜像地址:
|
||||
|
||||
| 镜像仓库 | 最新预览版 | 稳定版 | slim版 | armv7版 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 阿里云【默认】 | `registry.cn-shenzhen.aliyuncs.com/certd/certd:latest` | `certd:stable` | `certd:slim` | `certd:armv7` |
|
||||
| Docker Hub | `certd/certd:latest` | `certd:stable` | `certd:slim` | `certd:armv7` |
|
||||
| GitHub Packages | `ghcr.io/certd/certd:latest` | `certd:stable` | `certd:slim` | `certd:armv7` |
|
||||
|
||||
> 后面的各个版本省略了镜像地址,使用时需要将镜像地址拼接完整。
|
||||
|
||||
##### 2. 版本标签说明:
|
||||
|
||||
**最新版本标签:**
|
||||
|
||||
| 版本 | 标签 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 最新预览版【默认】 | `certd:latest` | 指向最新开发版本,包含最新功能,但稳定性不如稳定版 |
|
||||
| 最新稳定版 | `certd:stable` | 指向经过充分测试的生产就绪版本,推荐生产环境使用 |
|
||||
|
||||
**系统分支版本:**
|
||||
|
||||
> 根据基础镜像不同,分为如下三个分支版本,没有特殊需求选择默认的即可(他们功能是一样的)
|
||||
|
||||
| 系统版本 | 版本标签 | 基础系统 | 说明 | 稳定版标签 | 指定版本 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| alpine【默认】 | `certd:latest` | Alpine Linux | 默认版本,镜像体积小 | `certd:stable` | `certd:1.43.0` |
|
||||
| slim | `certd:slim` | Debian slim | 基于glibc,dns解析兼容性好 | `certd:slim-stable` | `certd:1.43.0-slim` |
|
||||
| armv7 | `certd:armv7` | Alpine Linux | ARMv7 架构专用版本 | `certd:armv7-stable` | `certd:1.43.0-armv7` |
|
||||
|
||||
|
||||
> 如果您不确定使用哪个版本,请使用默认的 `certd:latest` 版本。
|
||||
|
||||
最新版本号:
|
||||

|
||||
|
||||
|
||||
##### 3. 镜像构建说明:
|
||||
|
||||
- 镜像构建通过`Actions`自动执行,过程公开透明,请放心使用
|
||||
- [点我查看预览版构建日志](https://github.com/certd/certd/actions/workflows/release-image.yml)
|
||||
- [点我查看稳定版发布日志](https://github.com/certd/certd/actions/workflows/stable-release.yml)
|
||||
|
||||

|
||||
|
||||
> 注意:
|
||||
> * 本应用存储的证书、授权信息等属于高度敏感数据,请做好安全防护
|
||||
> * 请务必使用HTTPS协议访问本应用,避免被中间人攻击
|
||||
> * 请务必使用web应用防火墙防护本应用,防止XSS、SQL注入等攻击
|
||||
> * 请务必做好服务器本身的安全防护,防止数据库泄露
|
||||
> * 请务必做好数据备份,避免数据丢失
|
||||
> * [更多安全生产建议点我](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
##### 4. 安全注意事项:
|
||||
|
||||
> - 本应用存储的证书、授权信息等属于高度敏感数据,请做好安全防护
|
||||
> - 请务必使用HTTPS协议访问本应用,避免被中间人攻击
|
||||
> - 请务必使用web应用防火墙防护本应用,防止XSS、SQL注入等攻击
|
||||
> - 请务必做好服务器本身的安全防护,防止数据库泄露
|
||||
> - 请务必做好数据备份,避免数据丢失
|
||||
> - [更多安全生产建议点我](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
|
||||
## 五、生态
|
||||
|
||||
### 1. 客户端工具 SSL-Assistant
|
||||
`SSL Assistant` 是一个运行于主机上的证书部署管理助手客户端。
|
||||
支持自动扫描主机`Nginx`配置,然后从`Certd`拉取证书并部署。
|
||||
|
||||
### 1. 官方客户端 Certd Client
|
||||
|
||||
`Certd Client` 是 Certd 官方证书部署客户端,运行于应用服务器上。自动发现本机 Nginx、Apache 和 IIS 站点,从 Certd 获取新证书并部署到本机。适用于不希望服务器开放 SSH、无法由 Certd 直接访问目标服务器的场景。
|
||||
|
||||
项目主页:[AtomGit](https://atomgit.com/certd/certd-client/) | [GitHub](https://github.com/certd/certd-client/)
|
||||
下载地址:[AtomGit Releases](https://atomgit.com/certd/certd-client/releases) | [GitHub Releases](https://github.com/certd/certd-client/releases)
|
||||
|
||||
### 2. 第三方客户端 SSL-Assistant
|
||||
|
||||
`SSL Assistant` 是一个运行于主机上的证书部署管理助手客户端。
|
||||
支持自动扫描主机`Nginx`配置,然后从`Certd`拉取证书并部署。
|
||||
在不想暴露ssh主机密码情况下,该工具非常好用。
|
||||
|
||||
开源地址: https://github.com/Youngxj/SSL-Assistant
|
||||
|
||||
|
||||
## 六、更多帮助
|
||||
|
||||
请访问官方文档:[https://certd.docmirror.cn/](https://certd.docmirror.cn/guide/)
|
||||
|
||||
* 升级方法:[升级方法](https://certd.docmirror.cn/guide/install/upgrade/)
|
||||
* 常见问题:[忘记密码](https://certd.docmirror.cn/guide/use/forgotpasswd/)
|
||||
* 多数据库:[多数据库配置](https://certd.docmirror.cn/guide/install/database/)
|
||||
* 站点安全:[站点安全特性](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
* 更新日志:[CHANGELOG](./CHANGELOG.md)
|
||||
|
||||
- 升级方法:[升级方法](https://certd.docmirror.cn/guide/install/upgrade/)
|
||||
- 常见问题:[忘记密码](https://certd.docmirror.cn/guide/use/forgotpasswd/)
|
||||
- 多数据库:[多数据库配置](https://certd.docmirror.cn/guide/install/database/)
|
||||
- 站点安全:[站点安全特性](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
- 更新日志:[CHANGELOG](./CHANGELOG.md)
|
||||
|
||||
## 七、联系作者
|
||||
|
||||
如有疑问,欢迎加入群聊(请备注certd)
|
||||
|
||||
| 加群 | 微信群 | QQ群 |
|
||||
|---------|-------|-------|
|
||||
| 加群 | 微信群 | QQ群 |
|
||||
| ------ | ----------------------------------------------------------- | ----------------------------------------------------------- |
|
||||
| 二维码 | <img height="230" src="./docs/guide/contact/images/wx.png"> | <img height="230" src="./docs/guide/contact/images/qq.png"> |
|
||||
|
||||
也可以加作者好友
|
||||
|
||||
| 加作者好友 | 微信 QQ |
|
||||
|---------|-------------------------------------------------------------|
|
||||
| 二维码 | <img height="230" src="./docs/guide/contact/images/me.png"> |
|
||||
|
||||
| 加作者好友 | 微信 QQ |
|
||||
| ---------- | ----------------------------------------------------------- |
|
||||
| 二维码 | <img height="230" src="./docs/guide/contact/images/me.png"> |
|
||||
|
||||
## 八、赞助捐赠
|
||||
|
||||
开源为什么要做专业版收费?
|
||||
1. 纯靠为爱发电不可持续(比如:我的[dev-sidecar项目](https://github.com/docmirror/dev-sidecar)即便是拥有20K+star,也差点凉凉,幸亏有另外大佬接手用爱发电)
|
||||
2. 没有赞助的项目,作者会比较任性,不会用心倾听用户的心声,不顾用户体验(比如:下意识拒绝需求、频繁破坏性变更升级、全盘推倒重来之类的)
|
||||
3. 没有赞助的项目,交流群的戾气有时候比较重,容易起冲突
|
||||
|
||||
1. 纯靠为爱发电不可持续(比如:我的[dev-sidecar项目](https://github.com/docmirror/dev-sidecar)即便是拥有20K+star,也差点凉凉,幸亏有另外大佬接手用爱发电)
|
||||
2. 没有赞助的项目,作者会比较任性,不会用心倾听用户的心声,不顾用户体验(比如:下意识拒绝需求、频繁破坏性变更升级、全盘推倒重来之类的)
|
||||
3. 没有赞助的项目,交流群的戾气有时候比较重,容易起冲突
|
||||
|
||||
赞助权益:
|
||||
|
||||
1. 可加入专属VIP群,可以获得作者一对一技术支持,必要时可以远程协助
|
||||
2. 您的需求我们将优先实现,并且可能将作为专业版功能提供
|
||||
3. 获得专业版功能
|
||||
|
||||
[50元专业版优惠券限时领取](https://app.handfree.work/subject/#/app/certd/product)
|
||||
|
||||
> [50元专业版优惠券限时领取](https://app.handfree.work/subject/#/app/certd/product)
|
||||
> https://app.handfree.work/subject/#/app/certd/product
|
||||
> app.handfree.work是Certd官方激活码购买平台
|
||||
|
||||
|
||||
专业版、商业版特权对比
|
||||
|
||||
| 功能 | 免费版 | 专业版 | 商业版 |
|
||||
|---------|---------------------------------------|--------------------------------|---------------------------------|
|
||||
| 证书申请 | 无限制 | 无限制 | 无限制 |
|
||||
| 证书域名数量 | 无限制 | 无限制 | 无限制 |
|
||||
| 证书流水线条数 | 无限制 | 无限制 | 无限制 |
|
||||
| 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署、宝塔、1Panel等大部分插件 | 群晖、威联通、proxmox等 | 同专业版 |
|
||||
| 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、钉钉、飞书、anpush、server酱等 | 同专业版 |
|
||||
| 站点监控 | 限制1条 | 无限制 | 无限制 |
|
||||
| 批量操作 | 无 | 流水线模版,流水线复制,批量运行,批量设置通知、定时等 | 同专业版 |
|
||||
| VIP群 | 无 | 可加,一对一技术支持,必要时可申请远程协助 | 商业版技术支持 |
|
||||
| 站点个性化 | 无 | 无 | 可自定义站点名称、Logo等,移除Certd元素,首页警告等 |
|
||||
| 套餐功能 | 无 | 无 | 支持配置套餐供用户购买 |
|
||||
| 数据统计 | 无 | 无 | 支持站点各类统计数据 |
|
||||
| 插件管理 | 无 | 无 | 支持公共EAB设置,插件选项配置 |
|
||||
| 是否可商用 | 不允许 | 不允许 | 可对外运营 |
|
||||
| 功能 | 免费版 | 专业版 | 商业版 |
|
||||
| ---------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------- |
|
||||
| 证书申请 | 无限制 | 无限制 | 无限制 |
|
||||
| 证书域名数量 | 无限制 | 无限制 | 无限制 |
|
||||
| 证书流水线条数 | 无限制 | 无限制 | 无限制 |
|
||||
| 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署、宝塔、1Panel等大部分插件 | 群晖、威联通、proxmox等 | 同专业版 |
|
||||
| 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、钉钉、飞书、anpush、server酱等 | 同专业版 |
|
||||
| 站点监控 | 限制1条 | 无限制 | 无限制 |
|
||||
| 批量操作 | 无 | 流水线模版,流水线复制,批量运行,批量设置通知、定时等 | 同专业版 |
|
||||
| VIP群 | 无 | 可加,一对一技术支持,必要时可申请远程协助 | 商业版技术支持 |
|
||||
| 站点个性化 | 无 | 无 | 可自定义站点名称、Logo等,移除Certd元素,首页警告等 |
|
||||
| 套餐功能 | 无 | 无 | 支持配置套餐供用户购买 |
|
||||
| 数据统计 | 无 | 无 | 支持站点各类统计数据 |
|
||||
| 插件管理 | 无 | 无 | 支持公共EAB设置,插件选项配置 |
|
||||
| 是否可商用 | 不允许 | 不允许 | 可对外运营 |
|
||||
|
||||
## 九、贡献代码
|
||||
|
||||
@@ -212,16 +251,16 @@ https://certd.handfree.work/
|
||||
</a>
|
||||
|
||||
## 十、 开源许可
|
||||
* 本项目遵循 GNU Affero General Public License(AGPL)开源协议。
|
||||
* 允许个人和公司内部自由使用、复制、修改和分发本项目,未获得商业授权情况下禁止任何形式的商业用途
|
||||
* 未获得商业授权情况下,禁止任何对logo、版权信息及授权许可相关代码的修改。
|
||||
* 如需商业授权,请联系作者。
|
||||
|
||||
- 本项目遵循 GNU Affero General Public License(AGPL)开源协议。
|
||||
- 允许个人和公司内部自由使用、复制、修改和分发本项目,未获得商业授权情况下禁止任何形式的商业用途
|
||||
- 未获得商业授权情况下,禁止任何对logo、版权信息及授权许可相关代码的修改。
|
||||
- 如需商业授权,请联系作者。
|
||||
|
||||
## 十一、我的其他项目(求Star)
|
||||
|
||||
| 项目名称 | stars | 项目描述 |
|
||||
| --------- |--------- |----------- |
|
||||
| [fast-crud](https://gitee.com/fast-crud/fast-crud/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/fast-crud/fast-crud?logo=github"/> | 基于vue3的crud快速开发框架 |
|
||||
| [dev-sidecar](https://github.com/docmirror/dev-sidecar/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"/> | 直连访问github工具,无需FQ,解决github无法访问的问题 |
|
||||
| [winsvc-manager](https://github.com/greper/winsvc-manager/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/greper/winsvc-manager?logo=github"/> | 可视化包装应用成为一个Windows服务,使其后台运行 |
|
||||
| 项目名称 | stars | 项目描述 |
|
||||
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
|
||||
| [fast-crud](https://gitee.com/fast-crud/fast-crud/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/fast-crud/fast-crud?logo=github"/> | 基于vue3的crud快速开发框架 |
|
||||
| [dev-sidecar](https://github.com/docmirror/dev-sidecar/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"/> | 直连访问github工具,无需FQ,解决github无法访问的问题 |
|
||||
| [winsvc-manager](https://github.com/greper/winsvc-manager/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/greper/winsvc-manager?logo=github"/> | 可视化包装应用成为一个Windows服务,使其后台运行 |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Certd
|
||||
# Certd
|
||||
|
||||
[中文](./README.md) | English
|
||||
|
||||
@@ -7,40 +7,40 @@ Certd® is a free, fully automated certificate management system that ensures yo
|
||||
> We pioneered the pipeline-based certificate application and deployment model, which has been "referenced" by multiple projects. Being copied is also a form of success.
|
||||
|
||||
> Regarding certificate renewal:
|
||||
>* In fact, it's impossible to renew or reissue a certificate without modifying the certificate file itself.
|
||||
>* What we refer to as renewal is essentially applying for a new certificate following the full process and redeploying it.
|
||||
>* Free certificates expire in 90 days, which may be shortened in the future. Therefore, automated deployment is essential.
|
||||
>
|
||||
> - In fact, it's impossible to renew or reissue a certificate without modifying the certificate file itself.
|
||||
> - What we refer to as renewal is essentially applying for a new certificate following the full process and redeploying it.
|
||||
> - Free certificates expire in 90 days, which may be shortened in the future. Therefore, automated deployment is essential.
|
||||
|
||||
> The number of pipelines is now unlimited. Welcome to use it.
|
||||
|
||||
Official Open Source Address:
|
||||
|
||||
Official Open Source Address:
|
||||
|
||||
[Github](https://github.com/certd/certd) 
|
||||
[Gitee](https://gitee.com/certd/certd) 
|
||||
[AtomGit](https://atomgit.com/certd/certd) 
|
||||
|
||||
|
||||
[Github](https://github.com/certd/certd) 
|
||||
[Gitee](https://gitee.com/certd/certd) 
|
||||
[AtomGit](https://atomgit.com/certd/certd) 
|
||||
|
||||
## 1. Features
|
||||
|
||||
This project not only supports automated certificate application but also automated certificate deployment and updates, ensuring your certificates never expire.
|
||||
|
||||
* Fully automated certificate application (supports domains registered with all registrars and multiple domain verification methods such as DNS-01, HTTP-01, and CNAME proxy).
|
||||
* Fully automated certificate deployment and updates (currently supports deployment to over 70 plugins, including hosts, Alibaba Cloud, Tencent Cloud, etc.).
|
||||
* Supports wildcard domains/pan-domains, allows multiple domains in a single certificate, and supports various certificate formats such as pem, pfx, der, and jks.
|
||||
* Multiple notification methods, including email, webhook, WeChat Work, DingTalk, Lark, and anpush.
|
||||
* On-premises deployment, local data storage, simple and quick installation. Images are built by Github Actions, with a transparent process.
|
||||
* Multiple security measures, including authorization encryption, site hiding, 2FA, and password brute-force protection.
|
||||
* Supports multiple databases such as SQLite, PostgreSQL, MySQL, and MariaDB.
|
||||
* Open API support.
|
||||
* Site certificate monitoring.
|
||||
* Multi-user management.
|
||||
* Multi-language support (Chinese and English switching).
|
||||
* Downward compatibility across all versions, with one-click worry-free upgrades.
|
||||
- Fully automated certificate application (supports domains registered with all registrars and multiple domain verification methods such as DNS-01, HTTP-01, and CNAME proxy).
|
||||
- Fully automated certificate deployment and updates (currently supports deployment to over 70 plugins, including hosts, Alibaba Cloud, Tencent Cloud, etc.).
|
||||
- Supports wildcard domains/pan-domains, allows multiple domains in a single certificate, and supports various certificate formats such as pem, pfx, der, and jks.
|
||||
- Multiple notification methods, including email, webhook, WeChat Work, DingTalk, Lark, and anpush.
|
||||
- On-premises deployment, local data storage, simple and quick installation. Images are built by Github Actions, with a transparent process.
|
||||
- Multiple security measures, including authorization encryption, site hiding, 2FA, and password brute-force protection.
|
||||
- Supports multiple databases such as SQLite, PostgreSQL, MySQL, and MariaDB.
|
||||
- Open API support.
|
||||
- Site certificate monitoring.
|
||||
- Multi-user management.
|
||||
- Multi-language support (Chinese and English switching).
|
||||
- Downward compatibility across all versions, with one-click worry-free upgrades.
|
||||
|
||||

|
||||
|
||||
## 2. Online Experience
|
||||
|
||||
Visit the official demo site and register to experience it.
|
||||
|
||||
https://certd.handfree.work/
|
||||
@@ -51,14 +51,17 @@ https://certd.handfree.work/
|
||||

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

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

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

|
||||
|
||||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
||||
@@ -77,6 +81,7 @@ If the current deployment plugins don't meet your needs, you can also download t
|
||||
For more tutorials, please visit the official documentation [certd.docmirror.cn](https://certd.docmirror.cn/guide/).
|
||||
|
||||
## 4. On-Premises Deployment
|
||||
|
||||
Since certificates, authorization information, and other data are highly sensitive, please make sure to deploy them on-premises to ensure data security.
|
||||
|
||||
You can choose one of the following deployment methods based on your needs:
|
||||
@@ -85,87 +90,128 @@ You can choose one of the following deployment methods based on your needs:
|
||||
2. 【Recommended】[BT Panel Deployment](https://certd.docmirror.cn/guide/install/docker/)
|
||||
3. 【Recommended】[1Panel Deployment](https://certd.docmirror.cn/guide/install/1panel/)
|
||||
4. 【Recommended】[Rainyun One-Click Deployment](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2_): Double your first recharge, only $2.2 per month.
|
||||
[<img src="https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-cn.svg">](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2_)
|
||||
[<img src="https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-cn.svg">](https://app.rainyun.com/apps/rca/store/6646/?ref=NzExMDQ2_)
|
||||
5. 【Not Recommended】[Source Code Deployment](https://certd.docmirror.cn/guide/install/source/)
|
||||
|
||||
#### Docker Image Information:
|
||||
* Domestic Image Addresses:
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest`
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:armv7`, `[version]-armv7`
|
||||
* DockerHub Addresses:
|
||||
* `https://hub.docker.com/r/greper/certd`
|
||||
* `greper/certd:latest`
|
||||
* `greper/certd:armv7`, `greper/certd:[version]-armv7`
|
||||
* GitHub Packages Addresses:
|
||||
* `ghcr.io/certd/certd:latest`
|
||||
* `ghcr.io/certd/certd:armv7`, `ghcr.io/certd/certd:[version]-armv7`
|
||||
|
||||
* Images are built automatically by `Actions`, with a transparent process. Please use them with confidence.
|
||||
* [Click here to view image build logs](https://github.com/certd/certd/actions/workflows/build-image.yml)
|
||||
**Release channels:**
|
||||
|
||||
| Channel | Description |
|
||||
| --- | --- |
|
||||
| `stable` / `slim-stable` | **Stable version**, production-ready and fully tested, recommended for production environments |
|
||||
| `latest` / `slim` / `armv7` | **Preview version**, latest development build with newest features but potentially less stable |
|
||||
|
||||
**Image tags:**
|
||||
|
||||
| Channel | Tag | Versioned Tag | Base System | Description |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **Stable** | `stable` | `[version]-stable` | Alpine Linux | Recommended for production |
|
||||
| | `slim-stable` | `[version]-slim-stable` | Debian slim | Better DNS resolution compatibility |
|
||||
| **Preview** | `latest` | `[version]` | Alpine Linux | Default, small image size |
|
||||
| | `slim` | `[version]-slim` | Debian slim | Better DNS resolution compatibility |
|
||||
| | `armv7` | `[version]-armv7` | Alpine Linux | ARMv7 architecture |
|
||||
|
||||
**Stable version image addresses:**
|
||||
|
||||
| Registry | `stable` | `slim-stable` |
|
||||
| --- | --- | --- |
|
||||
| Aliyun | `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:stable` | `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:slim-stable` |
|
||||
| Docker Hub | `greper/certd:stable` | `greper/certd:slim-stable` |
|
||||
| GitHub Packages | `ghcr.io/certd/certd:stable` | `ghcr.io/certd/certd:slim-stable` |
|
||||
|
||||
**Preview version image addresses:**
|
||||
|
||||
| Registry | `latest` | `slim` | `armv7` |
|
||||
| --- | --- | --- | --- |
|
||||
| Aliyun | `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest` | `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:slim` | `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:armv7` |
|
||||
| Docker Hub | `greper/certd:latest` | `greper/certd:slim` | `greper/certd:armv7` |
|
||||
| GitHub Packages | `ghcr.io/certd/certd:latest` | `ghcr.io/certd/certd:slim` | `ghcr.io/certd/certd:armv7` |
|
||||
|
||||
> For versioned tags, replace tag name with `[version]-tag`, e.g. replace `stable` with `[version]-stable`
|
||||
|
||||
- Images are built automatically by `Actions`, with a transparent process. Please use them with confidence.
|
||||
- [Click here to view preview version build logs](https://github.com/certd/certd/actions/workflows/release-image.yml)
|
||||
- [Click here to view stable version release logs](https://github.com/certd/certd/actions/workflows/stable-release.yml)
|
||||

|
||||
|
||||
> Note:
|
||||
> * The certificates, authorization information, and other data stored in this application are highly sensitive. Please take appropriate security measures.
|
||||
> * Make sure to use the HTTPS protocol to access this application to avoid man-in-the-middle attacks.
|
||||
> * Make sure to use a web application firewall to protect this application from attacks such as XSS and SQL injection.
|
||||
> * Make sure to secure the server itself to prevent database leakage.
|
||||
> * Make sure to back up your data to avoid data loss.
|
||||
> * [Click here for more production safety suggestions](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
>
|
||||
> - The certificates, authorization information, and other data stored in this application are highly sensitive. Please take appropriate security measures.
|
||||
> - Make sure to use the HTTPS protocol to access this application to avoid man-in-the-middle attacks.
|
||||
> - Make sure to use a web application firewall to protect this application from attacks such as XSS and SQL injection.
|
||||
> - Make sure to secure the server itself to prevent database leakage.
|
||||
> - Make sure to back up your data to avoid data loss.
|
||||
> - [Click here for more production safety suggestions](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
|
||||
## 5. Ecosystem
|
||||
|
||||
### 1. Client Tool: SSL-Assistant
|
||||
### 1. Official Client: Certd Client
|
||||
|
||||
`Certd Client` is the official Certd certificate deployment client that runs on application servers. It automatically discovers local Nginx, Apache, and IIS sites, retrieves new certificates from Certd, and deploys them locally. It is designed for servers that should not expose SSH or cannot be accessed directly by Certd.
|
||||
|
||||
Project Home: [AtomGit](https://atomgit.com/certd/certd-client/) | [GitHub](https://github.com/certd/certd-client/)
|
||||
Downloads: [AtomGit Releases](https://atomgit.com/certd/certd-client/releases) | [GitHub Releases](https://github.com/certd/certd-client/releases)
|
||||
|
||||
### 2. Third-Party Client: SSL-Assistant
|
||||
|
||||
`SSL Assistant` is a certificate deployment and management assistant client that runs on hosts. It supports automatic scanning of the host's `Nginx` configuration and pulling certificates from `Certd` for deployment. This tool is very useful when you don't want to expose your SSH host password.
|
||||
|
||||
Open-source Address: https://github.com/Youngxj/SSL-Assistant
|
||||
|
||||
## 6. More Help
|
||||
|
||||
Please visit the official documentation: [https://certd.docmirror.cn/](https://certd.docmirror.cn/guide/).
|
||||
|
||||
* Upgrade Method: [Upgrade Guide](https://certd.docmirror.cn/guide/install/upgrade/)
|
||||
* Common Issues: [Forgot Password](https://certd.docmirror.cn/guide/use/forgotpasswd/)
|
||||
* Multi-Database: [Multi-Database Configuration](https://certd.docmirror.cn/guide/install/database/)
|
||||
* Site Security: [Site Security Features](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
* Changelog: [CHANGELOG](./CHANGELOG.md)
|
||||
- Upgrade Method: [Upgrade Guide](https://certd.docmirror.cn/guide/install/upgrade/)
|
||||
- Common Issues: [Forgot Password](https://certd.docmirror.cn/guide/use/forgotpasswd/)
|
||||
- Multi-Database: [Multi-Database Configuration](https://certd.docmirror.cn/guide/install/database/)
|
||||
- Site Security: [Site Security Features](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
- Changelog: [CHANGELOG](./CHANGELOG.md)
|
||||
|
||||
## 7. Contact the Author
|
||||
|
||||
If you have any questions, feel free to join the group chat (please mention 'certd' in your message).
|
||||
|
||||
| Join Group | WeChat Group | QQ Group |
|
||||
|---------|-------|-------|
|
||||
| QR Code | <img height="230" src="./docs/guide/contact/images/wx.png"> | <img height="230" src="./docs/guide/contact/images/qq.png"> |
|
||||
| Join Group | WeChat Group | QQ Group |
|
||||
| ---------- | ----------------------------------------------------------- | ----------------------------------------------------------- |
|
||||
| QR Code | <img height="230" src="./docs/guide/contact/images/wx.png"> | <img height="230" src="./docs/guide/contact/images/qq.png"> |
|
||||
|
||||
You can also add the author as a friend.
|
||||
|
||||
| Add Author as Friend | WeChat QQ |
|
||||
|---------|-------|-------|
|
||||
| QR Code | <img height="230" src="./docs/guide/contact/images/me.png"> |
|
||||
| Add Author as Friend | WeChat QQ |
|
||||
| -------------------- | ----------------------------------------------------------- |
|
||||
| QR Code | <img height="230" src="./docs/guide/contact/images/me.png"> |
|
||||
|
||||
## 8. Donation
|
||||
************************
|
||||
[](https://github.com/sponsors/greper)
|
||||
************************
|
||||
|
||||
---
|
||||
|
||||
[](https://github.com/sponsors/greper)
|
||||
|
||||
---
|
||||
|
||||
Support open-source projects and contribute with love. I've joined Afdian.
|
||||
https://afdian.com/a/greper
|
||||
|
||||
Benefits of Contribution:
|
||||
|
||||
1. Join the exclusive contributor group and get one-on-one technical support from the author.
|
||||
2. Your requests will be prioritized and implemented as professional edition features.
|
||||
3. Receive a one-year professional edition activation code.
|
||||
|
||||
Comparison of Professional Edition Privileges:
|
||||
|
||||
| Feature | Free Edition | Professional Edition |
|
||||
|---------|---------------------------------------|--------------------------------|
|
||||
| Free Certificate Application | Unlimited for free | Unlimited for free |
|
||||
| Number of Domains | Unlimited | Unlimited |
|
||||
| Number of Certificate Pipelines | Unlimited | Unlimited |
|
||||
| Site Certificate Monitoring | Limited to 1 | Unlimited |
|
||||
| Automatic Deployment Plugins | Most plugins such as Alibaba Cloud CDN, Tencent Cloud, QiNiu CDN, Host Deployment, Baota, 1Panel | Synology |
|
||||
| Notifications | Email, Custom Webhook | Email without configuration, WeChat Work, DingTalk, Lark, anpush, ServerChan, etc. |
|
||||
| Feature | Free Edition | Professional Edition |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
|
||||
| Free Certificate Application | Unlimited for free | Unlimited for free |
|
||||
| Number of Domains | Unlimited | Unlimited |
|
||||
| Number of Certificate Pipelines | Unlimited | Unlimited |
|
||||
| Site Certificate Monitoring | Limited to 1 | Unlimited |
|
||||
| Automatic Deployment Plugins | Most plugins such as Alibaba Cloud CDN, Tencent Cloud, QiNiu CDN, Host Deployment, Baota, 1Panel | Synology |
|
||||
| Notifications | Email, Custom Webhook | Email without configuration, WeChat Work, DingTalk, Lark, anpush, ServerChan, etc. |
|
||||
|
||||
************************
|
||||
---
|
||||
|
||||
## 9. Contribute Code
|
||||
|
||||
@@ -181,14 +227,15 @@ Thank you to the following contributors.
|
||||
</a>
|
||||
|
||||
## 10. Open-Source License
|
||||
* This project follows the GNU Affero General Public License (AGPL).
|
||||
* Individuals and companies are allowed to use, copy, modify, and distribute this project freely for internal use. Any form of commercial use is prohibited without obtaining commercial authorization.
|
||||
* Without commercial authorization, any modification of the logo, copyright information, and license-related code is prohibited.
|
||||
* For commercial authorization, please contact the author.
|
||||
|
||||
- This project follows the GNU Affero General Public License (AGPL).
|
||||
- Individuals and companies are allowed to use, copy, modify, and distribute this project freely for internal use. Any form of commercial use is prohibited without obtaining commercial authorization.
|
||||
- Without commercial authorization, any modification of the logo, copyright information, and license-related code is prohibited.
|
||||
- For commercial authorization, please contact the author.
|
||||
|
||||
## 11. My Other Projects (Please Star)
|
||||
|
||||
| Project Name | Stars | Project Description |
|
||||
|----------------|---------------|--------------|
|
||||
| [fast-crud](https://gitee.com/fast-crud/fast-crud/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/fast-crud/fast-crud?logo=github"/> | A fast CRUD development framework based on Vue3. |
|
||||
| Project Name | Stars | Project Description |
|
||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| [fast-crud](https://gitee.com/fast-crud/fast-crud/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/fast-crud/fast-crud?logo=github"/> | A fast CRUD development framework based on Vue3. |
|
||||
| [dev-sidecar](https://github.com/docmirror/dev-sidecar/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"/> | A tool to access GitHub directly without a VPN, solving the problem of inaccessible GitHub. |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export default { setSuccess: "Settings saved", editTitle: "Edit Certificate Application Template", addTitle: "Add Certificate Application Template", name: "Template Name", default: "Default", setDefault: "Set as Default", disabled: "Disabled", createTime: "Created At", config: "Configuration" };
|
||||
@@ -2,9 +2,15 @@ version: '3.3' # 兼容旧版docker-compose
|
||||
services:
|
||||
certd:
|
||||
# 镜像 # ↓↓↓↓↓ ---- 镜像版本号,建议改成固定版本号,例如:certd:1.29.0
|
||||
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||
image: registry.cn-shenzhen.aliyuncs.com/certd/certd:latest # 稳定版为 certd/certd:stable
|
||||
# image: ghcr.io/certd/certd:latest # --------- 如果 报镜像not found,可以尝试其他镜像源
|
||||
# image: greper/certd:latest
|
||||
# image: certd/certd:latest
|
||||
# --------- 生产建议使用稳定版, latest改成stable即可
|
||||
# image: registry.cn-shenzhen.aliyuncs.com/certd/certd:stable
|
||||
|
||||
|
||||
# security_opt: # --------- 如果slim镜像下启动报错,尝试去掉这两行注释
|
||||
# - seccomp=unconfined # 解决slim镜像下WorkerThreadsTaskRunner::DelayedTaskScheduler::Start() 报错问题
|
||||
container_name: certd # 容器名
|
||||
restart: unless-stopped # 自动重启
|
||||
volumes:
|
||||
@@ -71,7 +77,13 @@ services:
|
||||
# - certd_typeorm_dataSource_default_password=yourpasswd # 密码
|
||||
# - certd_typeorm_dataSource_default_database=certd # 数据库名
|
||||
|
||||
# ↓↓↓↓ --------------------------------------------------------- 自动升级,上面certd的版本号要保持为latest
|
||||
# #↓↓↓↓ ---------------------------- 如果数据库服务端开启了加密传输 require_secure_transport-ON
|
||||
# - certd_typeorm_dataSource_default_ssl_rejectUnauthorized=false # 忽略证书校验,或者配置下面的三项路径
|
||||
# - certd_typeorm_dataSource_default_ssl_ca # 证书CA路径【如果上面false,无需配置】
|
||||
# - certd_typeorm_dataSource_default_ssl_key # 私钥路径【如果上面false,无需配置】
|
||||
# - certd_typeorm_dataSource_default_ssl_cert # 证书路径【如果上面false,无需配置】
|
||||
|
||||
# ↓↓↓↓ --------------------------------------------------------- 自动升级,上面certd的版本号要保持为latest / stable
|
||||
# certd-updater: # 添加 Watchtower 服务
|
||||
# image: containrrr/watchtower:latest
|
||||
# container_name: certd-updater
|
||||
|
||||
@@ -135,6 +135,7 @@ export default defineConfig({
|
||||
{text: "支付宝配置", link: "/guide/use/comm/payments/alipay.md"},
|
||||
{text: "微信支付配置", link: "/guide/use/comm/payments/wxpay.md"},
|
||||
{text: "彩虹易支付配置", link: "/guide/use/comm/payments/yizhifu.md"},
|
||||
{text: "插件选项映射", link: "/guide/use/comm/plugin/"},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -3,6 +3,332 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.45.0](https://github.com/certd/certd/compare/v1.44.4...v1.45.0) (2026-10-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* [BUG]使用天翼云CDN部署证书时无法匹配域名 ([bb1f232](https://github.com/certd/certd/commit/bb1f232f415c522851dede979f5d609dda844fd3))
|
||||
* 缺失运行时嵌套依赖时添加清除缓存提示 ([2d0b85b](https://github.com/certd/certd/commit/2d0b85b3054fc1aa82b3ab5db34a2a56308f71f2))
|
||||
* 支持google persist校验方式 ([97d2b50](https://github.com/certd/certd/commit/97d2b5007409ec79ea864d437c473a2f9b5dfae4))
|
||||
* **config:** 修复环境变量加载逻辑并更新配置文件 ([07f0d3b](https://github.com/certd/certd/commit/07f0d3b4d626628a0e3dfc7e5c52e8c4a98bad47))
|
||||
* **ctyun-cdn:** 修复天翼云CDN部署插件的域名选择问题 ([ea7d14c](https://github.com/certd/certd/commit/ea7d14c289b8720781bf101bfef59eac7bb03765))
|
||||
* **webhook:** 修复模版转义换行符,避免手动上传的证书报错 ([2735feb](https://github.com/certd/certd/commit/2735feb3302f8308708dafc8b295adcd4b91d7f0))
|
||||
|
||||
### Features
|
||||
|
||||
* **client:** 新增客户端管理功能 ([3dbbe72](https://github.com/certd/certd/commit/3dbbe72fc15c114ca6b5e8ff45cb21f258b80650))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 宝塔站点列表支持搜索和排序 ([4420472](https://github.com/certd/certd/commit/4420472f8fac272d30fb8ccb1cc2ee9763989001))
|
||||
* 网宿插件双鉴权支持 ([241b2e5](https://github.com/certd/certd/commit/241b2e55848471e61b5d2be0c87a7dc9a0d29557))
|
||||
* **monitor:** 站点证书监控支持手动选中触发检查 ([f60e63f](https://github.com/certd/certd/commit/f60e63fbaf00460d5050cd7705bd75d57dec202d))
|
||||
* **open-api:** openkey增加用途备注 ([bbeaf61](https://github.com/certd/certd/commit/bbeaf617d19750515f6eca51863e74e23bc1de50))
|
||||
* **tencent clb:** 修改所有CLB地域的endpoint为就近接入 ([c427735](https://github.com/certd/certd/commit/c4277350bcc8cf034cf4e76db2a6daa1842bc5d7))
|
||||
|
||||
## [1.44.4](https://github.com/certd/certd/compare/v1.44.3...v1.44.4) (2026-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复添加步骤会修改所有步骤标题的bug ([51e83e4](https://github.com/certd/certd/commit/51e83e4c38f7f319314fdc38ef33cf5720b2dde0))
|
||||
* 修复证书插件配置无法打开的bug ([5563abb](https://github.com/certd/certd/commit/5563abb13a62140f4dee668ab768cf4ff9371ddb))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 新增余额管理,管理员充值功能 ([bded368](https://github.com/certd/certd/commit/bded368cbb8974b6937ae260e448c25fae5c33ad))
|
||||
* **acme-account-access:** AcmeAccount授权允许修改eab,重新生成account ([6a649aa](https://github.com/certd/certd/commit/6a649aaca083ccd3b517f7d676a58220aa33b37d))
|
||||
* **ui:** 商业版套餐购买不要求设置支付方式 ([e971145](https://github.com/certd/certd/commit/e9711456860d7db40914a0c295534f7bca56f83c))
|
||||
|
||||
## [1.44.3](https://github.com/certd/certd/compare/v1.44.2...v1.44.3) (2026-09-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **plugin-service:** 修复同步自己开发的云端插件不显示已安装状态问题 ([dac94b6](https://github.com/certd/certd/commit/dac94b64f0ceb7176e2cf07ce220be0aa5ed98d2))
|
||||
* **plugin:** 修复插件配置保存与加载的相关问题 ([bd94334](https://github.com/certd/certd/commit/bd9433478a43d5d64ce6370386d0fe0aaff07d2e))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **plugin:** add Fastly custom TLS certificates integration ([#797](https://github.com/certd/certd/issues/797)) [@szhu25](https://github.com/szhu25) ([2a2e963](https://github.com/certd/certd/commit/2a2e963914c4dfc192cbe0a4bbb9c115e626da01))
|
||||
|
||||
## [1.44.2](https://github.com/certd/certd/compare/v1.44.1...v1.44.2) (2026-09-03)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复插件市场插件安装无效的bug ([15d2bd8](https://github.com/certd/certd/commit/15d2bd8484a9ddd142bf4ef03d839c74405f9e6d))
|
||||
* preserve Route53 TXT record values ([#791](https://github.com/certd/certd/issues/791)) ([f5430a8](https://github.com/certd/certd/commit/f5430a8925cf6cf4e16c75f2358fbd78437e6705))
|
||||
|
||||
## [1.44.1](https://github.com/certd/certd/compare/v1.44.0...v1.44.1) (2026-09-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复编辑证书申请任务导致清空ACME账号的bug ([d67379f](https://github.com/certd/certd/commit/d67379f29725bbd6dcdefe97d101023c7fd11f03))
|
||||
* 修复大量问题 ([f911e06](https://github.com/certd/certd/commit/f911e06a698d568ae228880ec89b7e25fdd1305b))
|
||||
* 修复旧流水线保存时清空证书仓库证书内容的bug ([f58f2f3](https://github.com/certd/certd/commit/f58f2f3cd603c37e55ac5868fdd2ca99aa937e44))
|
||||
* **pipeline-controller:** 处理非编辑场景下保留id的问题 ([6606f32](https://github.com/certd/certd/commit/6606f3267868e3aadaca0092ef4c83198312553c))
|
||||
* **pipeline:** 修正流水线保存时的ID判断逻辑并增加参数校验 ([6af12d4](https://github.com/certd/certd/commit/6af12d49fce1144943dc37ba574b3c9356998dcd))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **dashboard:** 新增仪表盘站点监控和域名管理的统计卡片 ([9842a24](https://github.com/certd/certd/commit/9842a24a50a841f710ee7c8050a38e3334c58394))
|
||||
|
||||
# [1.44.0](https://github.com/certd/certd/compare/v1.43.0...v1.44.0) (2026-08-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复证书申请时EAB判断逻辑,已选择Acme账号的情况下不需要EAB ([d87821e](https://github.com/certd/certd/commit/d87821ee02b17136fc925df4547223332bf22823))
|
||||
* **pipeline:** 校验定时触发器cron表达式,拦截2月31号等无效日期 ([#785](https://github.com/certd/certd/issues/785)) [@yukaidi1220](https://github.com/yukaidi1220) ([f8e492d](https://github.com/certd/certd/commit/f8e492d6cb49257e56bbd06b28fd6eb32c923c28))
|
||||
* **plugin-ai-dev:** 优化AI插件测试流程并修复日志获取问题 ([faf9828](https://github.com/certd/certd/commit/faf9828168f6ce82adc530a65eaf313d6c9904b5))
|
||||
* **plugin-item-card:** 移除分数格式化时去掉.0的逻辑 ([a91d7c0](https://github.com/certd/certd/commit/a91d7c000a2aa6456a249433ff90a47787ec90f0))
|
||||
* **ssh:** 修复 keyboard-interactive 认证可能抛类型错误的问题 ([5e867c8](https://github.com/certd/certd/commit/5e867c86c30eb43f1e5aeee8c22d47596e173a8c))
|
||||
* **start.sh:** 优化前端zip包下载校验逻辑 ([15ee6ea](https://github.com/certd/certd/commit/15ee6ead49db3620d2ade641aadbfcb13ac3e6dc))
|
||||
* **tencent access:** 修复腾讯云国际站接口endpoint拼接问题 ([f614872](https://github.com/certd/certd/commit/f61487284f79d3f5a72c9f7eee04999a93728326))
|
||||
|
||||
### Features
|
||||
|
||||
* 实现自定义ACME证书颁发机构支持 ([97c417b](https://github.com/certd/certd/commit/97c417b1ad64b9a14bee8bfe98a2e789b9278820))
|
||||
* 新增证书吊销后置任务与证书状态管理 ([1cc9641](https://github.com/certd/certd/commit/1cc9641f5669710d1e5809995ad395c843855a12))
|
||||
* 新增AI插件开发全流程能力 ([6f9dffe](https://github.com/certd/certd/commit/6f9dffe6e59cc125bd394d7db6086d66a9c71e49))
|
||||
* 支持审计日志,操作日志 ([f2855d6](https://github.com/certd/certd/commit/f2855d6dac74c9db71d92f99601e35c360b10666))
|
||||
* 支持在线插件下载安装审核等 ([255960d](https://github.com/certd/certd/commit/255960d434eebb3d567a08f737f1642ab417b5d0))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 统一镜像地址格式 certd/certd ([49007d3](https://github.com/certd/certd/commit/49007d391565099d94dec375eb88e946856506b0))
|
||||
* 新增AI插件开发受限令牌与隔离API ([3a9069f](https://github.com/certd/certd/commit/3a9069f6e6242940229fd63c686f7e445408dbbb))
|
||||
* 优化源码启动脚本,增加快速启动 ([0cfc3b7](https://github.com/certd/certd/commit/0cfc3b7ae90fa031d75f0b395556a04d4efee76c))
|
||||
* 统一将路由前缀从/certd改为/cert ([4db0f83](https://github.com/certd/certd/commit/4db0f83304dc6fd9199673c48b1805421f024601))
|
||||
* 新增官方客户端Certd Client的多语言配置与页面入口 ([fbfe125](https://github.com/certd/certd/commit/fbfe1256a5c8be6dfb2fbae7e6130eb5f6c6d946))
|
||||
* 新增证书吊销功能,添加证书状态字段 ([5074572](https://github.com/certd/certd/commit/5074572694383c8e1bf2880e26827987683dc62c))
|
||||
* 新增自定义ACME管理功能,完善证书颁发机构适配 ([2ab23f5](https://github.com/certd/certd/commit/2ab23f50b216e27495fc823d2269ca0ba6366d15))
|
||||
* 移除全局反向代理配置,迁移到自定义ACME配置 ([c57110e](https://github.com/certd/certd/commit/c57110e42aada31dd0028b56b5baec1b19722525))
|
||||
* 在线插件支持通知类型 ([c0f194f](https://github.com/certd/certd/commit/c0f194f4438bd7ca3f52f63ca088543abde7428c))
|
||||
* 增加稳定版,预览版区分,预览版是最新版,稳定版在预览版验证稳定后,再将预览版转为稳定版 ([1574090](https://github.com/certd/certd/commit/15740904e5e97ee767c39e4401dbc1d645795c38))
|
||||
* 支持AI开发在线插件 ([eae7edb](https://github.com/certd/certd/commit/eae7edbda0fd7357163f33fb4084fcba21396f5f))
|
||||
* **domain:** 域名管理增加remark字段 ([e4041ea](https://github.com/certd/certd/commit/e4041eabece1bab2c1c4b955129cf7a7fe7302d0))
|
||||
* **login,settings:** 仅第三方登录开启后,在重启10分钟后将无法使用密码登录 ([1d12ad7](https://github.com/certd/certd/commit/1d12ad73c6ca827d2eb36bda867f9d9fe62dab48))
|
||||
* **plugin:** 插件安装支持检测依赖 ([e79660c](https://github.com/certd/certd/commit/e79660c5d17ed4049508a00a359950a54470332f))
|
||||
* **plugin:** 新增插件评分展示、排序与个人插件筛选功能 ([7ab5029](https://github.com/certd/certd/commit/7ab502991e0c001777b268b9f159311ef5e000a0))
|
||||
* **server:** response优化为gzip压缩 ([f38522c](https://github.com/certd/certd/commit/f38522ca0b2185f7f35538f53cb51dcf86d0bfc8))
|
||||
* **tencent-clb:** 重构腾讯云CLB部署插件的地域选择组件,改为远程下拉选择器 ([30d4fc8](https://github.com/certd/certd/commit/30d4fc84a9e940d1d07e1f25856eb6fa13da9ba1))
|
||||
|
||||
# [1.43.0](https://github.com/certd/certd/compare/v1.42.6...v1.43.0) (2026-08-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 优化火山引擎dcdn,单个单个部署,规避超时问题 ([cf008b9](https://github.com/certd/certd/commit/cf008b9cff54542dc551fb159578dbd49006229c))
|
||||
* **pipeline:** 修复过期/损坏的安装锁导致的依赖安装失败 ([1017a38](https://github.com/certd/certd/commit/1017a38eb48d6778745d4905d9ec4f6067a261d8))
|
||||
* **ui:** 修复oauth设置页保存后未正确刷新的问题 ([8ab699a](https://github.com/certd/certd/commit/8ab699a9104b47e02a88ad764e995a495deb775e))
|
||||
* **unicloud:** 修复unicloud登录接口改版后请求失败的问题 ([18583f6](https://github.com/certd/certd/commit/18583f6ce025fa8d365fad5a8c9c6020f3bcfbae))
|
||||
|
||||
### Features
|
||||
|
||||
* 优化开放接口证书自动申请功能 ([6339cdf](https://github.com/certd/certd/commit/6339cdffa9f79505dada5617d8c7fcfacc419a2e))
|
||||
* **pipeline:** 新增流水线批量编辑、阶段宽度调整功能 ([e5a1844](https://github.com/certd/certd/commit/e5a18448522be88bc504a45a46ad599f3c39ca30))
|
||||
* **ssh:** ssh连接支持跳板机 ([2cb4e55](https://github.com/certd/certd/commit/2cb4e551fa7616f587a2d907f9b513f7df3a9957))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 部署到京东云CDN支持设置跳转类型 ([e992192](https://github.com/certd/certd/commit/e9921928df011c2435af73b68ebc3d773f13c16a))
|
||||
* 统一通知类型常量管理,新增开放接口通知能力 ([edb249c](https://github.com/certd/certd/commit/edb249c2ad3c173dbfd04d8d156f895a6706ffd1))
|
||||
* 优化宝塔报错提示 ([1cfa766](https://github.com/certd/certd/commit/1cfa76683b40da9e9198552f2226419d4afa86a3))
|
||||
* 优化第三方登录设置提示 ([1468eb1](https://github.com/certd/certd/commit/1468eb1ef292a9e21a2a43131b86b8acb3688307))
|
||||
* 优化第三方依赖安装失败日志输出 ([18b2d3a](https://github.com/certd/certd/commit/18b2d3ac2078d0c6636af897f8f66e4eb5ff832c))
|
||||
* 优化SqliteError: disk I/O error报错修复提示 ([7d22fe3](https://github.com/certd/certd/commit/7d22fe3d7d0de97bae2ceedd051a0c16a1cd90e3))
|
||||
* 证书成功通知增加有效期显示 ([f1b6704](https://github.com/certd/certd/commit/f1b67049d16ebcabe6d6d9b6cb53a8a2b7a9265c))
|
||||
* **cert-plugin:** 证书申请支持失败重试 ([0ddb1f6](https://github.com/certd/certd/commit/0ddb1f69d2a46b993e792862ce9952336d532f5b))
|
||||
* Improve English localization coverage ([#778](https://github.com/certd/certd/issues/778)) @MephistoJB ([bd82147](https://github.com/certd/certd/commit/bd821474969a22078b9d2e73518e765b8c9a26c7))
|
||||
* **install:** 补充迁移到PostgreSQL后,表自增序列从1开始的修复SQL脚本和说明 ([80374ca](https://github.com/certd/certd/commit/80374cae8a43fd17eb180381a093267e466a0bc2))
|
||||
* **plugin-ucloud:** ucloud us3部署插件增加region选择 ([8165a5f](https://github.com/certd/certd/commit/8165a5ff8986e759948c06f924d12e605b2ec8f6))
|
||||
* **tencent-clb:** 为腾讯云CLB部署插件支持远程选择输入 ([967846b](https://github.com/certd/certd/commit/967846bef590b76d27e472180b96372ff55cfb6f))
|
||||
* **ui:** 域名选择器支持点击复制域名 ([b173311](https://github.com/certd/certd/commit/b173311468d2c1f318d1333257c3ebcf916da071))
|
||||
|
||||
## [1.42.6](https://github.com/certd/certd/compare/v1.42.5...v1.42.6) (2026-07-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复正常批量删除流水线报权限不足的bug ([5b50083](https://github.com/certd/certd/commit/5b500830a122c6c42dab054e57fed509050f94da))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化动态加载依赖镜像地址,多次重试 ([5f53b81](https://github.com/certd/certd/commit/5f53b81c75dd242b4260ac08cae14c6d1a08a883))
|
||||
|
||||
## [1.42.5](https://github.com/certd/certd/compare/v1.42.4...v1.42.5) (2026-07-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复上传到cos报runtimeDepsService未初始化的问题 ([167b303](https://github.com/certd/certd/commit/167b303faeca02cc11cf97e4be2a3df914852167))
|
||||
* 修复dingtalk通知格式没有换行的bug ([7ed1be9](https://github.com/certd/certd/commit/7ed1be994f8b4b74cdeb38743060c912c027248b))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 给SQLITE_IOERR_WRITE增加友好报错提示,将certd:latest镜像改为certd:slim ([b91c9e4](https://github.com/certd/certd/commit/b91c9e4ea671cb359ef164e27864de1d66cba9d3))
|
||||
* 优化vke keubconfig获取方式,改成先查询,如果没有再创建临时config ([604fa5b](https://github.com/certd/certd/commit/604fa5be634d099d797bfee5c2b0f26ce0ac8461))
|
||||
|
||||
## [1.42.4](https://github.com/certd/certd/compare/v1.42.3...v1.42.4) (2026-07-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复火山引擎查不到自定义源站域名的问题 ([02dabe1](https://github.com/certd/certd/commit/02dabe11db3e9b13ca4621ce9ddd2b808bfca390))
|
||||
* 修复火山引擎自定义源站域名查询不到的问题 ([e44bf9d](https://github.com/certd/certd/commit/e44bf9d77375d48ac7fd1582e69fae02dfd248fa))
|
||||
* **pipeline:** 重构运行时依赖加载逻辑,修复火山引擎DNS解析报runtimeDepsService未初始化的bug ([ec69b8f](https://github.com/certd/certd/commit/ec69b8f11bfd4b20991aef74a72a47182ca79a9d))
|
||||
|
||||
## [1.42.3](https://github.com/certd/certd/compare/v1.42.2...v1.42.3) (2026-07-08)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **volcengine-alb:** 修复火山引擎ALB 默认证书部署类型会部署到扩展证书的问题 ([0a068a2](https://github.com/certd/certd/commit/0a068a274673e9768954e9f7367c267d44f3b530))
|
||||
|
||||
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复火山视频点播源站选择不到自定义源站的bug ([0071bcb](https://github.com/certd/certd/commit/0071bcb0e4dd108c86d7ca01820a9f6e6960e440))
|
||||
* 修复企业模式下弹出邮箱绑定提醒的问题 ([8d9dad9](https://github.com/certd/certd/commit/8d9dad9c82f6f2fd3ab3040068946a33f37145b1))
|
||||
* 修复AsiaIsp CDN证书重复情况下部署失败的问题 ([c3d6db3](https://github.com/certd/certd/commit/c3d6db3f1ef2f1c897b7989521fe8809dffaded1))
|
||||
* 修复cname用阿里云校验时报找不到runtimeDepsService的错误 ([072edd7](https://github.com/certd/certd/commit/072edd7affee424ab3411f4d41d338f084d7cac6))
|
||||
|
||||
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复多域名无法使用passkey登录的bug ([d176f9c](https://github.com/certd/certd/commit/d176f9cc0ebd051a614bfac74d1616d1945fc9a3))
|
||||
* 修复企业模式下登录报projectId不能为空的问题 ([a65366b](https://github.com/certd/certd/commit/a65366bbe1aadea8baaffbdadab58a5b631d9417))
|
||||
* **login:** 修复输入法 composing 状态下回车触发提交的问题 ([b74db81](https://github.com/certd/certd/commit/b74db81304bbe68476bbec5ea4307a2264060e92))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **certd-server:** 使用 jks-go转换jks证书,大幅精简镜像大小 ([c78898e](https://github.com/certd/certd/commit/c78898e4c10dd1701467d2e42e3f72bd8f2a352f))
|
||||
* **pipeline:** 将默认历史保留条数从30调整为100 ([d3e4677](https://github.com/certd/certd/commit/d3e4677ea4fac8e7533749d7f4187e410489e536))
|
||||
|
||||
# [1.42.0](https://github.com/certd/certd/compare/v1.41.4...v1.42.0) (2026-07-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复jdk证书格式的问题 ([260f5ae](https://github.com/certd/certd/commit/260f5ae777b83493b0c578fe30fd00ec0c873226))
|
||||
* 修复telegram - 符号转义问题 ([d5882f1](https://github.com/certd/certd/commit/d5882f16bedb09baf09ace92049b02872620f5dc))
|
||||
* **aliyun:** 修复阿里云CDN/DCDN根据证书自动匹配不到证书的bug ([1ae185d](https://github.com/certd/certd/commit/1ae185d0bc356f4678bc38ca0582ce3396f82ebe))
|
||||
|
||||
### Features
|
||||
|
||||
* 通过插件配置懒加载依赖,动态加载第三方依赖包,精简安装镜像大小 ([01568ca](https://github.com/certd/certd/commit/01568ca1489069046b5a89ebdd4ced2f7f6ddf93))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 阿里云ESA证书部署支持SaaS模式 ([82276b5](https://github.com/certd/certd/commit/82276b53a8474a18a3d0237050907c994fc748f0))
|
||||
* 【破坏性更新】 证书压缩包不再生成文件存储,而是实时打包下载,证书申请插件不再输出certZip ([7cff1a9](https://github.com/certd/certd/commit/7cff1a98424120585205889874b3ef4956a30583))
|
||||
* 火山引擎点播插件支持部署到自定义源站域名 ([095791c](https://github.com/certd/certd/commit/095791cdc2b7c1f4b913b634643afec5e30fe9b0))
|
||||
* 基础镜像改成node:22-trixie-slim,对网络兼容性更好 ([c66a2bd](https://github.com/certd/certd/commit/c66a2bd77ab6dbb3e3fe2c00562b66287a9429ea))
|
||||
* 新增橙域网络(asia-isp) CDN证书部署插件 ([b48831e](https://github.com/certd/certd/commit/b48831e60b0059bef7ef9a34ab61c9dd2f684641))
|
||||
* 优化阿里云API网关增加翻页查询 ([ed58ae3](https://github.com/certd/certd/commit/ed58ae3c5339e4a0238a92acfe7ea6d2f566ea28))
|
||||
* 优化用户体验,首次访问时弹出邮箱账号绑定用以初始化账号 ([608cc2a](https://github.com/certd/certd/commit/608cc2a81ff0b4872c9fe11ed9c9c0b4b90a12a3))
|
||||
* 优化ACME账号字段的选择提示 ([bfd3cac](https://github.com/certd/certd/commit/bfd3cacc687fc5cbc3cb2ca3cadbc140de300dc2))
|
||||
* 支持全自动匹配部署宝塔网站证书 ([4dff48e](https://github.com/certd/certd/commit/4dff48e807c32a7623ec9206cf39c88e88f89f6a))
|
||||
* **cert-plugin:** 调整更新天数自动减半逻辑,仅7天ip证书生效,其他情况下不减半 ([56e5524](https://github.com/certd/certd/commit/56e5524a0f4af3645d70bc3b3ec750b45ba8de10))
|
||||
* dns默认ipv4first ([194463b](https://github.com/certd/certd/commit/194463bea9e797315aa7a724f4b2930701570419))
|
||||
* **passkey:** passkey支持多域名rpid ([79f6586](https://github.com/certd/certd/commit/79f65868ca0f5162bbc2f935ce89abc28011d816))
|
||||
* **plugin:** 在线插件编辑支持配置第三方依赖和插件依赖 ([635f069](https://github.com/certd/certd/commit/635f069012d4193cfb7cb051c96e28eec1247ca2))
|
||||
|
||||
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **plugin:** 增加 Dynadot DNS and access 插件 ([a3a215b](https://github.com/certd/certd/commit/a3a215b7ae2b90efcde91270ce4165bbfe77dc64))
|
||||
|
||||
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复litessl无法申请证书,报authorization must be pending 错误的问题 ([d6cd9d1](https://github.com/certd/certd/commit/d6cd9d136d2812b2335917305f36d6d9414507ad))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 首页夜间模式主图切换为黑色背景 ([15484bc](https://github.com/certd/certd/commit/15484bc119fef7a0ca7f3fdab01d665fde47e688))
|
||||
|
||||
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cert-plugin:** 修复DNS提供商授权无法回显的bug ([016ae86](https://github.com/certd/certd/commit/016ae865b1d914fe5792e77a08e3ab5358df5f89))
|
||||
* Parse PEM chain and import certificate chain ([#747](https://github.com/certd/certd/issues/747)) ([454912d](https://github.com/certd/certd/commit/454912d31407d350cbd170953ccbd0564e74fd6c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 添加AWS Rate Limit应对措施 ([#748](https://github.com/certd/certd/issues/748)) ([56b8c68](https://github.com/certd/certd/commit/56b8c689ec2b5cff49010a8c765483dd36803e9d))
|
||||
* 新增站点证书监控从DNS解析记录批量导入功能 ([f9541fa](https://github.com/certd/certd/commit/f9541fab701e01ba57af061da322204c894adfb8))
|
||||
* 优化 HiPM DNSMgr 插件,添加域名查询双层策略 ([#744](https://github.com/certd/certd/issues/744)) @WUHINS ([0f3f851](https://github.com/certd/certd/commit/0f3f8519e04d95cb848e28b98a3d4fcbed481fce))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "perf: 添加AWS Rate Limit应对措施 (#748)" (#749) ([5e8bdac](https://github.com/certd/certd/commit/5e8bdac00850bed4f5f2a272bee42c490730ec21)), closes [#748](https://github.com/certd/certd/issues/748) [#749](https://github.com/certd/certd/issues/749)
|
||||
|
||||
## [1.41.1](https://github.com/certd/certd/compare/v1.41.0...v1.41.1) (2026-06-05)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 流水线、监控站点支持导出 ([99fd308](https://github.com/certd/certd/commit/99fd3083f259cdb96fd656f04858dd708d1251c7))
|
||||
* 优化列表页面请求两次的问题 ([5546af5](https://github.com/certd/certd/commit/5546af518e92c765513787ccaf8e856be789bcf9))
|
||||
* 优化邀请注册流程 ([7a71e45](https://github.com/certd/certd/commit/7a71e45799d782d0691606fb42b4236f1d3009b0))
|
||||
* **settings:** 新增NO_PROXY代理排除配置 ([c0df8be](https://github.com/certd/certd/commit/c0df8be83237e323c2c9a5bd02507430a86a00cc))
|
||||
* **volcengine-vke:** 火山VKE集群证书支持两种类型的证书保密字典 ([77b8024](https://github.com/certd/certd/commit/77b802445322d576d54d194f7c505da49e0e824c))
|
||||
|
||||
# [1.41.0](https://github.com/certd/certd/compare/v1.40.5...v1.41.0) (2026-06-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云证书订单orderid 选择出错的问题 ([41254d1](https://github.com/certd/certd/commit/41254d10b748a2d3e6ba43c7e11411650c748d1b))
|
||||
* **monitor:** 修复开放接口自动创建证书流水线重复触发和等待时间不足的问题 ([91d5c90](https://github.com/certd/certd/commit/91d5c90eb0eaf65c81dddbd2d4d4b404cb8b4d07))
|
||||
* **pipeline:** 修复批量随机修改定时没有生效的bug ([2e19dda](https://github.com/certd/certd/commit/2e19dda72e70b525a7c269e18e963a5ee602f59f))
|
||||
|
||||
### Features
|
||||
|
||||
* 商业版支持邀请返佣功能 ([f9a310b](https://github.com/certd/certd/commit/f9a310b6c3bbf30f221482a0c59e9c30080bdfc8))
|
||||
* 商业版支持邀请推广功能 ([f1d2a10](https://github.com/certd/certd/commit/f1d2a1033a0f8d3dbd91fc9793e07bd0b858b539))
|
||||
* 新增管理员针对用户流水线和证书监控管理功能 ([0211552](https://github.com/certd/certd/commit/021155278e7375f8487b0531ed1b5ad52512f007))
|
||||
* 新增套餐激活码功能,通过CDK兑换套餐 ([81d6289](https://github.com/certd/certd/commit/81d6289a8631b073b49f24dee4b14bb1c8f31071))
|
||||
* 新增推广等级激励功能 ([5096df5](https://github.com/certd/certd/commit/5096df5cc0d8f0ad8aa327b8e2a900ba23714bd8))
|
||||
* 新增证书申请参数模版管理,开放接口支持使用证书参数模版和指定证书申请参数 ([f8b71a0](https://github.com/certd/certd/commit/f8b71a0e612fad527cf49136335e0b46f0f379cd))
|
||||
* 支持dns-persist-01持久化验证方式申请证书,优化Acme账号的存储方式 ([67b05e2](https://github.com/certd/certd/commit/67b05e2d75e96b9f855e1ca0b3d0d8d03b92d8e6))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 插件全局配置支持下拉选项自定义映射功能 ([c637985](https://github.com/certd/certd/commit/c637985575b09196b04cce37ac14fbe68c029bde))
|
||||
* 商业版提现增加收款二维码上传 ([83a5a21](https://github.com/certd/certd/commit/83a5a21f956e50942541f1532f3a8dcaa5821d34))
|
||||
* **aliyun-apig:** 优化阿里云API网关部署插件的查询及翻页 ([3e4b7f3](https://github.com/certd/certd/commit/3e4b7f30ac6f3c976c8274bdf256c69b8a2c46db))
|
||||
* **trade:** 优化商品购买页面的规格展示和折扣计算,支持订单取消 ([6624769](https://github.com/certd/certd/commit/66247690326ce2789900fc9110c08b3502cea655))
|
||||
|
||||
## [1.40.5](https://github.com/certd/certd/compare/v1.40.4...v1.40.5) (2026-05-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 安装glibc,增加Alpine镜像下 dns解析结果的兼容性 ([1a08bd3](https://github.com/certd/certd/commit/1a08bd340e1e7d3f9acf5d40f7bba7998459b8fb))
|
||||
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/certd/certd/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
|
||||
* 修复查询阿里云cdn Dcdn 域名太多无法选择的bug ([346fb73](https://github.com/certd/certd/commit/346fb730a37e035576f5d9ea5c0d74c052b34aeb))
|
||||
|
||||
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **pipeline-service:** 修复流水线运行时超过套餐部署次数仍然能够正常运行的bug ([5e59651](https://github.com/certd/certd/commit/5e59651d45bc91919629e35995ff1b3cff6b87ea))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 商业版套餐只支持设置为可叠加 ([5e72f75](https://github.com/certd/certd/commit/5e72f75395fb632a30e80c07d35d8ba40ef631fa))
|
||||
* 新增阿里云直播证书部署插件 ([8edb6f8](https://github.com/certd/certd/commit/8edb6f8727bd148f106801bef25567880fd35e9e))
|
||||
|
||||
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复暗黑模式下注册页面验证码看不清的问题 ([5ba33be](https://github.com/certd/certd/commit/5ba33be30f765f06cafbfcc04f5e25320db01449))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修复商业版套餐添加和修改时的字段显示 ([fb5b00d](https://github.com/certd/certd/commit/fb5b00d73f925036a65ce5003c57c1199578c34d))
|
||||
|
||||
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -39,13 +39,21 @@ pnpm install
|
||||
pnpm init
|
||||
```
|
||||
|
||||
### lib包编译:
|
||||
将packages下面依赖的包都编译一遍,并监听改动。
|
||||
```shell
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### 启动 server:
|
||||
启动server
|
||||
```shell
|
||||
cd packages/ui/certd-server
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### 启动 client:
|
||||
启动前端
|
||||
```shell
|
||||
cd packages/ui/certd-client
|
||||
pnpm dev
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
| 证书域名数量 | 无限制 | 无限制 | 无限制 |
|
||||
| 证书流水线条数 | 无限制 | 无限制 | 无限制 |
|
||||
| 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署、宝塔、1Panel等大部分插件 | 群晖、威联通、proxmox等 | 同专业版 |
|
||||
| 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、钉钉、飞书、anpush、server酱等 | 同专业版 |
|
||||
| 通知 | 邮件通知、自定义webhook | 企微、钉钉、飞书、anpush、server酱等 | 同专业版 |
|
||||
| 站点监控 | 限制1条 | 无限制 | 无限制 |
|
||||
| 批量操作 | 无 | 流水线模版,流水线复制,批量运行,批量设置通知、定时等 | 同专业版 |
|
||||
| VIP群 | 无 | 可加,一对一技术支持,必要时可申请远程协助 | 商业版技术支持 |
|
||||
|
||||
@@ -1,20 +1,32 @@
|
||||
# 镜像说明
|
||||
|
||||
## 镜像版本说明
|
||||
|
||||
| 版本标签 | 基础系统 | OpenJDK | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `latest` / `[version]` | Alpine Linux | 有 | **推荐**,默认版本,镜像体积更小,功能完整,支持所有插件 |
|
||||
| `slim` / `[version]-slim` | Debian slim | 有 | glibc 兼容性更好,适用于依赖 glibc 的特殊场景 |
|
||||
| `armv7` / `[version]-armv7` | Alpine Linux | 有 | ARMv7 架构专用版本 |
|
||||
|
||||
## 国内镜像地址:
|
||||
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest`
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest`
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:slim`、`[version]-slim`
|
||||
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:armv7`、`[version]-armv7`
|
||||
|
||||
## DockerHub地址:
|
||||
* `https://hub.docker.com/r/greper/certd`
|
||||
* `greper/certd:latest`
|
||||
* `greper/certd:slim`、`greper/certd:[version]-slim`
|
||||
* `greper/certd:armv7`、`greper/certd:[version]-armv7`
|
||||
|
||||
## GitHub Packages地址:
|
||||
* `ghcr.io/certd/certd:latest`
|
||||
* `ghcr.io/certd/certd:slim`、`ghcr.io/certd/certd:[version]-slim`
|
||||
* `ghcr.io/certd/certd:armv7`、`ghcr.io/certd/certd:[version]-armv7`
|
||||
*
|
||||
|
||||
## 镜像构建公开
|
||||
镜像构建通过`Actions`自动执行,过程公开透明,请放心使用
|
||||
镜像构建通过`Actions`自动执行,过程公开透明,请放心使用
|
||||
* [点我查看镜像构建日志](https://github.com/certd/certd/actions/workflows/build-image.yml)
|
||||
|
||||

|
||||
@@ -6,7 +6,7 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
|
||||
关键字:证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具
|
||||
|
||||
|
||||
| 官方开源地址: | |
|
||||
| |官方开源地址: |
|
||||
| ---- | ---- |
|
||||
| [Github](https://github.com/certd/certd)|  |
|
||||
| [Gitee](https://gitee.com/certd/certd) |  |
|
||||
|
||||
@@ -103,9 +103,14 @@ docker-compose up -d
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
> 重要: 建议Fetch大小改成1000,避免内存溢出
|
||||
|
||||
下一步、下一步,直到数据加载设置,勾选`在加载前截断目标表`(此选项很重要,并且会清空mysql certd数据库中的数据)
|
||||

|
||||
> 重要: 在插入行后做提交,也改成1000,避免内存溢出
|
||||
|
||||
#### 5. 导入完成
|
||||
|
||||
@@ -115,4 +120,58 @@ docker-compose up -d
|
||||
|
||||
访问MySQL版本测试,数据已成功迁移
|
||||
|
||||
确认没有问题之后,删除旧版certd
|
||||
确认没有问题之后,删除旧版certd
|
||||
|
||||
|
||||
## 三、问题
|
||||
|
||||
### 1. 迁移到PostgreSQL之后,所有表的Sequence会从1开始
|
||||
|
||||
执行如下sql 语句,批量将所有表的id自增设置到当前数据的最大值【仅迁移到postgresql需要执行】
|
||||
```sql
|
||||
DO $$
|
||||
DECLARE
|
||||
rec RECORD;
|
||||
seq_name TEXT;
|
||||
max_id BIGINT;
|
||||
BEGIN
|
||||
-- 遍历所有用户表(排除系统schema)
|
||||
FOR rec IN
|
||||
SELECT table_schema, table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_type = 'BASE TABLE'
|
||||
AND table_schema NOT IN ('pg_catalog', 'information_schema')
|
||||
LOOP
|
||||
-- 检查表是否存在名为 'id' 的列
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = rec.table_schema
|
||||
AND table_name = rec.table_name
|
||||
AND column_name = 'id'
|
||||
) THEN
|
||||
-- 获取该列关联的序列名(如果是 serial 或 identity 列)
|
||||
seq_name := pg_get_serial_sequence(
|
||||
quote_ident(rec.table_schema) || '.' || quote_ident(rec.table_name),
|
||||
'id'
|
||||
);
|
||||
|
||||
IF seq_name IS NOT NULL THEN
|
||||
-- 查询当前表中 id 的最大值
|
||||
EXECUTE format('SELECT MAX(id) FROM %I.%I', rec.table_schema, rec.table_name) INTO max_id;
|
||||
|
||||
IF max_id IS NULL THEN
|
||||
-- 表为空,将序列重置为初始值 1(下次调用 nextval 返回 1)
|
||||
PERFORM setval(seq_name, 1, false);
|
||||
RAISE NOTICE '表 %.% 为空,序列 % 已重置为 1', rec.table_schema, rec.table_name, seq_name;
|
||||
ELSE
|
||||
-- 将序列当前值设置为最大值,下次调用 nextval 返回 max_id + 1
|
||||
PERFORM setval(seq_name, max_id, true);
|
||||
RAISE NOTICE '表 %.% 的序列 % 已设置为 %', rec.table_schema, rec.table_name, seq_name, max_id;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
```
|
||||
@@ -2,6 +2,46 @@
|
||||
|
||||
## 一、安装
|
||||
|
||||
### 镜像版本选择
|
||||
|
||||
Certd 提供多种 Docker 镜像版本,您可以根据需要选择:
|
||||
|
||||
#### 1. 镜像地址:
|
||||
|
||||
| 镜像仓库 | 最新预览版 | 稳定版 | slim版 | armv7版 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 阿里云【默认】 | `registry.cn-shenzhen.aliyuncs.com/certd/certd:latest` | `certd:stable` | `certd:slim` | `certd:armv7` |
|
||||
| Docker Hub | `certd/certd:latest` | `certd:stable` | `certd:slim` | `certd:armv7` |
|
||||
| GitHub Packages | `ghcr.io/certd/certd:latest` | `certd:stable` | `certd:slim` | `certd:armv7` |
|
||||
|
||||
> 后面的各个版本省略了镜像地址,使用时需要将镜像地址拼接完整。
|
||||
|
||||
#### 2. 版本标签说明:
|
||||
|
||||
**最新版本标签:**
|
||||
|
||||
| 版本 | 标签 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 最新预览版【默认】 | `certd:latest` | 指向最新开发版本,包含最新功能,但稳定性不如稳定版 |
|
||||
| 最新稳定版 | `certd:stable` | 指向经过充分测试的生产就绪版本,推荐生产环境使用 |
|
||||
|
||||
**系统分支版本:**
|
||||
|
||||
> 根据基础镜像不同,分为如下三个分支版本,没有特殊需求选择默认的即可(他们功能是一样的)
|
||||
|
||||
| 系统版本 | 版本标签 | 基础系统 | 说明 | 稳定版标签 | 指定版本 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| alpine【默认】 | `certd:latest` | Alpine Linux | 默认版本,镜像体积小 | `certd:stable` | `certd:1.43.0` |
|
||||
| slim | `certd:slim` | Debian slim | 基于glibc,dns解析兼容性好 | `certd:slim-stable` | `certd:1.43.0-slim` |
|
||||
| armv7 | `certd:armv7` | Alpine Linux | ARMv7 架构专用版本 | `certd:armv7-stable` | `certd:1.43.0-armv7` |
|
||||
|
||||
|
||||
> 如果您不确定使用哪个版本,请使用默认的 `certd:latest` 版本。
|
||||
|
||||
最新版本号:
|
||||

|
||||
|
||||
|
||||
### 一键脚本安装(推荐)
|
||||
|
||||
如果您的服务器未安装 Docker,该脚本会自动为您安装 Docker 和 Docker Compose,并启动 Certd 容器。
|
||||
|
||||
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 41 KiB |
@@ -31,7 +31,11 @@ header中传入x-certd-token即可调用开放接口
|
||||
支持证书id和域名两种方式获取证书。
|
||||
|
||||
### 创建新的证书申请
|
||||
参数autoApply=true,将在没有证书时自动触发申请证书,检查逻辑如下:
|
||||
参数`autoApply=true`将在没有证书时自动触发申请证书。申请参数支持另外传入:
|
||||
- `autoApplyTemplateId`:使用指定 ID 的证书申请参数模版;不传时不使用模版
|
||||
- `autoApplyParams`:自定义证书申请参数,会与系统默认参数、模版参数合并,并覆盖同名字段
|
||||
|
||||
检查逻辑如下:
|
||||
1. 如果证书仓库里面有,且没有过期,就直接返回证书
|
||||
2. 如果没有或者已过期,就会去找流水线,有就触发流水线执行
|
||||
3. 如果没有流水线,就创建一个流水线,触发运行(`注意:需要提前在域名管理中配置好域名校验方式,否则会申请失败`)
|
||||
@@ -43,9 +47,15 @@ header中传入x-certd-token即可调用开放接口
|
||||
|
||||
## 客户端工具
|
||||
|
||||
### SSL-Assistant
|
||||
### 官方客户端:Certd Client
|
||||
`Certd Client` 是 Certd 的官方证书部署客户端。运行在应用服务器上,自动发现本机 Nginx、Apache 和 IIS 站点,然后从 Certd 获取新证书并部署到本机。适用于不希望服务器开放 SSH、无法由 Certd 直接访问目标服务器的场景。
|
||||
|
||||
项目主页:[AtomGit](https://atomgit.com/certd/certd-client/) | [GitHub](https://github.com/certd/certd-client/)
|
||||
下载地址:[AtomGit Releases](https://atomgit.com/certd/certd-client/releases) | [GitHub Releases](https://github.com/certd/certd-client/releases)
|
||||
|
||||
### 第三方客户端:SSL-Assistant
|
||||
`SSL Assistant` 是一个基于 Go 语言开发的跨平台证书部署管理助手。
|
||||
支持自动扫描主机`Nginx`配置,然后从Certd拉取证书并部署。
|
||||
在不想暴露ssh主机密码情况下,该工具非常好用。
|
||||
|
||||
开源地址: https://github.com/Youngxj/SSL-Assistant
|
||||
开源地址: https://github.com/Youngxj/SSL-Assistant
|
||||
|
||||
@@ -18,67 +18,71 @@
|
||||
| 14.| **SFTP授权** | |
|
||||
| 15.| **阿里云OSS授权** | 包含地域和Bucket |
|
||||
| 16.| **APISIX授权** | |
|
||||
| 17.| **亚马逊云aws授权** | |
|
||||
| 18.| **亚马逊云科技(国区)授权** | |
|
||||
| 19.| **微软云Azure授权** | |
|
||||
| 20.| **BIND9 DNS 授权** | 通过 SSH 连接到 BIND9 服务器,使用 nsupdate 命令管理 DNS 记录 |
|
||||
| 21.| **CacheFly** | CacheFly |
|
||||
| 22.| **EAB授权** | ZeroSSL证书申请需要EAB授权 |
|
||||
| 23.| **google cloud** | 谷歌云授权 |
|
||||
| 24.| **cloudflare授权** | |
|
||||
| 25.| **中国移动CND授权** | |
|
||||
| 26.| **授权插件示例** | 这是一个示例授权插件,用于演示如何实现一个授权插件 |
|
||||
| 27.| **dns.la授权** | |
|
||||
| 28.| **彩虹DNS** | 彩虹DNS管理系统授权 |
|
||||
| 29.| **多吉云** | |
|
||||
| 30.| **Dokploy授权** | |
|
||||
| 31.| **farcdn授权** | |
|
||||
| 32.| **FlexCDN授权** | |
|
||||
| 33.| **Gcore** | Gcore |
|
||||
| 34.| **Github授权** | |
|
||||
| 35.| **godaddy授权** | |
|
||||
| 36.| **HiPM DNSMgr** | HiPM DNSMgr API Token 授权 |
|
||||
| 37.| **金山云授权** | |
|
||||
| 38.| **FTP授权** | |
|
||||
| 39.| **七牛OSS授权** | |
|
||||
| 40.| **腾讯云COS授权** | 腾讯云对象存储授权,包含地域和存储桶 |
|
||||
| 41.| **s3/minio授权** | S3/minio oss授权 |
|
||||
| 42.| **namesilo授权** | |
|
||||
| 43.| **Next Terminal 授权** | 用于访问 Next Terminal API 的授权配置 |
|
||||
| 44.| **Nginx Proxy Manager 授权** | 用于登录 Nginx Proxy Manager,并为代理主机证书部署提供授权。 |
|
||||
| 45.| **1panel授权** | 账号和密码 |
|
||||
| 46.| **支付宝** | |
|
||||
| 47.| **白山云授权** | |
|
||||
| 48.| **宝塔云WAF授权** | 用于连接和管理宝塔云WAF服务的授权配置 |
|
||||
| 49.| **cdnfly授权** | |
|
||||
| 50.| **k8s授权** | |
|
||||
| 51.| **括彩云cdn授权** | 括彩云CDN,每月免费30G,[注册即领](https://kuocaicdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 52.| **LeCDN授权** | |
|
||||
| 53.| **lucky** | |
|
||||
| 54.| **猫云授权** | |
|
||||
| 55.| **plesk授权** | |
|
||||
| 56.| **长亭雷池授权** | |
|
||||
| 57.| **群晖登录授权** | |
|
||||
| 58.| **uniCloud** | unicloud授权 |
|
||||
| 59.| **微信支付** | |
|
||||
| 60.| **易盾rcdn授权** | 易盾CDN,每月免费30G,[注册即领](https://rhcdn.yiduncdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 61.| **易发云短信** | sms.yfyidc.cn/ |
|
||||
| 62.| **易盾DCDN授权** | https://user.yiduncdn.com |
|
||||
| 63.| **易支付** | |
|
||||
| 64.| **proxmox** | |
|
||||
| 65.| **Spaceship.com 授权** | Spaceship.com API 授权插件 |
|
||||
| 66.| **Technitium DNS Server** | Technitium DNS Server 自建DNS服务器授权 |
|
||||
| 67.| **UCloud授权** | 优刻得授权 |
|
||||
| 68.| **又拍云** | |
|
||||
| 69.| **网宿授权** | |
|
||||
| 70.| **西部数码授权** | |
|
||||
| 71.| **我爱云授权** | 我爱云CDN |
|
||||
| 72.| **新网授权(代理方式)** | |
|
||||
| 73.| **新网授权** | |
|
||||
| 74.| **新网互联授权** | 仅支持代理账号,ip需要加入白名单 |
|
||||
| 75.| **Zenlayer授权** | Zenlayer授权 |
|
||||
| 76.| **GoEdge授权** | |
|
||||
| 77.| **雨云授权** | https://app.rainyun.com/ |
|
||||
| 17.| **橙域网络(asia-isp)授权** | 橙域网络CDN API授权,用于部署证书到橙域CDN |
|
||||
| 18.| **亚马逊云aws授权** | |
|
||||
| 19.| **亚马逊云科技(国区)授权** | |
|
||||
| 20.| **微软云Azure授权** | |
|
||||
| 21.| **BIND9 DNS 授权** | 通过 SSH 连接到 BIND9 服务器,使用 nsupdate 命令管理 DNS 记录 |
|
||||
| 22.| **CacheFly** | CacheFly |
|
||||
| 23.| **ACME账号** | 用于复用ACME账号私钥和账号地址,证书申请时不再临时创建账号 |
|
||||
| 24.| **EAB授权** | ZeroSSL证书申请需要EAB授权 |
|
||||
| 25.| **google cloud** | 谷歌云授权 |
|
||||
| 26.| **cloudflare授权** | |
|
||||
| 27.| **中国移动CND授权** | |
|
||||
| 28.| **授权插件示例** | 这是一个示例授权插件,用于演示如何实现一个授权插件 |
|
||||
| 29.| **dns.la授权** | |
|
||||
| 30.| **彩虹DNS** | 彩虹DNS管理系统授权 |
|
||||
| 31.| **多吉云** | |
|
||||
| 32.| **Dokploy授权** | |
|
||||
| 33.| **Dynadot授权** | |
|
||||
| 34.| **farcdn授权** | |
|
||||
| 35.| **Fastly授权** | Fastly CDN / TLS Custom Certificates API 授权 |
|
||||
| 36.| **FlexCDN授权** | |
|
||||
| 37.| **Gcore** | Gcore |
|
||||
| 38.| **Github授权** | |
|
||||
| 39.| **godaddy授权** | |
|
||||
| 40.| **HiPM DNSMgr** | HiPM DNSMgr API Token 授权 |
|
||||
| 41.| **金山云授权** | |
|
||||
| 42.| **FTP授权** | |
|
||||
| 43.| **七牛OSS授权** | |
|
||||
| 44.| **腾讯云COS授权** | 腾讯云对象存储授权,包含地域和存储桶 |
|
||||
| 45.| **s3/minio授权** | S3/minio oss授权 |
|
||||
| 46.| **namesilo授权** | |
|
||||
| 47.| **Next Terminal 授权** | 用于访问 Next Terminal API 的授权配置 |
|
||||
| 48.| **Nginx Proxy Manager 授权** | 用于登录 Nginx Proxy Manager,并为代理主机证书部署提供授权。 |
|
||||
| 49.| **1panel授权** | 账号和密码 |
|
||||
| 50.| **支付宝** | |
|
||||
| 51.| **白山云授权** | |
|
||||
| 52.| **宝塔云WAF授权** | 用于连接和管理宝塔云WAF服务的授权配置 |
|
||||
| 53.| **cdnfly授权** | |
|
||||
| 54.| **k8s授权** | |
|
||||
| 55.| **括彩云cdn授权** | 括彩云CDN,每月免费30G,[注册即领](https://kuocaicdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 56.| **LeCDN授权** | |
|
||||
| 57.| **lucky** | |
|
||||
| 58.| **猫云授权** | |
|
||||
| 59.| **plesk授权** | |
|
||||
| 60.| **长亭雷池授权** | |
|
||||
| 61.| **群晖登录授权** | |
|
||||
| 62.| **uniCloud** | unicloud授权 |
|
||||
| 63.| **微信支付** | |
|
||||
| 64.| **易盾rcdn授权** | 易盾CDN,每月免费30G,[注册即领](https://rhcdn.yiduncdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 65.| **易发云短信** | sms.yfyidc.cn/ |
|
||||
| 66.| **易盾DCDN授权** | https://user.yiduncdn.com |
|
||||
| 67.| **易支付** | |
|
||||
| 68.| **proxmox** | |
|
||||
| 69.| **Spaceship.com 授权** | Spaceship.com API 授权插件 |
|
||||
| 70.| **Technitium DNS Server** | Technitium DNS Server 自建DNS服务器授权 |
|
||||
| 71.| **UCloud授权** | 优刻得授权 |
|
||||
| 72.| **又拍云** | |
|
||||
| 73.| **网宿授权** | |
|
||||
| 74.| **西部数码授权** | |
|
||||
| 75.| **我爱云授权** | 我爱云CDN |
|
||||
| 76.| **新网授权(代理方式)** | |
|
||||
| 77.| **新网授权** | |
|
||||
| 78.| **新网互联授权** | 仅支持代理账号,ip需要加入白名单 |
|
||||
| 79.| **Zenlayer授权** | Zenlayer授权 |
|
||||
| 80.| **GoEdge授权** | |
|
||||
| 81.| **雨云授权** | https://app.rainyun.com/ |
|
||||
|
||||
<style module>
|
||||
table th:first-of-type {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# 任务插件
|
||||
共 `131` 款任务插件
|
||||
共 `139` 款任务插件
|
||||
## 1. 证书申请
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **证书申请(JS版)** | 免费通配符域名证书申请,支持多个域名打到同一个证书上 |
|
||||
| 2.| **已有证书托管** | 手动上传自定义证书后,自动部署(每次证书有更新,都需要手动上传一次) |
|
||||
| 3.| **获取阿里云订阅证书** | 从阿里云拉取订阅模式的商用证书(支持 API 1.0 和 2.0) |
|
||||
| 4.| **证书申请(Lego)** | 支持海量DNS解析提供商,推荐使用,一样的免费通配符域名证书申请,支持多个域名打到同一个证书上 |
|
||||
| 1.| **吊销旧证书** | 新证书申请成功,并全部部署成功后,吊销本流水线产生的旧证书。(注意 如果本流水线证书还在别处有使用或手动部署,请慎重添加此吊销任务) |
|
||||
| 2.| **证书申请(JS版)** | 免费通配符域名证书申请,支持多个域名打到同一个证书上 |
|
||||
| 3.| **已有证书托管** | 手动上传自定义证书后,自动部署(每次证书有更新,都需要手动上传一次) |
|
||||
| 4.| **获取阿里云订阅证书** | 从阿里云拉取订阅模式的商用证书(支持 API 1.0 和 2.0) |
|
||||
| 5.| **证书申请(Lego)** | 支持海量DNS解析提供商,推荐使用,一样的免费通配符域名证书申请,支持多个域名打到同一个证书上 |
|
||||
## 2. 主机
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
@@ -25,30 +26,35 @@
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **APISIX-更新证书** | 自动更新APISIX证书 |
|
||||
| 2.| **CacheFly-部署证书到CacheFly** | 部署证书到 CacheFly |
|
||||
| 3.| **中国移动-部署证书到CDN** | 中国移动自动部署证书到CDN |
|
||||
| 4.| **多吉云-部署到多吉云CDN** | |
|
||||
| 5.| **farcdn-更新证书** | www.farcdn.net |
|
||||
| 6.| **FlexCDN-更新证书** | |
|
||||
| 7.| **Gcore-刷新Gcore证书** | 刷新现有的证书 |
|
||||
| 8.| **Gcore-部署证书到Gcore** | 仅上传 并不会部署到cdn |
|
||||
| 9.| **GoEdge-更新证书** | GoEdge |
|
||||
| 10.| **金山云-更新CDN证书** | 金山云自动更新CDN证书 |
|
||||
| 11.| **白山云-更新证书** | |
|
||||
| 12.| **cdnfly-部署证书到cdnfly** | cdnfly |
|
||||
| 13.| **天翼云-部署证书到CDN** | 部署证书到天翼云CDN和全站加速 |
|
||||
| 14.| **括彩云-部署到括彩云CDN** | 括彩云CDN,每月免费30G,[注册即领](https://kuocaicdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 15.| **LeCDN-更新证书V2** | 支持新版本LeCDN |
|
||||
| 16.| **LeCDN-更新证书** | |
|
||||
| 17.| **Maoyun-更新猫云CDN证书** | |
|
||||
| 18.| **易盾-部署到易盾DCDN** | 主要是防御,http://user.yiduncdn.com/ |
|
||||
| 19.| **易盾-部署到易盾RCDN** | 易盾CDN,每月免费30G,[注册即领](https://rhcdn.yiduncdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 20.| **雨云-更新证书** | app.rainyun.com |
|
||||
| 21.| **又拍云-部署证书到CDN/USS** | 支持又拍云CDN,又拍云云存储USS |
|
||||
| 22.| **网宿-更新证书** | 网宿证书自动更新 |
|
||||
| 23.| **西数-部署到虚拟主机** | 西部数码部署证书到虚拟主机 |
|
||||
| 24.| **我爱云-部署证书到我爱云CDN** | 部署证书到我爱云CDN |
|
||||
| 25.| **Zenlayer-刷新证书** | 刷新Zenlayer CDN证书 |
|
||||
| 2.| **橙域网络-部署证书到CDN** | 部署证书到橙域网络(asia-isp) CDN加速域名 |
|
||||
| 3.| **CacheFly-部署证书到CacheFly** | 部署证书到 CacheFly |
|
||||
| 4.| **中国移动-部署证书到CDN** | 中国移动自动部署证书到CDN |
|
||||
| 5.| **多吉云-部署到多吉云CDN** | |
|
||||
| 6.| **farcdn-更新证书** | www.farcdn.net |
|
||||
| 7.| **Fastly-部署TLS激活** | 部署 Fastly 证书 (创建 TLS Activation 绑定证书到域名) |
|
||||
| 8.| **Fastly-清除缓存** | 清除 Fastly 指定 Service 的所有缓存 (Purge All) |
|
||||
| 9.| **Fastly-更新证书** | 自动更新 Fastly CDN 上的已有自定义证书 |
|
||||
| 10.| **Fastly-上传证书到Fastly** | 部署 / 上传 SSL/TLS 自定义证书到 Fastly CDN |
|
||||
| 11.| **FlexCDN-更新证书** | |
|
||||
| 12.| **Gcore-刷新Gcore证书** | 刷新现有的证书 |
|
||||
| 13.| **Gcore-部署证书到Gcore** | 仅上传 并不会部署到cdn |
|
||||
| 14.| **GoEdge-更新证书** | GoEdge |
|
||||
| 15.| **金山云-更新CDN证书** | 金山云自动更新CDN证书 |
|
||||
| 16.| **白山云-更新证书** | |
|
||||
| 17.| **cdnfly-部署证书到cdnfly** | cdnfly |
|
||||
| 18.| **天翼云-部署证书到CDN** | 部署证书到天翼云CDN和全站加速 |
|
||||
| 19.| **括彩云-部署到括彩云CDN** | 括彩云CDN,每月免费30G,[注册即领](https://kuocaicdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 20.| **LeCDN-更新证书V2** | 支持新版本LeCDN |
|
||||
| 21.| **LeCDN-更新证书** | |
|
||||
| 22.| **Maoyun-更新猫云CDN证书** | |
|
||||
| 23.| **易盾-部署到易盾DCDN** | 主要是防御,http://user.yiduncdn.com/ |
|
||||
| 24.| **易盾-部署到易盾RCDN** | 易盾CDN,每月免费30G,[注册即领](https://rhcdn.yiduncdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 25.| **雨云-更新证书** | app.rainyun.com |
|
||||
| 26.| **又拍云-部署证书到CDN/USS** | 支持又拍云CDN,又拍云云存储USS |
|
||||
| 27.| **网宿-更新证书** | 网宿证书自动更新 |
|
||||
| 28.| **西数-部署到虚拟主机** | 西部数码部署证书到虚拟主机 |
|
||||
| 29.| **我爱云-部署证书到我爱云CDN** | 部署证书到我爱云CDN |
|
||||
| 30.| **Zenlayer-刷新证书** | 刷新Zenlayer CDN证书 |
|
||||
## 4. 面板
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
@@ -62,22 +68,23 @@
|
||||
| 7.| **1Panel-部署面板证书** | 更新1Panel的面板证书 |
|
||||
| 8.| **1Panel-更新站点证书** | 更新1Panel的站点证书 |
|
||||
| 9.| **宝塔-删除过期证书** | 删除证书夹中过期证书 |
|
||||
| 10.| **宝塔-WAF证书部署** | 部署宝塔云WAF/aaWAF |
|
||||
| 11.| **宝塔-面板证书部署** | 部署宝塔面板本身的ssl证书 |
|
||||
| 12.| **宝塔win-网站证书部署** | 部署到Windows版宝塔管理的站点的ssl证书 |
|
||||
| 13.| **宝塔-网站证书部署** | 部署宝塔管理的站点的ssl证书,目前支持宝塔网站站点、docker站点等。本插件也支持aaPanel。 |
|
||||
| 14.| **K8S-Apply自定义yaml** | apply自定义yaml到k8s |
|
||||
| 15.| **K8S-Ingress 证书部署** | 部署证书到k8s的Ingress |
|
||||
| 16.| **K8S-部署证书到Secret** | 部署证书到k8s的secret |
|
||||
| 17.| **lucky-更新Lucky证书** | |
|
||||
| 18.| **Plesk-部署Plesk网站证书** | |
|
||||
| 19.| **Plesk-更新证书** | 不会创建新证书记录,直接更新旧的证书 |
|
||||
| 20.| **雷池-更新证书(支持控制台和防护应用)** | 更新长亭雷池WAF的证书,支持更新控制台和防护应用的证书。 |
|
||||
| 21.| **群晖-部署证书到群晖面板** | Synology,支持6.x以上版本 |
|
||||
| 22.| **群晖-刷新OTP登录有效期** | 群晖登录状态可能30天失效,需要在失效之前登录一次,刷新有效期,您可以将其放在“部署到群晖面板”任务之后 |
|
||||
| 23.| **uniCloud-部署到服务空间** | 部署到服务空间 |
|
||||
| 24.| **Proxmox-上传证书到Proxmox** | |
|
||||
| 25.| **威联通-部署证书到威联通** | 部署证书到qnap |
|
||||
| 10.| **宝塔-全自动部署** | 根据证书域名自动匹配宝塔站点,全自动部署SSL证书。新增加速域名自动感知,自动新增部署 |
|
||||
| 11.| **宝塔-WAF证书部署** | 部署宝塔云WAF/aaWAF |
|
||||
| 12.| **宝塔-面板证书部署** | 部署宝塔面板本身的ssl证书 |
|
||||
| 13.| **宝塔win-网站证书部署** | 部署到Windows版宝塔管理的站点的ssl证书 |
|
||||
| 14.| **宝塔-网站证书部署** | 部署宝塔管理的站点的ssl证书,目前支持宝塔网站站点、docker站点等。本插件也支持aaPanel。 |
|
||||
| 15.| **K8S-Apply自定义yaml** | apply自定义yaml到k8s |
|
||||
| 16.| **K8S-Ingress 证书部署** | 部署证书到k8s的Ingress |
|
||||
| 17.| **K8S-部署证书到Secret** | 部署证书到k8s的secret |
|
||||
| 18.| **lucky-更新Lucky证书** | |
|
||||
| 19.| **Plesk-部署Plesk网站证书** | |
|
||||
| 20.| **Plesk-更新证书** | 不会创建新证书记录,直接更新旧的证书 |
|
||||
| 21.| **雷池-更新证书(支持控制台和防护应用)** | 更新长亭雷池WAF的证书,支持更新控制台和防护应用的证书。 |
|
||||
| 22.| **群晖-部署证书到群晖面板** | Synology,支持6.x以上版本 |
|
||||
| 23.| **群晖-刷新OTP登录有效期** | 群晖登录状态可能30天失效,需要在失效之前登录一次,刷新有效期,您可以将其放在“部署到群晖面板”任务之后 |
|
||||
| 24.| **uniCloud-部署到服务空间** | 部署到服务空间 |
|
||||
| 25.| **Proxmox-上传证书到Proxmox** | |
|
||||
| 26.| **威联通-部署证书到威联通** | 部署证书到qnap |
|
||||
## 5. 阿里云
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
@@ -90,16 +97,17 @@
|
||||
| 6.| **阿里云-部署证书至API网关** | 自动部署域名证书至阿里云API网关(APIGateway) |
|
||||
| 7.| **阿里云-部署证书至CDN** | 自动部署域名证书至阿里云CDN |
|
||||
| 8.| **阿里云-部署证书至DCDN** | 依赖证书申请前置任务,自动部署域名证书至阿里云DCDN |
|
||||
| 9.| **阿里云-部署至ESA** | 部署证书到阿里云ESA(边缘安全加速),自动删除过期证书 |
|
||||
| 9.| **阿里云-部署至ESA** | 部署证书到阿里云ESA(边缘安全加速),支持边缘证书和SaaS证书两种模式 |
|
||||
| 10.| **阿里云-部署至阿里云FC(3.0)** | 部署证书到阿里云函数计算(FC3.0) |
|
||||
| 11.| **阿里云-部署至GA** | 部署证书到阿里云GA(全球加速),支持更新默认证书和扩展证书 |
|
||||
| 12.| **阿里云-部署至NLB(网络负载均衡)** | NLB,网络负载均衡,更新监听器的默认证书 |
|
||||
| 13.| **阿里云-部署证书至OSS** | 部署域名证书至阿里云OSS自定义域名,不是上传到阿里云oss |
|
||||
| 14.| **阿里云-部署至CLB(传统负载均衡)** | 部署证书到阿里云CLB(传统负载均衡) |
|
||||
| 15.| **阿里云-部署至VOD** | 部署证书到阿里云视频点播(vod) |
|
||||
| 16.| **阿里云-部署至阿里云WAF(云产品接入)** | 部署证书到阿里云WAF(云产品接入),CNAME方式接入的请选择另外一个waf插件 |
|
||||
| 17.| **阿里云-部署至阿里云WAF(cname接入)** | 部署证书到阿里云WAF(cname接入),云资源的请选择另外一个waf插件 |
|
||||
| 18.| **阿里云-上传证书到CAS** | 上传证书到阿里云证书管理服务(CAS),如果不想在阿里云上同一份证书上传多次,可以把此任务作为前置任务,其他阿里云任务证书那一项选择此任务的输出 |
|
||||
| 12.| **阿里云-部署至直播(Live)** | 部署证书到阿里云视频直播(Live)域名 |
|
||||
| 13.| **阿里云-部署至NLB(网络负载均衡)** | NLB,网络负载均衡,更新监听器的默认证书 |
|
||||
| 14.| **阿里云-部署证书至OSS** | 部署域名证书至阿里云OSS自定义域名,不是上传到阿里云oss |
|
||||
| 15.| **阿里云-部署至CLB(传统负载均衡)** | 部署证书到阿里云CLB(传统负载均衡) |
|
||||
| 16.| **阿里云-部署至VOD** | 部署证书到阿里云视频点播(vod) |
|
||||
| 17.| **阿里云-部署至阿里云WAF(云产品接入)** | 部署证书到阿里云WAF(云产品接入),CNAME方式接入的请选择另外一个waf插件 |
|
||||
| 18.| **阿里云-部署至阿里云WAF(cname接入)** | 部署证书到阿里云WAF(cname接入),云资源的请选择另外一个waf插件 |
|
||||
| 19.| **阿里云-上传证书到CAS** | 上传证书到阿里云证书管理服务(CAS),如果不想在阿里云上同一份证书上传多次,可以把此任务作为前置任务,其他阿里云任务证书那一项选择此任务的输出 |
|
||||
## 6. 华为云
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
@@ -112,7 +120,7 @@
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **腾讯云-删除即将过期证书** | 仅删除未使用的证书 |
|
||||
| 1.| **腾讯云-删除即将过期证书** | 仅删除即将过期且未使用的证书 |
|
||||
| 2.| **腾讯云-部署证书到任意云资源** | 支持负载均衡、CDN、DDoS、直播、点播、Web应用防火墙、API网关、TEO、容器服务、对象存储、轻应用服务器、云原生微服务、云开发 |
|
||||
| 3.| **腾讯云-部署到CDN(废弃)** | 已废弃,请使用v2版 |
|
||||
| 4.| **腾讯云-部署到CDN-v2** | 推荐使用,支持CDN域名以及COS加速域名 |
|
||||
|
||||
@@ -4,30 +4,31 @@
|
||||
|-----|-----|-----|
|
||||
| 1.| **阿里ESA** | 阿里ESA DNS解析 |
|
||||
| 2.| **阿里云** | 阿里云DNS解析提供商 |
|
||||
| 3.| **AWS Route53** | AWS Route53 DNS解析提供商 |
|
||||
| 4.| **Azure DNS** | Azure DNS 解析提供商 |
|
||||
| 5.| **火山引擎** | 火山引擎DNS解析提供商 |
|
||||
| 6.| **京东云** | 京东云DNS解析提供商 |
|
||||
| 7.| **新网(代理方式)** | 新网域名解析(代理方式) |
|
||||
| 8.| **新网** | 新网域名解析 |
|
||||
| 9.| **BIND9 DNS** | 通过 SSH 连接到 BIND9 服务器,使用 nsupdate 命令管理 DNS 记录 |
|
||||
| 10.| **cloudflare** | cloudflare dns provider |
|
||||
| 11.| **dns.la** | dns.la |
|
||||
| 12.| **godaddy** | GoDaddy |
|
||||
| 13.| **HiPM DNSMgr** | HiPM DNSMgr DNS 解析提供商 |
|
||||
| 14.| **华为云** | 华为云DNS解析提供商 |
|
||||
| 15.| **namesilo** | namesilo dns provider |
|
||||
| 16.| **雨云** | 雨云DNS解析提供商 |
|
||||
| 17.| **Technitium DNS Server** | Technitium DNS Server 自建DNS服务器 |
|
||||
| 18.| **腾讯云** | 腾讯云域名DNS解析提供者 |
|
||||
| 19.| **腾讯云EO DNS** | 腾讯云EO DNS解析提供者 |
|
||||
| 20.| **西部数码** | west dns provider |
|
||||
| 21.| **Google Cloud DNS** | Google Cloud DNS提供商 |
|
||||
| 22.| **Dns提供商Demo** | dns provider示例 |
|
||||
| 23.| **彩虹DNS** | 彩虹DNS管理系统 |
|
||||
| 24.| **Spaceship** | Spaceship 域名解析 |
|
||||
| 25.| **51dns** | 51DNS |
|
||||
| 26.| **新网互联** | 新网互联 |
|
||||
| 3.| **腾讯云** | 腾讯云域名DNS解析提供者 |
|
||||
| 4.| **腾讯云EO DNS** | 腾讯云EO DNS解析提供者 |
|
||||
| 5.| **AWS Route53** | AWS Route53 DNS解析提供商 |
|
||||
| 6.| **Azure DNS** | Azure DNS 解析提供商 |
|
||||
| 7.| **cloudflare** | cloudflare dns provider |
|
||||
| 8.| **华为云** | 华为云DNS解析提供商 |
|
||||
| 9.| **火山引擎** | 火山引擎DNS解析提供商 |
|
||||
| 10.| **Google Cloud DNS** | Google Cloud DNS提供商 |
|
||||
| 11.| **京东云** | 京东云DNS解析提供商 |
|
||||
| 12.| **新网(代理方式)** | 新网域名解析(代理方式) |
|
||||
| 13.| **新网** | 新网域名解析 |
|
||||
| 14.| **BIND9 DNS** | 通过 SSH 连接到 BIND9 服务器,使用 nsupdate 命令管理 DNS 记录 |
|
||||
| 15.| **dns.la** | dns.la |
|
||||
| 16.| **Dynadot** | Dynadot DNS提供商 |
|
||||
| 17.| **godaddy** | GoDaddy |
|
||||
| 18.| **HiPM DNSMgr** | HiPM DNSMgr DNS 解析提供商 |
|
||||
| 19.| **namesilo** | namesilo dns provider |
|
||||
| 20.| **雨云** | 雨云DNS解析提供商 |
|
||||
| 21.| **Technitium DNS Server** | Technitium DNS Server 自建DNS服务器 |
|
||||
| 22.| **西部数码** | west dns provider |
|
||||
| 23.| **Dns提供商Demo** | dns provider示例 |
|
||||
| 24.| **彩虹DNS** | 彩虹DNS管理系统 |
|
||||
| 25.| **Spaceship** | Spaceship 域名解析 |
|
||||
| 26.| **51dns** | 51DNS |
|
||||
| 27.| **新网互联** | 新网互联 |
|
||||
|
||||
<style module>
|
||||
table th:first-of-type {
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
|
||||
* [支付宝支付配置](./payments/alipay.md)
|
||||
* [微信支付配置](./payments/wxpay.md)
|
||||
* [彩虹易支付配置](./payments/yizhifu.md)
|
||||
* [彩虹易支付配置](./payments/yizhifu.md)
|
||||
* [插件选项映射](./plugin/)
|
||||
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 133 KiB |
@@ -0,0 +1,37 @@
|
||||
# 插件选项映射
|
||||
|
||||
商业版可以通过插件配置,自定义插件中下拉选择框的选项显示内容。
|
||||
|
||||
## 适用场景
|
||||
|
||||
插件中部分下拉选择框的选项可能带有"免费"、"测试"等字眼,商业版运营场景下需要隐藏或改写这些文字。
|
||||
|
||||
## 配置方式
|
||||
|
||||
1. 进入"系统管理" → "插件管理"
|
||||
2. 找到需要配置的插件(如 CertApply 证书申请),点击"配置"按钮
|
||||
3. 在"插件参数自定义"对话框中,找到带有下拉选项的参数(如"证书颁发机构")
|
||||
4. 该参数的配置行会多出一项"选项映射",点击"自定义"
|
||||
|
||||
### 填写映射关系
|
||||
|
||||

|
||||
|
||||
系统会列出该下拉框的所有**选项值**和**原始显示内容**:
|
||||
|
||||
| 选项值 | 原始显示 | 自定义显示 |
|
||||
|---|---|---|
|
||||
| letsencrypt | Let's Encrypt(免费,新手推荐,支持IP证书) | [输入框] |
|
||||
| google | Google(免费) | [输入框] |
|
||||
|
||||
- "自定义显示"一列为输入框,默认 placeholder 显示原始内容
|
||||
- 只需填写**需要改写**的选项,留空的选项将保持原始显示
|
||||
- 例如:将 Let's Encrypt(免费,新手推荐,支持IP证书) 改写为 Let's Encrypt
|
||||
|
||||
### 保存生效
|
||||
|
||||

|
||||
|
||||
填写完成后保存配置,用户在创建证书流水线时看到的选项文字即会变更为自定义内容。
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 92 KiB |
@@ -2,13 +2,13 @@
|
||||
|
||||
|
||||
## 腾讯企业邮箱配置
|
||||
1. 开启smtp
|
||||
1. 开启smtp
|
||||

|
||||
2. 获取授权码作为密码
|
||||
2. 获取授权码作为密码
|
||||

|
||||

|
||||
3. 填写域名、端口和密码
|
||||

|
||||
3. 填写域名、端口和密码
|
||||

|
||||
|
||||
## QQ邮箱配置
|
||||
1. smtp配置
|
||||
@@ -19,5 +19,7 @@ smtp端口: 465
|
||||
是否SSL: 是
|
||||
```
|
||||
|
||||
2. 获取授权码
|
||||
2. 获取授权码
|
||||
登录qq邮箱,点击账号与安全
|
||||
|
||||

|
||||
|
||||
@@ -46,8 +46,9 @@ docker compose up -d
|
||||
> 如果忘记管理员账号,请查看修改密码时的启动日志,会打印管理员账号名
|
||||
|
||||
|
||||
## 二、仅有第三方登录,没有登录窗口
|
||||
## 二、仅有第三方登录,没有登录窗口 / 自动跳到第三方登录等
|
||||
|
||||
当开启仅使用第三方登录模式时,如果第三方登录未配置或已失效,则会导致无法登录
|
||||
服务重启后的前10分钟内,可以访问 `http://你的certd地址/#/login?oauthOnly=false` 显示密码登录入口。
|
||||
|
||||
您可以通过访问 `http://你的certd地址/#/login?oauthOnly=false` 来临时关闭仅使用第三方登录模式,以使用密码登录。
|
||||
> 注意:仅使用第三方登录开启后,仅限于服务重启后的前10分钟内可使用密码登录;超过窗口期即使`oauthOnly=false`,也无法使用密码登录。
|
||||
|
||||
|
After Width: | Height: | Size: 379 KiB |
@@ -1,15 +1,23 @@
|
||||
# google证书申请教程
|
||||
|
||||
## 1、启用API
|
||||
## 1、 添加流水线
|
||||
|
||||
点击“创建证书流水线”按钮
|
||||
|
||||
## 2、 生成google ACME账号
|
||||
|
||||

|
||||
|
||||
## 3、 获取Google EAB
|
||||
|
||||
### 3.1、启用API
|
||||
打开如下链接,启用 API
|
||||
|
||||
https://console.cloud.google.com/apis/library/publicca.googleapis.com
|
||||
|
||||
打开该链接后点击“启用”,随后等待右侧出现“API已启用”则可以关闭该页。
|
||||
|
||||
## 2、 获取授权
|
||||
以下两种方式任选其一
|
||||
### 2.1 直接获取EAB 【推荐】
|
||||
## 3.2、 创建EAB
|
||||
|
||||
|
||||
1. 打开“Google Cloud Shell”(在右上角点击激活CloudShell图标)。
|
||||
@@ -28,31 +36,13 @@ keyId: xxxxxxxxxxxxx]
|
||||
```
|
||||

|
||||
|
||||
3. 到Certd中,创建一条EAB授权记录,填写keyId(=kid) 和 b64MacKey 信息
|
||||
3. 到Certd中,创建一条EAB授权记录,填写keyId(=kid) 和 b64MacKey 信息
|
||||
注意:keyId没有`]`结尾,不要把`]`也复制了
|
||||
|
||||
## 4、 生成Google ACME账号
|
||||
|
||||
注意:EAB授权使用过一次之后,会绑定邮箱,后续再次使用时,要使用相同的邮箱,所以邮箱切记不要修改
|
||||
否则会报错 `Unknown external account binding (EAB) key. This may be due to the EAB key expiring which occurs 7 days after creation`
|
||||
|
||||
4. 创建证书流水线,选择证书提供商为google,选择EAB授权,运行流水线申请证书
|
||||
|
||||
|
||||
### 2.2 通过google服务账号接口获取授权
|
||||
|
||||
此方式可以自动获取EAB,需要服务端配置代理
|
||||
|
||||
1. 创建服务账号
|
||||
https://console.cloud.google.com/projectselector2/iam-admin/serviceaccounts/create?walkthrough_id=iam--create-service-account&hl=zh-cn#step_index=1
|
||||
|
||||
2. 选择一个项目,进入创建服务账号页面
|
||||
3. 给服务账号起一个名字,点击`创建并继续`
|
||||
4. 向此服务账号授予对项目的访问权限: `选择角色`->`基本`->`Owner`
|
||||
5. 点击完成
|
||||
6. 点击服务账号,进入服务账号详情页面
|
||||
7. 点击`添加密钥`->`创建新密钥`->`JSON`,下载密钥文件
|
||||
8. 将json文件内容粘贴到 certd中 Google服务授权输入框中
|
||||
|
||||
9. 创建证书流水线,选择证书提供商为google, 选择服务账号授权,运行流水线申请证书
|
||||
|
||||
|
||||
## 5、创建证书流水线,运行流水线申请证书
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
`Certd`默认启用https,监听7002端口
|
||||
如果你想关闭https,或者修改端口,可以在环境变量中配置
|
||||
```shell
|
||||
CERTD_HTTPS_ENABLE=true
|
||||
CERTD_HTTPS_port=7002
|
||||
certd_https_enabled=true
|
||||
certd_https_port=7002
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.40.3"
|
||||
"version": "1.45.0"
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
"vitepress-plugin-lightbox": "^1.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "lerna bootstrap --hoist",
|
||||
"start:server": "cd ./packages/ui/certd-server && pnpm start",
|
||||
"start": "cd ./packages/ui/certd-server && pnpm start",
|
||||
"devb": "lerna run dev-build",
|
||||
"i-all": "lerna link && lerna exec npm install ",
|
||||
"publish": "pnpm run prepublishOnly2 && lerna publish --force-publish=pro/plus-core --conventional-commits && pnpm run afterpublishOnly ",
|
||||
"publish2": " npm run pub_all && pnpm run afterpublishOnly",
|
||||
"afterpublishOnly": "pnpm run copylogs && time /t >trigger/build.trigger && git add ./trigger/build.trigger && git commit -m \"build: trigger build image\" && TIMEOUT /T 10 && pnpm run commitAll",
|
||||
"transform-sql": "cd ./packages/ui/certd-server/db/ && node --experimental-json-modules transform.js",
|
||||
"plugin-doc-gen": "cd ./packages/ui/certd-server/ && pnpm run export-metadata",
|
||||
@@ -27,7 +27,7 @@
|
||||
"commitPro": "cd ./packages/pro/ && git add . && git commit -m \"build: publish\" && git push",
|
||||
"copylogs": "copyfiles \"CHANGELOG.md\" ./docs/guide/changelogs/",
|
||||
"prepublishOnly1": "pnpm run test:unit && pnpm run check && lerna run build ",
|
||||
"prepublishOnly2": "pnpm run test:unit && pnpm run check && pnpm run before-build && lerna run build && pnpm run plugin-doc-gen",
|
||||
"prepublishOnly2": "pnpm run before-build && lerna run build && pnpm run test:unit && pnpm run check && pnpm run plugin-doc-gen",
|
||||
"before-build": "pnpm run transform-sql && cd ./packages/core/basic && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"",
|
||||
"deploy1": "node --experimental-json-modules ./scripts/deploy.js ",
|
||||
"check": "node --experimental-json-modules ./scripts/publish-check.js",
|
||||
@@ -39,18 +39,20 @@
|
||||
"test:unit": "cross-env NODE_ENV=unittest pnpm -r --workspace-concurrency=1 run test:unit",
|
||||
"pub": "echo 1",
|
||||
"dev": "pnpm run -r --parallel compile ",
|
||||
"pub_all":"pnpm run -r --parallel pub ",
|
||||
"lint_all": "pnpm run -r --parallel lint ",
|
||||
"pub_all": "node ./scripts/pub-all.js",
|
||||
"release": "time /t >trigger/release.trigger && git add trigger/release.trigger && git commit -m \"build: release\" && git push",
|
||||
"publish_to_atomgit": "node --experimental-json-modules ./scripts/publish-atomgit.js",
|
||||
"publish_to_gitee": "node --experimental-json-modules ./scripts/publish-gitee.js",
|
||||
"publish_to_github": "node --experimental-json-modules ./scripts/publish-github.js",
|
||||
"get_version": "node --experimental-json-modules ./scripts/version.js"
|
||||
"get_version": "node --experimental-json-modules ./scripts/version.js",
|
||||
"stable": "node ./scripts/stable.js",
|
||||
"set-release-stable": "node ./scripts/set-release-stable.js"
|
||||
},
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"copyfiles": "^2.4.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"root": "link:",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"workspaces": [
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
"ecmaVersion": 2022,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"dist",
|
||||
"node_modules"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:prettier/recommended",
|
||||
"prettier"
|
||||
@@ -36,5 +32,9 @@
|
||||
"ignoreUrls": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"node_modules/**",
|
||||
"dist/**"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,6 +3,111 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.45.0](https://github.com/publishlab/node-acme-client/compare/v1.44.4...v1.45.0) (2026-10-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 支持google persist校验方式 ([97d2b50](https://github.com/publishlab/node-acme-client/commit/97d2b5007409ec79ea864d437c473a2f9b5dfae4))
|
||||
|
||||
## [1.44.4](https://github.com/publishlab/node-acme-client/compare/v1.44.3...v1.44.4) (2026-09-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.44.3](https://github.com/publishlab/node-acme-client/compare/v1.44.2...v1.44.3) (2026-09-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.44.2](https://github.com/publishlab/node-acme-client/compare/v1.44.1...v1.44.2) (2026-09-03)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.44.1](https://github.com/publishlab/node-acme-client/compare/v1.44.0...v1.44.1) (2026-09-02)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
# [1.44.0](https://github.com/publishlab/node-acme-client/compare/v1.43.0...v1.44.0) (2026-08-28)
|
||||
|
||||
### Features
|
||||
|
||||
* 新增证书吊销后置任务与证书状态管理 ([1cc9641](https://github.com/publishlab/node-acme-client/commit/1cc9641f5669710d1e5809995ad395c843855a12))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 新增证书吊销功能,添加证书状态字段 ([5074572](https://github.com/publishlab/node-acme-client/commit/5074572694383c8e1bf2880e26827987683dc62c))
|
||||
* 移除全局反向代理配置,迁移到自定义ACME配置 ([c57110e](https://github.com/publishlab/node-acme-client/commit/c57110e42aada31dd0028b56b5baec1b19722525))
|
||||
|
||||
# [1.43.0](https://github.com/publishlab/node-acme-client/compare/v1.42.6...v1.43.0) (2026-08-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.42.6](https://github.com/publishlab/node-acme-client/compare/v1.42.5...v1.42.6) (2026-07-18)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.42.5](https://github.com/publishlab/node-acme-client/compare/v1.42.4...v1.42.5) (2026-07-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.42.4](https://github.com/publishlab/node-acme-client/compare/v1.42.3...v1.42.4) (2026-07-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.42.3](https://github.com/publishlab/node-acme-client/compare/v1.42.2...v1.42.3) (2026-07-08)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.42.2](https://github.com/publishlab/node-acme-client/compare/v1.42.1...v1.42.2) (2026-07-07)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.42.1](https://github.com/publishlab/node-acme-client/compare/v1.42.0...v1.42.1) (2026-07-06)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
# [1.42.0](https://github.com/publishlab/node-acme-client/compare/v1.41.4...v1.42.0) (2026-07-05)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 新增橙域网络(asia-isp) CDN证书部署插件 ([b48831e](https://github.com/publishlab/node-acme-client/commit/b48831e60b0059bef7ef9a34ab61c9dd2f684641))
|
||||
|
||||
## [1.41.4](https://github.com/publishlab/node-acme-client/compare/v1.41.3...v1.41.4) (2026-06-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.41.3](https://github.com/publishlab/node-acme-client/compare/v1.41.2...v1.41.3) (2026-06-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复litessl无法申请证书,报authorization must be pending 错误的问题 ([d6cd9d1](https://github.com/publishlab/node-acme-client/commit/d6cd9d136d2812b2335917305f36d6d9414507ad))
|
||||
|
||||
## [1.41.2](https://github.com/publishlab/node-acme-client/compare/v1.41.1...v1.41.2) (2026-06-10)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.41.1](https://github.com/publishlab/node-acme-client/compare/v1.41.0...v1.41.1) (2026-06-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
# [1.41.0](https://github.com/publishlab/node-acme-client/compare/v1.40.5...v1.41.0) (2026-06-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云证书订单orderid 选择出错的问题 ([41254d1](https://github.com/publishlab/node-acme-client/commit/41254d10b748a2d3e6ba43c7e11411650c748d1b))
|
||||
|
||||
### Features
|
||||
|
||||
* 支持dns-persist-01持久化验证方式申请证书,优化Acme账号的存储方式 ([67b05e2](https://github.com/publishlab/node-acme-client/commit/67b05e2d75e96b9f855e1ca0b3d0d8d03b92d8e6))
|
||||
|
||||
## [1.40.5](https://github.com/publishlab/node-acme-client/compare/v1.40.4...v1.40.5) (2026-05-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云证书订单orderid 选择出错的问题 ([af9047b](https://github.com/publishlab/node-acme-client/commit/af9047bf3c54ce71b11727ccc6220288ed1f57be))
|
||||
|
||||
## [1.40.4](https://github.com/publishlab/node-acme-client/compare/v1.40.3...v1.40.4) (2026-05-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.40.3](https://github.com/publishlab/node-acme-client/compare/v1.40.2...v1.40.3) (2026-05-21)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
@@ -147,21 +147,6 @@ const autoOpts = {
|
||||
const certificate = await client.auto(autoOpts);
|
||||
```
|
||||
|
||||
### Challenge priority
|
||||
|
||||
When ordering a certificate using auto mode, `acme-client` uses a priority list when selecting challenges to respond to. Its default value is `['http-01', 'dns-01']` which translates to "use `http-01` if any challenges exist, otherwise fall back to `dns-01`".
|
||||
|
||||
While most challenges can be validated using the method of your choosing, please note that **wildcard certificates can only be validated through `dns-01`**. More information regarding Let's Encrypt challenge types [can be found here](https://letsencrypt.org/docs/challenge-types/).
|
||||
|
||||
To modify challenge priority, provide a list of challenge types in `challengePriority`:
|
||||
|
||||
```js
|
||||
await client.auto({
|
||||
...,
|
||||
challengePriority: ['http-01', 'dns-01'],
|
||||
});
|
||||
```
|
||||
|
||||
### Internal challenge verification
|
||||
|
||||
When using auto mode, `acme-client` will first validate that challenges are satisfied internally before completing the challenge at the ACME provider. In some cases (firewalls, etc) this internal challenge verification might not be possible to complete.
|
||||
|
||||
@@ -1,518 +0,0 @@
|
||||
## Classes
|
||||
|
||||
<dl>
|
||||
<dt><a href="#AcmeClient">AcmeClient</a></dt>
|
||||
<dd><p>AcmeClient</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
## Objects
|
||||
|
||||
<dl>
|
||||
<dt><a href="#Client">Client</a> : <code>object</code></dt>
|
||||
<dd><p>ACME client</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="AcmeClient"></a>
|
||||
|
||||
## AcmeClient
|
||||
AcmeClient
|
||||
|
||||
**Kind**: global class
|
||||
|
||||
* [AcmeClient](#AcmeClient)
|
||||
* [new AcmeClient(opts)](#new_AcmeClient_new)
|
||||
* [.getTermsOfServiceUrl()](#AcmeClient+getTermsOfServiceUrl) ⇒ <code>Promise.<(string\|null)></code>
|
||||
* [.getAccountUrl()](#AcmeClient+getAccountUrl) ⇒ <code>string</code>
|
||||
* [.createAccount([data])](#AcmeClient+createAccount) ⇒ <code>Promise.<object></code>
|
||||
* [.updateAccount([data])](#AcmeClient+updateAccount) ⇒ <code>Promise.<object></code>
|
||||
* [.updateAccountKey(newAccountKey, [data])](#AcmeClient+updateAccountKey) ⇒ <code>Promise.<object></code>
|
||||
* [.createOrder(data)](#AcmeClient+createOrder) ⇒ <code>Promise.<object></code>
|
||||
* [.getOrder(order)](#AcmeClient+getOrder) ⇒ <code>Promise.<object></code>
|
||||
* [.finalizeOrder(order, csr)](#AcmeClient+finalizeOrder) ⇒ <code>Promise.<object></code>
|
||||
* [.getAuthorizations(order)](#AcmeClient+getAuthorizations) ⇒ <code>Promise.<Array.<object>></code>
|
||||
* [.deactivateAuthorization(authz)](#AcmeClient+deactivateAuthorization) ⇒ <code>Promise.<object></code>
|
||||
* [.getChallengeKeyAuthorization(challenge)](#AcmeClient+getChallengeKeyAuthorization) ⇒ <code>Promise.<string></code>
|
||||
* [.verifyChallenge(authz, challenge)](#AcmeClient+verifyChallenge) ⇒ <code>Promise</code>
|
||||
* [.completeChallenge(challenge)](#AcmeClient+completeChallenge) ⇒ <code>Promise.<object></code>
|
||||
* [.waitForValidStatus(item)](#AcmeClient+waitForValidStatus) ⇒ <code>Promise.<object></code>
|
||||
* [.getCertificate(order, [preferredChain])](#AcmeClient+getCertificate) ⇒ <code>Promise.<string></code>
|
||||
* [.revokeCertificate(cert, [data])](#AcmeClient+revokeCertificate) ⇒ <code>Promise</code>
|
||||
* [.auto(opts)](#AcmeClient+auto) ⇒ <code>Promise.<string></code>
|
||||
|
||||
<a name="new_AcmeClient_new"></a>
|
||||
|
||||
### new AcmeClient(opts)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| opts | <code>object</code> | |
|
||||
| opts.directoryUrl | <code>string</code> | ACME directory URL |
|
||||
| opts.accountKey | <code>buffer</code> \| <code>string</code> | PEM encoded account private key |
|
||||
| [opts.accountUrl] | <code>string</code> | Account URL, default: `null` |
|
||||
| [opts.externalAccountBinding] | <code>object</code> | |
|
||||
| [opts.externalAccountBinding.kid] | <code>string</code> | External account binding KID |
|
||||
| [opts.externalAccountBinding.hmacKey] | <code>string</code> | External account binding HMAC key |
|
||||
| [opts.backoffAttempts] | <code>number</code> | Maximum number of backoff attempts, default: `10` |
|
||||
| [opts.backoffMin] | <code>number</code> | Minimum backoff attempt delay in milliseconds, default: `5000` |
|
||||
| [opts.backoffMax] | <code>number</code> | Maximum backoff attempt delay in milliseconds, default: `30000` |
|
||||
|
||||
**Example**
|
||||
Create ACME client instance
|
||||
```js
|
||||
const client = new acme.Client({
|
||||
directoryUrl: acme.directory.letsencrypt.staging,
|
||||
accountKey: 'Private key goes here',
|
||||
});
|
||||
```
|
||||
**Example**
|
||||
Create ACME client instance
|
||||
```js
|
||||
const client = new acme.Client({
|
||||
directoryUrl: acme.directory.letsencrypt.staging,
|
||||
accountKey: 'Private key goes here',
|
||||
accountUrl: 'Optional account URL goes here',
|
||||
backoffAttempts: 10,
|
||||
backoffMin: 5000,
|
||||
backoffMax: 30000,
|
||||
});
|
||||
```
|
||||
**Example**
|
||||
Create ACME client with external account binding
|
||||
```js
|
||||
const client = new acme.Client({
|
||||
directoryUrl: 'https://acme-provider.example.com/directory-url',
|
||||
accountKey: 'Private key goes here',
|
||||
externalAccountBinding: {
|
||||
kid: 'YOUR-EAB-KID',
|
||||
hmacKey: 'YOUR-EAB-HMAC-KEY',
|
||||
},
|
||||
});
|
||||
```
|
||||
<a name="AcmeClient+getTermsOfServiceUrl"></a>
|
||||
|
||||
### acmeClient.getTermsOfServiceUrl() ⇒ <code>Promise.<(string\|null)></code>
|
||||
Get Terms of Service URL if available
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<(string\|null)></code> - ToS URL
|
||||
**Example**
|
||||
Get Terms of Service URL
|
||||
```js
|
||||
const termsOfService = client.getTermsOfServiceUrl();
|
||||
|
||||
if (!termsOfService) {
|
||||
// CA did not provide Terms of Service
|
||||
}
|
||||
```
|
||||
<a name="AcmeClient+getAccountUrl"></a>
|
||||
|
||||
### acmeClient.getAccountUrl() ⇒ <code>string</code>
|
||||
Get current account URL
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>string</code> - Account URL
|
||||
**Throws**:
|
||||
|
||||
- <code>Error</code> No account URL found
|
||||
|
||||
**Example**
|
||||
Get current account URL
|
||||
```js
|
||||
try {
|
||||
const accountUrl = client.getAccountUrl();
|
||||
}
|
||||
catch (e) {
|
||||
// No account URL exists, need to create account first
|
||||
}
|
||||
```
|
||||
<a name="AcmeClient+createAccount"></a>
|
||||
|
||||
### acmeClient.createAccount([data]) ⇒ <code>Promise.<object></code>
|
||||
Create a new account
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.3
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<object></code> - Account
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [data] | <code>object</code> | Request data |
|
||||
|
||||
**Example**
|
||||
Create a new account
|
||||
```js
|
||||
const account = await client.createAccount({
|
||||
termsOfServiceAgreed: true,
|
||||
});
|
||||
```
|
||||
**Example**
|
||||
Create a new account with contact info
|
||||
```js
|
||||
const account = await client.createAccount({
|
||||
termsOfServiceAgreed: true,
|
||||
contact: ['mailto:test@example.com'],
|
||||
});
|
||||
```
|
||||
<a name="AcmeClient+updateAccount"></a>
|
||||
|
||||
### acmeClient.updateAccount([data]) ⇒ <code>Promise.<object></code>
|
||||
Update existing account
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.3.2
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<object></code> - Account
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [data] | <code>object</code> | Request data |
|
||||
|
||||
**Example**
|
||||
Update existing account
|
||||
```js
|
||||
const account = await client.updateAccount({
|
||||
contact: ['mailto:foo@example.com'],
|
||||
});
|
||||
```
|
||||
<a name="AcmeClient+updateAccountKey"></a>
|
||||
|
||||
### acmeClient.updateAccountKey(newAccountKey, [data]) ⇒ <code>Promise.<object></code>
|
||||
Update account private key
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.3.5
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<object></code> - Account
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| newAccountKey | <code>buffer</code> \| <code>string</code> | New PEM encoded private key |
|
||||
| [data] | <code>object</code> | Additional request data |
|
||||
|
||||
**Example**
|
||||
Update account private key
|
||||
```js
|
||||
const newAccountKey = 'New private key goes here';
|
||||
const result = await client.updateAccountKey(newAccountKey);
|
||||
```
|
||||
<a name="AcmeClient+createOrder"></a>
|
||||
|
||||
### acmeClient.createOrder(data) ⇒ <code>Promise.<object></code>
|
||||
Create a new order
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.4
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<object></code> - Order
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| data | <code>object</code> | Request data |
|
||||
|
||||
**Example**
|
||||
Create a new order
|
||||
```js
|
||||
const order = await client.createOrder({
|
||||
identifiers: [
|
||||
{ type: 'dns', value: 'example.com' },
|
||||
{ type: 'dns', value: 'test.example.com' },
|
||||
],
|
||||
});
|
||||
```
|
||||
<a name="AcmeClient+getOrder"></a>
|
||||
|
||||
### acmeClient.getOrder(order) ⇒ <code>Promise.<object></code>
|
||||
Refresh order object from CA
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.4
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<object></code> - Order
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| order | <code>object</code> | Order object |
|
||||
|
||||
**Example**
|
||||
```js
|
||||
const order = { ... }; // Previously created order object
|
||||
const result = await client.getOrder(order);
|
||||
```
|
||||
<a name="AcmeClient+finalizeOrder"></a>
|
||||
|
||||
### acmeClient.finalizeOrder(order, csr) ⇒ <code>Promise.<object></code>
|
||||
Finalize order
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.4
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<object></code> - Order
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| order | <code>object</code> | Order object |
|
||||
| csr | <code>buffer</code> \| <code>string</code> | PEM encoded Certificate Signing Request |
|
||||
|
||||
**Example**
|
||||
Finalize order
|
||||
```js
|
||||
const order = { ... }; // Previously created order object
|
||||
const csr = { ... }; // Previously created Certificate Signing Request
|
||||
const result = await client.finalizeOrder(order, csr);
|
||||
```
|
||||
<a name="AcmeClient+getAuthorizations"></a>
|
||||
|
||||
### acmeClient.getAuthorizations(order) ⇒ <code>Promise.<Array.<object>></code>
|
||||
Get identifier authorizations from order
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.5
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<Array.<object>></code> - Authorizations
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| order | <code>object</code> | Order |
|
||||
|
||||
**Example**
|
||||
Get identifier authorizations
|
||||
```js
|
||||
const order = { ... }; // Previously created order object
|
||||
const authorizations = await client.getAuthorizations(order);
|
||||
|
||||
authorizations.forEach((authz) => {
|
||||
const { challenges } = authz;
|
||||
});
|
||||
```
|
||||
<a name="AcmeClient+deactivateAuthorization"></a>
|
||||
|
||||
### acmeClient.deactivateAuthorization(authz) ⇒ <code>Promise.<object></code>
|
||||
Deactivate identifier authorization
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.2
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<object></code> - Authorization
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| authz | <code>object</code> | Identifier authorization |
|
||||
|
||||
**Example**
|
||||
Deactivate identifier authorization
|
||||
```js
|
||||
const authz = { ... }; // Identifier authorization resolved from previously created order
|
||||
const result = await client.deactivateAuthorization(authz);
|
||||
```
|
||||
<a name="AcmeClient+getChallengeKeyAuthorization"></a>
|
||||
|
||||
### acmeClient.getChallengeKeyAuthorization(challenge) ⇒ <code>Promise.<string></code>
|
||||
Get key authorization for ACME challenge
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-8.1
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<string></code> - Key authorization
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| challenge | <code>object</code> | Challenge object returned by API |
|
||||
|
||||
**Example**
|
||||
Get challenge key authorization
|
||||
```js
|
||||
const challenge = { ... }; // Challenge from previously resolved identifier authorization
|
||||
const key = await client.getChallengeKeyAuthorization(challenge);
|
||||
|
||||
// Write key somewhere to satisfy challenge
|
||||
```
|
||||
<a name="AcmeClient+verifyChallenge"></a>
|
||||
|
||||
### acmeClient.verifyChallenge(authz, challenge) ⇒ <code>Promise</code>
|
||||
Verify that ACME challenge is satisfied
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| authz | <code>object</code> | Identifier authorization |
|
||||
| challenge | <code>object</code> | Authorization challenge |
|
||||
|
||||
**Example**
|
||||
Verify satisfied ACME challenge
|
||||
```js
|
||||
const authz = { ... }; // Identifier authorization
|
||||
const challenge = { ... }; // Satisfied challenge
|
||||
await client.verifyChallenge(authz, challenge);
|
||||
```
|
||||
<a name="AcmeClient+completeChallenge"></a>
|
||||
|
||||
### acmeClient.completeChallenge(challenge) ⇒ <code>Promise.<object></code>
|
||||
Notify CA that challenge has been completed
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.1
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<object></code> - Challenge
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| challenge | <code>object</code> | Challenge object returned by API |
|
||||
|
||||
**Example**
|
||||
Notify CA that challenge has been completed
|
||||
```js
|
||||
const challenge = { ... }; // Satisfied challenge
|
||||
const result = await client.completeChallenge(challenge);
|
||||
```
|
||||
<a name="AcmeClient+waitForValidStatus"></a>
|
||||
|
||||
### acmeClient.waitForValidStatus(item) ⇒ <code>Promise.<object></code>
|
||||
Wait for ACME provider to verify status on a order, authorization or challenge
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.1
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<object></code> - Valid order, authorization or challenge
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| item | <code>object</code> | An order, authorization or challenge object |
|
||||
|
||||
**Example**
|
||||
Wait for valid challenge status
|
||||
```js
|
||||
const challenge = { ... };
|
||||
await client.waitForValidStatus(challenge);
|
||||
```
|
||||
**Example**
|
||||
Wait for valid authorization status
|
||||
```js
|
||||
const authz = { ... };
|
||||
await client.waitForValidStatus(authz);
|
||||
```
|
||||
**Example**
|
||||
Wait for valid order status
|
||||
```js
|
||||
const order = { ... };
|
||||
await client.waitForValidStatus(order);
|
||||
```
|
||||
<a name="AcmeClient+getCertificate"></a>
|
||||
|
||||
### acmeClient.getCertificate(order, [preferredChain]) ⇒ <code>Promise.<string></code>
|
||||
Get certificate from ACME order
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.4.2
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<string></code> - Certificate
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| order | <code>object</code> | | Order object |
|
||||
| [preferredChain] | <code>string</code> | <code>null</code> | Indicate which certificate chain is preferred if a CA offers multiple, by exact issuer common name, default: `null` |
|
||||
|
||||
**Example**
|
||||
Get certificate
|
||||
```js
|
||||
const order = { ... }; // Previously created order
|
||||
const certificate = await client.getCertificate(order);
|
||||
```
|
||||
**Example**
|
||||
Get certificate with preferred chain
|
||||
```js
|
||||
const order = { ... }; // Previously created order
|
||||
const certificate = await client.getCertificate(order, 'DST Root CA X3');
|
||||
```
|
||||
<a name="AcmeClient+revokeCertificate"></a>
|
||||
|
||||
### acmeClient.revokeCertificate(cert, [data]) ⇒ <code>Promise</code>
|
||||
Revoke certificate
|
||||
|
||||
https://datatracker.ietf.org/doc/html/rfc8555#section-7.6
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cert | <code>buffer</code> \| <code>string</code> | PEM encoded certificate |
|
||||
| [data] | <code>object</code> | Additional request data |
|
||||
|
||||
**Example**
|
||||
Revoke certificate
|
||||
```js
|
||||
const certificate = { ... }; // Previously created certificate
|
||||
const result = await client.revokeCertificate(certificate);
|
||||
```
|
||||
**Example**
|
||||
Revoke certificate with reason
|
||||
```js
|
||||
const certificate = { ... }; // Previously created certificate
|
||||
const result = await client.revokeCertificate(certificate, {
|
||||
reason: 4,
|
||||
});
|
||||
```
|
||||
<a name="AcmeClient+auto"></a>
|
||||
|
||||
### acmeClient.auto(opts) ⇒ <code>Promise.<string></code>
|
||||
Auto mode
|
||||
|
||||
**Kind**: instance method of [<code>AcmeClient</code>](#AcmeClient)
|
||||
**Returns**: <code>Promise.<string></code> - Certificate
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| opts | <code>object</code> | |
|
||||
| opts.csr | <code>buffer</code> \| <code>string</code> | Certificate Signing Request |
|
||||
| opts.challengeCreateFn | <code>function</code> | Function returning Promise triggered before completing ACME challenge |
|
||||
| opts.challengeRemoveFn | <code>function</code> | Function returning Promise triggered after completing ACME challenge |
|
||||
| [opts.email] | <code>string</code> | Account email address |
|
||||
| [opts.termsOfServiceAgreed] | <code>boolean</code> | Agree to Terms of Service, default: `false` |
|
||||
| [opts.skipChallengeVerification] | <code>boolean</code> | Skip internal challenge verification before notifying ACME provider, default: `false` |
|
||||
| [opts.challengePriority] | <code>Array.<string></code> | Array defining challenge type priority, default: `['http-01', 'dns-01']` |
|
||||
| [opts.preferredChain] | <code>string</code> | Indicate which certificate chain is preferred if a CA offers multiple, by exact issuer common name, default: `null` |
|
||||
|
||||
**Example**
|
||||
Order a certificate using auto mode
|
||||
```js
|
||||
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||
altNames: ['test.example.com'],
|
||||
});
|
||||
|
||||
const certificate = await client.auto({
|
||||
csr: certificateRequest,
|
||||
email: 'test@example.com',
|
||||
termsOfServiceAgreed: true,
|
||||
challengeCreateFn: async (authz, challenge, keyAuthorization) => {
|
||||
// Satisfy challenge here
|
||||
},
|
||||
challengeRemoveFn: async (authz, challenge, keyAuthorization) => {
|
||||
// Clean up challenge here
|
||||
},
|
||||
});
|
||||
```
|
||||
**Example**
|
||||
Order a certificate using auto mode with preferred chain
|
||||
```js
|
||||
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||
altNames: ['test.example.com'],
|
||||
});
|
||||
|
||||
const certificate = await client.auto({
|
||||
csr: certificateRequest,
|
||||
email: 'test@example.com',
|
||||
termsOfServiceAgreed: true,
|
||||
preferredChain: 'DST Root CA X3',
|
||||
challengeCreateFn: async () => {},
|
||||
challengeRemoveFn: async () => {},
|
||||
});
|
||||
```
|
||||
<a name="Client"></a>
|
||||
|
||||
## Client : <code>object</code>
|
||||
ACME client
|
||||
|
||||
**Kind**: global namespace
|
||||
|
||||
@@ -49,7 +49,6 @@ function log(m) {
|
||||
csr,
|
||||
email: 'test@example.com',
|
||||
termsOfServiceAgreed: true,
|
||||
challengePriority: ['dns-01'],
|
||||
challengeCreateFn: (authz, challenge, keyAuthorization) => {
|
||||
/* TODO: Implement this */
|
||||
log(`[TODO] Add TXT record key=_acme-challenge.${authz.identifier.value} value=${keyAuthorization}`);
|
||||
|
||||
@@ -60,7 +60,6 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
||||
csr,
|
||||
email: 'test@example.com',
|
||||
termsOfServiceAgreed: true,
|
||||
challengePriority: ['http-01'],
|
||||
challengeCreateFn: (authz, challenge, keyAuthorization) => {
|
||||
challengeResponses[challenge.token] = keyAuthorization;
|
||||
},
|
||||
|
||||
@@ -59,7 +59,6 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
||||
csr,
|
||||
email: 'test@example.com',
|
||||
termsOfServiceAgreed: true,
|
||||
challengePriority: ['tls-alpn-01'],
|
||||
challengeCreateFn: async (authz, challenge, keyAuthorization) => {
|
||||
alpnResponses[authz.identifier.value] = await acme.crypto.createAlpnCertificate(authz, keyAuthorization);
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.40.3",
|
||||
"version": "1.45.0",
|
||||
"type": "module",
|
||||
"module": "./dist/index.js",
|
||||
"main": "./dist/index.js",
|
||||
@@ -18,7 +18,7 @@
|
||||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.40.3",
|
||||
"@certd/basic": "^1.45.0",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.9.0",
|
||||
@@ -27,39 +27,40 @@
|
||||
"https-proxy-agent": "^7.0.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"node-forge": "^1.3.1",
|
||||
"psl": "^1.15.0",
|
||||
"punycode.js": "^2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.14.10",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"chai": "^4.4.1",
|
||||
"chai": "^5.1.0",
|
||||
"chai-as-promised": "^7.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"esmock": "^2.7.5",
|
||||
"jsdoc-to-markdown": "^8.0.1",
|
||||
"mocha": "^10.6.0",
|
||||
"nock": "^13.5.4",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier": "3.3.3",
|
||||
"rimraf": "^5.0.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsd": "^0.31.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"scripts": {
|
||||
"before-build": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true});fs.rmSync('tsconfig.tsbuildinfo',{force:true});\"",
|
||||
"before-build": "rimraf dist && rimraf dist-test && rimraf tsconfig.tsbuildinfo && rimraf .rollup.cache",
|
||||
"build": "npm run before-build && tsc -p tsconfig.build.json --skipLibCheck",
|
||||
"build-docs": "jsdoc2md dist/client.js > docs/client.md && jsdoc2md dist/crypto/index.js > docs/crypto.md && jsdoc2md dist/crypto/forge.js > docs/forge.md",
|
||||
"lint": "eslint \"src/**/*.ts\" \"types/**/*.ts\"",
|
||||
"lint": "eslint --fix \"src/**/*.ts\" \"types/**/*.ts\"",
|
||||
"lint-types": "tsd --files \"types/index.test-d.ts\"",
|
||||
"prepublishOnly": "npm run build && npm run build-docs",
|
||||
"prepublishOnly": "npm run build",
|
||||
"test": "mocha -t 60000 \"test/setup.js\" \"test/**/*.spec.js\"",
|
||||
"before-test:unit": "node -e \"const fs=require('fs');fs.rmSync('dist-test',{recursive:true,force:true});fs.rmSync('tsconfig.test.tsbuildinfo',{force:true});\"",
|
||||
"test:unit": "cross-env NODE_ENV=unittest npm run before-test:unit && cross-env NODE_ENV=unittest tsc -p tsconfig.test.json --skipLibCheck && cross-env NODE_ENV=unittest mocha -t 60000 \"dist-test/**/*.test.js\"",
|
||||
"test:unit": "cross-env NODE_ENV=unittest mocha --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
||||
"pub": "npm publish",
|
||||
"compile": "tsc --skipLibCheck --watch"
|
||||
"compile": " tsc --skipLibCheck --watch",
|
||||
"format": "prettier --write src"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -76,5 +77,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "678b70cee8510a2b5217788c5db9469f49cbd439"
|
||||
"gitHead": "fcbf1045fe3806fa1a0bebf5038a6f67aec283d0"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* ACME API client
|
||||
*/
|
||||
@@ -20,6 +20,7 @@ class AcmeApi {
|
||||
getLocationFromHeader(resp) {
|
||||
let locationUrl = resp.headers.location;
|
||||
const mapping = this.http.urlMapping;
|
||||
// 服务器返回的是反代地址,这里还原为 ACME 原始资源 URL,供后续 JWS url 使用。
|
||||
if (mapping.mappings) {
|
||||
// eslint-disable-next-line guard-for-in,no-restricted-syntax
|
||||
for (const key in mapping.mappings) {
|
||||
@@ -237,11 +238,12 @@ class AcmeApi {
|
||||
* https://datatracker.ietf.org/doc/html/rfc8555#section-7.6
|
||||
*
|
||||
* @param {object} data Request payload
|
||||
* @param {object} [opts] Request options, e.g. `{ includeJwsKid: false }` to sign with certificate private key (jwk) instead of account key
|
||||
* @returns {Promise<object>} HTTP response
|
||||
*/
|
||||
|
||||
revokeCert(data) {
|
||||
return this.apiResourceRequest('revokeCert', data, [200]);
|
||||
revokeCert(data, opts = {}) {
|
||||
return this.apiResourceRequest('revokeCert', data, [200], opts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import assert from "node:assert/strict";
|
||||
import auto from "./auto.js";
|
||||
import { createCsr, createPrivateRsaKey } from "./crypto/index.js";
|
||||
|
||||
declare const describe: any;
|
||||
declare const it: any;
|
||||
|
||||
describe("auto challenge status polling", () => {
|
||||
it("polls the authorization URL after completing a challenge", async () => {
|
||||
const [, csr] = await createCsr({ commonName: "example.com" }, await createPrivateRsaKey());
|
||||
const challenge = {
|
||||
type: "dns-01",
|
||||
url: "https://ca.example/chall/1",
|
||||
token: "token",
|
||||
};
|
||||
const authz = {
|
||||
status: "pending",
|
||||
identifier: { type: "dns", value: "example.com" },
|
||||
url: "https://ca.example/authz/1",
|
||||
challenges: [challenge],
|
||||
};
|
||||
const order = {
|
||||
status: "pending",
|
||||
url: "https://ca.example/order/1",
|
||||
finalize: "https://ca.example/order/1/finalize",
|
||||
authorizations: [authz.url],
|
||||
};
|
||||
const polledUrls: string[] = [];
|
||||
const originalSetTimeout = globalThis.setTimeout;
|
||||
|
||||
(globalThis as any).setTimeout = (fn: (...args: any[]) => void) => originalSetTimeout(fn, 0);
|
||||
|
||||
try {
|
||||
const certificate = await auto(
|
||||
{
|
||||
logger: { info: () => {} },
|
||||
sslProvider: "litessl",
|
||||
getAccountUrl: () => "https://ca.example/acct/1",
|
||||
createOrder: async () => order,
|
||||
getAuthorizations: async () => [authz],
|
||||
getChallengeKeyAuthorization: async () => "key-authorization",
|
||||
verifyChallenge: async () => {},
|
||||
completeChallenge: async () => ({ ...challenge, status: "processing" }),
|
||||
waitForValidStatus: async (item: { url: string }) => {
|
||||
polledUrls.push(item.url);
|
||||
return { ...item, status: "valid" };
|
||||
},
|
||||
finalizeOrder: async () => ({ ...order, status: "valid", certificate: "https://ca.example/cert/1" }),
|
||||
getCertificate: async () => "CERTIFICATE",
|
||||
} as any,
|
||||
{
|
||||
csr,
|
||||
termsOfServiceAgreed: true,
|
||||
waitDnsDiffuseTime: 0,
|
||||
challengeCreateFn: async (_authz: any, keyAuthorizationGetter: (challenge: any) => Promise<string>) => ({
|
||||
challenge,
|
||||
keyAuthorization: await keyAuthorizationGetter(challenge),
|
||||
}),
|
||||
challengeRemoveFn: async () => {},
|
||||
}
|
||||
);
|
||||
|
||||
assert.equal(certificate, "CERTIFICATE");
|
||||
assert.deepEqual(polledUrls, [authz.url]);
|
||||
} finally {
|
||||
(globalThis as any).setTimeout = originalSetTimeout;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -16,7 +16,6 @@ const defaultOpts = {
|
||||
preferredChain: null,
|
||||
termsOfServiceAgreed: false,
|
||||
skipChallengeVerification: false,
|
||||
challengePriority: ["http-01", "dns-01"],
|
||||
challengeCreateFn: async () => {
|
||||
throw new Error("Missing challengeCreateFn()");
|
||||
},
|
||||
@@ -172,7 +171,7 @@ export default async (client, userOpts) => {
|
||||
}
|
||||
challengeCompleted = true;
|
||||
log(`[auto] [${d}] 等待返回valid状态`);
|
||||
await client.waitForValidStatus(challenge,d);
|
||||
await client.waitForValidStatus(authz,d);
|
||||
});
|
||||
|
||||
|
||||
@@ -277,7 +276,7 @@ export default async (client, userOpts) => {
|
||||
}
|
||||
|
||||
log("开始向提供商请求检查验证");
|
||||
await runPromisePa(completeChallengeTasks, 1000);
|
||||
await runPromisePa(completeChallengeTasks, 4000);
|
||||
} catch (e) {
|
||||
log(`证书申请失败${e.message}`);
|
||||
throw e;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Axios instance
|
||||
*/
|
||||
import axios from 'axios';
|
||||
import { parseRetryAfterHeader } from './util.js';
|
||||
const { AxiosError } = axios;
|
||||
import {getGlobalAgents, HttpError} from '@certd/basic'
|
||||
import { log } from './logger.js';
|
||||
@@ -113,12 +112,9 @@ instance.interceptors.response.use(null, async (error) => {
|
||||
log(`Caught ${code}, retry attempt ${config.retryAttempt}/${retryMaxAttempts} to URL ${config.url}`);
|
||||
|
||||
const retryAfter = (retryDefaultDelay * config.retryAttempt);
|
||||
/* Attempt to parse Retry-After header, fallback to default delay */
|
||||
const headerRetryAfter = response ? parseRetryAfterHeader(response.headers['retry-after']) : 0;
|
||||
|
||||
if (headerRetryAfter > 0) {
|
||||
const waitMinutes = (headerRetryAfter / 60).toFixed(1);
|
||||
log(`Found retry-after response header with value: ${response.headers['retry-after']}, waiting ${waitMinutes} minutes`);
|
||||
if (response?.status === 429) {
|
||||
// CA 限流按产品策略立即失败,不能依据 Retry-After 自动重试,避免继续消耗配额。
|
||||
log(`CA rate limit encountered (HTTP 429), failing immediately; Retry-After=${response.headers['retry-after']}`);
|
||||
log(JSON.stringify(response.data));
|
||||
return Promise.reject(new HttpError(error));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* ACME client
|
||||
*
|
||||
@@ -263,7 +263,14 @@ class AcmeClient {
|
||||
const accountUrl = this.api.getAccountUrl();
|
||||
|
||||
/* Create new HTTP and API clients using new key */
|
||||
const newHttpClient = new HttpClient(this.opts.directoryUrl, newAccountKey, this.opts.externalAccountBinding);
|
||||
const newHttpClient = new HttpClient(
|
||||
this.opts.directoryUrl,
|
||||
newAccountKey,
|
||||
this.opts.externalAccountBinding,
|
||||
this.opts.urlMapping,
|
||||
this.logger,
|
||||
true,
|
||||
);
|
||||
const newApiClient = new AcmeApi(newHttpClient, accountUrl);
|
||||
|
||||
/* Get old JWK */
|
||||
@@ -280,6 +287,8 @@ class AcmeClient {
|
||||
/* Replace existing HTTP and API client */
|
||||
this.http = newHttpClient;
|
||||
this.api = newApiClient;
|
||||
// 更新本地配置,避免后续重建客户端时又使用旧账号密钥。
|
||||
this.opts.accountKey = newAccountKey;
|
||||
|
||||
return resp.data;
|
||||
}
|
||||
@@ -467,6 +476,10 @@ class AcmeClient {
|
||||
return createHash('sha256').update(result).digest('base64url');
|
||||
}
|
||||
|
||||
if (challenge.type === 'dns-persist-01') {
|
||||
return '';
|
||||
}
|
||||
|
||||
/* https://datatracker.ietf.org/doc/html/rfc8737 */
|
||||
if (challenge.type === 'tls-alpn-01') {
|
||||
return result;
|
||||
@@ -677,11 +690,21 @@ class AcmeClient {
|
||||
* reason: 4,
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @example Revoke certificate with certificate private key (RFC 8555 §7.6)
|
||||
* 当无法提供ACME账号私钥时,可以使用证书私钥签名吊销请求:
|
||||
* ```js
|
||||
* const client = new acme.Client({
|
||||
* directoryUrl: acme.directory.letsencrypt.production,
|
||||
* accountKey: certificateKey, // 证书私钥,而非账号私钥
|
||||
* });
|
||||
* const result = await client.revokeCertificate(certificate, {}, { includeJwsKid: false });
|
||||
* ```
|
||||
*/
|
||||
|
||||
async revokeCertificate(cert, data = {}) {
|
||||
async revokeCertificate(cert, data = {}, opts = {}) {
|
||||
data.certificate = getPemBodyAsB64u(cert);
|
||||
const resp = await this.api.revokeCert(data);
|
||||
const resp = await this.api.revokeCert(data, opts);
|
||||
return resp.data;
|
||||
}
|
||||
|
||||
@@ -695,7 +718,6 @@ class AcmeClient {
|
||||
* @param {string} [opts.email] Account email address
|
||||
* @param {boolean} [opts.termsOfServiceAgreed] Agree to Terms of Service, default: `false`
|
||||
* @param {boolean} [opts.skipChallengeVerification] Skip internal challenge verification before notifying ACME provider, default: `false`
|
||||
* @param {string[]} [opts.challengePriority] Array defining challenge type priority, default: `['http-01', 'dns-01']`
|
||||
* @param {string} [opts.preferredChain] Indicate which certificate chain is preferred if a CA offers multiple, by exact issuer common name, default: `null`
|
||||
* @returns {Promise<string>} Certificate
|
||||
*
|
||||
|
||||
@@ -527,6 +527,8 @@ export const createAlpnCertificate = async (authz, keyAuthorization, keyPem = nu
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
// TLS-ALPN-01 只需要一张短期挑战证书;有效期不能为零,否则部分 TLS 实现会直接拒绝。
|
||||
const notAfter = new Date(now.getTime() + 24 * 60 * 60 * 1000);
|
||||
const commonName = authz.identifier.value;
|
||||
|
||||
/* Pseudo-random serial - max 20 bytes, 11 for epoch (year 5138), 9 random */
|
||||
@@ -537,14 +539,8 @@ export const createAlpnCertificate = async (authz, keyAuthorization, keyPem = nu
|
||||
const [keys, signingAlgorithm] = await getWebCryptoKeyPair(keyPem);
|
||||
|
||||
const extensions = [
|
||||
/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 */
|
||||
new x509.KeyUsagesExtension(x509.KeyUsageFlags.keyCertSign | x509.KeyUsageFlags.cRLSign, true), // eslint-disable-line no-bitwise
|
||||
|
||||
/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.9 */
|
||||
new x509.BasicConstraintsExtension(true, 2, true),
|
||||
|
||||
/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.2 */
|
||||
await x509.SubjectKeyIdentifierExtension.create(keys.publicKey),
|
||||
/* TLS 服务端挑战证书只用于签名,不是 CA 证书。 */
|
||||
new x509.KeyUsagesExtension(x509.KeyUsageFlags.digitalSignature, true),
|
||||
|
||||
/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 */
|
||||
createSubjectAltNameExtension([commonName]),
|
||||
@@ -562,7 +558,7 @@ export const createAlpnCertificate = async (authz, keyAuthorization, keyPem = nu
|
||||
extensions,
|
||||
serialNumber,
|
||||
notBefore: now,
|
||||
notAfter: now,
|
||||
notAfter,
|
||||
name: createCsrSubject({
|
||||
CN: commonName,
|
||||
}),
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// @ts-ignore
|
||||
import psl from "psl";
|
||||
|
||||
export function getDnsPersistIssuer(directoryUrl?: string) {
|
||||
if (!directoryUrl) {
|
||||
return "letsencrypt.org";
|
||||
}
|
||||
|
||||
let directory: URL;
|
||||
try {
|
||||
directory = new URL(directoryUrl);
|
||||
} catch {
|
||||
throw new Error(`ACME Directory URL无效,无法生成DNS持久验证Issuer:${directoryUrl}`);
|
||||
}
|
||||
|
||||
const issuer = psl.get(directory.hostname);
|
||||
if (!issuer) {
|
||||
throw new Error(`无法从ACME Directory URL获取可注册主域名:${directory.hostname}`);
|
||||
}
|
||||
return issuer;
|
||||
}
|
||||