Compare commits
422 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb77ba5885 | ||
|
|
34887cba7c | ||
|
|
14a3f055ee | ||
|
|
882bcdc954 | ||
|
|
801050d3ff | ||
|
|
f7a7c7f11c | ||
|
|
2aac79af54 | ||
|
|
813fc562e3 | ||
|
|
86fc556bbe | ||
|
|
680e6952ba | ||
|
|
e53b2161d4 | ||
|
|
b617b45495 | ||
|
|
583d308459 | ||
|
|
9354c60380 | ||
|
|
b8bbbee1e0 | ||
|
|
205275b52d | ||
|
|
30840bbba5 | ||
|
|
299a722aa9 | ||
|
|
9421da2cde | ||
|
|
312047e0ee | ||
|
|
4ac3618f7e | ||
|
|
3fb9b00f66 | ||
|
|
a492fbe18c | ||
|
|
0383233315 | ||
|
|
4752c49fed | ||
|
|
8149034bdc | ||
|
|
e7ce12772a | ||
|
|
0434f95a1e | ||
|
|
769b24aa88 | ||
|
|
94a0292fad | ||
|
|
410231cd1f | ||
|
|
1d4e048777 | ||
|
|
c16fe1a807 | ||
|
|
e8ed831b28 | ||
|
|
c7c89efbe7 | ||
|
|
d7f3d9c512 | ||
|
|
ce67cc5a39 | ||
|
|
945d0da36f | ||
|
|
898311c6e5 | ||
|
|
5d6bc03f21 | ||
|
|
018743299b | ||
|
|
18e7238067 | ||
|
|
b7d1ff8960 | ||
|
|
0d44373de6 | ||
|
|
3d680e50e2 | ||
|
|
9542079e20 | ||
|
|
081e83e0bf | ||
|
|
9c8ab98efb | ||
|
|
bf26db77cb | ||
|
|
08ea915d24 | ||
|
|
fb62f1e105 | ||
|
|
261b3a8546 | ||
|
|
563adbec2a | ||
|
|
c6dfe11bdb | ||
|
|
e4bfa90a77 | ||
|
|
b833d09466 | ||
|
|
3ec0ba7052 | ||
|
|
57eb66b889 | ||
|
|
a048eb95a9 | ||
|
|
23e58b914e | ||
|
|
1170f635fd | ||
|
|
553aceac44 | ||
|
|
e24de70c02 | ||
|
|
bba2b25757 | ||
|
|
4132ec3617 | ||
|
|
9b3c7e16c0 | ||
|
|
0448538073 | ||
|
|
80157496d5 | ||
|
|
62e2ed2fb8 | ||
|
|
a750592eb5 | ||
|
|
5e6d729631 | ||
|
|
24fe824757 | ||
|
|
84a3f3346a | ||
|
|
bd26dfecb8 | ||
|
|
43182de732 | ||
|
|
d58109f4be | ||
|
|
59935df6b1 | ||
|
|
252da5d7e1 | ||
|
|
c3e7590f53 | ||
|
|
65cd1dc850 | ||
|
|
2203bb5268 | ||
|
|
8e5c36968a | ||
|
|
9ad0e6fb57 | ||
|
|
7d55383cf7 | ||
|
|
6dc65eea2f | ||
|
|
7210f63884 | ||
|
|
f94db675fb | ||
|
|
e6cf4d3e07 | ||
|
|
cc5098c4bc | ||
|
|
025e606db4 | ||
|
|
d3e8bacd58 | ||
|
|
308b21bb33 | ||
|
|
262c1d7fcb | ||
|
|
722c3a0e83 | ||
|
|
f885b49daf | ||
|
|
6731c465e7 | ||
|
|
28811c46d8 | ||
|
|
599cf17c9e | ||
|
|
f0af36b59e | ||
|
|
e73e2739c1 | ||
|
|
efdeacf01a | ||
|
|
3a829ad53b | ||
|
|
605de595b1 | ||
|
|
daf22b7f15 | ||
|
|
0e8ebaa885 | ||
|
|
829fa29cf1 | ||
|
|
ddb46f9dda | ||
|
|
df1f216b5b | ||
|
|
b8b94dfd77 | ||
|
|
4489096e57 | ||
|
|
a4f736e0f3 | ||
|
|
d8935337d6 | ||
|
|
211f66dc0a | ||
|
|
d964b129b0 | ||
|
|
a758b1d6d4 | ||
|
|
037305d8cd | ||
|
|
cfdd3c621f | ||
|
|
5339963524 | ||
|
|
af7d05e669 | ||
|
|
bf1d03a30e | ||
|
|
3bb88d9f93 | ||
|
|
b0eb71421f | ||
|
|
e82a59289b | ||
|
|
8e23b14bf3 | ||
|
|
cd9dac7765 | ||
|
|
40f4488009 | ||
|
|
4c13a3e86a | ||
|
|
b139139f50 | ||
|
|
55e16f4b17 | ||
|
|
46b4ff73c9 | ||
|
|
970a1f0f79 | ||
|
|
11ff80ab28 | ||
|
|
7cd036f41e | ||
|
|
0909671be6 | ||
|
|
b798b824db | ||
|
|
71c093c042 | ||
|
|
9878c12512 | ||
|
|
b43797a0fb | ||
|
|
312589ab1c | ||
|
|
bff8add010 | ||
|
|
6b9f295167 | ||
|
|
9cdc59b272 | ||
|
|
0e8b271e8d | ||
|
|
87aae4087c | ||
|
|
75326b1ddd | ||
|
|
7d8dd523a2 | ||
|
|
993ca36755 | ||
|
|
c34346cb31 | ||
|
|
7643975ef9 | ||
|
|
799ad61dcc | ||
|
|
1c3cb1b21b | ||
|
|
9d9ca88ebe | ||
|
|
faad7cb6d7 | ||
|
|
d81a33f24a | ||
|
|
398337826e | ||
|
|
7469310fdb | ||
|
|
fe993b54f3 | ||
|
|
1ed1c62f76 | ||
|
|
524c4fd1e8 | ||
|
|
591df58992 | ||
|
|
4ad08d983a | ||
|
|
7a663d31cb | ||
|
|
e6fc92eccb | ||
|
|
97d692910b | ||
|
|
b546cf3ad0 | ||
|
|
6353f0139b | ||
|
|
c9e6bd0c2f | ||
|
|
1e67e9333e | ||
|
|
6f054ee594 | ||
|
|
05d43f38ce | ||
|
|
b8ab077b57 | ||
|
|
36dd4ef3eb | ||
|
|
a66e1c04c9 | ||
|
|
3098f6a82f | ||
|
|
4a8eaa9ffa | ||
|
|
3462e454d0 | ||
|
|
eabd16dd71 | ||
|
|
122d766cab | ||
|
|
980d1ee0b9 | ||
|
|
e9f248d8ec | ||
|
|
2906576de0 | ||
|
|
fd875feef3 | ||
|
|
871d3ece90 | ||
|
|
8014abc836 | ||
|
|
0840454143 | ||
|
|
06fd95782a | ||
|
|
ef0f0f6b43 | ||
|
|
b15bf8ef98 | ||
|
|
dd2087b101 | ||
|
|
12d0b66c61 | ||
|
|
f3bbb9e8b2 | ||
|
|
dcd646b465 | ||
|
|
bd4aa4806f | ||
|
|
b122bbced9 | ||
|
|
5edae845cb | ||
|
|
b7af3c10e4 | ||
|
|
2453048288 | ||
|
|
221b6a6fc6 | ||
|
|
851ad70a6c | ||
|
|
1844e9a9db | ||
|
|
04e9f4e909 | ||
|
|
e6e2587bfc | ||
|
|
70bd2f0581 | ||
|
|
9e08cfd1d1 | ||
|
|
cd93a2d72c | ||
|
|
11a4d4f55c | ||
|
|
f33570d514 | ||
|
|
1ee3b64a19 | ||
|
|
a3a56f3346 | ||
|
|
564ed8f0d3 | ||
|
|
268ec4bd7f | ||
|
|
e55e6cc512 | ||
|
|
6c6bb78568 | ||
|
|
178c62512d | ||
|
|
9eaf9fd933 | ||
|
|
04abf9dd76 | ||
|
|
355059df3c | ||
|
|
4a6c32877f | ||
|
|
258f6b5001 | ||
|
|
78d9501fce | ||
|
|
15975bb92c | ||
|
|
fef8c3cb1a | ||
|
|
4b226d7730 | ||
|
|
41abc8cab8 | ||
|
|
4d3b3834f5 | ||
|
|
9b1ba574ff | ||
|
|
ee7d950c15 | ||
|
|
8ca41f18be | ||
|
|
9d522bd9ef | ||
|
|
f9633616e2 | ||
|
|
9a0dd53cd7 | ||
|
|
6bbcec6163 | ||
|
|
fdee69bdaf | ||
|
|
2ec4adf7d5 | ||
|
|
709684d00f | ||
|
|
989fd1ec6d | ||
|
|
7d57c5abc0 | ||
|
|
0c42bb845d | ||
|
|
07037e8d49 | ||
|
|
a1fc3841df | ||
|
|
1fee156457 | ||
|
|
82bdccf7e7 | ||
|
|
7936c34472 | ||
|
|
365fd0bd5b | ||
|
|
f63ee41405 | ||
|
|
26359b9d16 | ||
|
|
5abdb577fb | ||
|
|
c67c4741e5 | ||
|
|
60bc4be9ea | ||
|
|
b83f87b6c8 | ||
|
|
0a73ba1a53 | ||
|
|
a4d397f24b | ||
|
|
809f231981 | ||
|
|
1499c637ee | ||
|
|
e5805a028b | ||
|
|
5cb0463cf6 | ||
|
|
12c208cad4 | ||
|
|
1946a4e68a | ||
|
|
dfed0af053 | ||
|
|
fc064aa9f8 | ||
|
|
edaf08361f | ||
|
|
92c93822b9 | ||
|
|
18a19096d3 | ||
|
|
7e707cd973 | ||
|
|
d33b8caf14 | ||
|
|
e533f9407f | ||
|
|
193a19b79c | ||
|
|
609a252ee0 | ||
|
|
3be70c3696 | ||
|
|
3c2fbd720f | ||
|
|
11b413d0dc | ||
|
|
a117fd7d93 | ||
|
|
794695c313 | ||
|
|
7478dd7f47 | ||
|
|
2d17501072 | ||
|
|
034bb71b10 | ||
|
|
97f102533c | ||
|
|
a90b6a8589 | ||
|
|
e8f6c665f9 | ||
|
|
6dac89e9a1 | ||
|
|
4f512a6cdd | ||
|
|
94f162c189 | ||
|
|
f5807d215f | ||
|
|
3189e65bad | ||
|
|
3febc53061 | ||
|
|
efd8135341 | ||
|
|
56405eff6c | ||
|
|
e0fad9d9a9 | ||
|
|
8fe942d8d5 | ||
|
|
cf98e789d8 | ||
|
|
ff58b9a317 | ||
|
|
65e7d390b8 | ||
|
|
54ae378e30 | ||
|
|
347695cf66 | ||
|
|
8f4d854b0d | ||
|
|
94bd846726 | ||
|
|
0365841549 | ||
|
|
74bd1f64a0 | ||
|
|
5bce03410e | ||
|
|
32ff658e84 | ||
|
|
c10ceed753 | ||
|
|
eb45b56a87 | ||
|
|
283b150d60 | ||
|
|
7329a22132 | ||
|
|
50b48d956f | ||
|
|
55d7a05af8 | ||
|
|
6c70b0655a | ||
|
|
0004eac764 | ||
|
|
5fe24465d7 | ||
|
|
364ceb2399 | ||
|
|
88b90986b1 | ||
|
|
5143823e43 | ||
|
|
363e23dd13 | ||
|
|
44a6190e17 | ||
|
|
4475ed0dea | ||
|
|
6a23da3de3 | ||
|
|
0f1d5a7730 | ||
|
|
5b4c3bb668 | ||
|
|
ad49f9d788 | ||
|
|
397ceefa02 | ||
|
|
e11b1ca4e8 | ||
|
|
8e983e7286 | ||
|
|
f970ae7529 | ||
|
|
b0973b5ca8 | ||
|
|
4784bf9dba | ||
|
|
6b8dbf5235 | ||
|
|
48f698e84b | ||
|
|
ec0cdf8b96 | ||
|
|
2a6cc01eed | ||
|
|
acc1365101 | ||
|
|
c5409c78ba | ||
|
|
b97de6c06b | ||
|
|
abe755cb69 | ||
|
|
4e3f499d76 | ||
|
|
3cebe51796 | ||
|
|
25bd17dc6e | ||
|
|
2525f54dc3 | ||
|
|
2127bb7e69 | ||
|
|
ed6d74f1ba | ||
|
|
02dd11f196 | ||
|
|
37b9ae30e2 | ||
|
|
0463dbcc75 | ||
|
|
111ef97d9c | ||
|
|
e8e854e392 | ||
|
|
cedbaf70c0 | ||
|
|
ff43b9ab3e | ||
|
|
47c4ba9dd6 | ||
|
|
2899aa1b19 | ||
|
|
ecff16c89d | ||
|
|
6ff738144a | ||
|
|
26028bb1eb | ||
|
|
eb4d5ddfd5 | ||
|
|
093ee006e4 | ||
|
|
9f8aa15af8 | ||
|
|
74d66a0131 | ||
|
|
626a86dea7 | ||
|
|
9ab029a296 | ||
|
|
8e1a81ae53 | ||
|
|
d76e1a3204 | ||
|
|
b585782007 | ||
|
|
2d198bcef7 | ||
|
|
0edcd9174f | ||
|
|
daa5b44f8e | ||
|
|
949660bc01 | ||
|
|
899a0b75b0 | ||
|
|
8cdb2afa69 | ||
|
|
00ec2ce33e | ||
|
|
2f7fd95684 | ||
|
|
55b1794004 | ||
|
|
e20972d4e7 | ||
|
|
749d727f50 | ||
|
|
9b524728c0 | ||
|
|
f81b4b9680 | ||
|
|
d2eaea7a44 | ||
|
|
f77c2dae23 | ||
|
|
a72737fdd5 | ||
|
|
4ab6b72e6f | ||
|
|
1468e74a6c | ||
|
|
09b5a21af1 | ||
|
|
6ad0d8e42f | ||
|
|
deb3b2f412 | ||
|
|
893391a3d1 | ||
|
|
7503d52857 | ||
|
|
fb860981d6 | ||
|
|
f302c7fb74 | ||
|
|
a8be2a77cf | ||
|
|
c2345e6118 | ||
|
|
539f8f3343 | ||
|
|
9a06c1e35b | ||
|
|
382de0d6d6 | ||
|
|
4883b3bb88 | ||
|
|
0a90523d61 | ||
|
|
fa63f2a838 | ||
|
|
fd8ac3ae37 | ||
|
|
51c1b193e5 | ||
|
|
ee99bcf8a1 | ||
|
|
324086ca49 | ||
|
|
e9610eaede | ||
|
|
7d5c714211 | ||
|
|
24e275fdb3 | ||
|
|
597b9d0e17 | ||
|
|
4d710a1aaf | ||
|
|
5de033814b | ||
|
|
aaec840d8c | ||
|
|
e579cf6ceb | ||
|
|
798e72f663 | ||
|
|
e79d862256 | ||
|
|
53133db456 | ||
|
|
39f8484b2a | ||
|
|
892256c0b9 | ||
|
|
0545945697 | ||
|
|
ad0125fe0d | ||
|
|
fb325b5447 | ||
|
|
56ff9e6344 | ||
|
|
74b431481d | ||
|
|
12102ef641 | ||
|
|
445541c38f | ||
|
|
820f03e162 | ||
|
|
516a958c66 | ||
|
|
9667f3309b | ||
|
|
82735f3c02 | ||
|
|
752acb591f |
@@ -10,5 +10,7 @@ trim_trailing_whitespace = true
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
|
||||||
[*.go]
|
[*.go]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
|
|||||||
80
.github/ISSUE_TEMPLATE/1-bug_report.yml
vendored
Normal file
80
.github/ISSUE_TEMPLATE/1-bug_report.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
name: "🐞 Bug Report"
|
||||||
|
description: "报告缺陷来帮助我们完善。 / Create a report to help us improve."
|
||||||
|
title: "[Bug] 简要描述你发现的缺陷"
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Welcome!
|
||||||
|
|
||||||
|
**在提交 Issue 之前,请确认以下事项**:
|
||||||
|
1. 我**确认**已尝试过使用当前最新版本,并能复现问题。由于开发者精力有限,非当前最新版本的问题将被直接关闭,感谢理解。
|
||||||
|
2. 我**确认**已搜索过[已有的 Issues](https://github.com/certimate-go/certimate/issues)(包括已关闭的),没有类似的问题。
|
||||||
|
3. 我**确认**已阅读过[文档](https://docs.certimate.me/),没有类似的问题。
|
||||||
|
4. 请**务必**按照模板规范详细描述问题,否则 Issue 将会被直接关闭。
|
||||||
|
5. 请保持每个 Issue 只包含一个缺陷报告。如果有多个缺陷,请分别提交 Issue。
|
||||||
|
|
||||||
|
**Before you submit the issue, please make sure of the following checklist**:
|
||||||
|
1. Yes, I'm using the latest release and can reproduce the issue. Issues that are not in the latest version will be closed directly.
|
||||||
|
2. Yes, I've searched for [existing issues](https://github.com/certimate-go/certimate/issues) (including closed ones) on GitHub and didn't find any similar.
|
||||||
|
3. Yes, I've read the [documentation](https://docs.certimate.me/en/) and didn't find any similar.
|
||||||
|
4. Please describe the problem in detail according to the template specification, otherwise the issue will be closed directly.
|
||||||
|
5. Please limit one report per issue.
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: 软件版本 / Release Version
|
||||||
|
description: 请提供 Certimate 的具体版本(请不要填写 `latest` 之类的无效版本号)。 / Please provide the specific version of Certimate.
|
||||||
|
placeholder: (e.g. v1.0.0)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 缺陷描述 / Description
|
||||||
|
description: 请详细清晰地描述你发现的缺陷或故障,如果可能请上传截图。 / Describe the bug you found in detail and clearly, and upload screenshots if possible.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 复现步骤 / Steps to reproduce
|
||||||
|
description: 请提供可复现的完整步骤。 / Please walk us through it step by step.
|
||||||
|
placeholder: |
|
||||||
|
1. ...
|
||||||
|
2. ...
|
||||||
|
3. ...
|
||||||
|
...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 日志 / Logs
|
||||||
|
description: 在此处添加日志信息(如果有的话)。 / Add logs here if available.
|
||||||
|
value: |-
|
||||||
|
<details>
|
||||||
|
|
||||||
|
```console
|
||||||
|
# 请在此粘贴日志 / Paste logs here
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 其他 / Miscellaneous
|
||||||
|
description: 在此处添加关于该 Issue 的任何其他信息。 / Add any other context about the issue here.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: 贡献 / Contribution
|
||||||
|
options:
|
||||||
|
- label: 我乐意为此贡献 PR! / I am interested in contributing a PR for this!
|
||||||
|
required: false
|
||||||
52
.github/ISSUE_TEMPLATE/2-feature_request.yml
vendored
Normal file
52
.github/ISSUE_TEMPLATE/2-feature_request.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: "💡 Feature Request"
|
||||||
|
description: "提出新功能请求或改进意见。 / Suggest an idea for this project."
|
||||||
|
title: "[Feature] 简要描述你希望实现的功能"
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Welcome!
|
||||||
|
|
||||||
|
**在提交 Issue 之前,请确认以下事项**:
|
||||||
|
1. 我**确认**是基于当前最新大版本而提出的新功能请求或改进意见。
|
||||||
|
2. 我**确认**已搜索过[已有的 Issues](https://github.com/certimate-go/certimate/issues)(包括已关闭的),没有类似的问题。
|
||||||
|
3. 我**确认**已阅读过[文档](https://docs.certimate.me/),没有类似的问题。
|
||||||
|
4. 请**务必**按照模板规范详细描述问题,否则 Issue 将会被直接关闭。
|
||||||
|
5. 请保持每个 Issue 只包含一个功能请求。如果有多个需求,请分别提交 Issue。
|
||||||
|
|
||||||
|
**Before you submit the issue, please make sure of the following checklist**:
|
||||||
|
1. Yes, I'm using the latest release.
|
||||||
|
2. Yes, I've searched for [existing issues](https://github.com/certimate-go/certimate/issues) (including closed ones) on GitHub and didn't find any similar.
|
||||||
|
3. Yes, I've read the [documentation](https://docs.certimate.me/en/) and didn't find any similar.
|
||||||
|
4. Please describe the problem in detail according to the template specification, otherwise the issue will be closed directly.
|
||||||
|
5. Please limit one request per issue.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 功能描述 / Description
|
||||||
|
description: 请详细清晰地描述你希望添加的功能,如果可能请上传截图。 / Describe the feature you'd like to add in detail and clearly, and upload screenshots if possible.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 请求动机 / Motivation
|
||||||
|
description: 为什么这个功能对项目有帮助? / Why is this feature helpful to the project?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 其他 / Miscellaneous
|
||||||
|
description: 在此处添加关于该 Issue 的任何其他信息(新增提供商请求请补充 API 文档链接等资料)。 / Add any other context about the problem here.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: 贡献 / Contribution
|
||||||
|
options:
|
||||||
|
- label: 我乐意为此贡献 PR! / I am interested in contributing a PR for this!
|
||||||
|
required: false
|
||||||
44
.github/ISSUE_TEMPLATE/3-questions.yml
vendored
Normal file
44
.github/ISSUE_TEMPLATE/3-questions.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
name: "❓ Questions"
|
||||||
|
description: "遇到了困难需要求助? / Have problem in use and need help?"
|
||||||
|
title: "简要描述你遇到的问题"
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Welcome!
|
||||||
|
|
||||||
|
**在提交 Issue 之前,请确认以下事项**:
|
||||||
|
1. 我**确认**正在使用的是当前最新版本。
|
||||||
|
2. 我**确认**已搜索过[已有的 Issues](https://github.com/certimate-go/certimate/issues)(包括已关闭的),没有类似的问题。
|
||||||
|
3. 我**确认**已阅读过[文档](https://docs.certimate.me/),没有类似的问题。
|
||||||
|
4. 请**务必**按照模板规范详细描述问题,否则 Issue 将会被直接关闭。
|
||||||
|
5. 请保持每个 Issue 只包含一个问题求助。如果有多个问题,请分别提交 Issue。
|
||||||
|
|
||||||
|
**Before you submit the issue, please make sure of the following checklist**:
|
||||||
|
1. Yes, I'm using the latest release.
|
||||||
|
2. Yes, I've searched for [existing issues](https://github.com/certimate-go/certimate/issues) (including closed ones) on GitHub and didn't find any similar.
|
||||||
|
3. Yes, I've read the [documentation](https://docs.certimate.me/en/) and didn't find any similar.
|
||||||
|
4. Please describe the problem in detail according to the template specification, otherwise the issue will be closed directly.
|
||||||
|
5. Please limit one question per issue.
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: 软件版本 / Release Version
|
||||||
|
description: 请提供 Certimate 的具体版本(请不要填写 `latest` 之类的无效版本号)。 / Please provide the specific version of Certimate.
|
||||||
|
placeholder: (e.g. v1.0.0)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 问题描述 / Description
|
||||||
|
description: 请详细清晰地描述你遇到的问题,如果可能请上传截图。 / Describe the problem you encountered in detail and clearly, and upload screenshots if possible.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: 其他 / Miscellaneous
|
||||||
|
description: 在此处添加关于该问题的任何其他信息。 / Add any other context about the problem here.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,33 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: 创建一个报告来帮助我们改进
|
|
||||||
title: "[Bug] 标题简要描述问题"
|
|
||||||
labels: bug
|
|
||||||
assignees: ""
|
|
||||||
---
|
|
||||||
|
|
||||||
**描述问题**
|
|
||||||
简要描述问题是什么,1 个 ISSUE 只描述一个问题。
|
|
||||||
|
|
||||||
**复现步骤**
|
|
||||||
复现该问题的步骤:
|
|
||||||
|
|
||||||
1. 去到 '...'
|
|
||||||
2. 点击 '...'
|
|
||||||
3. 滚动到 '...'
|
|
||||||
4. 发现问题
|
|
||||||
|
|
||||||
**期望的结果**
|
|
||||||
简要描述你期望发生的事情。
|
|
||||||
|
|
||||||
**截图**
|
|
||||||
如有可能,请添加截图以帮助解释问题。
|
|
||||||
|
|
||||||
**环境**
|
|
||||||
|
|
||||||
- 操作系统: [e.g. Windows, macOS]
|
|
||||||
- 浏览器: [e.g. Chrome, Safari]
|
|
||||||
- 仓库版本: [e.g. v1.0.0]
|
|
||||||
|
|
||||||
**其他信息**
|
|
||||||
在此处添加关于该问题的任何其他信息。
|
|
||||||
9
.github/ISSUE_TEMPLATE/config.yml
vendored
9
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,8 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: 加入频道讨论
|
- name: "🌐 加入频道讨论"
|
||||||
url: https://t.me/+ZXphsppxUg41YmVl
|
about: "加入到电报频道寻求更多帮助。 / Join in our Telegram channel."
|
||||||
about: 加入到电报频道寻求更多帮助
|
url: "https://t.me/+ZXphsppxUg41YmVl"
|
||||||
|
- name: "📖 常见问题"
|
||||||
|
about: "请先阅读文档 FAQ,可能会有你需要的答案。 / Please take a look to FAQs."
|
||||||
|
url: "https://docs.certimate.me/docs/reference/faq"
|
||||||
|
|||||||
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: 提出一个新功能请求
|
|
||||||
title: "[Feature] 简要描述你希望实现的功能"
|
|
||||||
labels: enhancement
|
|
||||||
assignees: ""
|
|
||||||
---
|
|
||||||
|
|
||||||
**功能描述**
|
|
||||||
简要描述你希望添加的功能和相关问题,1 个 ISSUE 只描述一个功能。
|
|
||||||
|
|
||||||
**动机**
|
|
||||||
为什么这个功能对项目有帮助?
|
|
||||||
|
|
||||||
**替代方案**
|
|
||||||
描述你已经考虑过的替代方案。
|
|
||||||
|
|
||||||
**其他信息**
|
|
||||||
在这里添加任何相关的附加信息或截图。
|
|
||||||
5
.github/workflows/push_image.yml
vendored
5
.github/workflows/push_image.yml
vendored
@@ -32,8 +32,8 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
usual2970/certimate
|
certimate/certimate
|
||||||
registry.cn-shanghai.aliyuncs.com/usual2970/certimate
|
registry.cn-shanghai.aliyuncs.com/certimate/certimate
|
||||||
tags: |
|
tags: |
|
||||||
type=ref,event=branch
|
type=ref,event=branch
|
||||||
type=ref,event=pr
|
type=ref,event=pr
|
||||||
@@ -61,4 +61,3 @@ jobs:
|
|||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/push_image_next.yml
vendored
4
.github/workflows/push_image_next.yml
vendored
@@ -31,8 +31,8 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
usual2970/certimate
|
certimate/certimate
|
||||||
registry.cn-shanghai.aliyuncs.com/usual2970/certimate
|
registry.cn-shanghai.aliyuncs.com/certimate/certimate
|
||||||
tags: |
|
tags: |
|
||||||
type=ref,event=tag,pattern={{version}}
|
type=ref,event=tag,pattern={{version}}
|
||||||
flavor: |
|
flavor: |
|
||||||
|
|||||||
193
.github/workflows/release.yml
vendored
193
.github/workflows/release.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Base Build
|
name: Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -6,7 +6,7 @@ on:
|
|||||||
- "v[0-9]*"
|
- "v[0-9]*"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
goreleaser:
|
prepare-ui:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -19,19 +19,190 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 20.11.0
|
node-version: 20.11.0
|
||||||
|
|
||||||
|
- name: Build WebUI
|
||||||
|
run: |
|
||||||
|
npm --prefix=./ui ci
|
||||||
|
npm --prefix=./ui run build
|
||||||
|
|
||||||
|
- name: Upload UI build artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ui-build
|
||||||
|
path: ./ui/dist
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
build-linux:
|
||||||
|
needs: prepare-ui
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ">=1.23.0"
|
go-version-file: "go.mod"
|
||||||
|
|
||||||
- name: Build WebUI
|
- name: Download UI build artifacts
|
||||||
run: npm --prefix=./ui ci && npm --prefix=./ui run build
|
uses: actions/download-artifact@v4
|
||||||
|
|
||||||
- name: Run GoReleaser
|
|
||||||
uses: goreleaser/goreleaser-action@v3
|
|
||||||
with:
|
with:
|
||||||
distribution: goreleaser
|
name: ui-build
|
||||||
version: latest
|
path: ./ui/dist
|
||||||
args: release --clean
|
|
||||||
|
- name: Build Linux binaries
|
||||||
|
env:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
GOOS: linux
|
||||||
|
run: |
|
||||||
|
mkdir -p dist/linux
|
||||||
|
for ARCH in amd64 arm64 armv7; do
|
||||||
|
if [ "$ARCH" == "armv7" ]; then
|
||||||
|
go env -w GOARCH=arm
|
||||||
|
go env -w GOARM=7
|
||||||
|
else
|
||||||
|
go env -w GOARCH=$ARCH
|
||||||
|
go env -u GOARM
|
||||||
|
fi
|
||||||
|
go build -ldflags="-s -w -X github.com/certimate-go/certimate.Version=${GITHUB_REF#refs/tags/}" -o dist/linux/certimate_${GITHUB_REF#refs/tags/}_linux_$ARCH
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Upload Linux binaries
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: linux-binaries
|
||||||
|
path: dist/linux/
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
build-macos:
|
||||||
|
needs: prepare-ui
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: "go.mod"
|
||||||
|
|
||||||
|
- name: Download UI build artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ui-build
|
||||||
|
path: ./ui/dist
|
||||||
|
|
||||||
|
- name: Build macOS binaries
|
||||||
|
env:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
GOOS: darwin
|
||||||
|
run: |
|
||||||
|
mkdir -p dist/darwin
|
||||||
|
for ARCH in amd64 arm64; do
|
||||||
|
go env -w GOARCH=$ARCH
|
||||||
|
go build -ldflags="-s -w -X github.com/certimate-go/certimate.Version=${GITHUB_REF#refs/tags/}" -o dist/darwin/certimate_${GITHUB_REF#refs/tags/}_darwin_$ARCH
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Upload macOS binaries
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: macos-binaries
|
||||||
|
path: dist/darwin/
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
build-windows:
|
||||||
|
needs: prepare-ui
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: "go.mod"
|
||||||
|
|
||||||
|
- name: Download UI build artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ui-build
|
||||||
|
path: ./ui/dist
|
||||||
|
|
||||||
|
- name: Build Windows binaries
|
||||||
|
env:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
GOOS: windows
|
||||||
|
run: |
|
||||||
|
mkdir -p dist/windows
|
||||||
|
for ARCH in amd64 arm64; do
|
||||||
|
go env -w GOARCH=$ARCH
|
||||||
|
go build -ldflags="-s -w -X github.com/certimate-go/certimate.Version=${GITHUB_REF#refs/tags/}" -o dist/windows/certimate_${GITHUB_REF#refs/tags/}_windows_$ARCH.exe
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Upload Windows binaries
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: windows-binaries
|
||||||
|
path: dist/windows/
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
create-release:
|
||||||
|
needs: [build-linux, build-macos, build-windows]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Download all binaries
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: ./artifacts
|
||||||
|
|
||||||
|
- name: Prepare release assets
|
||||||
|
run: |
|
||||||
|
mkdir -p dist
|
||||||
|
cp -r artifacts/linux-binaries/* dist/
|
||||||
|
cp -r artifacts/macos-binaries/* dist/
|
||||||
|
cp -r artifacts/windows-binaries/* dist/
|
||||||
|
|
||||||
|
find dist -type f -not -name "*.exe" -exec chmod +x {} \;
|
||||||
|
|
||||||
|
cd dist
|
||||||
|
for bin in certimate_*; do
|
||||||
|
if [[ "$bin" == *".exe" ]]; then
|
||||||
|
entrypoint="certimate.exe"
|
||||||
|
else
|
||||||
|
entrypoint="certimate"
|
||||||
|
fi
|
||||||
|
|
||||||
|
tmpdir=$(mktemp -d)
|
||||||
|
cp "$bin" "${tmpdir}/${entrypoint}"
|
||||||
|
cp ../LICENSE ../README.md ../CHANGELOG.md "$tmpdir"
|
||||||
|
|
||||||
|
if [[ "$bin" == *".exe" ]]; then
|
||||||
|
zip -j "${bin%.exe}.zip" "$tmpdir"/*
|
||||||
|
else
|
||||||
|
zip -j -X "${bin}.zip" "$tmpdir"/*
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
done
|
||||||
|
|
||||||
|
sha256sum *.zip > checksums.txt
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
dist/*.zip
|
||||||
|
dist/checksums.txt
|
||||||
|
draft: true
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ builds:
|
|||||||
main: ./
|
main: ./
|
||||||
binary: certimate
|
binary: certimate
|
||||||
ldflags:
|
ldflags:
|
||||||
- -s -w -X github.com/usual2970/certimate.Version={{ .Version }}
|
- -s -w -X github.com/certimate-go/certimate.Version={{ .Version }}
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=0
|
- CGO_ENABLED=0
|
||||||
goos:
|
goos:
|
||||||
@@ -30,17 +30,20 @@ builds:
|
|||||||
- goos: darwin
|
- goos: darwin
|
||||||
goarch: arm
|
goarch: arm
|
||||||
|
|
||||||
|
# upx:
|
||||||
|
# - enabled: true
|
||||||
|
|
||||||
release:
|
release:
|
||||||
draft: true
|
draft: true
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- id: archive_noncgo
|
- id: archive_noncgo
|
||||||
builds: [build_noncgo]
|
builds: [build_noncgo]
|
||||||
format: zip
|
format: "zip"
|
||||||
files:
|
files:
|
||||||
- CHANGELOG.md
|
- LICENSE
|
||||||
- LICENSE.md
|
|
||||||
- README.md
|
- README.md
|
||||||
|
- CHANGELOG.md
|
||||||
|
|
||||||
checksum:
|
checksum:
|
||||||
name_template: "checksums.txt"
|
name_template: "checksums.txt"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
A full changelog of past releases is available on [GitHub Releases](https://github.com/usual2970/certimate/releases) page.
|
A full changelog of past releases is available on [GitHub Releases](https://github.com/certimate-go/certimate/releases) page.
|
||||||
|
|||||||
116
CONTRIBUTING.md
116
CONTRIBUTING.md
@@ -1,76 +1,106 @@
|
|||||||
# 向 Certimate 贡献代码
|
# 贡献指南
|
||||||
|
|
||||||
感谢你抽出时间来改进 Certimate!以下是向 Certimate 主仓库提交 PR(Pull Request)时的操作指南。
|
非常感谢你抽出时间来帮助改进 Certimate!以下是向 Certimate 提交 Pull Request 时的操作指南。
|
||||||
|
|
||||||
- [向 Certimate 贡献代码](#向-certimate-贡献代码)
|
我们需要保持敏捷和快速迭代,同时也希望确保贡献者能获得尽可能流畅的参与体验。这份贡献指南旨在帮助你熟悉代码库和我们的工作方式,让你可以尽快进入有趣的开发环节。
|
||||||
- [前提条件](#前提条件)
|
|
||||||
- [修改 Go 代码](#修改-go-代码)
|
|
||||||
- [修改管理页面 (Admin UI)](#修改管理页面-admin-ui)
|
|
||||||
|
|
||||||
## 前提条件
|
索引:
|
||||||
|
|
||||||
- Go 1.22+ (用于修改 Go 代码)
|
- [开发](#开发)
|
||||||
- Node 20+ (用于修改 UI)
|
- [要求](#要求)
|
||||||
|
- [后端代码](#后端代码)
|
||||||
|
- [前端代码](#前端代码)
|
||||||
|
- [提交 PR](#提交-pr)
|
||||||
|
- [提交流程](#提交流程)
|
||||||
|
- [获取帮助](#获取帮助)
|
||||||
|
|
||||||
如果还没有这样做,你可以 fork Certimate 的主仓库,并克隆到本地以便进行修改:
|
---
|
||||||
|
|
||||||
```bash
|
## 开发
|
||||||
git clone https://github.com/your_username/certimate.git
|
|
||||||
```
|
|
||||||
|
|
||||||
> **重要提示:**
|
### 要求
|
||||||
> 建议为每个 Bug 修复或新功能创建一个从 `main` 分支派生的新分支。如果你计划提交多个 PR,请保持不同的改动在独立分支中,以便更容易进行代码审查并最终合并。
|
|
||||||
> 保持一个 PR 只实现一个功能。
|
|
||||||
|
|
||||||
## 修改 Go 代码
|
- Go 1.24+(用于修改后端代码)
|
||||||
|
- Node.js 22.0+(用于修改前端代码)
|
||||||
|
|
||||||
假设你已经对 Certimate 的 Go 代码做了一些修改,现在你想要运行它:
|
### 后端代码
|
||||||
|
|
||||||
1. 进入根目录
|
Certimate 的后端代码是使用 Golang 开发的,是一个基于 [Pocketbase](https://github.com/pocketbase/pocketbase) 构建的单体应用。
|
||||||
2. 运行以下命令启动服务:
|
|
||||||
|
|
||||||
|
假设你已经对 Certimate 的后端代码做出了一些修改,现在你想要运行它,请遵循以下步骤:
|
||||||
|
|
||||||
|
1. 进入根目录;
|
||||||
|
2. 安装依赖:
|
||||||
|
```bash
|
||||||
|
go mod vendor
|
||||||
|
```
|
||||||
|
3. 启动本地开发服务:
|
||||||
```bash
|
```bash
|
||||||
go run main.go serve
|
go run main.go serve
|
||||||
```
|
```
|
||||||
|
|
||||||
这将启动一个 Web 服务器,默认运行在 `http://localhost:8090`,并使用来自 `ui/dist` 的预构建管理页面。
|
这将启动一个 Web 服务器,默认运行在 `http://localhost:8090`,并使用来自 `/ui/dist` 的预构建管理页面。
|
||||||
|
|
||||||
**在向主仓库提交 PR 之前,建议你:**
|
> 如果你遇到报错 `ui/embed.go: pattern all:dist: no matching files found`,请参考“[前端代码](#前端代码)”这一小节构建 WebUI。
|
||||||
|
|
||||||
- 使用 [gofumpt](https://github.com/mvdan/gofumpt) 对你的代码进行格式化。
|
**在向主仓库提交 PR 之前,你应该:**
|
||||||
|
|
||||||
- 为你的改动添加单元测试或集成测试(Certimate 使用 Go 的标准 `testing` 包)。你可以通过以下命令运行测试(在项目根目录下):
|
- 使用 [gofumpt](https://github.com/mvdan/gofumpt) 格式化你的代码。推荐使用 VSCode,并安装 gofumpt 插件,以便在保存时自动格式化。
|
||||||
|
- 为你的改动添加单元测试或集成测试(使用 Go 标准库中的 `testing` 包)。
|
||||||
|
|
||||||
```bash
|
### 前端代码
|
||||||
go test ./...
|
|
||||||
```
|
|
||||||
|
|
||||||
## 修改管理页面 (Admin UI)
|
Certimate 的前端代码是使用 TypeScript 开发的,是一个基于 [React](https://github.com/facebook/react) 和 [Vite](https://github.com/vitejs/vite) 构建的单页应用。
|
||||||
|
|
||||||
Certimate 的管理页面是一个基于 React 和 Vite 构建的单页应用(SPA)。
|
假设你已经对 Certimate 的前端代码做出了一些修改,现在你想要运行它,请遵循以下步骤:
|
||||||
|
|
||||||
要启动 Admin UI:
|
|
||||||
|
|
||||||
1. 进入 `ui` 项目目录。
|
|
||||||
|
|
||||||
2. 运行 `npm install` 安装依赖。
|
|
||||||
|
|
||||||
|
1. 进入 `/ui` 目录;
|
||||||
|
2. 安装依赖:
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
3. 启动 Vite 开发服务器:
|
3. 启动 Vite 开发服务器:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
你可以通过浏览器访问 `http://localhost:5173` 来查看运行中的管理页面。
|
这将启动一个 Web 服务器,默认运行在 `http://localhost:5173`,你可以通过浏览器访问来查看运行中的 WebUI。
|
||||||
|
|
||||||
由于 Admin UI 只是一个客户端应用,运行时需要 Certimate 的后端服务作为支撑。你可以手动运行 Certimate,或者使用预构建的可执行文件。
|
完成修改后,运行以下命令来构建 WebUI,以便它能被嵌入到 Go 包中:
|
||||||
|
|
||||||
所有对 Admin UI 的修改将会自动反映在浏览器中,无需手动刷新页面。
|
|
||||||
|
|
||||||
完成修改后,运行以下命令来构建 Admin UI,以便它能被嵌入到 Go 包中:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
完成所有步骤后,你可以将改动提交 PR 到 Certimate 主仓库。
|
**在向主仓库提交 PR 之前,你应该:**
|
||||||
|
|
||||||
|
- 使用 [ESLint](https://github.com/eslint/eslint) 格式化你的代码。推荐使用 VSCode,并安装 ESLint+Prettier 插件,以便在保存时自动格式化。
|
||||||
|
|
||||||
|
## 提交 PR
|
||||||
|
|
||||||
|
在提交 PR 之前,请先创建一个 Issue 来讨论你的修改方案,并等待来自项目维护者的反馈。这样做有助于:
|
||||||
|
|
||||||
|
- 让我们充分理解你的修改内容;
|
||||||
|
- 评估修改是否符合项目路线图;
|
||||||
|
- 避免重复工作;
|
||||||
|
- 防止你投入时间到可能无法被合并的修改中。
|
||||||
|
|
||||||
|
### 提交流程
|
||||||
|
|
||||||
|
1. Fork 本仓库;
|
||||||
|
2. 在提交 PR 之前,请先发起 Issue 讨论你想要做的修改;
|
||||||
|
3. 为你的修改创建一个新的分支;
|
||||||
|
4. 请为你的修改添加相应的测试;
|
||||||
|
5. 确保你的代码能通过现有的测试;
|
||||||
|
6. 请在 PR 描述中关联相关 Issue;
|
||||||
|
7. 等待合并!
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
>
|
||||||
|
> 建议为每个新功能或 Bug 修复创建一个从 `main` 分支派生的新分支。如果你计划提交多个 PR,请保持不同的改动在独立分支中,以便更容易进行代码审查并最终合并。
|
||||||
|
>
|
||||||
|
> 保持一个 PR 只实现一个功能或修复。
|
||||||
|
|
||||||
|
## 获取帮助
|
||||||
|
|
||||||
|
如果你在贡献过程中遇到困难或问题,可以通过 GitHub Issues 向我们提问。
|
||||||
|
|||||||
@@ -1,81 +1,106 @@
|
|||||||
# Contributing to Certimate
|
# Contribution Guide
|
||||||
|
|
||||||
Thank you for taking the time to improve Certimate! Below is a guide for submitting a PR (Pull Request) to the main Certimate repository.
|
Thank you for taking the time to improve Certimate! Below is a guide for submitting a PR (Pull Request) to the Certimate repository.
|
||||||
|
|
||||||
- [Contributing to Certimate](#contributing-to-certimate)
|
We need to be nimble and ship fast given where we are, but we also want to make sure that contributors like you get as smooth an experience at contributing as possible. We've assembled this contribution guide for that purpose, aiming at getting you familiarized with the codebase & how we work with contributors, so you could quickly jump to the fun part.
|
||||||
|
|
||||||
|
Index:
|
||||||
|
|
||||||
|
- [Development](#development)
|
||||||
- [Prerequisites](#prerequisites)
|
- [Prerequisites](#prerequisites)
|
||||||
- [Making Changes in the Go Code](#making-changes-in-the-go-code)
|
- [Backend Code](#backend-code)
|
||||||
- [Making Changes in the Admin UI](#making-changes-in-the-admin-ui)
|
- [Frontend Code](#frontend-code)
|
||||||
|
- [Submitting PR](#submitting-pr)
|
||||||
|
- [Pull Request Process](#pull-request-process)
|
||||||
|
- [Getting Help](#getting-help)
|
||||||
|
|
||||||
## Prerequisites
|
---
|
||||||
|
|
||||||
- Go 1.22+ (for Go code changes)
|
## Development
|
||||||
- Node 20+ (for Admin UI changes)
|
|
||||||
|
|
||||||
If you haven't done so already, you can fork the Certimate repository and clone your fork to work locally:
|
### Prerequisites
|
||||||
|
|
||||||
```bash
|
- Go 1.24+ (for backend code changes)
|
||||||
git clone https://github.com/your_username/certimate.git
|
- Node.js 22.0+ (for frontend code changes)
|
||||||
```
|
|
||||||
|
|
||||||
> **Important:**
|
### Backend Code
|
||||||
> It is recommended to create a new branch from `main` for each bug fix or feature. If you plan to submit multiple PRs, ensure the changes are in separate branches for easier review and eventual merge.
|
|
||||||
> Keep each PR focused on a single feature or fix.
|
|
||||||
|
|
||||||
## Making Changes in the Go Code
|
The backend code of Certimate is developed using Golang. It is a monolithic application based on [Pocketbase](https://github.com/pocketbase/pocketbase).
|
||||||
|
|
||||||
Once you have made changes to the Go code in Certimate, follow these steps to run the project:
|
Once you have made changes to the backend code in Certimate, follow these steps to run the project:
|
||||||
|
|
||||||
1. Navigate to the root directory.
|
1. Navigate to the root directory.
|
||||||
|
2. Install dependencies:
|
||||||
2. Start the service by running:
|
```bash
|
||||||
|
go mod vendor
|
||||||
|
```
|
||||||
|
3. Start the local development server:
|
||||||
```bash
|
```bash
|
||||||
go run main.go serve
|
go run main.go serve
|
||||||
```
|
```
|
||||||
|
|
||||||
This will start a web server at `http://localhost:8090` using the prebuilt Admin UI located in `ui/dist`.
|
This will start a web server at `http://localhost:8090` using the prebuilt WebUI located in `/ui/dist`.
|
||||||
|
|
||||||
**Before submitting a PR to the main repository, consider:**
|
> If you encounter an error `ui/embed.go: pattern all:dist: no matching files found`, please refer to _[Frontend Code](#frontend-code)_ and build WebUI first.
|
||||||
|
|
||||||
- Format your source code by using [gofumpt](https://github.com/mvdan/gofumpt).
|
**Before submitting a PR to the main repository, you should:**
|
||||||
|
|
||||||
- Adding unit or integration tests for your changes. Certimate uses Go’s standard `testing` package. You can run tests using the following command (while in the root project directory):
|
- Format your source code by using [gofumpt](https://github.com/mvdan/gofumpt). Recommended using VSCode and installing the gofumpt plugin to automatically format when saving.
|
||||||
|
- Adding unit or integration tests for your changes (with go standard library `testing` package).
|
||||||
|
|
||||||
```bash
|
### Frontend Code
|
||||||
go test ./...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Making Changes in the Admin UI
|
The frontend code of Certimate is developed using TypeScript. It is a SPA based on [React](https://github.com/facebook/react) and [Vite](https://github.com/vitejs/vite).
|
||||||
|
|
||||||
Certimate’s Admin UI is a single-page application (SPA) built using React and Vite.
|
Once you have made changes to the backend code in Certimate, follow these steps to run the project:
|
||||||
|
|
||||||
To start the Admin UI:
|
|
||||||
|
|
||||||
1. Navigate to the `ui` project directory.
|
|
||||||
|
|
||||||
2. Install the necessary dependencies by running:
|
|
||||||
|
|
||||||
|
1. Navigate to the `/ui` directory.
|
||||||
|
2. Install dependencies:
|
||||||
```bash
|
```bash
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
3. Start the local development server:
|
||||||
3. Start the Vite development server:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
You can now access the running Admin UI at `http://localhost:5173` in your browser.
|
This will start a web server at `http://localhost:5173`. You can now access the WebUI in your browser.
|
||||||
|
|
||||||
Since the Admin UI is a client-side application, you will also need to have the Certimate backend running. You can either manually run Certimate or use a prebuilt executable.
|
After completing your changes, build the WebUI so it can be embedded into the Go package:
|
||||||
|
|
||||||
Any changes you make in the Admin UI will be automatically reflected in the browser without requiring a page reload.
|
|
||||||
|
|
||||||
After completing your changes, build the Admin UI so it can be embedded into the Go package:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
Once all steps are completed, you are ready to submit a PR to the main Certimate repository.
|
**Before submitting a PR to the main repository, you should:**
|
||||||
|
|
||||||
|
- Format your source code by using [ESLint](https://github.com/eslint/eslint). Recommended using VSCode and installing the ESLint plugin to automatically format when saving.
|
||||||
|
|
||||||
|
## Submitting PR
|
||||||
|
|
||||||
|
Before opening a Pull Request, please open an issue to discuss the change and get feedback from the maintainers. This will helps us:
|
||||||
|
|
||||||
|
- To understand the context of the change.
|
||||||
|
- To ensure it fits into Certimate's roadmap.
|
||||||
|
- To prevent us from duplicating work.
|
||||||
|
- To prevent you from spending time on a change that we may not be able to accept.
|
||||||
|
|
||||||
|
### Pull Request Process
|
||||||
|
|
||||||
|
1. Fork the repository.
|
||||||
|
2. Before you draft a PR, please open an issue to discuss the changes you want to make.
|
||||||
|
3. Create a new branch for your changes.
|
||||||
|
4. Please add tests for your changes accordingly.
|
||||||
|
5. Ensure your code passes the existing tests.
|
||||||
|
6. Please link the issue in the PR description.
|
||||||
|
7. Get merged!
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
>
|
||||||
|
> It is recommended to create a new branch from `main` for each bug fix or feature. If you plan to submit multiple PRs, ensure the changes are in separate branches for easier review and eventual merge.
|
||||||
|
>
|
||||||
|
> Keep each PR focused on a single feature or fix.
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
If you ever get stuck or get a burning question while contributing, simply shoot your queries our way via the GitHub issues.
|
||||||
|
|||||||
21
Dockerfile
21
Dockerfile
@@ -1,33 +1,24 @@
|
|||||||
FROM node:20-alpine3.19 AS front-builder
|
FROM node:20-alpine3.19 AS webui-builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY . /app/
|
COPY . /app/
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
cd /app/ui && \
|
cd /app/ui && \
|
||||||
npm install && \
|
npm install && \
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
|
|
||||||
FROM golang:1.23-alpine AS builder
|
|
||||||
|
|
||||||
|
FROM golang:1.24-alpine AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY ../. /app/
|
COPY ../. /app/
|
||||||
|
|
||||||
RUN rm -rf /app/ui/dist
|
RUN rm -rf /app/ui/dist
|
||||||
|
COPY --from=webui-builder /app/ui/dist /app/ui/dist
|
||||||
COPY --from=front-builder /app/ui/dist /app/ui/dist
|
ENV CGO_ENABLED=0
|
||||||
|
RUN go build -ldflags="-s -w" -o certimate
|
||||||
RUN go build -o certimate
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY --from=builder /app/certimate .
|
COPY --from=builder /app/certimate .
|
||||||
|
ENTRYPOINT ["./certimate", "serve", "--http", "0.0.0.0:8090"]
|
||||||
ENTRYPOINT ["./certimate", "serve", "--http", "0.0.0.0:8090"]
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 certimate-go
|
||||||
Copyright (c) 2024 Yoan.Liu
|
Copyright (c) 2024 Yoan.Liu
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
3
Makefile
3
Makefile
@@ -21,7 +21,8 @@ $(OS_ARCH):
|
|||||||
@mkdir -p $(BUILD_DIR)
|
@mkdir -p $(BUILD_DIR)
|
||||||
GOOS=$(word 1,$(subst /, ,$@)) \
|
GOOS=$(word 1,$(subst /, ,$@)) \
|
||||||
GOARCH=$(word 2,$(subst /, ,$@)) \
|
GOARCH=$(word 2,$(subst /, ,$@)) \
|
||||||
go build -o $(BUILD_DIR)/$(BINARY_NAME)_$(word 1,$(subst /, ,$@))_$(word 2,$(subst /, ,$@)) -ldflags="-X main.version=$(VERSION)" .
|
CGO_ENABLED=0 \
|
||||||
|
go build -o $(BUILD_DIR)/$(BINARY_NAME)_$(word 1,$(subst /, ,$@))_$(word 2,$(subst /, ,$@)) -ldflags="-X main.version=$(VERSION) -s -w" .
|
||||||
|
|
||||||
# 清理构建文件
|
# 清理构建文件
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
45
README.md
45
README.md
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
[](https://github.com/usual2970/certimate)
|
[](https://github.com/certimate-go/certimate)
|
||||||
[](https://github.com/usual2970/certimate)
|
[](https://github.com/certimate-go/certimate)
|
||||||
[](https://hub.docker.com/r/usual2970/certimate)
|
[](https://hub.docker.com/r/certimate/certimate)
|
||||||
[](https://github.com/usual2970/certimate/releases)
|
[](https://github.com/certimate-go/certimate/releases)
|
||||||
[](https://mit-license.org/)
|
[](https://mit-license.org/)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
做个人产品或者在中小企业里负责运维的同学,会遇到要管理多个域名的情况,需要给域名申请证书。但是手动申请证书有以下缺点:
|
做个人产品或者在中小企业里负责运维的同学,会遇到要管理多个域名的情况,需要给域名申请证书。但是手动申请证书有以下缺点:
|
||||||
|
|
||||||
- 😱 麻烦:申请证书并部署到服务的流程虽不复杂,但也挺麻烦的,犹其是你有多个域名需要维护的时候。
|
- 😱 麻烦:申请证书并部署到服务的流程虽不复杂,但也挺麻烦的,尤其是你有多个域名需要维护的时候。
|
||||||
- 😭 易忘:另外当前免费证书的有效期只有 90 天,这就要求你定期的操作,增加了工作量的同时,你也很容易忘掉续期,从而导致网站访问不了。
|
- 😭 易忘:另外当前免费证书的有效期只有 90 天,这就要求你定期的操作,增加了工作量的同时,你也很容易忘掉续期,从而导致网站访问不了。
|
||||||
|
|
||||||
Certimate 就是为了解决上述问题而产生的,它具有以下优势:
|
Certimate 就是为了解决上述问题而产生的,它具有以下优势:
|
||||||
@@ -38,17 +38,17 @@ Certimate 旨在为用户提供一个安全、简便的 SSL 证书管理解决
|
|||||||
- 灵活的工作流编排方式,证书从申请到部署完全自动化;
|
- 灵活的工作流编排方式,证书从申请到部署完全自动化;
|
||||||
- 支持单域名、多域名、泛域名证书,可选 RSA、ECC 签名算法;
|
- 支持单域名、多域名、泛域名证书,可选 RSA、ECC 签名算法;
|
||||||
- 支持 PEM、PFX、JKS 等多种格式输出证书;
|
- 支持 PEM、PFX、JKS 等多种格式输出证书;
|
||||||
- 支持 20+ 域名托管商(如阿里云、腾讯云、Cloudflare 等,[点此查看](https://docs.certimate.me/docs/reference/providers#supported-dns-providers)完整提供商清单);
|
- 支持 30+ 域名托管商(如阿里云、腾讯云、Cloudflare 等,[点此查看完整清单](https://docs.certimate.me/docs/reference/providers#supported-dns-providers));
|
||||||
- 支持 60+ 部署目标(如 Kubernetes、CDN、WAF、负载均衡等,[点此查看](https://docs.certimate.me/docs/reference/providers#supported-host-providers)完整提供商清单);
|
- 支持 100+ 部署目标(如 Kubernetes、CDN、WAF、负载均衡等,[点此查看完整清单](https://docs.certimate.me/docs/reference/providers#supported-hosting-providers));
|
||||||
- 支持邮件、钉钉、飞书、企业微信、Webhook 等多种通知渠道;
|
- 支持邮件、钉钉、飞书、企业微信、Webhook 等多种通知渠道;
|
||||||
- 支持 Let's Encrypt、ZeroSSL、Google Trust Services 等多种 ACME 证书颁发机构;
|
- 支持 Let's Encrypt、Buypass、Google Trust Services、SSL.com、ZeroSSL 等多种 ACME 证书颁发机构;
|
||||||
- 更多特性等待探索。
|
- 更多特性等待探索。
|
||||||
|
|
||||||
## ⏱️ 快速启动
|
## ⏱️ 快速启动
|
||||||
|
|
||||||
**5 分钟部署 Certimate!**
|
**5 分钟部署 Certimate!**
|
||||||
|
|
||||||
以二进制部署为例,从 [GitHub Releases](https://github.com/usual2970/certimate/releases) 页面下载预先编译好的二进制可执行文件压缩包,解压缩后在终端中执行:
|
以二进制部署为例,从 [GitHub Releases](https://github.com/certimate-go/certimate/releases) 页面下载预先编译好的二进制可执行文件压缩包,解压缩后在终端中执行:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./certimate serve
|
./certimate serve
|
||||||
@@ -71,10 +71,10 @@ Certimate 旨在为用户提供一个安全、简便的 SSL 证书管理解决
|
|||||||
|
|
||||||
相关文章:
|
相关文章:
|
||||||
|
|
||||||
- [使用 CNAME 实现 DNS-01 challenge](https://docs.certimate.me/blog/cname)
|
- [《使用 CNAME 完成 ACME DNS-01 质询》](https://docs.certimate.me/blog/cname)
|
||||||
- [v0.3.0:第二个不向后兼容的大版本](https://docs.certimate.me/blog/v0.3.0)
|
- [《v0.3.0:第二个不向后兼容的大版本》](https://docs.certimate.me/blog/v0.3.0)
|
||||||
- [v0.2.0:第一个不向后兼容的大版本](https://docs.certimate.me/blog/v0.2.0)
|
- [《v0.2.0:第一个不向后兼容的大版本》](https://docs.certimate.me/blog/v0.2.0)
|
||||||
- [Why Certimate?](https://docs.certimate.me/blog/why-certimate)
|
- [《Why Certimate?》](https://docs.certimate.me/blog/why-certimate)
|
||||||
|
|
||||||
## ⭐ 运行界面
|
## ⭐ 运行界面
|
||||||
|
|
||||||
@@ -82,18 +82,19 @@ Certimate 旨在为用户提供一个安全、简便的 SSL 证书管理解决
|
|||||||
|
|
||||||
## 🤝 参与贡献
|
## 🤝 参与贡献
|
||||||
|
|
||||||
Certimate 是一个免费且开源的项目,采用 [MIT License](./LICENSE.md)。你可以使用它做任何你想做的事,甚至把它当作一个付费服务提供给用户。
|
Certimate 是一个免费且开源的项目。我们欢迎任何人为 Certimate 做出贡献,以帮助改善 Certimate。包括但不限于:提交代码、反馈缺陷、交流想法,或分享你基于 Certimate 的使用案例。同时,我们也欢迎用户在个人博客或社交媒体上分享 Certimate。
|
||||||
|
|
||||||
你可以通过以下方式来支持 Certimate 的开发:
|
如果你想要贡献代码,请先阅读我们的[贡献指南](./CONTRIBUTING.md)。
|
||||||
|
|
||||||
- 提交代码:如果你发现了 Bug 或有新的功能需求,而你又有相关经验,可以[提交代码](CONTRIBUTING.md)给我们。
|
请在 https://github.com/certimate-go/certimate 提交 [Issues](https://github.com/certimate-go/certimate/issues) 和 [Pull Requests](https://github.com/certimate-go/certimate/pulls)。
|
||||||
- 提交 Issue:功能建议或者 Bug 可以[提交 Issue](https://github.com/usual2970/certimate/issues) 给我们。
|
|
||||||
|
|
||||||
支持更多提供商、UI 的优化改进、Bug 修复、文档完善等,欢迎大家参与贡献。
|
#### 感谢以下贡献者对 Certimate 做出的贡献:
|
||||||
|
|
||||||
|
[](https://github.com/certimate-go/certimate/graphs/contributors)
|
||||||
|
|
||||||
## ⛔ 免责声明
|
## ⛔ 免责声明
|
||||||
|
|
||||||
Certimate 基于 [MIT License](https://opensource.org/licenses/MIT) 发布,完全免费提供,旨在“按现状”供用户使用。作者及贡献者不对使用本软件所产生的任何直接或间接后果承担责任,包括但不限于性能下降、数据丢失、服务中断、或任何其他类型的损害。
|
Certimate 遵循 [MIT License](https://opensource.org/licenses/MIT) 开源协议,完全免费提供,旨在“按现状”供用户使用。作者及贡献者不对使用本软件所产生的任何直接或间接后果承担责任,包括但不限于性能下降、数据丢失、服务中断、或任何其他类型的损害。
|
||||||
|
|
||||||
**无任何保证**:本软件不提供任何明示或暗示的保证,包括但不限于对特定用途的适用性、无侵权性、商用性及可靠性的保证。
|
**无任何保证**:本软件不提供任何明示或暗示的保证,包括但不限于对特定用途的适用性、无侵权性、商用性及可靠性的保证。
|
||||||
|
|
||||||
@@ -104,8 +105,8 @@ Certimate 基于 [MIT License](https://opensource.org/licenses/MIT) 发布,完
|
|||||||
- [Telegram](https://t.me/+ZXphsppxUg41YmVl)
|
- [Telegram](https://t.me/+ZXphsppxUg41YmVl)
|
||||||
- 微信群聊(超 200 人需邀请入群,可先加作者好友)
|
- 微信群聊(超 200 人需邀请入群,可先加作者好友)
|
||||||
|
|
||||||
<img src="https://i.imgur.com/8xwsLTA.png" width="240"/>
|
<img src="https://i.imgur.com/8xwsLTA.png" width="200"/>
|
||||||
|
|
||||||
## 🚀 Star 趋势图
|
## 🚀 Star 趋势图
|
||||||
|
|
||||||
[](https://starchart.cc/usual2970/certimate)
|
[](https://starchart.cc/certimate-go/certimate)
|
||||||
|
|||||||
45
README_EN.md
45
README_EN.md
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
[](https://github.com/usual2970/certimate)
|
[](https://github.com/certimate-go/certimate)
|
||||||
[](https://github.com/usual2970/certimate)
|
[](https://github.com/certimate-go/certimate)
|
||||||
[](https://hub.docker.com/r/usual2970/certimate)
|
[](https://hub.docker.com/r/certimate/certimate)
|
||||||
[](https://github.com/usual2970/certimate/releases)
|
[](https://github.com/certimate-go/certimate/releases)
|
||||||
[](https://mit-license.org/)
|
[](https://mit-license.org/)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -38,17 +38,17 @@ Certimate aims to provide users with a secure and user-friendly SSL certificate
|
|||||||
- Flexible workflow orchestration, fully automation from certificate application to deployment;
|
- Flexible workflow orchestration, fully automation from certificate application to deployment;
|
||||||
- Supports single-domain, multi-domain, wildcard certificates, with options for RSA or ECC.
|
- Supports single-domain, multi-domain, wildcard certificates, with options for RSA or ECC.
|
||||||
- Supports various certificate formats such as PEM, PFX, JKS.
|
- Supports various certificate formats such as PEM, PFX, JKS.
|
||||||
- Supports more than 20+ domain registrars (e.g., Alibaba Cloud, Tencent Cloud, Cloudflare, etc. [Check out this link](https://docs.certimate.me/en/docs/reference/providers#supported-dns-providers));
|
- Supports more than 30+ domain registrars (e.g., Alibaba Cloud, Tencent Cloud, Cloudflare, etc. [Check out this link](https://docs.certimate.me/en/docs/reference/providers#supported-dns-providers));
|
||||||
- Supports more than 60+ deployment targets (e.g., Kubernetes, CDN, WAF, load balancers, etc. [Check out this link](https://docs.certimate.me/en/docs/reference/providers#supported-host-providers));
|
- Supports more than 100+ deployment targets (e.g., Kubernetes, CDN, WAF, load balancers, etc. [Check out this link](https://docs.certimate.me/en/docs/reference/providers#supported-hosting-providers));
|
||||||
- Supports multiple notification channels including email, DingTalk, Feishu, WeCom, Webhook, and more;
|
- Supports multiple notification channels including email, DingTalk, Feishu, WeCom, Webhook, and more;
|
||||||
- Supports multiple ACME CAs including Let's Encrypt, ZeroSSL, Google Trust Services, and more;
|
- Supports multiple ACME CAs including Let's Encrypt, Buypass, Google Trust Services,SSL.com, ZeroSSL, and more;
|
||||||
- More features waiting to be discovered.
|
- More features waiting to be discovered.
|
||||||
|
|
||||||
## ⏱️ Fast Track
|
## ⏱️ Fast Track
|
||||||
|
|
||||||
**Deploy Certimate in 5 minutes!**
|
**Deploy Certimate in 5 minutes!**
|
||||||
|
|
||||||
Download the archived package of precompiled binary files directly from [GitHub Releases](https://github.com/usual2970/certimate/releases), extract and then execute:
|
Download the archived package of precompiled binary files directly from [GitHub Releases](https://github.com/certimate-go/certimate/releases), extract and then execute:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./certimate serve
|
./certimate serve
|
||||||
@@ -65,14 +65,14 @@ Work with Certimate right now. Or read other content in the documentation to lea
|
|||||||
|
|
||||||
## 📄 Documentation
|
## 📄 Documentation
|
||||||
|
|
||||||
Please visit the documentation site [docs.certimate.me](https://docs.certimate.me/en/).
|
For full documentation, please visit [docs.certimate.me](https://docs.certimate.me/en/).
|
||||||
|
|
||||||
Related articles:
|
Related articles:
|
||||||
|
|
||||||
- [使用 CNAME 实现 DNS-01 challenge](https://docs.certimate.me/blog/cname)
|
- [_使用 CNAME 完成 ACME DNS-01 质询_](https://docs.certimate.me/blog/cname)
|
||||||
- [v0.3.0:第二个不向后兼容的大版本](https://docs.certimate.me/blog/v0.3.0)
|
- [_v0.3.0:第二个不向后兼容的大版本_](https://docs.certimate.me/blog/v0.3.0)
|
||||||
- [v0.2.0:第一个不向后兼容的大版本](https://docs.certimate.me/blog/v0.2.0)
|
- [_v0.2.0:第一个不向后兼容的大版本_](https://docs.certimate.me/blog/v0.2.0)
|
||||||
- [Why Certimate?](https://docs.certimate.me/blog/why-certimate)
|
- [_Why Certimate?_](https://docs.certimate.me/blog/why-certimate)
|
||||||
|
|
||||||
## ⭐ Screenshot
|
## ⭐ Screenshot
|
||||||
|
|
||||||
@@ -80,18 +80,19 @@ Related articles:
|
|||||||
|
|
||||||
## 🤝 Contributing
|
## 🤝 Contributing
|
||||||
|
|
||||||
Certimate is a free and open-source project, licensed under the [MIT License](./LICENSE.md). You can use it for anything you want, even offering it as a paid service to users.
|
Certimate is a free and open-source project, and your feedback and contributions are needed and always welcome. Contributions include but are not limited to: submitting code, reporting bugs, sharing ideas, or showcasing your use cases based on Certimate. We also encourage users to share Certimate on personal blogs or social media.
|
||||||
|
|
||||||
You can support the development of Certimate in the following ways:
|
For those who'd like to contribute code, see our [Contribution Guide](./CONTRIBUTING_EN.md).
|
||||||
|
|
||||||
- **Submit Code**: If you find a bug or have new feature requests, and you have relevant experience, [you can submit code to us](CONTRIBUTING_EN.md).
|
[Issues](https://github.com/certimate-go/certimate/issues) and [Pull Requests](https://github.com/certimate-go/certimate/pulls) are opened at https://github.com/certimate-go/certimate.
|
||||||
- **Submit an Issue**: For feature suggestions or bugs, you can [submit an issue](https://github.com/usual2970/certimate/issues) to us.
|
|
||||||
|
|
||||||
Support for more service providers, UI enhancements, bug fixes, and documentation improvements are all welcome. We encourage everyone to contribute.
|
#### Contributors
|
||||||
|
|
||||||
|
[](https://github.com/certimate-go/certimate/graphs/contributors)
|
||||||
|
|
||||||
## ⛔ Disclaimer
|
## ⛔ Disclaimer
|
||||||
|
|
||||||
This software is provided under the [MIT License](https://opensource.org/licenses/MIT) and distributed “as-is” without any warranty of any kind. The authors and contributors are not responsible for any damages or losses resulting from the use or inability to use this software, including but not limited to data loss, business interruption, or any other potential harm.
|
This repository is available under the [MIT License](https://opensource.org/licenses/MIT), and distributed “as-is” without any warranty of any kind. The authors and contributors are not responsible for any damages or losses resulting from the use or inability to use this software, including but not limited to data loss, business interruption, or any other potential harm.
|
||||||
|
|
||||||
**No Warranties**: This software comes without any express or implied warranties, including but not limited to implied warranties of merchantability, fitness for a particular purpose, and non-infringement.
|
**No Warranties**: This software comes without any express or implied warranties, including but not limited to implied warranties of merchantability, fitness for a particular purpose, and non-infringement.
|
||||||
|
|
||||||
@@ -102,8 +103,8 @@ This software is provided under the [MIT License](https://opensource.org/license
|
|||||||
- [Telegram](https://t.me/+ZXphsppxUg41YmVl)
|
- [Telegram](https://t.me/+ZXphsppxUg41YmVl)
|
||||||
- Wechat Group
|
- Wechat Group
|
||||||
|
|
||||||
<img src="https://i.imgur.com/zSHEoIm.png" width="240"/>
|
<img src="https://i.imgur.com/zSHEoIm.png" width="200"/>
|
||||||
|
|
||||||
## 🚀 Star History
|
## 🚀 Star History
|
||||||
|
|
||||||
[](https://starchart.cc/usual2970/certimate)
|
[](https://starchart.cc/certimate-go/certimate)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
version: "3.0"
|
version: "3.0"
|
||||||
services:
|
services:
|
||||||
certimate:
|
certimate:
|
||||||
image: registry.cn-shanghai.aliyuncs.com/usual2970/certimate:latest
|
image: certimate/certimate:latest
|
||||||
container_name: certimate_server
|
container_name: certimate
|
||||||
ports:
|
ports:
|
||||||
- 8090:8090
|
- 8090:8090
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
207
go.mod
207
go.mod
@@ -1,88 +1,98 @@
|
|||||||
module github.com/usual2970/certimate
|
module github.com/certimate-go/certimate
|
||||||
|
|
||||||
go 1.23.0
|
go 1.24.0
|
||||||
|
|
||||||
toolchain go1.23.2
|
toolchain go1.24.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1
|
||||||
github.com/G-Core/gcorelabscdn-go v1.0.28
|
github.com/Edgio/edgio-api v0.0.0-workspace
|
||||||
|
github.com/G-Core/gcorelabscdn-go v1.0.31
|
||||||
github.com/alibabacloud-go/alb-20200616/v2 v2.2.8
|
github.com/alibabacloud-go/alb-20200616/v2 v2.2.8
|
||||||
|
github.com/alibabacloud-go/apig-20240327/v3 v3.2.2
|
||||||
github.com/alibabacloud-go/cas-20200407/v3 v3.0.4
|
github.com/alibabacloud-go/cas-20200407/v3 v3.0.4
|
||||||
github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2
|
github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4
|
github.com/alibabacloud-go/cloudapi-20160714/v5 v5.7.4
|
||||||
github.com/alibabacloud-go/esa-20240910/v2 v2.23.0
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7
|
||||||
github.com/alibabacloud-go/fc-20230330/v4 v4.1.7
|
github.com/alibabacloud-go/ddoscoo-20200101/v4 v4.0.0
|
||||||
|
github.com/alibabacloud-go/esa-20240910/v2 v2.33.0
|
||||||
|
github.com/alibabacloud-go/fc-20230330/v4 v4.3.5
|
||||||
github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12
|
github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12
|
||||||
|
github.com/alibabacloud-go/ga-20191120/v3 v3.1.8
|
||||||
github.com/alibabacloud-go/live-20161101 v1.1.1
|
github.com/alibabacloud-go/live-20161101 v1.1.1
|
||||||
github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3
|
github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3
|
||||||
github.com/alibabacloud-go/slb-20140515/v4 v4.0.10
|
github.com/alibabacloud-go/slb-20140515/v4 v4.0.10
|
||||||
github.com/alibabacloud-go/tea v1.3.4
|
github.com/alibabacloud-go/tea v1.3.9
|
||||||
github.com/alibabacloud-go/vod-20170321/v4 v4.7.0
|
github.com/alibabacloud-go/vod-20170321/v4 v4.8.4
|
||||||
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5
|
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.1.3
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||||
github.com/aws/aws-sdk-go-v2/service/acm v1.31.1
|
github.com/aws/aws-sdk-go-v2/service/acm v1.32.0
|
||||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.2
|
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1
|
||||||
github.com/baidubce/bce-sdk-go v0.9.221
|
github.com/aws/aws-sdk-go-v2/service/iam v1.42.0
|
||||||
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.42
|
github.com/baidubce/bce-sdk-go v0.9.228
|
||||||
github.com/go-acme/lego/v4 v4.22.2
|
github.com/blinkbean/dingtalk v1.1.3
|
||||||
|
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.46
|
||||||
|
github.com/go-acme/lego/v4 v4.23.1
|
||||||
|
github.com/go-lark/lark v1.16.0
|
||||||
github.com/go-resty/resty/v2 v2.16.5
|
github.com/go-resty/resty/v2 v2.16.5
|
||||||
github.com/go-viper/mapstructure/v2 v2.2.1
|
github.com/go-viper/mapstructure/v2 v2.2.1
|
||||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.141
|
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.150
|
||||||
github.com/jdcloud-api/jdcloud-sdk-go v1.64.0
|
github.com/jdcloud-api/jdcloud-sdk-go v1.64.0
|
||||||
github.com/libdns/dynv6 v1.0.0
|
github.com/libdns/dynv6 v1.0.0
|
||||||
github.com/libdns/libdns v0.2.3
|
github.com/libdns/libdns v0.2.3
|
||||||
github.com/nikoksr/notify v1.3.0
|
github.com/luthermonson/go-proxmox v0.2.2
|
||||||
github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0
|
github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0
|
||||||
github.com/pkg/sftp v1.13.8
|
github.com/pkg/sftp v1.13.9
|
||||||
github.com/pocketbase/dbx v1.11.0
|
github.com/pocketbase/dbx v1.11.0
|
||||||
github.com/pocketbase/pocketbase v0.26.1
|
github.com/pocketbase/pocketbase v0.28.2
|
||||||
github.com/povsister/scp v0.0.0-20240802064259-28781e87b246
|
github.com/povsister/scp v0.0.0-20250504051308-e467f71ea63c
|
||||||
github.com/qiniu/go-sdk/v7 v7.25.2
|
github.com/qiniu/go-sdk/v7 v7.25.3
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1155
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1127
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1166
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1127
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1173
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1117
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap v1.0.1163
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1172
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1126
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1169
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1115
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1166
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1125
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1164
|
||||||
github.com/ucloud/ucloud-sdk-go v0.22.31
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1170
|
||||||
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9
|
github.com/ucloud/ucloud-sdk-go v0.22.41
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.199
|
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.12
|
||||||
github.com/volcengine/volcengine-go-sdk v1.0.187
|
github.com/volcengine/volc-sdk-golang v1.0.208
|
||||||
|
github.com/volcengine/volcengine-go-sdk v1.1.8
|
||||||
gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1
|
gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1
|
||||||
gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0
|
gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0
|
||||||
golang.org/x/crypto v0.36.0
|
golang.org/x/crypto v0.38.0
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
|
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6
|
||||||
k8s.io/api v0.32.3
|
k8s.io/api v0.33.1
|
||||||
k8s.io/apimachinery v0.32.3
|
k8s.io/apimachinery v0.33.1
|
||||||
k8s.io/client-go v0.32.3
|
k8s.io/client-go v0.33.1
|
||||||
software.sslmate.com/src/go-pkcs12 v0.5.0
|
software.sslmate.com/src/go-pkcs12 v0.5.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 // indirect
|
||||||
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
|
||||||
github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.7 // indirect
|
github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.7 // indirect
|
||||||
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 // indirect
|
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 // indirect
|
||||||
github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect
|
github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect
|
||||||
github.com/alibabacloud-go/tea-oss-sdk v1.1.3 // indirect
|
github.com/alibabacloud-go/tea-oss-sdk v1.1.5 // indirect
|
||||||
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
|
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
|
||||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect
|
||||||
github.com/avast/retry-go v3.0.0+incompatible // indirect
|
github.com/avast/retry-go v3.0.0+incompatible // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1 // indirect
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 // indirect
|
||||||
github.com/blinkbean/dingtalk v1.1.3 // indirect
|
github.com/buger/goterm v1.0.4 // indirect
|
||||||
|
github.com/diskfs/go-diskfs v1.5.0 // indirect
|
||||||
|
github.com/djherbis/times v1.6.0 // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||||
github.com/go-lark/lark v1.15.1 // indirect
|
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
@@ -91,27 +101,32 @@ require (
|
|||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.16.0 // indirect
|
github.com/go-playground/validator/v10 v10.16.0 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
|
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
|
||||||
github.com/google/gnostic-models v0.6.9 // indirect
|
github.com/google/gnostic-models v0.6.9 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||||
|
github.com/jinzhu/copier v0.3.4 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/magefile/mage v1.14.0 // indirect
|
||||||
github.com/mailru/easyjson v0.9.0 // indirect
|
github.com/mailru/easyjson v0.9.0 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
|
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
|
||||||
|
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 // indirect
|
||||||
|
github.com/nrdcg/desec v0.10.0 // indirect
|
||||||
github.com/nrdcg/mailinabox v0.2.0 // indirect
|
github.com/nrdcg/mailinabox v0.2.0 // indirect
|
||||||
|
github.com/nrdcg/porkbun v0.4.0 // indirect
|
||||||
|
github.com/peterhellberg/link v1.2.0 // indirect
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||||
github.com/qiniu/dyn v1.3.0 // indirect
|
github.com/qiniu/dyn v1.3.0 // indirect
|
||||||
github.com/qiniu/x v1.10.5 // indirect
|
github.com/qiniu/x v1.10.5 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
|
||||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.17.2 // indirect
|
go.mongodb.org/mongo-driver v1.17.2 // indirect
|
||||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||||
@@ -119,15 +134,16 @@ require (
|
|||||||
gopkg.in/ns1/ns1-go.v2 v2.13.0 // indirect
|
gopkg.in/ns1/ns1-go.v2 v2.13.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
k8s.io/klog/v2 v2.130.1 // indirect
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
||||||
github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0
|
github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0
|
||||||
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
||||||
@@ -135,35 +151,35 @@ require (
|
|||||||
github.com/alibabacloud-go/openapi-util v0.1.1 // indirect
|
github.com/alibabacloud-go/openapi-util v0.1.1 // indirect
|
||||||
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
|
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
|
||||||
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
||||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.83 // indirect
|
github.com/aliyun/alibaba-cloud-sdk-go v1.63.100 // indirect
|
||||||
github.com/aliyun/credentials-go v1.4.3 // indirect
|
github.com/aliyun/credentials-go v1.4.6 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.36.3
|
github.com/aws/aws-sdk-go-v2 v1.36.3
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.29.5
|
github.com/aws/aws-sdk-go-v2/config v1.29.9
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.58
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.62
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect
|
||||||
github.com/aws/smithy-go v1.22.2 // indirect
|
github.com/aws/smithy-go v1.22.2 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||||
github.com/cloudflare/cloudflare-go v0.114.0 // indirect
|
github.com/cloudflare/cloudflare-go v0.115.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/disintegration/imaging v1.6.2 // indirect
|
github.com/disintegration/imaging v1.6.2 // indirect
|
||||||
github.com/domodwyer/mailyak/v3 v3.6.2
|
github.com/domodwyer/mailyak/v3 v3.6.2
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||||
github.com/ganigeorgiev/fexpr v0.4.1 // indirect
|
github.com/ganigeorgiev/fexpr v0.5.0 // indirect
|
||||||
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.4 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
@@ -172,40 +188,39 @@ require (
|
|||||||
github.com/kr/fs v0.1.0 // indirect
|
github.com/kr/fs v0.1.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/miekg/dns v1.1.62 // indirect
|
github.com/miekg/dns v1.1.64 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/nrdcg/namesilo v0.2.1 // indirect
|
github.com/nrdcg/namesilo v0.2.1 // indirect
|
||||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/spf13/cast v1.8.0 // indirect
|
||||||
github.com/spf13/cast v1.7.1 // indirect
|
|
||||||
github.com/spf13/cobra v1.9.1 // indirect
|
github.com/spf13/cobra v1.9.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.6 // indirect
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
github.com/stretchr/objx v0.5.2 // indirect
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 // indirect
|
||||||
github.com/stretchr/testify v1.10.0 // indirect
|
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084 // indirect
|
|
||||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||||
golang.org/x/image v0.25.0 // indirect
|
golang.org/x/image v0.27.0 // indirect
|
||||||
golang.org/x/mod v0.24.0 // indirect
|
golang.org/x/mod v0.24.0 // indirect
|
||||||
golang.org/x/net v0.37.0 // indirect
|
golang.org/x/net v0.40.0 // indirect
|
||||||
golang.org/x/oauth2 v0.28.0 // indirect
|
golang.org/x/oauth2 v0.30.0 // indirect
|
||||||
golang.org/x/sync v0.12.0
|
golang.org/x/sync v0.14.0
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/term v0.30.0 // indirect
|
golang.org/x/term v0.32.0 // indirect
|
||||||
golang.org/x/text v0.23.0 // indirect
|
golang.org/x/text v0.25.0 // indirect
|
||||||
golang.org/x/time v0.9.0
|
golang.org/x/time v0.11.0
|
||||||
golang.org/x/tools v0.31.0 // indirect
|
golang.org/x/tools v0.33.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.5 // indirect
|
google.golang.org/protobuf v1.36.5 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
modernc.org/libc v1.61.13 // indirect
|
modernc.org/libc v1.65.7 // indirect
|
||||||
modernc.org/mathutil v1.7.1 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/memory v1.8.2 // indirect
|
modernc.org/memory v1.11.0 // indirect
|
||||||
modernc.org/sqlite v1.36.1 // indirect
|
modernc.org/sqlite v1.37.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 => ./internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0
|
replace github.com/Edgio/edgio-api v0.0.0-workspace => ./pkg/sdk3rd/edgio/edgio-api@v0.0.0-workspace
|
||||||
|
|
||||||
replace gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 => ./internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1
|
replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 => ./pkg/sdk3rd/cmcc/ecloudsdkcore@v1.0.0
|
||||||
|
|
||||||
|
replace gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 => ./pkg/sdk3rd/cmcc/ecloudsdkclouddns@v1.0.1
|
||||||
|
|||||||
447
go.sum
447
go.sum
@@ -34,18 +34,14 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
|||||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
|
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys=
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0 h1:j8BorDEigD8UFOSZQiSqAMOOleyQOOQPnUAwV+Ls1gA=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 h1:btEsytNrA4TG3edZnnUnzOz8W2MjOd6Bu3/7xyOXSOY=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0/go.mod h1:5SlTxxL1U4LLipEr7pAbnu6Ck5y3aIEu4L/tVbGmpsY=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0 h1:2qsIIvxVT+uE6yrNldntJKlLRgxGbZ85kgtz5SNBhMw=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0 h1:2qsIIvxVT+uE6yrNldntJKlLRgxGbZ85kgtz5SNBhMw=
|
||||||
@@ -56,19 +52,23 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourceg
|
|||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1 h1:HUJQzFYTv7t3V1dxPms52eEgl0l9xCNqutDrY45Lvmw=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1/go.mod h1:ig/8nSkzmfxm5QGeIy5JYIEj8JEFy5JxvY3OB1YNRC4=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 h1:bFWuoEKg+gImo7pvkiQEFAc8ocibADgXeiLAxWhWmkI=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1/go.mod h1:Vih/3yc6yac2JzU4hzpaDupBJP0Flaia9rXXrU8xyww=
|
||||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
|
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
|
||||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
|
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4=
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
github.com/G-Core/gcorelabscdn-go v1.0.28 h1:6ymVMV3HPTICO5BWJCEcZZzgY+Pc/+/TQMzeXMN77GQ=
|
github.com/G-Core/gcorelabscdn-go v1.0.31 h1:0ulvvM3yMDQ+Q5089tLsQxffL7I4pqf2bFCurU+DeHw=
|
||||||
github.com/G-Core/gcorelabscdn-go v1.0.28/go.mod h1:iSGXaTvZBzDHQW+rKFS918BgFVpONcyLEijwh8WsXpE=
|
github.com/G-Core/gcorelabscdn-go v1.0.31/go.mod h1:iSGXaTvZBzDHQW+rKFS918BgFVpONcyLEijwh8WsXpE=
|
||||||
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
@@ -95,10 +95,14 @@ github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do2
|
|||||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
|
||||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
|
||||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
|
||||||
|
github.com/alibabacloud-go/apig-20240327/v3 v3.2.2 h1:yH84ePgqtA2tF3ly7Tf3AA5ogl2SC8kqCNG4+zz4yo4=
|
||||||
|
github.com/alibabacloud-go/apig-20240327/v3 v3.2.2/go.mod h1:XLaCapbSH7olJTs42wisDO9JvX9BGy5acZk0bLNejDs=
|
||||||
github.com/alibabacloud-go/cas-20200407/v3 v3.0.4 h1:ngRlctbt135zoujwX0lXSv9m4h1/bmg/yalQS0z1EWc=
|
github.com/alibabacloud-go/cas-20200407/v3 v3.0.4 h1:ngRlctbt135zoujwX0lXSv9m4h1/bmg/yalQS0z1EWc=
|
||||||
github.com/alibabacloud-go/cas-20200407/v3 v3.0.4/go.mod h1:6n9MZ9SH3HlSzfe2oKwjOqhJx3dxvW2gMDO+lq8t9U4=
|
github.com/alibabacloud-go/cas-20200407/v3 v3.0.4/go.mod h1:6n9MZ9SH3HlSzfe2oKwjOqhJx3dxvW2gMDO+lq8t9U4=
|
||||||
github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2 h1:+KJOPukTM+xMyiLOW5qBwYKG2df3Ar7coRsqc1juKO8=
|
github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2 h1:+KJOPukTM+xMyiLOW5qBwYKG2df3Ar7coRsqc1juKO8=
|
||||||
github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2/go.mod h1:GnPiPL3HlzCi8SGiLiVgKrAFkP1vTtcF4yGtjsl4wfo=
|
github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2/go.mod h1:GnPiPL3HlzCi8SGiLiVgKrAFkP1vTtcF4yGtjsl4wfo=
|
||||||
|
github.com/alibabacloud-go/cloudapi-20160714/v5 v5.7.4 h1:SsyAoXM1R4J3I4xQdPW/rRW8cTo2KN440/4h/pGiwRQ=
|
||||||
|
github.com/alibabacloud-go/cloudapi-20160714/v5 v5.7.4/go.mod h1:eUmD1G4BjEBOAHIeJrHJL7pyLGgXSRTPLjBmYY7uPEg=
|
||||||
github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
|
github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
|
||||||
github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
|
github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
|
||||||
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
|
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
|
||||||
@@ -108,15 +112,19 @@ github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+M
|
|||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.5/go.mod h1:kUe8JqFmoVU7lfBauaDD5taFaW7mBI+xVsyHutYtabg=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.5/go.mod h1:kUe8JqFmoVU7lfBauaDD5taFaW7mBI+xVsyHutYtabg=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9/go.mod h1:bb+Io8Sn2RuM3/Rpme6ll86jMyFSrD1bxeV/+v61KeU=
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4 h1:IGSZHlOnWwBbLtX5xDplQvZOH0nkrV7Wmq+Fto7JK5w=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.11/go.mod h1:wHxkgZT1ClZdcwEVP/pDgYK/9HucsnCfMipmJgCz4xY=
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4/go.mod h1:Wxis0IBFusdbo44HO6KYYCJR1rRkoh47QQOYWvaheSU=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 h1:ASXSBga98QrGMxbIThCD6jAti09gedLfvry6yJtsoBE=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7/go.mod h1:TBpgqm3XofZz2LCYjZhektGPU7ArEgascyzbm4SjFo4=
|
||||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
||||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
||||||
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
||||||
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||||
github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0 h1:EQmKhYju6y38kJ1ZvZROeJG2Q1Wk6hlc8KQrVhvGyaw=
|
github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0 h1:EQmKhYju6y38kJ1ZvZROeJG2Q1Wk6hlc8KQrVhvGyaw=
|
||||||
github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0/go.mod h1:b9qzvr/2V1f0r1Z6xUmkLqEouKcPGy4LCC22yV+6HQo=
|
github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0/go.mod h1:b9qzvr/2V1f0r1Z6xUmkLqEouKcPGy4LCC22yV+6HQo=
|
||||||
|
github.com/alibabacloud-go/ddoscoo-20200101/v4 v4.0.0 h1:z9dPOvBRxzpD+FQ2uu/p2Z92I+PY9MUZMauwC+8AC6M=
|
||||||
|
github.com/alibabacloud-go/ddoscoo-20200101/v4 v4.0.0/go.mod h1:Cdg3Fu4jFByamRzt3AkeiBssoVPRNDs+EPYMP2fIj78=
|
||||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
||||||
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
||||||
github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
|
github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
|
||||||
@@ -124,12 +132,14 @@ github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/ql
|
|||||||
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
||||||
github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8=
|
github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8=
|
||||||
github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
||||||
github.com/alibabacloud-go/esa-20240910/v2 v2.23.0 h1:Z/AALmxhOfzN+35tNCvm62/pET4IlxhDQn4nsdLqNzk=
|
github.com/alibabacloud-go/esa-20240910/v2 v2.33.0 h1:10IWxrMcF1W6/7BUJIJifrofduSG0wRFqDbRfIsR3Zw=
|
||||||
github.com/alibabacloud-go/esa-20240910/v2 v2.23.0/go.mod h1:P1w/+i7dE2xSXVHJznEOVImlLtqqrzUJQQk2AsyBJ6o=
|
github.com/alibabacloud-go/esa-20240910/v2 v2.33.0/go.mod h1:HZS5PmYJvcmH4vrJYuCvK3AnYzD9hLlO8CT0hgRyDXo=
|
||||||
github.com/alibabacloud-go/fc-20230330/v4 v4.1.7 h1:rQvPfzPaouL/WGNgMDMCplA4wDscmVFff7aLCUkjv4g=
|
github.com/alibabacloud-go/fc-20230330/v4 v4.3.5 h1:nDNjVzGwkQPbQnAuxAmxvS9x8QGLph8j0ptEdZDPGBA=
|
||||||
github.com/alibabacloud-go/fc-20230330/v4 v4.1.7/go.mod h1:ssEfKO6MskPtq7QaQnyiOHGWLXOZcl7a8YIf8u56DGc=
|
github.com/alibabacloud-go/fc-20230330/v4 v4.3.5/go.mod h1:vEJimQ6E/e+m2z0/oXdeQWlFw/Pi/Ar6NKcMrSvcILE=
|
||||||
github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12 h1:A3D8Mp6qf8DfR6Dt5MpS8aDVaWfS4N85T5CvGUvgrjM=
|
github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12 h1:A3D8Mp6qf8DfR6Dt5MpS8aDVaWfS4N85T5CvGUvgrjM=
|
||||||
github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12/go.mod h1:F5c0E5UB3k8v6neTtw3FBcJ1YCNFzVoL1JPRHTe33u4=
|
github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12/go.mod h1:F5c0E5UB3k8v6neTtw3FBcJ1YCNFzVoL1JPRHTe33u4=
|
||||||
|
github.com/alibabacloud-go/ga-20191120/v3 v3.1.8 h1:5GF0PXijDhxRQ3gTg9Ee/CVPtglkxuVdz4yIQgYLPgw=
|
||||||
|
github.com/alibabacloud-go/ga-20191120/v3 v3.1.8/go.mod h1:RVpR9VL4YECKoZCQijTYfPk8k52O61v6hSRekjxF0kw=
|
||||||
github.com/alibabacloud-go/live-20161101 v1.1.1 h1:rUGfA8RHmCMtQ5M3yMSyRde+yRXWqVecmiXBU3XrGJ8=
|
github.com/alibabacloud-go/live-20161101 v1.1.1 h1:rUGfA8RHmCMtQ5M3yMSyRde+yRXWqVecmiXBU3XrGJ8=
|
||||||
github.com/alibabacloud-go/live-20161101 v1.1.1/go.mod h1:g84w6qeAodT0/IHdc0tEed2a8PyhQhYl7TAj3jGl4A4=
|
github.com/alibabacloud-go/live-20161101 v1.1.1/go.mod h1:g84w6qeAodT0/IHdc0tEed2a8PyhQhYl7TAj3jGl4A4=
|
||||||
github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3 h1:LtyUVlgBEKyzWgQJurzXM6MXCt84sQr9cE5OKqYymko=
|
github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3 h1:LtyUVlgBEKyzWgQJurzXM6MXCt84sQr9cE5OKqYymko=
|
||||||
@@ -153,13 +163,14 @@ github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy
|
|||||||
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||||
github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA=
|
github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA=
|
||||||
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
||||||
github.com/alibabacloud-go/tea v1.3.2/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
github.com/alibabacloud-go/tea v1.3.8/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||||
github.com/alibabacloud-go/tea v1.3.4 h1:QGTns2930y+ANmoNcUS74TgYpsoqusSrLIyYDOvIFFI=
|
github.com/alibabacloud-go/tea v1.3.9 h1:bjgt1bvdY780vz/17iWNNtbXl4A77HWntWMeaUF3So0=
|
||||||
github.com/alibabacloud-go/tea v1.3.4/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
github.com/alibabacloud-go/tea v1.3.9/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||||
github.com/alibabacloud-go/tea-fileform v1.1.1 h1:1YG6erAP3joQ0XdCXYIotuD7zyOM6qCR49xkp5FZDeU=
|
github.com/alibabacloud-go/tea-fileform v1.1.1 h1:1YG6erAP3joQ0XdCXYIotuD7zyOM6qCR49xkp5FZDeU=
|
||||||
github.com/alibabacloud-go/tea-fileform v1.1.1/go.mod h1:ZeCV91o4ISmxidd686f0ebdS5EDHWU+vW+TkjLhrsFE=
|
github.com/alibabacloud-go/tea-fileform v1.1.1/go.mod h1:ZeCV91o4ISmxidd686f0ebdS5EDHWU+vW+TkjLhrsFE=
|
||||||
github.com/alibabacloud-go/tea-oss-sdk v1.1.3 h1:EhAHI6edMeqgkZEqP7r4nc9iMWAUBKGxJHoBsOSKTtU=
|
|
||||||
github.com/alibabacloud-go/tea-oss-sdk v1.1.3/go.mod h1:yUnodpR3Bf2rudLE7V/Gft5txjJF30Pk+hH77K/Eab0=
|
github.com/alibabacloud-go/tea-oss-sdk v1.1.3/go.mod h1:yUnodpR3Bf2rudLE7V/Gft5txjJF30Pk+hH77K/Eab0=
|
||||||
|
github.com/alibabacloud-go/tea-oss-sdk v1.1.5 h1:CFUFcqanvBaoGN/CyTHUZrVNtFZd1WTjem46m0HTTV0=
|
||||||
|
github.com/alibabacloud-go/tea-oss-sdk v1.1.5/go.mod h1:5fhlKMa/kWRJNgPYRt+5qSg3UidRvNbf9Z2bI8Dp5/s=
|
||||||
github.com/alibabacloud-go/tea-oss-utils v1.1.0 h1:y65crjjcZ2Pbb6UZtC2deuIZHDVTS3IaDWE7M9nVLRc=
|
github.com/alibabacloud-go/tea-oss-utils v1.1.0 h1:y65crjjcZ2Pbb6UZtC2deuIZHDVTS3IaDWE7M9nVLRc=
|
||||||
github.com/alibabacloud-go/tea-oss-utils v1.1.0/go.mod h1:PFCF12e9yEKyBUIn7X1IrF/pNjvxgkHy0CgxX4+xRuY=
|
github.com/alibabacloud-go/tea-oss-utils v1.1.0/go.mod h1:PFCF12e9yEKyBUIn7X1IrF/pNjvxgkHy0CgxX4+xRuY=
|
||||||
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
||||||
@@ -177,20 +188,21 @@ github.com/alibabacloud-go/tea-xml v1.1.1/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCE
|
|||||||
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||||
github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
|
github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
|
||||||
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||||
github.com/alibabacloud-go/vod-20170321/v4 v4.7.0 h1:hpsnJBX5EeMrFujopMCjfq+p8XbNvPhFw6LOTV/WHd8=
|
github.com/alibabacloud-go/vod-20170321/v4 v4.8.4 h1:MYP2xfrcud8vlWljQ4lhemNgAgi9/AUAa450n8TUXZo=
|
||||||
github.com/alibabacloud-go/vod-20170321/v4 v4.7.0/go.mod h1:TkgLKMSLu0qZN8Qdcu8svfHREyI64kjFvrp/GhrD4VQ=
|
github.com/alibabacloud-go/vod-20170321/v4 v4.8.4/go.mod h1:5ocQ6hIc9tpGixD2iy099aOGwIgpzjT2le4Krd4aLn8=
|
||||||
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5 h1:ldAm1nvsCq66igjtcZyGhAoLClr+2eZ/pMIBUdKCOMM=
|
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.1.3 h1:25tmcJxIitrk55crBGssPlqRzmFcpGVW5TEFxdUvfg0=
|
||||||
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5/go.mod h1:DohGoS8BnMxHXghHebtjPP7+GMdxPsRN19T3nn2HcCU=
|
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.1.3/go.mod h1:9itYSTzipL3NlvhvNYfTjFaapoZzG68nlu/KUdh9SpA=
|
||||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.83 h1:YBkf7H5CSgrlb3C1aWcpDt7Vk8UEGFPeD2OOirtt6IM=
|
github.com/aliyun/alibaba-cloud-sdk-go v1.63.100 h1:yUkCbrSM1cWtgBfRVKMQtdt22KhDvKY7g4V+92eG9wA=
|
||||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.83/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
|
github.com/aliyun/alibaba-cloud-sdk-go v1.63.100/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
|
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||||
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
||||||
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
|
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
|
||||||
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
|
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
|
||||||
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||||
github.com/aliyun/credentials-go v1.4.3 h1:N3iHyvHRMyOwY1+0qBLSf3hb5JFiOujVSVuEpgeGttY=
|
github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||||
github.com/aliyun/credentials-go v1.4.3/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
github.com/aliyun/credentials-go v1.4.6 h1:CG8rc/nxCNKfXbZWpWDzI9GjF4Tuu3Es14qT8Y0ClOk=
|
||||||
|
github.com/aliyun/credentials-go v1.4.6/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
@@ -206,40 +218,42 @@ github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm
|
|||||||
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
|
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.29.5 h1:4lS2IB+wwkj5J43Tq/AwvnscBerBJtQQ6YS7puzCI1k=
|
github.com/aws/aws-sdk-go-v2/config v1.29.9 h1:Kg+fAYNaJeGXp1vmjtidss8O2uXIsXwaRqsQJKXVr+0=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.29.5/go.mod h1:SNzldMlDVbN6nWxM7XsUiNXPSa1LWlqiXtvh/1PrJGg=
|
github.com/aws/aws-sdk-go-v2/config v1.29.9/go.mod h1:oU3jj2O53kgOU4TXq/yipt6ryiooYjlkqqVaZk7gY/U=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.58 h1:/d7FUpAPU8Lf2KUdjniQvfNdlMID0Sd9pS23FJ3SS9Y=
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.62 h1:fvtQY3zFzYJ9CfixuAQ96IxDrBajbBWGqjNTCa79ocU=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.58/go.mod h1:aVYW33Ow10CyMQGFgC0ptMRIqJWvJ4nxZb0sUiuQT/A=
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.62/go.mod h1:ElETBxIQqcxej++Cs8GyPBbgMys5DgQPTwo7cUPDKt8=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 h1:KwsodFKVQTlI5EyhRSugALzsV6mG/SGrdjlMXSZSdso=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28/go.mod h1:EY3APf9MzygVhKuPXAc5H+MkGb8k/DOSQjWS0LgkKqI=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/acm v1.31.1 h1:FB1PgU6vlXbqehxZiHuYQRWo5Ou6sQrFJcUaRe27lRo=
|
github.com/aws/aws-sdk-go-v2/service/acm v1.32.0 h1:Ik/TAn4TBw/t3JhQJKtwjgoOf6kg5nXc190TiGhNrmI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/acm v1.31.1/go.mod h1:3sKYAgRbuBa2QMYGh/WEclwnmfx+QoPhhX25PdSQSQM=
|
github.com/aws/aws-sdk-go-v2/service/acm v1.32.0/go.mod h1:3sKYAgRbuBa2QMYGh/WEclwnmfx+QoPhhX25PdSQSQM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.2 h1:S3JpsBLyn/jqSJ6GgsbDQHubmop6fshQk/iOaOeotsc=
|
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1 h1:6xZNYtuVwzBs8k+TmraERt0vL68Ppg9aUi+aTQmPaVM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.2/go.mod h1:FIBJ48TS+qJb+Ne4qJ+0NeIhtPTVXItXooTeNeVI4Po=
|
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1/go.mod h1:FIBJ48TS+qJb+Ne4qJ+0NeIhtPTVXItXooTeNeVI4Po=
|
||||||
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
|
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA=
|
github.com/aws/aws-sdk-go-v2/service/iam v1.42.0 h1:G6+UzGvubaet9QOh0664E9JeT+b6Zvop3AChozRqkrA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY=
|
github.com/aws/aws-sdk-go-v2/service/iam v1.42.0/go.mod h1:mPJkGQzeCoPs82ElNILor2JzZgYENr4UaSKUT8K27+c=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 h1:SYVGSFQHlchIcy6e7x12bsrxClCXSP5et8cqVhL8cuw=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13/go.mod h1:kizuDaLX37bG5WZaoxGPQR/LNFXpxp0vsUnqfkWXfNE=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1 h1:njgAP7Rtt4DGdTGFPhJ4gaZXCD1CDj/SZDa5W4ZgSTs=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1/go.mod h1:TN4PcCL0lvqmYcv+AV8iZFC4Sd0FM06QDaoBXrFEftU=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 h1:/eE3DogBjYlvlbhd2ssWyeuovWunHLxfgw3s/OJa4GQ=
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 h1:/nkJHXtJXJeelXHqG0898+fWKgvfaXBhGzbCsSmn9j8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.15/go.mod h1:2PCJYpi7EKeA5SkStAmZlF6fi0uUABuhtF8ILHjGc3Y=
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0/go.mod h1:kGYOjvTa0Vw0qxrqrOLut1vMnui6qLxqv/SX3vYeM8Y=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 h1:M/zwXiL2iXUrHputuXgmO94TVNmcenPHxgLXLutodKE=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 h1:8JdC7Gr9NROg1Rusk25IcZeTO59zLxsKgE0gkh5O6h0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14/go.mod h1:RVwIw3y/IqxC2YEXSIkAzRDdEU1iRabDPaYjpGCbCGQ=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 h1:TzeR06UCMUq+KA3bDkujxK1GVGy+G8qQN/QVYzGLkQE=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 h1:KwuLovgQPcdjNMfFt9OhUd9a2OwcOKhxfvF4glTzLuA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.14/go.mod h1:dspXf/oYWGWo6DEvj98wpaTeqt5+DMidZD0A9BYTizc=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 h1:PZV5W8yk4OtH1JAuhV2PXwwO9v5G5Aoj+eMCn4T+1Kc=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
|
||||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||||
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
|
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
|
||||||
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||||
github.com/baidubce/bce-sdk-go v0.9.221 h1:x5uTXND33m5TE3UBXYhlePuXcJi5rxNnBBt+bP7kPe0=
|
github.com/baidubce/bce-sdk-go v0.9.228 h1:XEY3/oAxXcsi7+3atib9fMI6YNE9sL5qo+WMZ+iqmNE=
|
||||||
github.com/baidubce/bce-sdk-go v0.9.221/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
|
github.com/baidubce/bce-sdk-go v0.9.228/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
@@ -247,8 +261,10 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
|||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/blinkbean/dingtalk v1.1.3 h1:MbidFZYom7DTFHD/YIs+eaI7kRy52kmWE/sy0xjo6E4=
|
github.com/blinkbean/dingtalk v1.1.3 h1:MbidFZYom7DTFHD/YIs+eaI7kRy52kmWE/sy0xjo6E4=
|
||||||
github.com/blinkbean/dingtalk v1.1.3/go.mod h1:9BaLuGSBqY3vT5hstValh48DbsKO7vaHaJnG9pXwbto=
|
github.com/blinkbean/dingtalk v1.1.3/go.mod h1:9BaLuGSBqY3vT5hstValh48DbsKO7vaHaJnG9pXwbto=
|
||||||
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.42 h1:Dm9FDjQP2SlAjUH7WAV7DFYDBFQz2uBxX6JULs0Sxs0=
|
github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
|
||||||
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.42/go.mod h1:CIL/T2dxgbIA79os+wl0Fq0vCbADTZNIddV6PNYB6DY=
|
github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE=
|
||||||
|
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.46 h1:Z0TagIjBDaoCZuJANP/P8+z+ef8dStVCBPjMZcI/y8s=
|
||||||
|
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.46/go.mod h1:CIL/T2dxgbIA79os+wl0Fq0vCbADTZNIddV6PNYB6DY=
|
||||||
github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||||
@@ -271,8 +287,8 @@ github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn
|
|||||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudflare/cloudflare-go v0.114.0 h1:ucoti4/7Exo0XQ+rzpn1H+IfVVe++zgiM+tyKtf0HUA=
|
github.com/cloudflare/cloudflare-go v0.115.0 h1:84/dxeeXweCc0PN5Cto44iTA8AkG1fyT11yPO5ZB7sM=
|
||||||
github.com/cloudflare/cloudflare-go v0.114.0/go.mod h1:O7fYfFfA6wKqKFn2QIR9lhj7FDw6VQCGOY6hd2TBtd0=
|
github.com/cloudflare/cloudflare-go v0.115.0/go.mod h1:Ds6urDwn/TF2uIU24mu7H91xkKP8gSAHxQ44DSZgVmU=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
@@ -290,6 +306,10 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
|
|||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||||
|
github.com/diskfs/go-diskfs v1.5.0 h1:0SANkrab4ifiZBytk380gIesYh5Gc+3i40l7qsrYP4s=
|
||||||
|
github.com/diskfs/go-diskfs v1.5.0/go.mod h1:bRFumZeGFCO8C2KNswrQeuj2m1WCVr4Ms5IjWMczMDk=
|
||||||
|
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
|
||||||
|
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||||
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
|
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
|
||||||
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
@@ -300,6 +320,8 @@ github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
|
|||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
|
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab h1:h1UgjJdAAhj+uPL68n7XASS6bU+07ZX1WJvVS2eyoeY=
|
||||||
|
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab/go.mod h1:GLo/8fDswSAniFG+BFIaiSPcK610jyzgEhWYPQwuQdw=
|
||||||
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
|
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
|
||||||
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
@@ -325,26 +347,26 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
|||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||||
github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw=
|
github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw=
|
||||||
github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k=
|
github.com/ganigeorgiev/fexpr v0.5.0 h1:XA9JxtTE/Xm+g/JFI6RfZEHSiQlk+1glLvRK1Lpv/Tk=
|
||||||
github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
github.com/ganigeorgiev/fexpr v0.5.0/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-acme/lego/v4 v4.22.2 h1:ck+HllWrV/rZGeYohsKQ5iKNnU/WAZxwOdiu6cxky+0=
|
github.com/go-acme/lego/v4 v4.23.1 h1:lZ5fGtGESA2L9FB8dNTvrQUq3/X4QOb8ExkKyY7LSV4=
|
||||||
github.com/go-acme/lego/v4 v4.22.2/go.mod h1:E2FndyI3Ekv0usNJt46mFb9LVpV/XBYT+4E3tz02Tzo=
|
github.com/go-acme/lego/v4 v4.23.1/go.mod h1:7UMVR7oQbIYw6V7mTgGwi4Er7B6Ww0c+c8feiBM0EgI=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E=
|
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
|
||||||
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
|
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
|
github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
|
||||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||||
github.com/go-lark/lark v1.15.1 h1:fo6PQKBJht/71N9Zn3/xjknOYx0TmdVuP+VP8NrUCsI=
|
github.com/go-lark/lark v1.16.0 h1:U6BwkLM9wrZedSM7cIiMofganr8PCvJN+M75w2lf2Gg=
|
||||||
github.com/go-lark/lark v1.15.1/go.mod h1:6ltbSztPZRT6IaO9ZIQyVaY5pVp/KeMizDYtfZkU+vM=
|
github.com/go-lark/lark v1.16.0/go.mod h1:6ltbSztPZRT6IaO9ZIQyVaY5pVp/KeMizDYtfZkU+vM=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
@@ -383,13 +405,13 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8Wd
|
|||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
|
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
|
github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
|
||||||
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||||
@@ -399,8 +421,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
|||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
@@ -430,8 +452,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
|||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
@@ -453,14 +473,13 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
@@ -470,8 +489,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
|||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20250315033105-103756e64e1d h1:tx51Lf+wdE+aavqH8TcPJoCjTf4cE8hrMzROghCely0=
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||||
github.com/google/pprof v0.0.0-20250315033105-103756e64e1d/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
@@ -487,22 +506,33 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
|
|||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||||
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
|
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
|
||||||
|
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
|
||||||
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||||
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
||||||
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
|
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||||
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
|
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||||
|
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
@@ -517,8 +547,8 @@ github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg
|
|||||||
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||||
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.141 h1:8i57QAi5u+iPAYze92bkIvZoHiS0J45ndul5glr/NE8=
|
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.150 h1:Ih+z79Ko1ClH4dlv7O1lyHRiVCjkb2NZYYk+1cSZbU8=
|
||||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.141/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY=
|
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.150/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY=
|
||||||
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
|
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
|
||||||
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
@@ -534,14 +564,14 @@ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJk
|
|||||||
github.com/jdcloud-api/jdcloud-sdk-go v1.64.0 h1:xZc/ZRcrOhDx9Ra9htu6ui2gUUttmLsXIqH61LcvY4U=
|
github.com/jdcloud-api/jdcloud-sdk-go v1.64.0 h1:xZc/ZRcrOhDx9Ra9htu6ui2gUUttmLsXIqH61LcvY4U=
|
||||||
github.com/jdcloud-api/jdcloud-sdk-go v1.64.0/go.mod h1:UrKjuULIWLjHFlG6aSPunArE5QX57LftMmStAZJBEX8=
|
github.com/jdcloud-api/jdcloud-sdk-go v1.64.0/go.mod h1:UrKjuULIWLjHFlG6aSPunArE5QX57LftMmStAZJBEX8=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
github.com/jinzhu/copier v0.3.4 h1:mfU6jI9PtCeUjkjQ322dlff9ELjGDu975C2p/nrubVI=
|
||||||
|
github.com/jinzhu/copier v0.3.4/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
|
|
||||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
|
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
@@ -557,13 +587,15 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||||
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
|
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
|
||||||
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
|
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||||
|
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||||
|
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||||
@@ -590,6 +622,10 @@ github.com/libdns/dynv6 v1.0.0/go.mod h1:65PL/bAlyH0J+0WGlOJYnMpoIuXcg/FmW4dTBYW
|
|||||||
github.com/libdns/libdns v0.1.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
github.com/libdns/libdns v0.1.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||||
github.com/libdns/libdns v0.2.3 h1:ba30K4ObwMGB/QTmqUxf3H4/GmUrCAIkMWejeGl12v8=
|
github.com/libdns/libdns v0.2.3 h1:ba30K4ObwMGB/QTmqUxf3H4/GmUrCAIkMWejeGl12v8=
|
||||||
github.com/libdns/libdns v0.2.3/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
github.com/libdns/libdns v0.2.3/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||||
|
github.com/luthermonson/go-proxmox v0.2.2 h1:BZ7VEj302wxw2i/EwTcyEiBzQib8teocB2SSkLHyySY=
|
||||||
|
github.com/luthermonson/go-proxmox v0.2.2/go.mod h1:oyFgg2WwTEIF0rP6ppjiixOHa5ebK1p8OaRiFhvICBQ=
|
||||||
|
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
|
||||||
|
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
@@ -610,8 +646,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
|
|||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||||
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
github.com/miekg/dns v1.1.64 h1:wuZgD9wwCE6XMT05UU/mlSko71eRSXEAm2EbjQXLKnQ=
|
||||||
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
github.com/miekg/dns v1.1.64/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
|
||||||
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||||
@@ -644,12 +680,16 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
|
|||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nikoksr/notify v1.3.0 h1:UxzfxzAYGQD9a5JYLBTVx0lFMxeHCke3rPCkfWdPgLs=
|
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 h1:ouZ2JWDl8IW5k1qugYbmpbmW8hn85Ig6buSMBRlz3KI=
|
||||||
github.com/nikoksr/notify v1.3.0/go.mod h1:Xor2hMmkvrCfkCKvXGbcrESez4brac2zQjhd6U2BbeM=
|
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3/go.mod h1:ZwadWt7mVhMHMbAQ1w8IhDqtWO3eWqWq72W7trnaiE8=
|
||||||
|
github.com/nrdcg/desec v0.10.0 h1:qrEDiqnsvNU9QE7lXIXi/tIHAfyaFXKxF2/8/52O8uM=
|
||||||
|
github.com/nrdcg/desec v0.10.0/go.mod h1:5+4vyhMRTs49V9CNoODF/HwT8Mwxv9DJ6j+7NekUnBs=
|
||||||
github.com/nrdcg/mailinabox v0.2.0 h1:IKq8mfKiVwNW2hQii/ng1dJ4yYMMv3HAP3fMFIq2CFk=
|
github.com/nrdcg/mailinabox v0.2.0 h1:IKq8mfKiVwNW2hQii/ng1dJ4yYMMv3HAP3fMFIq2CFk=
|
||||||
github.com/nrdcg/mailinabox v0.2.0/go.mod h1:0yxqeYOiGyxAu7Sb94eMxHPIOsPYXAjTeA9ZhePhGnc=
|
github.com/nrdcg/mailinabox v0.2.0/go.mod h1:0yxqeYOiGyxAu7Sb94eMxHPIOsPYXAjTeA9ZhePhGnc=
|
||||||
github.com/nrdcg/namesilo v0.2.1 h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=
|
github.com/nrdcg/namesilo v0.2.1 h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=
|
||||||
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
||||||
|
github.com/nrdcg/porkbun v0.4.0 h1:rWweKlwo1PToQ3H+tEO9gPRW0wzzgmI/Ob3n2Guticw=
|
||||||
|
github.com/nrdcg/porkbun v0.4.0/go.mod h1:/QMskrHEIM0IhC/wY7iTCUgINsxdT2WcOphktJ9+Q54=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
@@ -675,8 +715,13 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T
|
|||||||
github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 h1:2nosf3P75OZv2/ZO/9Px5ZgZ5gbKrzA3joN1QMfOGMQ=
|
github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 h1:2nosf3P75OZv2/ZO/9Px5ZgZ5gbKrzA3joN1QMfOGMQ=
|
||||||
github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0/go.mod h1:lAVhWwbNaveeJmxrxuSTxMgKpF6DjnuVpn6T8WiBwYQ=
|
github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0/go.mod h1:lAVhWwbNaveeJmxrxuSTxMgKpF6DjnuVpn6T8WiBwYQ=
|
||||||
github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM=
|
github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM=
|
||||||
|
github.com/peterhellberg/link v1.2.0 h1:UA5pg3Gp/E0F2WdX7GERiNrPQrM1K6CVJUUWfHa4t6c=
|
||||||
|
github.com/peterhellberg/link v1.2.0/go.mod h1:gYfAh+oJgQu2SrZHg5hROVRQe1ICoK0/HHJTcE0edxc=
|
||||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||||
|
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
|
||||||
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
@@ -685,19 +730,21 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||||
github.com/pkg/sftp v1.13.8 h1:Xt7eJ/xqXv7s0VuzFw7JXhZj6Oc1zI6l4GK8KP9sFB0=
|
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
||||||
github.com/pkg/sftp v1.13.8/go.mod h1:DmvEkvKE2lshEeuo2JMp06yqcx9HVnR7e3zqQl42F3U=
|
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
||||||
|
github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE=
|
||||||
|
github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU=
|
github.com/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU=
|
||||||
github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
||||||
github.com/pocketbase/pocketbase v0.26.1 h1:0WBqIRKKPCqp+xHPVLB4fevkoT9HVlR4BSuNwAt5oJ0=
|
github.com/pocketbase/pocketbase v0.28.2 h1:b6cfUfr5d4whvUFGFhI8oHRzx/eB76GCUQGftqgv9lM=
|
||||||
github.com/pocketbase/pocketbase v0.26.1/go.mod h1:t5y5pfnhrEg//RuSzSg0a926OLZ0oQj66jYs3BzDJwA=
|
github.com/pocketbase/pocketbase v0.28.2/go.mod h1:ElwIYS1b5xS9w0U7AK7tsm6FuC0lzw57H8p/118Cu7g=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||||
github.com/povsister/scp v0.0.0-20240802064259-28781e87b246 h1:c4D8BPWLOxxdaxQLfLKQXH2YXY/E9yo3jrDSL54XrTw=
|
github.com/povsister/scp v0.0.0-20250504051308-e467f71ea63c h1:1+j5JHz9mUzYSp0scuF6hzvJP28EDBFe5eBJb0xnGk4=
|
||||||
github.com/povsister/scp v0.0.0-20240802064259-28781e87b246/go.mod h1:i1Au86ZXK0ZalQNyBp2njCcyhSCR/QP/AMfILip+zNI=
|
github.com/povsister/scp v0.0.0-20250504051308-e467f71ea63c/go.mod h1:CiJNEeV6v0tUCNul/+gTjl+FgjfImoiuptJB9AEzqjE=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||||
@@ -720,22 +767,22 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
|||||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/qiniu/dyn v1.3.0 h1:s+xPTeV0H8yikgM4ZMBc7Rrefam8UNI3asBlkaOQg5o=
|
github.com/qiniu/dyn v1.3.0 h1:s+xPTeV0H8yikgM4ZMBc7Rrefam8UNI3asBlkaOQg5o=
|
||||||
github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk=
|
github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk=
|
||||||
github.com/qiniu/go-sdk/v7 v7.25.2 h1:URwgZpxySdiwu2yQpHk93X4LXWHyFRp1x3Vmlk/YWvo=
|
github.com/qiniu/go-sdk/v7 v7.25.3 h1:eYHh02q4i5MrlEn3qy823w7moieymFzb4dsP38Y43AI=
|
||||||
github.com/qiniu/go-sdk/v7 v7.25.2/go.mod h1:dmKtJ2ahhPWFVi9o1D5GemmWoh/ctuB9peqTowyTO8o=
|
github.com/qiniu/go-sdk/v7 v7.25.3/go.mod h1:dmKtJ2ahhPWFVi9o1D5GemmWoh/ctuB9peqTowyTO8o=
|
||||||
github.com/qiniu/x v1.10.5 h1:7V/CYWEmo9axJULvrJN6sMYh2FdY+esN5h8jwDkA4b0=
|
github.com/qiniu/x v1.10.5 h1:7V/CYWEmo9axJULvrJN6sMYh2FdY+esN5h8jwDkA4b0=
|
||||||
github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
|
github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
|
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
|
||||||
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
@@ -747,15 +794,15 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
|||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
github.com/spf13/cast v1.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk=
|
||||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
github.com/spf13/cast v1.8.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||||
@@ -782,34 +829,37 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1155 h1:ildxJtjnqiKZxWDVKHT/ncIknGDijtg60MuFELON8bY=
|
||||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1155/go.mod h1:iLASpooTdyXtx642E5Ws7cfWENsp4/uZ/78TFoln7OI=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115 h1:HsrXyqKQB2mKfGq+ZkbylRCMrbtPCmmUBrwA8MhhEX0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1166 h1:cEoDsBt7vGh7YtfVHVmgXKQURZANBE8UKK/So84QUdU=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115/go.mod h1:5cz1DtLlXK98U1Hh36oW4PjVOU+mbKg5wtCDmCc9Fcs=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1166/go.mod h1:0o5Cfgdh+bAx7kpQ5a5wce/ZUiDvy4Md8NcbrLtk6i8=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1127 h1:PiLZflqaW0690YsqIM/hqaVYjZJ3+cCJp4NHfw7h/uw=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1128/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1127/go.mod h1:V1+julLUOH0jKoVH6o6xgM4STWowzAL57M4VanUEEag=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1150/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1084/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1155/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1163/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1117/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1164/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1124/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1166/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1125/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1169/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1126/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1170/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1127 h1:1uG8zc0b9gLbyTr27T0CzGtcdrL86CGGJ6Flkq867f4=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1172/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1127/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1173 h1:W5bzEWiJwiwRZR0/P1l78OYWUXYsXLjhBaQ64c+9+fk=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084 h1:kwctN0WQYt8/iKP+iRCTCwdzEMIXsXklbRIib5rjeQ8=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1173/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084/go.mod h1:qE67ApiBzeRvzeDsV+GxyIDbVIDemsKpHXllQATz/Vw=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 h1:mrJ5Fbkd7sZIJ5F6oRfh5zebPQaudPH9Y0+GUmFytYU=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1117 h1:Yc/r5zUAyukVI3huIuwE7koowCjDjOWqeRpBILCvOSE=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128/go.mod h1:zbsYIBT+VTX4z4ocjTAdLBIWyNYj3z0BRqd0iPdnjsk=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1117/go.mod h1:YxsorHl3sTRw+2GsUObMqcumDqAQ3zo9rLMtf3Cxj8U=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap v1.0.1163 h1:putqrH5n1SVRqFWHOylVqYI5yLQUjRTkHqZPLT2yeVY=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115 h1:Qi7VWmJ0AQxEMlwKpbWfnsLA5QdNxekdcLJTBVdO85U=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap v1.0.1163/go.mod h1:aEWRXlAvovPUUoS3kVB/LVWEQ19WqzTj2lXGvR1YArY=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115/go.mod h1:P16nIMvmpSY+arTc2m2HyJmrYQP6CFnr48glz0+abyw=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150 h1:RQQYfZOFYlkxKR2+xp8el3+8xs9DhxBy+ajlHtapqtQ=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124 h1:LQKAlxFb0sYiE8ojK5h9+seuFzogoJtYnXmiRF+4F4Q=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150/go.mod h1:zpfr6EBWy7ClASTGUgIy01Gn4R79UXf+2QGQeyR124A=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124/go.mod h1:tYbK0FbHVG+78od7eZpzczE8qk0JWKO/osTQWuiJ3Fo=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1172 h1:6SUO0hTie3zxnUEMxmhnS1iRIXpAukSZV27Nrx4NwIk=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1126 h1:+CJQNXLdLP0GLaz2fnPECQsU+WdOmW3BQ54cNoQgMKA=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1172/go.mod h1:tmN4zfu70SD0iee3qfpc09NRLel30zGoAuzIs4X0Kfs=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1126/go.mod h1:eY3GoWilNoCPOEw2Lp4o+h02nEfc+BoZnqK3TlK6F7I=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1169 h1:oBymtJEmKDnS2NIR0PDLd+xCGQ+7uMoEt7zEB5Q3x8U=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1115 h1:rO0LdbcNtT5VlL9sB/K3Ve848uLp1rgg3R8igT9xsFQ=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1169/go.mod h1:K27PNEgRJ602ESXUNnlRnCkf1+XYHI6RVP/ylIe/Aro=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1115/go.mod h1:jJR8Y5sHuujSXZy0cpCgBk180TvPNsLw9hEoSH9w7iA=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1166 h1:+kIsoG2If/0y15PpZsXfT0QqTuwec9nMgo1JP8KQMkw=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1125 h1:IR9pJqHjHr7KyncRVxld9iltfnmy9sCC+0USZrs3rOw=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1166/go.mod h1:lGmBMXqe3vBg6Bi9h4mVpWLKd7jQIMRbndr8KNHBqSw=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1125/go.mod h1:5+5QrF7x+AW1KPM7F+YRzD74L88RXHZ6BxDF07b8QkE=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1164 h1:caaIGWOs/JtWOK5ptVMEiiGgzU7Jf6UpMv+9IbIa4vs=
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1164/go.mod h1:SJI2mc77gDC7Tw1QoF/4d5SwLvz8HQFUecWtIXb+r/Q=
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1170 h1:kcQCWuI9zOkZgL5CK66HNAJmSWCSJxRrDxXT+j02CeE=
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1170/go.mod h1:vTukVfThbBIc4lOf4eq/q51eEk78oZUJd2lAoJBOJwI=
|
||||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||||
@@ -818,16 +868,18 @@ github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaO
|
|||||||
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||||
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
|
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
|
||||||
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||||
github.com/ucloud/ucloud-sdk-go v0.22.31 h1:izZK+Re9ZkJAd1fHSVpFzgh8uKda4f5G6++iUw4n/mE=
|
github.com/ucloud/ucloud-sdk-go v0.22.41 h1:JndTJhCx7A1wggZfVb4KMm7D0Wfvd/HkmQVfSNjClQA=
|
||||||
github.com/ucloud/ucloud-sdk-go v0.22.31/go.mod h1:dyLmFHmUfgb4RZKYQP9IArlvQ2pxzFthfhwxRzOEPIw=
|
github.com/ucloud/ucloud-sdk-go v0.22.41/go.mod h1:dyLmFHmUfgb4RZKYQP9IArlvQ2pxzFthfhwxRzOEPIw=
|
||||||
|
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||||
|
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||||
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9 h1:fEnScn2dXfvfNcFnvJnpf/cYdj8kLIe5QC5qORlFO2c=
|
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.12 h1:u9+32DXQIOFPG8oQ3xrjSAUSyAcaq5bqO4cEBom/6lA=
|
||||||
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9/go.mod h1:IrjK84IJJTuOZOTMv/P18Ydjy/x+ow7fF7q11jAxXLM=
|
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.12/go.mod h1:IrjK84IJJTuOZOTMv/P18Ydjy/x+ow7fF7q11jAxXLM=
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU=
|
github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU=
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.199 h1:zv9QOqTl/IsLwtfC37GlJtcz6vMAHi+pjq8ILWjLYUc=
|
github.com/volcengine/volc-sdk-golang v1.0.208 h1:DyGUPjEKhWS08BkptfqenXTuUq+LKb7+gX/RBAtNl8w=
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.199/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
|
github.com/volcengine/volc-sdk-golang v1.0.208/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
|
||||||
github.com/volcengine/volcengine-go-sdk v1.0.187 h1:YpZjydoyHDA/ofnF6mYCelbOoo9pJsBEiQOOSJzGSOY=
|
github.com/volcengine/volcengine-go-sdk v1.1.8 h1:/T2p7qeeLWWhGrhtB00b8VNlE32S266LcO+jqFUYwzY=
|
||||||
github.com/volcengine/volcengine-go-sdk v1.0.187/go.mod h1:gfEDc1s7SYaGoY+WH2dRrS3qiuDJMkwqyfXWCa7+7oA=
|
github.com/volcengine/volcengine-go-sdk v1.1.8/go.mod h1:EyKoi6t6eZxoPNGr2GdFCZti2Skd7MO3eUzx7TtSvNo=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||||
@@ -895,8 +947,8 @@ golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOM
|
|||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
@@ -910,14 +962,14 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
|
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||||
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
|
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@@ -1000,16 +1052,16 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
|||||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
|
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||||
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -1027,8 +1079,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -1081,6 +1133,7 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -1089,6 +1142,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -1105,8 +1159,8 @@ golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@@ -1122,8 +1176,8 @@ golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
|||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -1142,15 +1196,15 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@@ -1205,8 +1259,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||||
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -1346,39 +1400,39 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls=
|
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
|
||||||
k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k=
|
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
|
||||||
k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U=
|
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
|
||||||
k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||||
k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU=
|
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
|
||||||
k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY=
|
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
|
||||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg=
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
|
||||||
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas=
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
|
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
|
||||||
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
|
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
|
||||||
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||||
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=
|
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
|
||||||
modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo=
|
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
|
||||||
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
|
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
|
||||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
modernc.org/fileutil v1.3.1 h1:8vq5fe7jdtEvoCf3Zf9Nm0Q05sH6kGx0Op2CPx1wTC8=
|
||||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
modernc.org/fileutil v1.3.1/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
||||||
modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
|
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||||
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||||
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
|
modernc.org/libc v1.65.7 h1:Ia9Z4yzZtWNtUIuiPuQ7Qf7kxYrxP1/jeHZzG8bFu00=
|
||||||
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
|
modernc.org/libc v1.65.7/go.mod h1:011EQibzzio/VX3ygj1qGFt5kMjP0lHb0qCW5/D/pQU=
|
||||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||||
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
|
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||||
modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU=
|
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||||
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||||
modernc.org/sqlite v1.36.1 h1:bDa8BJUH4lg6EGkLbahKe/8QqoF8p9gArSc6fTqYhyQ=
|
modernc.org/sqlite v1.37.1 h1:EgHJK/FPoqC+q2YBXg7fUmES37pCHFc97sI7zSayBEs=
|
||||||
modernc.org/sqlite v1.36.1/go.mod h1:7MPwH7Z6bREicF9ZVUR78P1IKuxfZ8mRIDHD0iD+8TU=
|
modernc.org/sqlite v1.37.1/go.mod h1:XwdRtsE1MpiBcL54+MbKcaDvcuej+IYSMfLN6gSKV8g=
|
||||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
@@ -1389,8 +1443,11 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
|||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk=
|
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
|
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||||
|
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||||
|
|||||||
@@ -1,38 +1,31 @@
|
|||||||
package applicant
|
package applicant
|
||||||
|
|
||||||
|
import "github.com/certimate-go/certimate/internal/domain"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sslProviderLetsEncrypt = "letsencrypt"
|
caLetsEncrypt = string(domain.CAProviderTypeLetsEncrypt)
|
||||||
sslProviderLetsEncryptStaging = "letsencrypt_staging"
|
caLetsEncryptStaging = string(domain.CAProviderTypeLetsEncryptStaging)
|
||||||
sslProviderZeroSSL = "zerossl"
|
caBuypass = string(domain.CAProviderTypeBuypass)
|
||||||
sslProviderGoogleTrustServices = "gts"
|
caGoogleTrustServices = string(domain.CAProviderTypeGoogleTrustServices)
|
||||||
)
|
caSSLCom = string(domain.CAProviderTypeSSLCom)
|
||||||
const defaultSSLProvider = sslProviderLetsEncrypt
|
caZeroSSL = string(domain.CAProviderTypeZeroSSL)
|
||||||
|
caCustom = string(domain.CAProviderTypeACMECA)
|
||||||
|
|
||||||
const (
|
caDefault = caLetsEncrypt
|
||||||
letsencryptUrl = "https://acme-v02.api.letsencrypt.org/directory"
|
|
||||||
letsencryptStagingUrl = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
|
||||||
zerosslUrl = "https://acme.zerossl.com/v2/DV90"
|
|
||||||
gtsUrl = "https://dv.acme-v02.api.pki.goog/directory"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var sslProviderUrls = map[string]string{
|
var caDirUrls = map[string]string{
|
||||||
sslProviderLetsEncrypt: letsencryptUrl,
|
caLetsEncrypt: "https://acme-v02.api.letsencrypt.org/directory",
|
||||||
sslProviderLetsEncryptStaging: letsencryptStagingUrl,
|
caLetsEncryptStaging: "https://acme-staging-v02.api.letsencrypt.org/directory",
|
||||||
sslProviderZeroSSL: zerosslUrl,
|
caBuypass: "https://api.buypass.com/acme/directory",
|
||||||
sslProviderGoogleTrustServices: gtsUrl,
|
caGoogleTrustServices: "https://dv.acme-v02.api.pki.goog/directory",
|
||||||
|
caSSLCom: "https://acme.ssl.com/sslcom-dv-rsa",
|
||||||
|
caSSLCom + "RSA": "https://acme.ssl.com/sslcom-dv-rsa",
|
||||||
|
caSSLCom + "ECC": "https://acme.ssl.com/sslcom-dv-ecc",
|
||||||
|
caZeroSSL: "https://acme.zerossl.com/v2/DV90",
|
||||||
}
|
}
|
||||||
|
|
||||||
type acmeSSLProviderConfig struct {
|
type acmeSSLProviderConfig struct {
|
||||||
Config acmeSSLProviderConfigContent `json:"config"`
|
Config map[domain.CAProviderType]map[string]any `json:"config"`
|
||||||
Provider string `json:"provider"`
|
Provider string `json:"provider"`
|
||||||
}
|
|
||||||
|
|
||||||
type acmeSSLProviderConfigContent struct {
|
|
||||||
ZeroSSL acmeSSLProviderEabConfig `json:"zerossl"`
|
|
||||||
GoogleTrustServices acmeSSLProviderEabConfig `json:"gts"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type acmeSSLProviderEabConfig struct {
|
|
||||||
EabHmacKey string `json:"eabHmacKey"`
|
|
||||||
EabKid string `json:"eabKid"`
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package applicant
|
package applicant
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -7,40 +7,51 @@ import (
|
|||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/lego"
|
"github.com/go-acme/lego/v4/lego"
|
||||||
"github.com/go-acme/lego/v4/registration"
|
"github.com/go-acme/lego/v4/registration"
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/certimate-go/certimate/internal/domain"
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/certutil"
|
"github.com/certimate-go/certimate/internal/repository"
|
||||||
"github.com/usual2970/certimate/internal/repository"
|
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
|
||||||
|
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
type acmeUser struct {
|
type acmeUser struct {
|
||||||
CA string
|
// 证书颁发机构标识。
|
||||||
Email string
|
// 通常等同于 [CAProviderType] 的值。
|
||||||
|
// 对于自定义 ACME CA,值为 "custom#{access_id}"。
|
||||||
|
CA string
|
||||||
|
// 邮箱。
|
||||||
|
Email string
|
||||||
|
// 注册信息。
|
||||||
Registration *registration.Resource
|
Registration *registration.Resource
|
||||||
|
|
||||||
|
// CSR 私钥。
|
||||||
privkey string
|
privkey string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAcmeUser(ca, email string) (*acmeUser, error) {
|
func newAcmeUser(ca, caAccessId, email string) (*acmeUser, error) {
|
||||||
repo := repository.NewAcmeAccountRepository()
|
repo := repository.NewAcmeAccountRepository()
|
||||||
|
|
||||||
applyUser := &acmeUser{
|
applyUser := &acmeUser{
|
||||||
CA: ca,
|
CA: ca,
|
||||||
Email: email,
|
Email: email,
|
||||||
}
|
}
|
||||||
|
if ca == caCustom {
|
||||||
|
applyUser.CA = fmt.Sprintf("%s#%s", ca, caAccessId)
|
||||||
|
}
|
||||||
|
|
||||||
acmeAccount, err := repo.GetByCAAndEmail(ca, email)
|
acmeAccount, err := repo.GetByCAAndEmail(applyUser.CA, applyUser.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
keyPEM, err := certutil.ConvertECPrivateKeyToPEM(key)
|
keyPEM, err := xcert.ConvertECPrivateKeyToPEM(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -64,7 +75,7 @@ func (u acmeUser) GetRegistration() *registration.Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *acmeUser) GetPrivateKey() crypto.PrivateKey {
|
func (u *acmeUser) GetPrivateKey() crypto.PrivateKey {
|
||||||
rs, _ := certutil.ParseECPrivateKeyFromPEM(u.privkey)
|
rs, _ := xcert.ParseECPrivateKeyFromPEM(u.privkey)
|
||||||
return rs
|
return rs
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,20 +83,19 @@ func (u *acmeUser) hasRegistration() bool {
|
|||||||
return u.Registration != nil
|
return u.Registration != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *acmeUser) getCAProvider() string {
|
||||||
|
return strings.Split(u.CA, "#")[0]
|
||||||
|
}
|
||||||
|
|
||||||
func (u *acmeUser) getPrivateKeyPEM() string {
|
func (u *acmeUser) getPrivateKeyPEM() string {
|
||||||
return u.privkey
|
return u.privkey
|
||||||
}
|
}
|
||||||
|
|
||||||
type acmeAccountRepository interface {
|
|
||||||
GetByCAAndEmail(ca, email string) (*domain.AcmeAccount, error)
|
|
||||||
Save(ca, email, key string, resource *registration.Resource) error
|
|
||||||
}
|
|
||||||
|
|
||||||
var registerGroup singleflight.Group
|
var registerGroup singleflight.Group
|
||||||
|
|
||||||
func registerAcmeUserWithSingleFlight(client *lego.Client, sslProviderConfig *acmeSSLProviderConfig, user *acmeUser) (*registration.Resource, error) {
|
func registerAcmeUserWithSingleFlight(client *lego.Client, user *acmeUser, userRegisterOptions map[string]any) (*registration.Resource, error) {
|
||||||
resp, err, _ := registerGroup.Do(fmt.Sprintf("register_acme_user_%s_%s", sslProviderConfig.Provider, user.GetEmail()), func() (interface{}, error) {
|
resp, err, _ := registerGroup.Do(fmt.Sprintf("register_acme_user_%s_%s", user.CA, user.Email), func() (interface{}, error) {
|
||||||
return registerAcmeUser(client, sslProviderConfig, user)
|
return registerAcmeUser(client, user, userRegisterOptions)
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -95,45 +105,101 @@ func registerAcmeUserWithSingleFlight(client *lego.Client, sslProviderConfig *ac
|
|||||||
return resp.(*registration.Resource), nil
|
return resp.(*registration.Resource), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerAcmeUser(client *lego.Client, sslProviderConfig *acmeSSLProviderConfig, user *acmeUser) (*registration.Resource, error) {
|
func registerAcmeUser(client *lego.Client, user *acmeUser, userRegisterOptions map[string]any) (*registration.Resource, error) {
|
||||||
var reg *registration.Resource
|
var reg *registration.Resource
|
||||||
var err error
|
var err error
|
||||||
switch sslProviderConfig.Provider {
|
switch user.getCAProvider() {
|
||||||
case sslProviderZeroSSL:
|
case caLetsEncrypt, caLetsEncryptStaging:
|
||||||
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
|
||||||
TermsOfServiceAgreed: true,
|
|
||||||
Kid: sslProviderConfig.Config.ZeroSSL.EabKid,
|
|
||||||
HmacEncoded: sslProviderConfig.Config.ZeroSSL.EabHmacKey,
|
|
||||||
})
|
|
||||||
case sslProviderGoogleTrustServices:
|
|
||||||
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
|
||||||
TermsOfServiceAgreed: true,
|
|
||||||
Kid: sslProviderConfig.Config.GoogleTrustServices.EabKid,
|
|
||||||
HmacEncoded: sslProviderConfig.Config.GoogleTrustServices.EabHmacKey,
|
|
||||||
})
|
|
||||||
case sslProviderLetsEncrypt, sslProviderLetsEncryptStaging:
|
|
||||||
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
|
|
||||||
|
case caBuypass:
|
||||||
|
{
|
||||||
|
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
case caGoogleTrustServices:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForGoogleTrustServices{}
|
||||||
|
if err := xmaps.Populate(userRegisterOptions, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
||||||
|
TermsOfServiceAgreed: true,
|
||||||
|
Kid: access.EabKid,
|
||||||
|
HmacEncoded: access.EabHmacKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
case caSSLCom:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForSSLCom{}
|
||||||
|
if err := xmaps.Populate(userRegisterOptions, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
||||||
|
TermsOfServiceAgreed: true,
|
||||||
|
Kid: access.EabKid,
|
||||||
|
HmacEncoded: access.EabHmacKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
case caZeroSSL:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForZeroSSL{}
|
||||||
|
if err := xmaps.Populate(userRegisterOptions, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
||||||
|
TermsOfServiceAgreed: true,
|
||||||
|
Kid: access.EabKid,
|
||||||
|
HmacEncoded: access.EabHmacKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
case caCustom:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForACMECA{}
|
||||||
|
if err := xmaps.Populate(userRegisterOptions, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if access.EabKid == "" && access.EabHmacKey == "" {
|
||||||
|
reg, err = client.Registration.Register(registration.RegisterOptions{
|
||||||
|
TermsOfServiceAgreed: true,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
||||||
|
TermsOfServiceAgreed: true,
|
||||||
|
Kid: access.EabKid,
|
||||||
|
HmacEncoded: access.EabHmacKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unsupported ssl provider: %s", sslProviderConfig.Provider)
|
err = fmt.Errorf("unsupported ca provider '%s'", user.CA)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo := repository.NewAcmeAccountRepository()
|
repo := repository.NewAcmeAccountRepository()
|
||||||
resp, err := repo.GetByCAAndEmail(sslProviderConfig.Provider, user.GetEmail())
|
resp, err := repo.GetByCAAndEmail(user.CA, user.Email)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
user.privkey = resp.Key
|
user.privkey = resp.Key
|
||||||
return resp.Resource, nil
|
return resp.Resource, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := repo.Save(context.Background(), &domain.AcmeAccount{
|
if _, err := repo.Save(context.Background(), &domain.AcmeAccount{
|
||||||
CA: sslProviderConfig.Provider,
|
CA: user.CA,
|
||||||
Email: user.GetEmail(),
|
Email: user.Email,
|
||||||
Key: user.getPrivateKeyPEM(),
|
Key: user.getPrivateKeyPEM(),
|
||||||
Resource: reg,
|
Resource: reg,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, fmt.Errorf("failed to save registration: %w", err)
|
return nil, fmt.Errorf("failed to save acme account registration: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return reg, nil
|
return reg, nil
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
"github.com/go-acme/lego/v4/certificate"
|
"github.com/go-acme/lego/v4/certificate"
|
||||||
@@ -17,73 +19,98 @@ import (
|
|||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/certimate-go/certimate/internal/domain"
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/sliceutil"
|
"github.com/certimate-go/certimate/internal/repository"
|
||||||
"github.com/usual2970/certimate/internal/repository"
|
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||||
|
xslices "github.com/certimate-go/certimate/pkg/utils/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ApplyCertResult struct {
|
type ApplyResult struct {
|
||||||
CertificateFullChain string
|
CSR string
|
||||||
|
FullChainCertificate string
|
||||||
IssuerCertificate string
|
IssuerCertificate string
|
||||||
PrivateKey string
|
PrivateKey string
|
||||||
ACMEAccountUrl string
|
ACMEAccountUrl string
|
||||||
ACMECertUrl string
|
ACMECertUrl string
|
||||||
ACMECertStableUrl string
|
ACMECertStableUrl string
|
||||||
CSR string
|
ARIReplaced bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Applicant interface {
|
type Applicant interface {
|
||||||
Apply() (*ApplyCertResult, error)
|
Apply(ctx context.Context) (*ApplyResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type applicantOptions struct {
|
type ApplicantWithWorkflowNodeConfig struct {
|
||||||
Domains []string
|
Node *domain.WorkflowNode
|
||||||
ContactEmail string
|
Logger *slog.Logger
|
||||||
Provider domain.ApplyDNSProviderType
|
|
||||||
ProviderAccessConfig map[string]any
|
|
||||||
ProviderApplyConfig map[string]any
|
|
||||||
KeyAlgorithm string
|
|
||||||
Nameservers []string
|
|
||||||
DnsPropagationTimeout int32
|
|
||||||
DnsTTL int32
|
|
||||||
DisableFollowCNAME bool
|
|
||||||
ReplacedARIAcctId string
|
|
||||||
ReplacedARICertId string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, error) {
|
||||||
if node.Type != domain.WorkflowNodeTypeApply {
|
if config.Node == nil {
|
||||||
return nil, fmt.Errorf("node type is not apply")
|
return nil, fmt.Errorf("node is nil")
|
||||||
|
}
|
||||||
|
if config.Node.Type != domain.WorkflowNodeTypeApply {
|
||||||
|
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeApply))
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeConfig := node.GetConfigForApply()
|
nodeCfg := config.Node.GetConfigForApply()
|
||||||
options := &applicantOptions{
|
options := &applicantProviderOptions{
|
||||||
Domains: sliceutil.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }),
|
Domains: xslices.Filter(strings.Split(nodeCfg.Domains, ";"), func(s string) bool { return s != "" }),
|
||||||
ContactEmail: nodeConfig.ContactEmail,
|
ContactEmail: nodeCfg.ContactEmail,
|
||||||
Provider: domain.ApplyDNSProviderType(nodeConfig.Provider),
|
Provider: domain.ACMEDns01ProviderType(nodeCfg.Provider),
|
||||||
ProviderApplyConfig: nodeConfig.ProviderConfig,
|
ProviderAccessConfig: make(map[string]any),
|
||||||
KeyAlgorithm: nodeConfig.KeyAlgorithm,
|
ProviderServiceConfig: nodeCfg.ProviderConfig,
|
||||||
Nameservers: sliceutil.Filter(strings.Split(nodeConfig.Nameservers, ";"), func(s string) bool { return s != "" }),
|
CAProvider: domain.CAProviderType(nodeCfg.CAProvider),
|
||||||
DnsPropagationTimeout: nodeConfig.DnsPropagationTimeout,
|
CAProviderAccessConfig: make(map[string]any),
|
||||||
DnsTTL: nodeConfig.DnsTTL,
|
CAProviderServiceConfig: nodeCfg.CAProviderConfig,
|
||||||
DisableFollowCNAME: nodeConfig.DisableFollowCNAME,
|
KeyAlgorithm: nodeCfg.KeyAlgorithm,
|
||||||
|
Nameservers: xslices.Filter(strings.Split(nodeCfg.Nameservers, ";"), func(s string) bool { return s != "" }),
|
||||||
|
DnsPropagationWait: nodeCfg.DnsPropagationWait,
|
||||||
|
DnsPropagationTimeout: nodeCfg.DnsPropagationTimeout,
|
||||||
|
DnsTTL: nodeCfg.DnsTTL,
|
||||||
|
DisableFollowCNAME: nodeCfg.DisableFollowCNAME,
|
||||||
}
|
}
|
||||||
|
|
||||||
accessRepo := repository.NewAccessRepository()
|
accessRepo := repository.NewAccessRepository()
|
||||||
if access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId); err != nil {
|
if nodeCfg.ProviderAccessId != "" {
|
||||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
|
if access, err := accessRepo.GetById(context.Background(), nodeCfg.ProviderAccessId); err != nil {
|
||||||
} else {
|
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.ProviderAccessId, err)
|
||||||
accessConfig, err := access.UnmarshalConfigToMap()
|
} else {
|
||||||
if err != nil {
|
options.ProviderAccessConfig = access.Config
|
||||||
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
|
}
|
||||||
|
}
|
||||||
|
if nodeCfg.CAProviderAccessId != "" {
|
||||||
|
if access, err := accessRepo.GetById(context.Background(), nodeCfg.CAProviderAccessId); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.CAProviderAccessId, err)
|
||||||
|
} else {
|
||||||
|
options.CAProviderAccessId = access.Id
|
||||||
|
options.CAProviderAccessConfig = access.Config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsRepo := repository.NewSettingsRepository()
|
||||||
|
if string(options.CAProvider) == "" {
|
||||||
|
settings, _ := settingsRepo.GetByName(context.Background(), "sslProvider")
|
||||||
|
|
||||||
|
sslProviderConfig := &acmeSSLProviderConfig{
|
||||||
|
Config: make(map[domain.CAProviderType]map[string]any),
|
||||||
|
Provider: caDefault,
|
||||||
|
}
|
||||||
|
if settings != nil {
|
||||||
|
if err := json.Unmarshal([]byte(settings.Content), sslProviderConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if sslProviderConfig.Provider == "" {
|
||||||
|
sslProviderConfig.Provider = caDefault
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
options.ProviderAccessConfig = accessConfig
|
options.CAProvider = domain.CAProviderType(sslProviderConfig.Provider)
|
||||||
|
options.CAProviderAccessConfig = sslProviderConfig.Config[options.CAProvider]
|
||||||
}
|
}
|
||||||
|
|
||||||
certRepo := repository.NewCertificateRepository()
|
certRepo := repository.NewCertificateRepository()
|
||||||
lastCertificate, _ := certRepo.GetByWorkflowNodeId(context.Background(), node.Id)
|
lastCertificate, _ := certRepo.GetByWorkflowNodeId(context.Background(), config.Node.Id)
|
||||||
if lastCertificate != nil {
|
if lastCertificate != nil && !lastCertificate.ACMERenewed {
|
||||||
newCertSan := slices.Clone(options.Domains)
|
newCertSan := slices.Clone(options.Domains)
|
||||||
oldCertSan := strings.Split(lastCertificate.SubjectAltNames, ";")
|
oldCertSan := strings.Split(lastCertificate.SubjectAltNames, ";")
|
||||||
slices.Sort(newCertSan)
|
slices.Sort(newCertSan)
|
||||||
@@ -93,42 +120,53 @@ func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
|||||||
lastCertX509, _ := certcrypto.ParsePEMCertificate([]byte(lastCertificate.Certificate))
|
lastCertX509, _ := certcrypto.ParsePEMCertificate([]byte(lastCertificate.Certificate))
|
||||||
if lastCertX509 != nil {
|
if lastCertX509 != nil {
|
||||||
replacedARICertId, _ := certificate.MakeARICertID(lastCertX509)
|
replacedARICertId, _ := certificate.MakeARICertID(lastCertX509)
|
||||||
options.ReplacedARIAcctId = lastCertificate.ACMEAccountUrl
|
options.ARIReplaceAcct = lastCertificate.ACMEAccountUrl
|
||||||
options.ReplacedARICertId = replacedARICertId
|
options.ARIReplaceCert = replacedARICertId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
applicant, err := createApplicant(options)
|
applicant, err := createApplicantProvider(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &proxyApplicant{
|
return &applicantImpl{
|
||||||
applicant: applicant,
|
applicant: applicant,
|
||||||
options: options,
|
options: options,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func apply(challengeProvider challenge.Provider, options *applicantOptions) (*ApplyCertResult, error) {
|
type applicantImpl struct {
|
||||||
settingsRepo := repository.NewSettingsRepository()
|
applicant challenge.Provider
|
||||||
settings, _ := settingsRepo.GetByName(context.Background(), "sslProvider")
|
options *applicantProviderOptions
|
||||||
|
}
|
||||||
|
|
||||||
sslProviderConfig := &acmeSSLProviderConfig{
|
var _ Applicant = (*applicantImpl)(nil)
|
||||||
Config: acmeSSLProviderConfigContent{},
|
|
||||||
Provider: defaultSSLProvider,
|
func (d *applicantImpl) Apply(ctx context.Context) (*ApplyResult, error) {
|
||||||
}
|
limiter := getLimiter(fmt.Sprintf("apply_%s", d.options.ContactEmail))
|
||||||
if settings != nil {
|
if err := limiter.Wait(ctx); err != nil {
|
||||||
if err := json.Unmarshal([]byte(settings.Content), sslProviderConfig); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sslProviderConfig.Provider == "" {
|
return applyUseLego(d.applicant, d.options)
|
||||||
sslProviderConfig.Provider = defaultSSLProvider
|
}
|
||||||
}
|
|
||||||
|
|
||||||
acmeUser, err := newAcmeUser(sslProviderConfig.Provider, options.ContactEmail)
|
const (
|
||||||
|
limitBurst = 300
|
||||||
|
limitRate float64 = float64(1) / float64(36)
|
||||||
|
)
|
||||||
|
|
||||||
|
var limiters sync.Map
|
||||||
|
|
||||||
|
func getLimiter(key string) *rate.Limiter {
|
||||||
|
limiter, _ := limiters.LoadOrStore(key, rate.NewLimiter(rate.Limit(limitRate), 300))
|
||||||
|
return limiter.(*rate.Limiter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOptions) (*ApplyResult, error) {
|
||||||
|
user, err := newAcmeUser(string(options.CAProvider), options.CAProviderAccessId, options.ContactEmail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -138,9 +176,29 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
|
|||||||
os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", strconv.FormatBool(options.DisableFollowCNAME))
|
os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", strconv.FormatBool(options.DisableFollowCNAME))
|
||||||
|
|
||||||
// Create an ACME client config
|
// Create an ACME client config
|
||||||
config := lego.NewConfig(acmeUser)
|
config := lego.NewConfig(user)
|
||||||
config.CADirURL = sslProviderUrls[sslProviderConfig.Provider]
|
config.Certificate.KeyType = parseLegoKeyAlgorithm(domain.CertificateKeyAlgorithmType(options.KeyAlgorithm))
|
||||||
config.Certificate.KeyType = parseKeyAlgorithm(domain.CertificateKeyAlgorithmType(options.KeyAlgorithm))
|
switch user.getCAProvider() {
|
||||||
|
case caSSLCom:
|
||||||
|
if strings.HasPrefix(options.KeyAlgorithm, "RSA") {
|
||||||
|
config.CADirURL = caDirUrls[caSSLCom+"RSA"]
|
||||||
|
} else if strings.HasPrefix(options.KeyAlgorithm, "EC") {
|
||||||
|
config.CADirURL = caDirUrls[caSSLCom+"ECC"]
|
||||||
|
} else {
|
||||||
|
config.CADirURL = caDirUrls[caSSLCom]
|
||||||
|
}
|
||||||
|
|
||||||
|
case caCustom:
|
||||||
|
caDirURL := xmaps.GetString(options.CAProviderAccessConfig, "endpoint")
|
||||||
|
if caDirURL != "" {
|
||||||
|
config.CADirURL = caDirURL
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("invalid ca provider endpoint")
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
config.CADirURL = caDirUrls[user.CA]
|
||||||
|
}
|
||||||
|
|
||||||
// Create an ACME client
|
// Create an ACME client
|
||||||
client, err := lego.NewClient(config)
|
client, err := lego.NewClient(config)
|
||||||
@@ -149,20 +207,28 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the DNS01 challenge provider
|
// Set the DNS01 challenge provider
|
||||||
challengeOptions := make([]dns01.ChallengeOption, 0)
|
client.Challenge.SetDNS01Provider(legoProvider,
|
||||||
if len(options.Nameservers) > 0 {
|
dns01.CondOption(
|
||||||
challengeOptions = append(challengeOptions, dns01.AddRecursiveNameservers(dns01.ParseNameservers(options.Nameservers)))
|
len(options.Nameservers) > 0,
|
||||||
challengeOptions = append(challengeOptions, dns01.DisableAuthoritativeNssPropagationRequirement())
|
dns01.AddRecursiveNameservers(dns01.ParseNameservers(options.Nameservers)),
|
||||||
}
|
),
|
||||||
client.Challenge.SetDNS01Provider(challengeProvider, challengeOptions...)
|
dns01.CondOption(
|
||||||
|
options.DnsPropagationWait > 0,
|
||||||
|
dns01.PropagationWait(time.Duration(options.DnsPropagationWait)*time.Second, true),
|
||||||
|
),
|
||||||
|
dns01.CondOption(
|
||||||
|
len(options.Nameservers) > 0 || options.DnsPropagationWait > 0,
|
||||||
|
dns01.DisableAuthoritativeNssPropagationRequirement(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
// New users need to register first
|
// New users need to register first
|
||||||
if !acmeUser.hasRegistration() {
|
if !user.hasRegistration() {
|
||||||
reg, err := registerAcmeUserWithSingleFlight(client, sslProviderConfig, acmeUser)
|
reg, err := registerAcmeUserWithSingleFlight(client, user, options.CAProviderAccessConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to register: %w", err)
|
return nil, fmt.Errorf("failed to register acme user: %w", err)
|
||||||
}
|
}
|
||||||
acmeUser.Registration = reg
|
user.Registration = reg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain a certificate
|
// Obtain a certificate
|
||||||
@@ -170,64 +236,41 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
|
|||||||
Domains: options.Domains,
|
Domains: options.Domains,
|
||||||
Bundle: true,
|
Bundle: true,
|
||||||
}
|
}
|
||||||
if options.ReplacedARICertId != "" && options.ReplacedARIAcctId != acmeUser.Registration.URI {
|
if options.ARIReplaceAcct == user.Registration.URI {
|
||||||
certRequest.ReplacesCertID = options.ReplacedARICertId
|
certRequest.ReplacesCertID = options.ARIReplaceCert
|
||||||
}
|
}
|
||||||
|
|
||||||
certResource, err := client.Certificate.Obtain(certRequest)
|
certResource, err := client.Certificate.Obtain(certRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ApplyCertResult{
|
return &ApplyResult{
|
||||||
CertificateFullChain: strings.TrimSpace(string(certResource.Certificate)),
|
CSR: strings.TrimSpace(string(certResource.CSR)),
|
||||||
|
FullChainCertificate: strings.TrimSpace(string(certResource.Certificate)),
|
||||||
IssuerCertificate: strings.TrimSpace(string(certResource.IssuerCertificate)),
|
IssuerCertificate: strings.TrimSpace(string(certResource.IssuerCertificate)),
|
||||||
PrivateKey: strings.TrimSpace(string(certResource.PrivateKey)),
|
PrivateKey: strings.TrimSpace(string(certResource.PrivateKey)),
|
||||||
ACMEAccountUrl: acmeUser.Registration.URI,
|
ACMEAccountUrl: user.Registration.URI,
|
||||||
ACMECertUrl: certResource.CertURL,
|
ACMECertUrl: certResource.CertURL,
|
||||||
ACMECertStableUrl: certResource.CertStableURL,
|
ACMECertStableUrl: certResource.CertStableURL,
|
||||||
CSR: strings.TrimSpace(string(certResource.CSR)),
|
ARIReplaced: certRequest.ReplacesCertID != "",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseKeyAlgorithm(algo domain.CertificateKeyAlgorithmType) certcrypto.KeyType {
|
func parseLegoKeyAlgorithm(algo domain.CertificateKeyAlgorithmType) certcrypto.KeyType {
|
||||||
switch algo {
|
alogMap := map[domain.CertificateKeyAlgorithmType]certcrypto.KeyType{
|
||||||
case domain.CertificateKeyAlgorithmTypeRSA2048:
|
domain.CertificateKeyAlgorithmTypeRSA2048: certcrypto.RSA2048,
|
||||||
return certcrypto.RSA2048
|
domain.CertificateKeyAlgorithmTypeRSA3072: certcrypto.RSA3072,
|
||||||
case domain.CertificateKeyAlgorithmTypeRSA3072:
|
domain.CertificateKeyAlgorithmTypeRSA4096: certcrypto.RSA4096,
|
||||||
return certcrypto.RSA3072
|
domain.CertificateKeyAlgorithmTypeRSA8192: certcrypto.RSA8192,
|
||||||
case domain.CertificateKeyAlgorithmTypeRSA4096:
|
domain.CertificateKeyAlgorithmTypeEC256: certcrypto.EC256,
|
||||||
return certcrypto.RSA4096
|
domain.CertificateKeyAlgorithmTypeEC384: certcrypto.EC384,
|
||||||
case domain.CertificateKeyAlgorithmTypeRSA8192:
|
domain.CertificateKeyAlgorithmTypeEC512: certcrypto.KeyType("P512"),
|
||||||
return certcrypto.RSA8192
|
}
|
||||||
case domain.CertificateKeyAlgorithmTypeEC256:
|
|
||||||
return certcrypto.EC256
|
if keyType, ok := alogMap[algo]; ok {
|
||||||
case domain.CertificateKeyAlgorithmTypeEC384:
|
return keyType
|
||||||
return certcrypto.EC384
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return certcrypto.RSA2048
|
return certcrypto.RSA2048
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 暂时使用代理模式以兼容之前版本代码,后续重新实现此处逻辑
|
|
||||||
type proxyApplicant struct {
|
|
||||||
applicant challenge.Provider
|
|
||||||
options *applicantOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
var limiters sync.Map
|
|
||||||
|
|
||||||
const (
|
|
||||||
limitBurst = 300
|
|
||||||
limitRate float64 = float64(1) / float64(36)
|
|
||||||
)
|
|
||||||
|
|
||||||
func getLimiter(key string) *rate.Limiter {
|
|
||||||
limiter, _ := limiters.LoadOrStore(key, rate.NewLimiter(rate.Limit(limitRate), 300))
|
|
||||||
return limiter.(*rate.Limiter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *proxyApplicant) Apply() (*ApplyCertResult, error) {
|
|
||||||
limiter := getLimiter(fmt.Sprintf("apply_%s", d.options.ContactEmail))
|
|
||||||
limiter.Wait(context.Background())
|
|
||||||
return apply(d.applicant, d.options)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,44 +5,78 @@ import (
|
|||||||
|
|
||||||
"github.com/go-acme/lego/v4/challenge"
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/certimate-go/certimate/internal/domain"
|
||||||
pACMEHttpReq "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq"
|
pACMEHttpReq "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/acmehttpreq"
|
||||||
pAliyun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun"
|
pAliyun "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/aliyun"
|
||||||
pAWSRoute53 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws-route53"
|
pAliyunESA "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/aliyun-esa"
|
||||||
pAzureDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/azure-dns"
|
pAWSRoute53 "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/aws-route53"
|
||||||
pBaiduCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud"
|
pAzureDNS "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/azure-dns"
|
||||||
pCloudflare "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare"
|
pBaiduCloud "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/baiducloud"
|
||||||
pClouDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudns"
|
pBunny "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/bunny"
|
||||||
pCMCCCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud"
|
pCloudflare "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/cloudflare"
|
||||||
pDNSLA "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla"
|
pClouDNS "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/cloudns"
|
||||||
pDynv6 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6"
|
pCMCCCloud "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/cmcccloud"
|
||||||
pGcore "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gcore"
|
pConstellix "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/constellix"
|
||||||
pGname "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname"
|
pCTCCCloud "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/ctcccloud"
|
||||||
pGoDaddy "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy"
|
pDeSEC "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/desec"
|
||||||
pHuaweiCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud"
|
pDigitalOcean "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/digitalocean"
|
||||||
pJDCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud"
|
pDNSLA "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/dnsla"
|
||||||
pNamecheap "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namecheap"
|
pDuckDNS "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/duckdns"
|
||||||
pNameDotCom "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom"
|
pDynv6 "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/dynv6"
|
||||||
pNameSilo "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo"
|
pGcore "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/gcore"
|
||||||
pNS1 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1"
|
pGname "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/gname"
|
||||||
pPowerDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns"
|
pGoDaddy "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/godaddy"
|
||||||
pRainYun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/rainyun"
|
pHetzner "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/hetzner"
|
||||||
pTencentCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud"
|
pHuaweiCloud "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/huaweicloud"
|
||||||
pVolcEngine "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine"
|
pJDCloud "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/jdcloud"
|
||||||
pWestcn "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/westcn"
|
pNamecheap "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/namecheap"
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/maputil"
|
pNameDotCom "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/namedotcom"
|
||||||
|
pNameSilo "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/namesilo"
|
||||||
|
pNetcup "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/netcup"
|
||||||
|
pNetlify "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/netlify"
|
||||||
|
pNS1 "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/ns1"
|
||||||
|
pPorkbun "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/porkbun"
|
||||||
|
pPowerDNS "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/powerdns"
|
||||||
|
pRainYun "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/rainyun"
|
||||||
|
pTencentCloud "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/tencentcloud"
|
||||||
|
pTencentCloudEO "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/tencentcloud-eo"
|
||||||
|
pUCloudUDNR "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/ucloud-udnr"
|
||||||
|
pVercel "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/vercel"
|
||||||
|
pVolcEngine "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/volcengine"
|
||||||
|
pWestcn "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/westcn"
|
||||||
|
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
type applicantProviderOptions struct {
|
||||||
|
Domains []string
|
||||||
|
ContactEmail string
|
||||||
|
Provider domain.ACMEDns01ProviderType
|
||||||
|
ProviderAccessConfig map[string]any
|
||||||
|
ProviderServiceConfig map[string]any
|
||||||
|
CAProvider domain.CAProviderType
|
||||||
|
CAProviderAccessId string
|
||||||
|
CAProviderAccessConfig map[string]any
|
||||||
|
CAProviderServiceConfig map[string]any
|
||||||
|
KeyAlgorithm string
|
||||||
|
Nameservers []string
|
||||||
|
DnsPropagationWait int32
|
||||||
|
DnsPropagationTimeout int32
|
||||||
|
DnsTTL int32
|
||||||
|
DisableFollowCNAME bool
|
||||||
|
ARIReplaceAcct string
|
||||||
|
ARIReplaceCert string
|
||||||
|
}
|
||||||
|
|
||||||
|
func createApplicantProvider(options *applicantProviderOptions) (challenge.Provider, error) {
|
||||||
/*
|
/*
|
||||||
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||||
NOTICE: If you add new constant, please keep ASCII order.
|
NOTICE: If you add new constant, please keep ASCII order.
|
||||||
*/
|
*/
|
||||||
switch options.Provider {
|
switch options.Provider {
|
||||||
case domain.ApplyDNSProviderTypeACMEHttpReq:
|
case domain.ACMEDns01ProviderTypeACMEHttpReq:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForACMEHttpReq{}
|
access := domain.AccessConfigForACMEHttpReq{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,44 +90,60 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeAliyun, domain.ApplyDNSProviderTypeAliyunDNS:
|
case domain.ACMEDns01ProviderTypeAliyun, domain.ACMEDns01ProviderTypeAliyunDNS, domain.ACMEDns01ProviderTypeAliyunESA:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForAliyun{}
|
access := domain.AccessConfigForAliyun{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
applicant, err := pAliyun.NewChallengeProvider(&pAliyun.ChallengeProviderConfig{
|
switch options.Provider {
|
||||||
AccessKeyId: access.AccessKeyId,
|
case domain.ACMEDns01ProviderTypeAliyun, domain.ACMEDns01ProviderTypeAliyunDNS:
|
||||||
AccessKeySecret: access.AccessKeySecret,
|
applicant, err := pAliyun.NewChallengeProvider(&pAliyun.ChallengeProviderConfig{
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
AccessKeyId: access.AccessKeyId,
|
||||||
DnsTTL: options.DnsTTL,
|
AccessKeySecret: access.AccessKeySecret,
|
||||||
})
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
return applicant, err
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeAliyunESA:
|
||||||
|
applicant, err := pAliyunESA.NewChallengeProvider(&pAliyunESA.ChallengeProviderConfig{
|
||||||
|
AccessKeyId: access.AccessKeyId,
|
||||||
|
AccessKeySecret: access.AccessKeySecret,
|
||||||
|
Region: xmaps.GetString(options.ProviderServiceConfig, "region"),
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeAWS, domain.ApplyDNSProviderTypeAWSRoute53:
|
case domain.ACMEDns01ProviderTypeAWS, domain.ACMEDns01ProviderTypeAWSRoute53:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForAWS{}
|
access := domain.AccessConfigForAWS{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
applicant, err := pAWSRoute53.NewChallengeProvider(&pAWSRoute53.ChallengeProviderConfig{
|
applicant, err := pAWSRoute53.NewChallengeProvider(&pAWSRoute53.ChallengeProviderConfig{
|
||||||
AccessKeyId: access.AccessKeyId,
|
AccessKeyId: access.AccessKeyId,
|
||||||
SecretAccessKey: access.SecretAccessKey,
|
SecretAccessKey: access.SecretAccessKey,
|
||||||
Region: maputil.GetString(options.ProviderApplyConfig, "region"),
|
Region: xmaps.GetString(options.ProviderServiceConfig, "region"),
|
||||||
HostedZoneId: maputil.GetString(options.ProviderApplyConfig, "hostedZoneId"),
|
HostedZoneId: xmaps.GetString(options.ProviderServiceConfig, "hostedZoneId"),
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeAzure, domain.ApplyDNSProviderTypeAzureDNS:
|
case domain.ACMEDns01ProviderTypeAzure, domain.ACMEDns01ProviderTypeAzureDNS:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForAzure{}
|
access := domain.AccessConfigForAzure{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,10 +158,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeBaiduCloud, domain.ApplyDNSProviderTypeBaiduCloudDNS:
|
case domain.ACMEDns01ProviderTypeBaiduCloud, domain.ACMEDns01ProviderTypeBaiduCloudDNS:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForBaiduCloud{}
|
access := domain.AccessConfigForBaiduCloud{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,25 +174,41 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeCloudflare:
|
case domain.ACMEDns01ProviderTypeBunny:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForCloudflare{}
|
access := domain.AccessConfigForBunny{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
applicant, err := pCloudflare.NewChallengeProvider(&pCloudflare.ChallengeProviderConfig{
|
applicant, err := pBunny.NewChallengeProvider(&pBunny.ChallengeProviderConfig{
|
||||||
DnsApiToken: access.DnsApiToken,
|
ApiKey: access.ApiKey,
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeClouDNS:
|
case domain.ACMEDns01ProviderTypeCloudflare:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForCloudflare{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pCloudflare.NewChallengeProvider(&pCloudflare.ChallengeProviderConfig{
|
||||||
|
DnsApiToken: access.DnsApiToken,
|
||||||
|
ZoneApiToken: access.ZoneApiToken,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeClouDNS:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForClouDNS{}
|
access := domain.AccessConfigForClouDNS{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,10 +221,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeCMCCCloud:
|
case domain.ACMEDns01ProviderTypeCMCCCloud, domain.ACMEDns01ProviderTypeCMCCCloudDNS:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForCMCCCloud{}
|
access := domain.AccessConfigForCMCCCloud{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,10 +237,72 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeDNSLA:
|
case domain.ACMEDns01ProviderTypeConstellix:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForConstellix{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pConstellix.NewChallengeProvider(&pConstellix.ChallengeProviderConfig{
|
||||||
|
ApiKey: access.ApiKey,
|
||||||
|
SecretKey: access.SecretKey,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeCTCCCloud, domain.ACMEDns01ProviderTypeCTCCCloudSmartDNS:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForCTCCCloud{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pCTCCCloud.NewChallengeProvider(&pCTCCCloud.ChallengeProviderConfig{
|
||||||
|
AccessKeyId: access.AccessKeyId,
|
||||||
|
SecretAccessKey: access.SecretAccessKey,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeDeSEC:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForDeSEC{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pDeSEC.NewChallengeProvider(&pDeSEC.ChallengeProviderConfig{
|
||||||
|
Token: access.Token,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeDigitalOcean:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForDigitalOcean{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pDigitalOcean.NewChallengeProvider(&pDigitalOcean.ChallengeProviderConfig{
|
||||||
|
AccessToken: access.AccessToken,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeDNSLA:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForDNSLA{}
|
access := domain.AccessConfigForDNSLA{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,10 +315,24 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeDynv6:
|
case domain.ACMEDns01ProviderTypeDuckDNS:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForDuckDNS{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pDuckDNS.NewChallengeProvider(&pDuckDNS.ChallengeProviderConfig{
|
||||||
|
Token: access.Token,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeDynv6:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForDynv6{}
|
access := domain.AccessConfigForDynv6{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,10 +344,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeGcore:
|
case domain.ACMEDns01ProviderTypeGcore:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForGcore{}
|
access := domain.AccessConfigForGcore{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,10 +359,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeGname:
|
case domain.ACMEDns01ProviderTypeGname:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForGname{}
|
access := domain.AccessConfigForGname{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,10 +375,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeGoDaddy:
|
case domain.ACMEDns01ProviderTypeGoDaddy:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForGoDaddy{}
|
access := domain.AccessConfigForGoDaddy{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,44 +391,59 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeHuaweiCloud, domain.ApplyDNSProviderTypeHuaweiCloudDNS:
|
case domain.ACMEDns01ProviderTypeHetzner:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForHetzner{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pHetzner.NewChallengeProvider(&pHetzner.ChallengeProviderConfig{
|
||||||
|
ApiToken: access.ApiToken,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeHuaweiCloud, domain.ACMEDns01ProviderTypeHuaweiCloudDNS:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForHuaweiCloud{}
|
access := domain.AccessConfigForHuaweiCloud{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
applicant, err := pHuaweiCloud.NewChallengeProvider(&pHuaweiCloud.ChallengeProviderConfig{
|
applicant, err := pHuaweiCloud.NewChallengeProvider(&pHuaweiCloud.ChallengeProviderConfig{
|
||||||
AccessKeyId: access.AccessKeyId,
|
AccessKeyId: access.AccessKeyId,
|
||||||
SecretAccessKey: access.SecretAccessKey,
|
SecretAccessKey: access.SecretAccessKey,
|
||||||
Region: maputil.GetString(options.ProviderApplyConfig, "region"),
|
Region: xmaps.GetString(options.ProviderServiceConfig, "region"),
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeJDCloud, domain.ApplyDNSProviderTypeJDCloudDNS:
|
case domain.ACMEDns01ProviderTypeJDCloud, domain.ACMEDns01ProviderTypeJDCloudDNS:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForJDCloud{}
|
access := domain.AccessConfigForJDCloud{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
applicant, err := pJDCloud.NewChallengeProvider(&pJDCloud.ChallengeProviderConfig{
|
applicant, err := pJDCloud.NewChallengeProvider(&pJDCloud.ChallengeProviderConfig{
|
||||||
AccessKeyId: access.AccessKeyId,
|
AccessKeyId: access.AccessKeyId,
|
||||||
AccessKeySecret: access.AccessKeySecret,
|
AccessKeySecret: access.AccessKeySecret,
|
||||||
RegionId: maputil.GetString(options.ProviderApplyConfig, "region_id"),
|
RegionId: xmaps.GetString(options.ProviderServiceConfig, "regionId"),
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeNamecheap:
|
case domain.ACMEDns01ProviderTypeNamecheap:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForNamecheap{}
|
access := domain.AccessConfigForNamecheap{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,10 +456,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeNameDotCom:
|
case domain.ACMEDns01ProviderTypeNameDotCom:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForNameDotCom{}
|
access := domain.AccessConfigForNameDotCom{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,10 +472,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeNameSilo:
|
case domain.ACMEDns01ProviderTypeNameSilo:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForNameSilo{}
|
access := domain.AccessConfigForNameSilo{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,10 +487,42 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeNS1:
|
case domain.ACMEDns01ProviderTypeNetcup:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForNetcup{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pNetcup.NewChallengeProvider(&pNetcup.ChallengeProviderConfig{
|
||||||
|
CustomerNumber: access.CustomerNumber,
|
||||||
|
ApiKey: access.ApiKey,
|
||||||
|
ApiPassword: access.ApiPassword,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeNetlify:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForNetlify{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pNetlify.NewChallengeProvider(&pNetlify.ChallengeProviderConfig{
|
||||||
|
ApiToken: access.ApiToken,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeNS1:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForNS1{}
|
access := domain.AccessConfigForNS1{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,26 +534,43 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypePowerDNS:
|
case domain.ACMEDns01ProviderTypePorkbun:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForPowerDNS{}
|
access := domain.AccessConfigForPorkbun{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
applicant, err := pPowerDNS.NewChallengeProvider(&pPowerDNS.ChallengeProviderConfig{
|
applicant, err := pPorkbun.NewChallengeProvider(&pPorkbun.ChallengeProviderConfig{
|
||||||
ApiUrl: access.ApiUrl,
|
|
||||||
ApiKey: access.ApiKey,
|
ApiKey: access.ApiKey,
|
||||||
|
SecretApiKey: access.SecretApiKey,
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeRainYun:
|
case domain.ACMEDns01ProviderTypePowerDNS:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForPowerDNS{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pPowerDNS.NewChallengeProvider(&pPowerDNS.ChallengeProviderConfig{
|
||||||
|
ServerUrl: access.ServerUrl,
|
||||||
|
ApiKey: access.ApiKey,
|
||||||
|
AllowInsecureConnections: access.AllowInsecureConnections,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeRainYun:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForRainYun{}
|
access := domain.AccessConfigForRainYun{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,26 +582,74 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeTencentCloud, domain.ApplyDNSProviderTypeTencentCloudDNS:
|
case domain.ACMEDns01ProviderTypeTencentCloud, domain.ACMEDns01ProviderTypeTencentCloudDNS, domain.ACMEDns01ProviderTypeTencentCloudEO:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForTencentCloud{}
|
access := domain.AccessConfigForTencentCloud{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
applicant, err := pTencentCloud.NewChallengeProvider(&pTencentCloud.ChallengeProviderConfig{
|
switch options.Provider {
|
||||||
SecretId: access.SecretId,
|
case domain.ACMEDns01ProviderTypeTencentCloud, domain.ACMEDns01ProviderTypeTencentCloudDNS:
|
||||||
SecretKey: access.SecretKey,
|
applicant, err := pTencentCloud.NewChallengeProvider(&pTencentCloud.ChallengeProviderConfig{
|
||||||
|
SecretId: access.SecretId,
|
||||||
|
SecretKey: access.SecretKey,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeTencentCloudEO:
|
||||||
|
applicant, err := pTencentCloudEO.NewChallengeProvider(&pTencentCloudEO.ChallengeProviderConfig{
|
||||||
|
SecretId: access.SecretId,
|
||||||
|
SecretKey: access.SecretKey,
|
||||||
|
ZoneId: xmaps.GetString(options.ProviderServiceConfig, "zoneId"),
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeUCloudUDNR:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForUCloud{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pUCloudUDNR.NewChallengeProvider(&pUCloudUDNR.ChallengeProviderConfig{
|
||||||
|
PrivateKey: access.PrivateKey,
|
||||||
|
PublicKey: access.PublicKey,
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeVolcEngine, domain.ApplyDNSProviderTypeVolcEngineDNS:
|
case domain.ACMEDns01ProviderTypeVercel:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForVercel{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applicant, err := pVercel.NewChallengeProvider(&pVercel.ChallengeProviderConfig{
|
||||||
|
ApiAccessToken: access.ApiAccessToken,
|
||||||
|
TeamId: access.TeamId,
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeVolcEngine, domain.ACMEDns01ProviderTypeVolcEngineDNS:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForVolcEngine{}
|
access := domain.AccessConfigForVolcEngine{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,10 +662,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ApplyDNSProviderTypeWestcn:
|
case domain.ACMEDns01ProviderTypeWestcn:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForWestcn{}
|
access := domain.AccessConfigForWestcn{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,5 +679,5 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("unsupported applicant provider: %s", string(options.Provider))
|
return nil, fmt.Errorf("unsupported applicant provider '%s'", string(options.Provider))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ import (
|
|||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/app"
|
"github.com/certimate-go/certimate/internal/app"
|
||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/certimate-go/certimate/internal/domain"
|
||||||
"github.com/usual2970/certimate/internal/domain/dtos"
|
"github.com/certimate-go/certimate/internal/domain/dtos"
|
||||||
"github.com/usual2970/certimate/internal/notify"
|
"github.com/certimate-go/certimate/internal/notify"
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/certutil"
|
"github.com/certimate-go/certimate/internal/repository"
|
||||||
"github.com/usual2970/certimate/internal/repository"
|
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -145,7 +145,7 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific
|
|||||||
{
|
{
|
||||||
const pfxPassword = "certimate"
|
const pfxPassword = "certimate"
|
||||||
|
|
||||||
certPFX, err := certutil.TransformCertificateFromPEMToPFX(certificate.Certificate, certificate.PrivateKey, pfxPassword)
|
certPFX, err := xcert.TransformCertificateFromPEMToPFX(certificate.Certificate, certificate.PrivateKey, pfxPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -183,7 +183,7 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific
|
|||||||
{
|
{
|
||||||
const jksPassword = "certimate"
|
const jksPassword = "certimate"
|
||||||
|
|
||||||
certJKS, err := certutil.TransformCertificateFromPEMToJKS(certificate.Certificate, certificate.PrivateKey, jksPassword, jksPassword, jksPassword)
|
certJKS, err := xcert.TransformCertificateFromPEMToJKS(certificate.Certificate, certificate.PrivateKey, jksPassword, jksPassword, jksPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -223,7 +223,7 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *CertificateService) ValidateCertificate(ctx context.Context, req *dtos.CertificateValidateCertificateReq) (*dtos.CertificateValidateCertificateResp, error) {
|
func (s *CertificateService) ValidateCertificate(ctx context.Context, req *dtos.CertificateValidateCertificateReq) (*dtos.CertificateValidateCertificateResp, error) {
|
||||||
certX509, err := certutil.ParseCertificateFromPEM(req.Certificate)
|
certX509, err := xcert.ParseCertificateFromPEM(req.Certificate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if time.Now().After(certX509.NotAfter) {
|
} else if time.Now().After(certX509.NotAfter) {
|
||||||
|
|||||||
@@ -5,77 +5,70 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/certimate-go/certimate/internal/domain"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
"github.com/certimate-go/certimate/internal/repository"
|
||||||
"github.com/usual2970/certimate/internal/repository"
|
"github.com/certimate-go/certimate/pkg/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Deployer interface {
|
type Deployer interface {
|
||||||
SetLogger(*slog.Logger)
|
|
||||||
|
|
||||||
Deploy(ctx context.Context) error
|
Deploy(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type deployerOptions struct {
|
type DeployerWithWorkflowNodeConfig struct {
|
||||||
Provider domain.DeployProviderType
|
Node *domain.WorkflowNode
|
||||||
ProviderAccessConfig map[string]any
|
Logger *slog.Logger
|
||||||
ProviderDeployConfig map[string]any
|
CertificatePEM string
|
||||||
|
PrivateKeyPEM string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWithDeployNode(node *domain.WorkflowNode, certdata struct {
|
func NewWithWorkflowNode(config DeployerWithWorkflowNodeConfig) (Deployer, error) {
|
||||||
Certificate string
|
if config.Node == nil {
|
||||||
PrivateKey string
|
return nil, fmt.Errorf("node is nil")
|
||||||
},
|
}
|
||||||
) (Deployer, error) {
|
if config.Node.Type != domain.WorkflowNodeTypeDeploy {
|
||||||
if node.Type != domain.WorkflowNodeTypeDeploy {
|
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeDeploy))
|
||||||
return nil, fmt.Errorf("node type is not deploy")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeConfig := node.GetConfigForDeploy()
|
nodeCfg := config.Node.GetConfigForDeploy()
|
||||||
|
options := &deployerProviderOptions{
|
||||||
|
Provider: domain.DeploymentProviderType(nodeCfg.Provider),
|
||||||
|
ProviderAccessConfig: make(map[string]any),
|
||||||
|
ProviderServiceConfig: nodeCfg.ProviderConfig,
|
||||||
|
}
|
||||||
|
|
||||||
accessRepo := repository.NewAccessRepository()
|
accessRepo := repository.NewAccessRepository()
|
||||||
access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId)
|
if nodeCfg.ProviderAccessId != "" {
|
||||||
if err != nil {
|
access, err := accessRepo.GetById(context.Background(), nodeCfg.ProviderAccessId)
|
||||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.ProviderAccessId, err)
|
||||||
|
} else {
|
||||||
|
options.ProviderAccessConfig = access.Config
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
accessConfig, err := access.UnmarshalConfigToMap()
|
deployer, err := createSSLDeployerProvider(options)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
deployer, err := createDeployer(&deployerOptions{
|
|
||||||
Provider: domain.DeployProviderType(nodeConfig.Provider),
|
|
||||||
ProviderAccessConfig: accessConfig,
|
|
||||||
ProviderDeployConfig: nodeConfig.ProviderConfig,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else {
|
||||||
|
deployer.SetLogger(config.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &proxyDeployer{
|
return &deployerImpl{
|
||||||
deployer: deployer,
|
provider: deployer,
|
||||||
deployCertificate: certdata.Certificate,
|
certPEM: config.CertificatePEM,
|
||||||
deployPrivateKey: certdata.PrivateKey,
|
privkeyPEM: config.PrivateKeyPEM,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 暂时使用代理模式以兼容之前版本代码,后续重新实现此处逻辑
|
type deployerImpl struct {
|
||||||
type proxyDeployer struct {
|
provider core.SSLDeployer
|
||||||
deployer deployer.Deployer
|
certPEM string
|
||||||
deployCertificate string
|
privkeyPEM string
|
||||||
deployPrivateKey string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *proxyDeployer) SetLogger(logger *slog.Logger) {
|
var _ Deployer = (*deployerImpl)(nil)
|
||||||
if logger == nil {
|
|
||||||
panic("logger is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
d.deployer.WithLogger(logger)
|
func (d *deployerImpl) Deploy(ctx context.Context) error {
|
||||||
}
|
_, err := d.provider.Deploy(ctx, d.certPEM, d.privkeyPEM)
|
||||||
|
|
||||||
func (d *proxyDeployer) Deploy(ctx context.Context) error {
|
|
||||||
_, err := d.deployer.Deploy(ctx, d.deployCertificate, d.deployPrivateKey)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -9,27 +8,26 @@ const CollectionNameAccess = "access"
|
|||||||
|
|
||||||
type Access struct {
|
type Access struct {
|
||||||
Meta
|
Meta
|
||||||
Name string `json:"name" db:"name"`
|
Name string `json:"name" db:"name"`
|
||||||
Provider string `json:"provider" db:"provider"`
|
Provider string `json:"provider" db:"provider"`
|
||||||
Config string `json:"config" db:"config"`
|
Config map[string]any `json:"config" db:"config"`
|
||||||
DeletedAt *time.Time `json:"deleted" db:"deleted"`
|
Reserve string `json:"reserve,omitempty" db:"reserve"`
|
||||||
}
|
DeletedAt *time.Time `json:"deleted" db:"deleted"`
|
||||||
|
|
||||||
func (a *Access) UnmarshalConfigToMap() (map[string]any, error) {
|
|
||||||
config := make(map[string]any)
|
|
||||||
if err := json.Unmarshal([]byte(a.Config), &config); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigFor1Panel struct {
|
type AccessConfigFor1Panel struct {
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
ApiVersion string `json:"apiVersion"`
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForACMECA struct {
|
||||||
|
Endpoint string `json:"endpoint"`
|
||||||
|
EabKid string `json:"eabKid,omitempty"`
|
||||||
|
EabHmacKey string `json:"eabHmacKey,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForACMEHttpReq struct {
|
type AccessConfigForACMEHttpReq struct {
|
||||||
Endpoint string `json:"endpoint"`
|
Endpoint string `json:"endpoint"`
|
||||||
Mode string `json:"mode,omitempty"`
|
Mode string `json:"mode,omitempty"`
|
||||||
@@ -40,6 +38,13 @@ type AccessConfigForACMEHttpReq struct {
|
|||||||
type AccessConfigForAliyun struct {
|
type AccessConfigForAliyun struct {
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForAPISIX struct {
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForAWS struct {
|
type AccessConfigForAWS struct {
|
||||||
@@ -64,7 +69,13 @@ type AccessConfigForBaishan struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForBaotaPanel struct {
|
type AccessConfigForBaotaPanel struct {
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForBaotaWAF struct {
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -74,18 +85,24 @@ type AccessConfigForBytePlus struct {
|
|||||||
SecretKey string `json:"secretKey"`
|
SecretKey string `json:"secretKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForBunny struct {
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForCacheFly struct {
|
type AccessConfigForCacheFly struct {
|
||||||
ApiToken string `json:"apiToken"`
|
ApiToken string `json:"apiToken"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForCdnfly struct {
|
type AccessConfigForCdnfly struct {
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
ApiSecret string `json:"apiSecret"`
|
ApiSecret string `json:"apiSecret"`
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForCloudflare struct {
|
type AccessConfigForCloudflare struct {
|
||||||
DnsApiToken string `json:"dnsApiToken"`
|
DnsApiToken string `json:"dnsApiToken"`
|
||||||
|
ZoneApiToken string `json:"zoneApiToken,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForClouDNS struct {
|
type AccessConfigForClouDNS struct {
|
||||||
@@ -98,6 +115,34 @@ type AccessConfigForCMCCCloud struct {
|
|||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForConstellix struct {
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
SecretKey string `json:"secretKey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForCTCCCloud struct {
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
SecretAccessKey string `json:"secretAccessKey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForDeSEC struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForDigitalOcean struct {
|
||||||
|
AccessToken string `json:"accessToken"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForDingTalkBot struct {
|
||||||
|
WebhookUrl string `json:"webhookUrl"`
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForDiscordBot struct {
|
||||||
|
BotToken string `json:"botToken"`
|
||||||
|
DefaultChannelId string `json:"defaultChannelId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForDNSLA struct {
|
type AccessConfigForDNSLA struct {
|
||||||
ApiId string `json:"apiId"`
|
ApiId string `json:"apiId"`
|
||||||
ApiSecret string `json:"apiSecret"`
|
ApiSecret string `json:"apiSecret"`
|
||||||
@@ -108,6 +153,10 @@ type AccessConfigForDogeCloud struct {
|
|||||||
SecretKey string `json:"secretKey"`
|
SecretKey string `json:"secretKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForDuckDNS struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForDynv6 struct {
|
type AccessConfigForDynv6 struct {
|
||||||
HttpToken string `json:"httpToken"`
|
HttpToken string `json:"httpToken"`
|
||||||
}
|
}
|
||||||
@@ -117,6 +166,25 @@ type AccessConfigForEdgio struct {
|
|||||||
ClientSecret string `json:"clientSecret"`
|
ClientSecret string `json:"clientSecret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForEmail struct {
|
||||||
|
SmtpHost string `json:"smtpHost"`
|
||||||
|
SmtpPort int32 `json:"smtpPort"`
|
||||||
|
SmtpTls bool `json:"smtpTls"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
DefaultSenderAddress string `json:"defaultSenderAddress,omitempty"`
|
||||||
|
DefaultSenderName string `json:"defaultSenderName,omitempty"`
|
||||||
|
DefaultReceiverAddress string `json:"defaultReceiverAddress,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForFlexCDN struct {
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
ApiRole string `json:"apiRole"`
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
AccessKey string `json:"accessKey"`
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForGcore struct {
|
type AccessConfigForGcore struct {
|
||||||
ApiToken string `json:"apiToken"`
|
ApiToken string `json:"apiToken"`
|
||||||
}
|
}
|
||||||
@@ -131,9 +199,27 @@ type AccessConfigForGoDaddy struct {
|
|||||||
ApiSecret string `json:"apiSecret"`
|
ApiSecret string `json:"apiSecret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForGoEdge struct {
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
ApiRole string `json:"apiRole"`
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
AccessKey string `json:"accessKey"`
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForGoogleTrustServices struct {
|
||||||
|
EabKid string `json:"eabKid"`
|
||||||
|
EabHmacKey string `json:"eabHmacKey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForHetzner struct {
|
||||||
|
ApiToken string `json:"apiToken"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForHuaweiCloud struct {
|
type AccessConfigForHuaweiCloud struct {
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
SecretAccessKey string `json:"secretAccessKey"`
|
SecretAccessKey string `json:"secretAccessKey"`
|
||||||
|
EnterpriseProjectId string `json:"enterpriseProjectId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForJDCloud struct {
|
type AccessConfigForJDCloud struct {
|
||||||
@@ -145,7 +231,25 @@ type AccessConfigForKubernetes struct {
|
|||||||
KubeConfig string `json:"kubeConfig,omitempty"`
|
KubeConfig string `json:"kubeConfig,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForLocal struct{}
|
type AccessConfigForLarkBot struct {
|
||||||
|
WebhookUrl string `json:"webhookUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForLeCDN struct {
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
ApiVersion string `json:"apiVersion"`
|
||||||
|
ApiRole string `json:"apiRole"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForMattermost struct {
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
DefaultChannelId string `json:"defaultChannelId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForNamecheap struct {
|
type AccessConfigForNamecheap struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@@ -161,13 +265,36 @@ type AccessConfigForNameSilo struct {
|
|||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForNetcup struct {
|
||||||
|
CustomerNumber string `json:"customerNumber"`
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
ApiPassword string `json:"apiPassword"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForNetlify struct {
|
||||||
|
ApiToken string `json:"apiToken"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForNS1 struct {
|
type AccessConfigForNS1 struct {
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForPorkbun struct {
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
SecretApiKey string `json:"secretApiKey"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForPowerDNS struct {
|
type AccessConfigForPowerDNS struct {
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForProxmoxVE struct {
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
ApiToken string `json:"apiToken"`
|
||||||
|
ApiTokenSecret string `json:"apiTokenSecret,omitempty"`
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForQiniu struct {
|
type AccessConfigForQiniu struct {
|
||||||
@@ -179,19 +306,51 @@ type AccessConfigForRainYun struct {
|
|||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForRatPanel struct {
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
AccessTokenId int32 `json:"accessTokenId"`
|
||||||
|
AccessToken string `json:"accessToken"`
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForSafeLine struct {
|
type AccessConfigForSafeLine struct {
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
ApiToken string `json:"apiToken"`
|
ApiToken string `json:"apiToken"`
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForSlackBot struct {
|
||||||
|
BotToken string `json:"botToken"`
|
||||||
|
DefaultChannelId string `json:"defaultChannelId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForSSH struct {
|
type AccessConfigForSSH struct {
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
Port int32 `json:"port"`
|
Port int32 `json:"port"`
|
||||||
Username string `json:"username"`
|
AuthMethod string `json:"authMethod,omitempty"`
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
Key string `json:"key,omitempty"`
|
Key string `json:"key,omitempty"`
|
||||||
KeyPassphrase string `json:"keyPassphrase,omitempty"`
|
KeyPassphrase string `json:"keyPassphrase,omitempty"`
|
||||||
|
JumpServers []struct {
|
||||||
|
Host string `json:"host"`
|
||||||
|
Port int32 `json:"port"`
|
||||||
|
AuthMethod string `json:"authMethod,omitempty"`
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
Key string `json:"key,omitempty"`
|
||||||
|
KeyPassphrase string `json:"keyPassphrase,omitempty"`
|
||||||
|
} `json:"jumpServers,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForSSLCom struct {
|
||||||
|
EabKid string `json:"eabKid"`
|
||||||
|
EabHmacKey string `json:"eabHmacKey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForTelegramBot struct {
|
||||||
|
BotToken string `json:"botToken"`
|
||||||
|
DefaultChatId int64 `json:"defaultChatId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForTencentCloud struct {
|
type AccessConfigForTencentCloud struct {
|
||||||
@@ -205,22 +364,51 @@ type AccessConfigForUCloud struct {
|
|||||||
ProjectId string `json:"projectId,omitempty"`
|
ProjectId string `json:"projectId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForUniCloud struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForUpyun struct {
|
type AccessConfigForUpyun struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForVercel struct {
|
||||||
|
ApiAccessToken string `json:"apiAccessToken"`
|
||||||
|
TeamId string `json:"teamId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForVolcEngine struct {
|
type AccessConfigForVolcEngine struct {
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
SecretAccessKey string `json:"secretAccessKey"`
|
SecretAccessKey string `json:"secretAccessKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForWangsu struct {
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForWebhook struct {
|
type AccessConfigForWebhook struct {
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
Method string `json:"method,omitempty"`
|
||||||
|
HeadersString string `json:"headers,omitempty"`
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
|
DefaultDataForDeployment string `json:"defaultDataForDeployment,omitempty"`
|
||||||
|
DefaultDataForNotification string `json:"defaultDataForNotification,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForWeComBot struct {
|
||||||
|
WebhookUrl string `json:"webhookUrl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForWestcn struct {
|
type AccessConfigForWestcn struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
ApiPassword string `json:"password"`
|
ApiPassword string `json:"apiPassword"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessConfigForZeroSSL struct {
|
||||||
|
EabKid string `json:"eabKid"`
|
||||||
|
EabHmacKey string `json:"eabHmacKey"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/certutil"
|
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
|
||||||
)
|
)
|
||||||
|
|
||||||
const CollectionNameCertificate = "certificate"
|
const CollectionNameCertificate = "certificate"
|
||||||
@@ -20,7 +20,7 @@ type Certificate struct {
|
|||||||
SerialNumber string `json:"serialNumber" db:"serialNumber"`
|
SerialNumber string `json:"serialNumber" db:"serialNumber"`
|
||||||
Certificate string `json:"certificate" db:"certificate"`
|
Certificate string `json:"certificate" db:"certificate"`
|
||||||
PrivateKey string `json:"privateKey" db:"privateKey"`
|
PrivateKey string `json:"privateKey" db:"privateKey"`
|
||||||
Issuer string `json:"issuer" db:"issuer"`
|
IssuerOrg string `json:"issuerOrg" db:"issuerOrg"`
|
||||||
IssuerCertificate string `json:"issuerCertificate" db:"issuerCertificate"`
|
IssuerCertificate string `json:"issuerCertificate" db:"issuerCertificate"`
|
||||||
KeyAlgorithm CertificateKeyAlgorithmType `json:"keyAlgorithm" db:"keyAlgorithm"`
|
KeyAlgorithm CertificateKeyAlgorithmType `json:"keyAlgorithm" db:"keyAlgorithm"`
|
||||||
EffectAt time.Time `json:"effectAt" db:"effectAt"`
|
EffectAt time.Time `json:"effectAt" db:"effectAt"`
|
||||||
@@ -28,6 +28,7 @@ type Certificate struct {
|
|||||||
ACMEAccountUrl string `json:"acmeAccountUrl" db:"acmeAccountUrl"`
|
ACMEAccountUrl string `json:"acmeAccountUrl" db:"acmeAccountUrl"`
|
||||||
ACMECertUrl string `json:"acmeCertUrl" db:"acmeCertUrl"`
|
ACMECertUrl string `json:"acmeCertUrl" db:"acmeCertUrl"`
|
||||||
ACMECertStableUrl string `json:"acmeCertStableUrl" db:"acmeCertStableUrl"`
|
ACMECertStableUrl string `json:"acmeCertStableUrl" db:"acmeCertStableUrl"`
|
||||||
|
ACMERenewed bool `json:"acmeRenewed" db:"acmeRenewed"`
|
||||||
WorkflowId string `json:"workflowId" db:"workflowId"`
|
WorkflowId string `json:"workflowId" db:"workflowId"`
|
||||||
WorkflowNodeId string `json:"workflowNodeId" db:"workflowNodeId"`
|
WorkflowNodeId string `json:"workflowNodeId" db:"workflowNodeId"`
|
||||||
WorkflowRunId string `json:"workflowRunId" db:"workflowRunId"`
|
WorkflowRunId string `json:"workflowRunId" db:"workflowRunId"`
|
||||||
@@ -38,7 +39,7 @@ type Certificate struct {
|
|||||||
func (c *Certificate) PopulateFromX509(certX509 *x509.Certificate) *Certificate {
|
func (c *Certificate) PopulateFromX509(certX509 *x509.Certificate) *Certificate {
|
||||||
c.SubjectAltNames = strings.Join(certX509.DNSNames, ";")
|
c.SubjectAltNames = strings.Join(certX509.DNSNames, ";")
|
||||||
c.SerialNumber = strings.ToUpper(certX509.SerialNumber.Text(16))
|
c.SerialNumber = strings.ToUpper(certX509.SerialNumber.Text(16))
|
||||||
c.Issuer = strings.Join(certX509.Issuer.Organization, ";")
|
c.IssuerOrg = strings.Join(certX509.Issuer.Organization, ";")
|
||||||
c.EffectAt = certX509.NotBefore
|
c.EffectAt = certX509.NotBefore
|
||||||
c.ExpireAt = certX509.NotAfter
|
c.ExpireAt = certX509.NotAfter
|
||||||
|
|
||||||
@@ -105,10 +106,10 @@ func (c *Certificate) PopulateFromPEM(certPEM, privkeyPEM string) *Certificate {
|
|||||||
c.Certificate = certPEM
|
c.Certificate = certPEM
|
||||||
c.PrivateKey = privkeyPEM
|
c.PrivateKey = privkeyPEM
|
||||||
|
|
||||||
_, issuerCertPEM, _ := certutil.ExtractCertificatesFromPEM(certPEM)
|
_, issuerCertPEM, _ := xcert.ExtractCertificatesFromPEM(certPEM)
|
||||||
c.IssuerCertificate = issuerCertPEM
|
c.IssuerCertificate = issuerCertPEM
|
||||||
|
|
||||||
certX509, _ := certutil.ParseCertificateFromPEM(certPEM)
|
certX509, _ := xcert.ParseCertificateFromPEM(certPEM)
|
||||||
if certX509 != nil {
|
if certX509 != nil {
|
||||||
c.PopulateFromX509(certX509)
|
c.PopulateFromX509(certX509)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package dtos
|
package dtos
|
||||||
|
|
||||||
type CertificateArchiveFileReq struct {
|
type CertificateArchiveFileReq struct {
|
||||||
CertificateId string `json:"-"`
|
CertificateId string `json:"-"`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package dtos
|
package dtos
|
||||||
|
|
||||||
import "github.com/usual2970/certimate/internal/domain"
|
import "github.com/certimate-go/certimate/internal/domain"
|
||||||
|
|
||||||
type NotifyTestPushReq struct {
|
type NotifyTestPushReq struct {
|
||||||
Channel domain.NotifyChannelType `json:"channel"`
|
Channel domain.NotifyChannelType `json:"channel"`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package dtos
|
package dtos
|
||||||
|
|
||||||
import "github.com/usual2970/certimate/internal/domain"
|
import "github.com/certimate-go/certimate/internal/domain"
|
||||||
|
|
||||||
type WorkflowStartRunReq struct {
|
type WorkflowStartRunReq struct {
|
||||||
WorkflowId string `json:"-"`
|
WorkflowId string `json:"-"`
|
||||||
|
|||||||
630
internal/domain/expr/expr.go
Normal file
630
internal/domain/expr/expr.go
Normal file
@@ -0,0 +1,630 @@
|
|||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
ExprType string
|
||||||
|
ExprComparisonOperator string
|
||||||
|
ExprLogicalOperator string
|
||||||
|
ExprValueType string
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GreaterThan ExprComparisonOperator = "gt"
|
||||||
|
GreaterOrEqual ExprComparisonOperator = "gte"
|
||||||
|
LessThan ExprComparisonOperator = "lt"
|
||||||
|
LessOrEqual ExprComparisonOperator = "lte"
|
||||||
|
Equal ExprComparisonOperator = "eq"
|
||||||
|
NotEqual ExprComparisonOperator = "neq"
|
||||||
|
|
||||||
|
And ExprLogicalOperator = "and"
|
||||||
|
Or ExprLogicalOperator = "or"
|
||||||
|
Not ExprLogicalOperator = "not"
|
||||||
|
|
||||||
|
Number ExprValueType = "number"
|
||||||
|
String ExprValueType = "string"
|
||||||
|
Boolean ExprValueType = "boolean"
|
||||||
|
|
||||||
|
ConstantExprType ExprType = "const"
|
||||||
|
VariantExprType ExprType = "var"
|
||||||
|
ComparisonExprType ExprType = "comparison"
|
||||||
|
LogicalExprType ExprType = "logical"
|
||||||
|
NotExprType ExprType = "not"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EvalResult struct {
|
||||||
|
Type ExprValueType
|
||||||
|
Value any
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) GetFloat64() (float64, error) {
|
||||||
|
if e.Type != Number {
|
||||||
|
return 0, fmt.Errorf("type mismatch: %s", e.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
stringValue, ok := e.Value.(string)
|
||||||
|
if !ok {
|
||||||
|
return 0, fmt.Errorf("value is not a string: %v", e.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
floatValue, err := strconv.ParseFloat(stringValue, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to parse float64: %v", err)
|
||||||
|
}
|
||||||
|
return floatValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) GetBool() (bool, error) {
|
||||||
|
if e.Type != Boolean {
|
||||||
|
return false, fmt.Errorf("type mismatch: %s", e.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
strValue, ok := e.Value.(string)
|
||||||
|
if ok {
|
||||||
|
if strValue == "true" {
|
||||||
|
return true, nil
|
||||||
|
} else if strValue == "false" {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("value is not a boolean: %v", e.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
boolValue, ok := e.Value.(bool)
|
||||||
|
if !ok {
|
||||||
|
return false, fmt.Errorf("value is not a boolean: %v", e.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return boolValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) GreaterThan(other *EvalResult) (*EvalResult, error) {
|
||||||
|
if e.Type != other.Type {
|
||||||
|
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Type {
|
||||||
|
case String:
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: e.Value.(string) > other.Value.(string),
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case Number:
|
||||||
|
left, err := e.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
right, err := other.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: left > right,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) GreaterOrEqual(other *EvalResult) (*EvalResult, error) {
|
||||||
|
if e.Type != other.Type {
|
||||||
|
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Type {
|
||||||
|
case String:
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: e.Value.(string) >= other.Value.(string),
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case Number:
|
||||||
|
left, err := e.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
right, err := other.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: left >= right,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) LessThan(other *EvalResult) (*EvalResult, error) {
|
||||||
|
if e.Type != other.Type {
|
||||||
|
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Type {
|
||||||
|
case String:
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: e.Value.(string) < other.Value.(string),
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case Number:
|
||||||
|
left, err := e.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
right, err := other.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: left < right,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) LessOrEqual(other *EvalResult) (*EvalResult, error) {
|
||||||
|
if e.Type != other.Type {
|
||||||
|
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Type {
|
||||||
|
case String:
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: e.Value.(string) <= other.Value.(string),
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case Number:
|
||||||
|
left, err := e.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
right, err := other.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: left <= right,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) Equal(other *EvalResult) (*EvalResult, error) {
|
||||||
|
if e.Type != other.Type {
|
||||||
|
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Type {
|
||||||
|
case String:
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: e.Value.(string) == other.Value.(string),
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case Number:
|
||||||
|
left, err := e.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
right, err := other.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: left == right,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case Boolean:
|
||||||
|
left, err := e.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
right, err := other.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: left == right,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) NotEqual(other *EvalResult) (*EvalResult, error) {
|
||||||
|
if e.Type != other.Type {
|
||||||
|
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Type {
|
||||||
|
case String:
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: e.Value.(string) != other.Value.(string),
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case Number:
|
||||||
|
left, err := e.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
right, err := other.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: left != right,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case Boolean:
|
||||||
|
left, err := e.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
right, err := other.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: left != right,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) And(other *EvalResult) (*EvalResult, error) {
|
||||||
|
if e.Type != other.Type {
|
||||||
|
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Type {
|
||||||
|
case Boolean:
|
||||||
|
left, err := e.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
right, err := other.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: left && right,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) Or(other *EvalResult) (*EvalResult, error) {
|
||||||
|
if e.Type != other.Type {
|
||||||
|
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Type {
|
||||||
|
case Boolean:
|
||||||
|
left, err := e.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
right, err := other.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: left || right,
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvalResult) Not() (*EvalResult, error) {
|
||||||
|
if e.Type != Boolean {
|
||||||
|
return nil, fmt.Errorf("type mismatch: %s", e.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
boolValue, err := e.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalResult{
|
||||||
|
Type: Boolean,
|
||||||
|
Value: !boolValue,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Expr interface {
|
||||||
|
GetType() ExprType
|
||||||
|
Eval(variables map[string]map[string]any) (*EvalResult, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExprValueSelector struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type ExprValueType `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConstantExpr struct {
|
||||||
|
Type ExprType `json:"type"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
ValueType ExprValueType `json:"valueType"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConstantExpr) GetType() ExprType { return c.Type }
|
||||||
|
|
||||||
|
func (c ConstantExpr) Eval(variables map[string]map[string]any) (*EvalResult, error) {
|
||||||
|
return &EvalResult{
|
||||||
|
Type: c.ValueType,
|
||||||
|
Value: c.Value,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type VariantExpr struct {
|
||||||
|
Type ExprType `json:"type"`
|
||||||
|
Selector ExprValueSelector `json:"selector"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v VariantExpr) GetType() ExprType { return v.Type }
|
||||||
|
|
||||||
|
func (v VariantExpr) Eval(variables map[string]map[string]any) (*EvalResult, error) {
|
||||||
|
if v.Selector.Id == "" {
|
||||||
|
return nil, fmt.Errorf("node id is empty")
|
||||||
|
}
|
||||||
|
if v.Selector.Name == "" {
|
||||||
|
return nil, fmt.Errorf("name is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := variables[v.Selector.Id]; !ok {
|
||||||
|
return nil, fmt.Errorf("node %s not found", v.Selector.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := variables[v.Selector.Id][v.Selector.Name]; !ok {
|
||||||
|
return nil, fmt.Errorf("variable %s not found in node %s", v.Selector.Name, v.Selector.Id)
|
||||||
|
}
|
||||||
|
return &EvalResult{
|
||||||
|
Type: v.Selector.Type,
|
||||||
|
Value: variables[v.Selector.Id][v.Selector.Name],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ComparisonExpr struct {
|
||||||
|
Type ExprType `json:"type"` // compare
|
||||||
|
Operator ExprComparisonOperator `json:"operator"`
|
||||||
|
Left Expr `json:"left"`
|
||||||
|
Right Expr `json:"right"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ComparisonExpr) GetType() ExprType { return c.Type }
|
||||||
|
|
||||||
|
func (c ComparisonExpr) Eval(variables map[string]map[string]any) (*EvalResult, error) {
|
||||||
|
left, err := c.Left.Eval(variables)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
right, err := c.Right.Eval(variables)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c.Operator {
|
||||||
|
case GreaterThan:
|
||||||
|
return left.GreaterThan(right)
|
||||||
|
case LessThan:
|
||||||
|
return left.LessThan(right)
|
||||||
|
case GreaterOrEqual:
|
||||||
|
return left.GreaterOrEqual(right)
|
||||||
|
case LessOrEqual:
|
||||||
|
return left.LessOrEqual(right)
|
||||||
|
case Equal:
|
||||||
|
return left.Equal(right)
|
||||||
|
case NotEqual:
|
||||||
|
return left.NotEqual(right)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown expression operator: %s", c.Operator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogicalExpr struct {
|
||||||
|
Type ExprType `json:"type"` // logical
|
||||||
|
Operator ExprLogicalOperator `json:"operator"`
|
||||||
|
Left Expr `json:"left"`
|
||||||
|
Right Expr `json:"right"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LogicalExpr) GetType() ExprType { return l.Type }
|
||||||
|
|
||||||
|
func (l LogicalExpr) Eval(variables map[string]map[string]any) (*EvalResult, error) {
|
||||||
|
left, err := l.Left.Eval(variables)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
right, err := l.Right.Eval(variables)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch l.Operator {
|
||||||
|
case And:
|
||||||
|
return left.And(right)
|
||||||
|
case Or:
|
||||||
|
return left.Or(right)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown expression operator: %s", l.Operator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotExpr struct {
|
||||||
|
Type ExprType `json:"type"` // not
|
||||||
|
Expr Expr `json:"expr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NotExpr) GetType() ExprType { return n.Type }
|
||||||
|
|
||||||
|
func (n NotExpr) Eval(variables map[string]map[string]any) (*EvalResult, error) {
|
||||||
|
inner, err := n.Expr.Eval(variables)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return inner.Not()
|
||||||
|
}
|
||||||
|
|
||||||
|
type rawExpr struct {
|
||||||
|
Type ExprType `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func MarshalExpr(e Expr) ([]byte, error) {
|
||||||
|
return json.Marshal(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalExpr(data []byte) (Expr, error) {
|
||||||
|
var typ rawExpr
|
||||||
|
if err := json.Unmarshal(data, &typ); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typ.Type {
|
||||||
|
case ConstantExprType:
|
||||||
|
var e ConstantExpr
|
||||||
|
if err := json.Unmarshal(data, &e); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return e, nil
|
||||||
|
case VariantExprType:
|
||||||
|
var e VariantExpr
|
||||||
|
if err := json.Unmarshal(data, &e); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return e, nil
|
||||||
|
case ComparisonExprType:
|
||||||
|
var e ComparisonExprRaw
|
||||||
|
if err := json.Unmarshal(data, &e); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return e.ToComparisonExpr()
|
||||||
|
case LogicalExprType:
|
||||||
|
var e LogicalExprRaw
|
||||||
|
if err := json.Unmarshal(data, &e); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return e.ToLogicalExpr()
|
||||||
|
case NotExprType:
|
||||||
|
var e NotExprRaw
|
||||||
|
if err := json.Unmarshal(data, &e); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return e.ToNotExpr()
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown expression type: %s", typ.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ComparisonExprRaw struct {
|
||||||
|
Type ExprType `json:"type"`
|
||||||
|
Operator ExprComparisonOperator `json:"operator"`
|
||||||
|
Left json.RawMessage `json:"left"`
|
||||||
|
Right json.RawMessage `json:"right"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ComparisonExprRaw) ToComparisonExpr() (ComparisonExpr, error) {
|
||||||
|
leftExpr, err := UnmarshalExpr(r.Left)
|
||||||
|
if err != nil {
|
||||||
|
return ComparisonExpr{}, err
|
||||||
|
}
|
||||||
|
rightExpr, err := UnmarshalExpr(r.Right)
|
||||||
|
if err != nil {
|
||||||
|
return ComparisonExpr{}, err
|
||||||
|
}
|
||||||
|
return ComparisonExpr{
|
||||||
|
Type: r.Type,
|
||||||
|
Operator: r.Operator,
|
||||||
|
Left: leftExpr,
|
||||||
|
Right: rightExpr,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogicalExprRaw struct {
|
||||||
|
Type ExprType `json:"type"`
|
||||||
|
Operator ExprLogicalOperator `json:"operator"`
|
||||||
|
Left json.RawMessage `json:"left"`
|
||||||
|
Right json.RawMessage `json:"right"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r LogicalExprRaw) ToLogicalExpr() (LogicalExpr, error) {
|
||||||
|
left, err := UnmarshalExpr(r.Left)
|
||||||
|
if err != nil {
|
||||||
|
return LogicalExpr{}, err
|
||||||
|
}
|
||||||
|
right, err := UnmarshalExpr(r.Right)
|
||||||
|
if err != nil {
|
||||||
|
return LogicalExpr{}, err
|
||||||
|
}
|
||||||
|
return LogicalExpr{
|
||||||
|
Type: r.Type,
|
||||||
|
Operator: r.Operator,
|
||||||
|
Left: left,
|
||||||
|
Right: right,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotExprRaw struct {
|
||||||
|
Type ExprType `json:"type"`
|
||||||
|
Expr json.RawMessage `json:"expr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r NotExprRaw) ToNotExpr() (NotExpr, error) {
|
||||||
|
inner, err := UnmarshalExpr(r.Expr)
|
||||||
|
if err != nil {
|
||||||
|
return NotExpr{}, err
|
||||||
|
}
|
||||||
|
return NotExpr{
|
||||||
|
Type: r.Type,
|
||||||
|
Expr: inner,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
127
internal/domain/expr/expr_test.go
Normal file
127
internal/domain/expr/expr_test.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLogicalEval(t *testing.T) {
|
||||||
|
// 测试逻辑表达式 and
|
||||||
|
logicalExpr := LogicalExpr{
|
||||||
|
Left: ConstantExpr{
|
||||||
|
Type: "const",
|
||||||
|
Value: "true",
|
||||||
|
ValueType: "boolean",
|
||||||
|
},
|
||||||
|
Operator: And,
|
||||||
|
Right: ConstantExpr{
|
||||||
|
Type: "const",
|
||||||
|
Value: "true",
|
||||||
|
ValueType: "boolean",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
result, err := logicalExpr.Eval(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to evaluate logical expression: %v", err)
|
||||||
|
}
|
||||||
|
if result.Value != true {
|
||||||
|
t.Errorf("expected true, got %v", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试逻辑表达式 or
|
||||||
|
orExpr := LogicalExpr{
|
||||||
|
Left: ConstantExpr{
|
||||||
|
Type: "const",
|
||||||
|
Value: "true",
|
||||||
|
ValueType: "boolean",
|
||||||
|
},
|
||||||
|
Operator: Or,
|
||||||
|
Right: ConstantExpr{
|
||||||
|
Type: "const",
|
||||||
|
Value: "true",
|
||||||
|
ValueType: "boolean",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
result, err = orExpr.Eval(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to evaluate logical expression: %v", err)
|
||||||
|
}
|
||||||
|
if result.Value != true {
|
||||||
|
t.Errorf("expected true, got %v", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalExpr(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Expr
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test1",
|
||||||
|
args: args{
|
||||||
|
data: []byte(`{"left":{"left":{"selector":{"id":"ODnYSOXB6HQP2_vz6JcZE","name":"certificate.validity","type":"boolean"},"type":"var"},"operator":"is","right":{"type":"const","value":true,"valueType":"boolean"},"type":"comparison"},"operator":"and","right":{"left":{"selector":{"id":"ODnYSOXB6HQP2_vz6JcZE","name":"certificate.daysLeft","type":"number"},"type":"var"},"operator":"eq","right":{"type":"const","value":2,"valueType":"number"},"type":"comparison"},"type":"logical"}`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := UnmarshalExpr(tt.args.data)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("UnmarshalExpr() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got == nil {
|
||||||
|
t.Errorf("UnmarshalExpr() got = nil, want %v", tt.want)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpr_Eval(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
variables map[string]map[string]any
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *EvalResult
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test1",
|
||||||
|
args: args{
|
||||||
|
variables: map[string]map[string]any{
|
||||||
|
"ODnYSOXB6HQP2_vz6JcZE": {
|
||||||
|
"certificate.validity": true,
|
||||||
|
"certificate.daysLeft": 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: []byte(`{"left":{"left":{"selector":{"id":"ODnYSOXB6HQP2_vz6JcZE","name":"certificate.validity","type":"boolean"},"type":"var"},"operator":"is","right":{"type":"const","value":true,"valueType":"boolean"},"type":"comparison"},"operator":"and","right":{"left":{"selector":{"id":"ODnYSOXB6HQP2_vz6JcZE","name":"certificate.daysLeft","type":"number"},"type":"var"},"operator":"eq","right":{"type":"const","value":2,"valueType":"number"},"type":"comparison"},"type":"logical"}`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
c, err := UnmarshalExpr(tt.args.data)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("UnmarshalExpr() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
got, err := c.Eval(tt.args.variables)
|
||||||
|
t.Log("got:", got)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("ConstExpr.Eval() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got.Value != true {
|
||||||
|
t.Errorf("ConstExpr.Eval() got = %v, want %v", got.Value, true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,11 +8,16 @@ type NotifyChannelType string
|
|||||||
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||||
NOTICE: If you add new constant, please keep ASCII order.
|
NOTICE: If you add new constant, please keep ASCII order.
|
||||||
*/
|
*/
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
const (
|
const (
|
||||||
NotifyChannelTypeBark = NotifyChannelType("bark")
|
NotifyChannelTypeBark = NotifyChannelType("bark")
|
||||||
NotifyChannelTypeDingTalk = NotifyChannelType("dingtalk")
|
NotifyChannelTypeDingTalk = NotifyChannelType("dingtalk")
|
||||||
NotifyChannelTypeEmail = NotifyChannelType("email")
|
NotifyChannelTypeEmail = NotifyChannelType("email")
|
||||||
|
NotifyChannelTypeGotify = NotifyChannelType("gotify")
|
||||||
NotifyChannelTypeLark = NotifyChannelType("lark")
|
NotifyChannelTypeLark = NotifyChannelType("lark")
|
||||||
|
NotifyChannelTypeMattermost = NotifyChannelType("mattermost")
|
||||||
|
NotifyChannelTypePushover = NotifyChannelType("pushover")
|
||||||
|
NotifyChannelTypePushPlus = NotifyChannelType("pushplus")
|
||||||
NotifyChannelTypeServerChan = NotifyChannelType("serverchan")
|
NotifyChannelTypeServerChan = NotifyChannelType("serverchan")
|
||||||
NotifyChannelTypeTelegram = NotifyChannelType("telegram")
|
NotifyChannelTypeTelegram = NotifyChannelType("telegram")
|
||||||
NotifyChannelTypeWebhook = NotifyChannelType("webhook")
|
NotifyChannelTypeWebhook = NotifyChannelType("webhook")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
type AccessProviderType string
|
type AccessProviderType string
|
||||||
|
|
||||||
@@ -9,170 +9,292 @@ type AccessProviderType string
|
|||||||
NOTICE: If you add new constant, please keep ASCII order.
|
NOTICE: If you add new constant, please keep ASCII order.
|
||||||
*/
|
*/
|
||||||
const (
|
const (
|
||||||
AccessProviderType1Panel = AccessProviderType("1panel")
|
AccessProviderType1Panel = AccessProviderType("1panel")
|
||||||
AccessProviderTypeACMEHttpReq = AccessProviderType("acmehttpreq")
|
AccessProviderTypeACMECA = AccessProviderType("acmeca")
|
||||||
AccessProviderTypeAkamai = AccessProviderType("akamai") // Akamai(预留)
|
AccessProviderTypeACMEHttpReq = AccessProviderType("acmehttpreq")
|
||||||
AccessProviderTypeAliyun = AccessProviderType("aliyun")
|
AccessProviderTypeAkamai = AccessProviderType("akamai") // Akamai(预留)
|
||||||
AccessProviderTypeAWS = AccessProviderType("aws")
|
AccessProviderTypeAliyun = AccessProviderType("aliyun")
|
||||||
AccessProviderTypeAzure = AccessProviderType("azure")
|
AccessProviderTypeAPISIX = AccessProviderType("apisix")
|
||||||
AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud")
|
AccessProviderTypeAWS = AccessProviderType("aws")
|
||||||
AccessProviderTypeBaishan = AccessProviderType("baishan")
|
AccessProviderTypeAzure = AccessProviderType("azure")
|
||||||
AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel")
|
AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud")
|
||||||
AccessProviderTypeBytePlus = AccessProviderType("byteplus")
|
AccessProviderTypeBaishan = AccessProviderType("baishan")
|
||||||
AccessProviderTypeCacheFly = AccessProviderType("cachefly")
|
AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel")
|
||||||
AccessProviderTypeCdnfly = AccessProviderType("cdnfly")
|
AccessProviderTypeBaotaWAF = AccessProviderType("baotawaf")
|
||||||
AccessProviderTypeCloudflare = AccessProviderType("cloudflare")
|
AccessProviderTypeBytePlus = AccessProviderType("byteplus")
|
||||||
AccessProviderTypeClouDNS = AccessProviderType("cloudns")
|
AccessProviderTypeBunny = AccessProviderType("bunny")
|
||||||
AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud")
|
AccessProviderTypeBuypass = AccessProviderType("buypass")
|
||||||
AccessProviderTypeCTCCCloud = AccessProviderType("ctcccloud") // 联通云(预留)
|
AccessProviderTypeCacheFly = AccessProviderType("cachefly")
|
||||||
AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 天翼云(预留)
|
AccessProviderTypeCdnfly = AccessProviderType("cdnfly")
|
||||||
AccessProviderTypeDNSLA = AccessProviderType("dnsla")
|
AccessProviderTypeCloudflare = AccessProviderType("cloudflare")
|
||||||
AccessProviderTypeDogeCloud = AccessProviderType("dogecloud")
|
AccessProviderTypeClouDNS = AccessProviderType("cloudns")
|
||||||
AccessProviderTypeDynv6 = AccessProviderType("dynv6")
|
AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud")
|
||||||
AccessProviderTypeEdgio = AccessProviderType("edgio")
|
AccessProviderTypeConstellix = AccessProviderType("constellix")
|
||||||
AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly(预留)
|
AccessProviderTypeCTCCCloud = AccessProviderType("ctcccloud")
|
||||||
AccessProviderTypeGname = AccessProviderType("gname")
|
AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 联通云(预留)
|
||||||
AccessProviderTypeGcore = AccessProviderType("gcore")
|
AccessProviderTypeDeSEC = AccessProviderType("desec")
|
||||||
AccessProviderTypeGoDaddy = AccessProviderType("godaddy")
|
AccessProviderTypeDigitalOcean = AccessProviderType("digitalocean")
|
||||||
AccessProviderTypeGoEdge = AccessProviderType("goedge") // GoEdge(预留)
|
AccessProviderTypeDingTalkBot = AccessProviderType("dingtalkbot")
|
||||||
AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud")
|
AccessProviderTypeDiscordBot = AccessProviderType("discordbot")
|
||||||
AccessProviderTypeJDCloud = AccessProviderType("jdcloud")
|
AccessProviderTypeDNSLA = AccessProviderType("dnsla")
|
||||||
AccessProviderTypeKubernetes = AccessProviderType("k8s")
|
AccessProviderTypeDogeCloud = AccessProviderType("dogecloud")
|
||||||
AccessProviderTypeLocal = AccessProviderType("local")
|
AccessProviderTypeDuckDNS = AccessProviderType("duckdns")
|
||||||
AccessProviderTypeNamecheap = AccessProviderType("namecheap")
|
AccessProviderTypeDynv6 = AccessProviderType("dynv6")
|
||||||
AccessProviderTypeNameDotCom = AccessProviderType("namedotcom")
|
AccessProviderTypeEdgio = AccessProviderType("edgio")
|
||||||
AccessProviderTypeNameSilo = AccessProviderType("namesilo")
|
AccessProviderTypeEmail = AccessProviderType("email")
|
||||||
AccessProviderTypeNS1 = AccessProviderType("ns1")
|
AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly(预留)
|
||||||
AccessProviderTypePowerDNS = AccessProviderType("powerdns")
|
AccessProviderTypeFlexCDN = AccessProviderType("flexcdn")
|
||||||
AccessProviderTypeQiniu = AccessProviderType("qiniu")
|
AccessProviderTypeGname = AccessProviderType("gname")
|
||||||
AccessProviderTypeQingCloud = AccessProviderType("qingcloud") // 青云(预留)
|
AccessProviderTypeGcore = AccessProviderType("gcore")
|
||||||
AccessProviderTypeRainYun = AccessProviderType("rainyun")
|
AccessProviderTypeGoDaddy = AccessProviderType("godaddy")
|
||||||
AccessProviderTypeSafeLine = AccessProviderType("safeline")
|
AccessProviderTypeGoEdge = AccessProviderType("goedge")
|
||||||
AccessProviderTypeSSH = AccessProviderType("ssh")
|
AccessProviderTypeGoogleTrustServices = AccessProviderType("googletrustservices")
|
||||||
AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud")
|
AccessProviderTypeHetzner = AccessProviderType("hetzner")
|
||||||
AccessProviderTypeUCloud = AccessProviderType("ucloud")
|
AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud")
|
||||||
AccessProviderTypeUpyun = AccessProviderType("upyun")
|
AccessProviderTypeJDCloud = AccessProviderType("jdcloud")
|
||||||
AccessProviderTypeVolcEngine = AccessProviderType("volcengine")
|
AccessProviderTypeKubernetes = AccessProviderType("k8s")
|
||||||
AccessProviderTypeWebhook = AccessProviderType("webhook")
|
AccessProviderTypeLarkBot = AccessProviderType("larkbot")
|
||||||
AccessProviderTypeWestcn = AccessProviderType("westcn")
|
AccessProviderTypeLetsEncrypt = AccessProviderType("letsencrypt")
|
||||||
|
AccessProviderTypeLetsEncryptStaging = AccessProviderType("letsencryptstaging")
|
||||||
|
AccessProviderTypeLeCDN = AccessProviderType("lecdn")
|
||||||
|
AccessProviderTypeLocal = AccessProviderType("local")
|
||||||
|
AccessProviderTypeMattermost = AccessProviderType("mattermost")
|
||||||
|
AccessProviderTypeNamecheap = AccessProviderType("namecheap")
|
||||||
|
AccessProviderTypeNameDotCom = AccessProviderType("namedotcom")
|
||||||
|
AccessProviderTypeNameSilo = AccessProviderType("namesilo")
|
||||||
|
AccessProviderTypeNetcup = AccessProviderType("netcup")
|
||||||
|
AccessProviderTypeNetlify = AccessProviderType("netlify")
|
||||||
|
AccessProviderTypeNS1 = AccessProviderType("ns1")
|
||||||
|
AccessProviderTypePorkbun = AccessProviderType("porkbun")
|
||||||
|
AccessProviderTypePowerDNS = AccessProviderType("powerdns")
|
||||||
|
AccessProviderTypeProxmoxVE = AccessProviderType("proxmoxve")
|
||||||
|
AccessProviderTypeQiniu = AccessProviderType("qiniu")
|
||||||
|
AccessProviderTypeQingCloud = AccessProviderType("qingcloud") // 青云(预留)
|
||||||
|
AccessProviderTypeRainYun = AccessProviderType("rainyun")
|
||||||
|
AccessProviderTypeRatPanel = AccessProviderType("ratpanel")
|
||||||
|
AccessProviderTypeSafeLine = AccessProviderType("safeline")
|
||||||
|
AccessProviderTypeSlackBot = AccessProviderType("slackbot")
|
||||||
|
AccessProviderTypeSSH = AccessProviderType("ssh")
|
||||||
|
AccessProviderTypeSSLCOM = AccessProviderType("sslcom")
|
||||||
|
AccessProviderTypeTelegramBot = AccessProviderType("telegrambot")
|
||||||
|
AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud")
|
||||||
|
AccessProviderTypeUCloud = AccessProviderType("ucloud")
|
||||||
|
AccessProviderTypeUniCloud = AccessProviderType("unicloud")
|
||||||
|
AccessProviderTypeUpyun = AccessProviderType("upyun")
|
||||||
|
AccessProviderTypeVercel = AccessProviderType("vercel")
|
||||||
|
AccessProviderTypeVolcEngine = AccessProviderType("volcengine")
|
||||||
|
AccessProviderTypeWangsu = AccessProviderType("wangsu")
|
||||||
|
AccessProviderTypeWebhook = AccessProviderType("webhook")
|
||||||
|
AccessProviderTypeWeComBot = AccessProviderType("wecombot")
|
||||||
|
AccessProviderTypeWestcn = AccessProviderType("westcn")
|
||||||
|
AccessProviderTypeZeroSSL = AccessProviderType("zerossl")
|
||||||
)
|
)
|
||||||
|
|
||||||
type ApplyDNSProviderType string
|
type CAProviderType string
|
||||||
|
|
||||||
/*
|
/*
|
||||||
申请证书 DNS 提供商常量值。
|
证书颁发机构提供商常量值。
|
||||||
短横线前的部分始终等于授权提供商类型。
|
短横线前的部分始终等于授权提供商类型。
|
||||||
|
|
||||||
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||||
NOTICE: If you add new constant, please keep ASCII order.
|
NOTICE: If you add new constant, please keep ASCII order.
|
||||||
*/
|
*/
|
||||||
const (
|
const (
|
||||||
ApplyDNSProviderTypeACMEHttpReq = ApplyDNSProviderType("acmehttpreq")
|
CAProviderTypeACMECA = CAProviderType(AccessProviderTypeACMECA)
|
||||||
ApplyDNSProviderTypeAliyun = ApplyDNSProviderType("aliyun") // 兼容旧值,等同于 [ApplyDNSProviderTypeAliyunDNS]
|
CAProviderTypeBuypass = CAProviderType(AccessProviderTypeBuypass)
|
||||||
ApplyDNSProviderTypeAliyunDNS = ApplyDNSProviderType("aliyun-dns")
|
CAProviderTypeGoogleTrustServices = CAProviderType(AccessProviderTypeGoogleTrustServices)
|
||||||
ApplyDNSProviderTypeAWS = ApplyDNSProviderType("aws") // 兼容旧值,等同于 [ApplyDNSProviderTypeAWSRoute53]
|
CAProviderTypeLetsEncrypt = CAProviderType(AccessProviderTypeLetsEncrypt)
|
||||||
ApplyDNSProviderTypeAWSRoute53 = ApplyDNSProviderType("aws-route53")
|
CAProviderTypeLetsEncryptStaging = CAProviderType(AccessProviderTypeLetsEncryptStaging)
|
||||||
ApplyDNSProviderTypeAzure = ApplyDNSProviderType("azure") // 兼容旧值,等同于 [ApplyDNSProviderTypeAzure]
|
CAProviderTypeSSLCom = CAProviderType(AccessProviderTypeSSLCOM)
|
||||||
ApplyDNSProviderTypeAzureDNS = ApplyDNSProviderType("azure-dns")
|
CAProviderTypeZeroSSL = CAProviderType(AccessProviderTypeZeroSSL)
|
||||||
ApplyDNSProviderTypeBaiduCloud = ApplyDNSProviderType("baiducloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeBaiduCloudDNS]
|
|
||||||
ApplyDNSProviderTypeBaiduCloudDNS = ApplyDNSProviderType("baiducloud-dns")
|
|
||||||
ApplyDNSProviderTypeCloudflare = ApplyDNSProviderType("cloudflare")
|
|
||||||
ApplyDNSProviderTypeClouDNS = ApplyDNSProviderType("cloudns")
|
|
||||||
ApplyDNSProviderTypeCMCCCloud = ApplyDNSProviderType("cmcccloud")
|
|
||||||
ApplyDNSProviderTypeDNSLA = ApplyDNSProviderType("dnsla")
|
|
||||||
ApplyDNSProviderTypeDynv6 = ApplyDNSProviderType("dynv6")
|
|
||||||
ApplyDNSProviderTypeGcore = ApplyDNSProviderType("gcore")
|
|
||||||
ApplyDNSProviderTypeGname = ApplyDNSProviderType("gname")
|
|
||||||
ApplyDNSProviderTypeGoDaddy = ApplyDNSProviderType("godaddy")
|
|
||||||
ApplyDNSProviderTypeHuaweiCloud = ApplyDNSProviderType("huaweicloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeHuaweiCloudDNS]
|
|
||||||
ApplyDNSProviderTypeHuaweiCloudDNS = ApplyDNSProviderType("huaweicloud-dns")
|
|
||||||
ApplyDNSProviderTypeJDCloud = ApplyDNSProviderType("jdcloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeJDCloudDNS]
|
|
||||||
ApplyDNSProviderTypeJDCloudDNS = ApplyDNSProviderType("jdcloud-dns")
|
|
||||||
ApplyDNSProviderTypeNamecheap = ApplyDNSProviderType("namecheap")
|
|
||||||
ApplyDNSProviderTypeNameDotCom = ApplyDNSProviderType("namedotcom")
|
|
||||||
ApplyDNSProviderTypeNameSilo = ApplyDNSProviderType("namesilo")
|
|
||||||
ApplyDNSProviderTypeNS1 = ApplyDNSProviderType("ns1")
|
|
||||||
ApplyDNSProviderTypePowerDNS = ApplyDNSProviderType("powerdns")
|
|
||||||
ApplyDNSProviderTypeRainYun = ApplyDNSProviderType("rainyun")
|
|
||||||
ApplyDNSProviderTypeTencentCloud = ApplyDNSProviderType("tencentcloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeTencentCloudDNS]
|
|
||||||
ApplyDNSProviderTypeTencentCloudDNS = ApplyDNSProviderType("tencentcloud-dns")
|
|
||||||
ApplyDNSProviderTypeVolcEngine = ApplyDNSProviderType("volcengine") // 兼容旧值,等同于 [ApplyDNSProviderTypeVolcEngineDNS]
|
|
||||||
ApplyDNSProviderTypeVolcEngineDNS = ApplyDNSProviderType("volcengine-dns")
|
|
||||||
ApplyDNSProviderTypeWestcn = ApplyDNSProviderType("westcn")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeployProviderType string
|
type ACMEDns01ProviderType string
|
||||||
|
|
||||||
/*
|
/*
|
||||||
部署目标提供商常量值。
|
ACME DNS-01 提供商常量值。
|
||||||
短横线前的部分始终等于授权提供商类型。
|
短横线前的部分始终等于授权提供商类型。
|
||||||
|
|
||||||
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||||
NOTICE: If you add new constant, please keep ASCII order.
|
NOTICE: If you add new constant, please keep ASCII order.
|
||||||
*/
|
*/
|
||||||
const (
|
const (
|
||||||
DeployProviderType1PanelConsole = DeployProviderType("1panel-console")
|
ACMEDns01ProviderTypeACMEHttpReq = ACMEDns01ProviderType(AccessProviderTypeACMEHttpReq)
|
||||||
DeployProviderType1PanelSite = DeployProviderType("1panel-site")
|
ACMEDns01ProviderTypeAliyun = ACMEDns01ProviderType(AccessProviderTypeAliyun) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAliyunDNS]
|
||||||
DeployProviderTypeAliyunALB = DeployProviderType("aliyun-alb")
|
ACMEDns01ProviderTypeAliyunDNS = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-dns")
|
||||||
DeployProviderTypeAliyunCAS = DeployProviderType("aliyun-cas")
|
ACMEDns01ProviderTypeAliyunESA = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-esa")
|
||||||
DeployProviderTypeAliyunCASDeploy = DeployProviderType("aliyun-casdeploy")
|
ACMEDns01ProviderTypeAWS = ACMEDns01ProviderType(AccessProviderTypeAWS) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAWSRoute53]
|
||||||
DeployProviderTypeAliyunCDN = DeployProviderType("aliyun-cdn")
|
ACMEDns01ProviderTypeAWSRoute53 = ACMEDns01ProviderType(AccessProviderTypeAWS + "-route53")
|
||||||
DeployProviderTypeAliyunCLB = DeployProviderType("aliyun-clb")
|
ACMEDns01ProviderTypeAzure = ACMEDns01ProviderType(AccessProviderTypeAzure) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAzure]
|
||||||
DeployProviderTypeAliyunDCDN = DeployProviderType("aliyun-dcdn")
|
ACMEDns01ProviderTypeAzureDNS = ACMEDns01ProviderType(AccessProviderTypeAzure + "-dns")
|
||||||
DeployProviderTypeAliyunESA = DeployProviderType("aliyun-esa")
|
ACMEDns01ProviderTypeBaiduCloud = ACMEDns01ProviderType(AccessProviderTypeBaiduCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeBaiduCloudDNS]
|
||||||
DeployProviderTypeAliyunFC = DeployProviderType("aliyun-fc")
|
ACMEDns01ProviderTypeBaiduCloudDNS = ACMEDns01ProviderType(AccessProviderTypeBaiduCloud + "-dns")
|
||||||
DeployProviderTypeAliyunLive = DeployProviderType("aliyun-live")
|
ACMEDns01ProviderTypeBunny = ACMEDns01ProviderType(AccessProviderTypeBunny)
|
||||||
DeployProviderTypeAliyunNLB = DeployProviderType("aliyun-nlb")
|
ACMEDns01ProviderTypeCloudflare = ACMEDns01ProviderType(AccessProviderTypeCloudflare)
|
||||||
DeployProviderTypeAliyunOSS = DeployProviderType("aliyun-oss")
|
ACMEDns01ProviderTypeClouDNS = ACMEDns01ProviderType(AccessProviderTypeClouDNS)
|
||||||
DeployProviderTypeAliyunVOD = DeployProviderType("aliyun-vod")
|
ACMEDns01ProviderTypeCMCCCloud = ACMEDns01ProviderType(AccessProviderTypeCMCCCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeCMCCCloudDNS]
|
||||||
DeployProviderTypeAliyunWAF = DeployProviderType("aliyun-waf")
|
ACMEDns01ProviderTypeCMCCCloudDNS = ACMEDns01ProviderType(AccessProviderTypeCMCCCloud + "-dns")
|
||||||
DeployProviderTypeAWSACM = DeployProviderType("aws-acm")
|
ACMEDns01ProviderTypeConstellix = ACMEDns01ProviderType(AccessProviderTypeConstellix)
|
||||||
DeployProviderTypeAWSCloudFront = DeployProviderType("aws-cloudfront")
|
ACMEDns01ProviderTypeCTCCCloud = ACMEDns01ProviderType(AccessProviderTypeCTCCCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeCTCCCloudSmartDNS]
|
||||||
DeployProviderTypeAzureKeyVault = DeployProviderType("azure-keyvault")
|
ACMEDns01ProviderTypeCTCCCloudSmartDNS = ACMEDns01ProviderType(AccessProviderTypeCTCCCloud + "-smartdns")
|
||||||
DeployProviderTypeBaiduCloudCDN = DeployProviderType("baiducloud-cdn")
|
ACMEDns01ProviderTypeDeSEC = ACMEDns01ProviderType(AccessProviderTypeDeSEC)
|
||||||
DeployProviderTypeBaishanCDN = DeployProviderType("baishan-cdn")
|
ACMEDns01ProviderTypeDigitalOcean = ACMEDns01ProviderType(AccessProviderTypeDigitalOcean)
|
||||||
DeployProviderTypeBaotaPanelConsole = DeployProviderType("baotapanel-console")
|
ACMEDns01ProviderTypeDNSLA = ACMEDns01ProviderType(AccessProviderTypeDNSLA)
|
||||||
DeployProviderTypeBaotaPanelSite = DeployProviderType("baotapanel-site")
|
ACMEDns01ProviderTypeDuckDNS = ACMEDns01ProviderType(AccessProviderTypeDuckDNS)
|
||||||
DeployProviderTypeBytePlusCDN = DeployProviderType("byteplus-cdn")
|
ACMEDns01ProviderTypeDynv6 = ACMEDns01ProviderType(AccessProviderTypeDynv6)
|
||||||
DeployProviderTypeCacheFly = DeployProviderType("cachefly")
|
ACMEDns01ProviderTypeGcore = ACMEDns01ProviderType(AccessProviderTypeGcore)
|
||||||
DeployProviderTypeCdnfly = DeployProviderType("cdnfly")
|
ACMEDns01ProviderTypeGname = ACMEDns01ProviderType(AccessProviderTypeGname)
|
||||||
DeployProviderTypeDogeCloudCDN = DeployProviderType("dogecloud-cdn")
|
ACMEDns01ProviderTypeGoDaddy = ACMEDns01ProviderType(AccessProviderTypeGoDaddy)
|
||||||
DeployProviderTypeEdgioApplications = DeployProviderType("edgio-applications")
|
ACMEDns01ProviderTypeHetzner = ACMEDns01ProviderType(AccessProviderTypeHetzner)
|
||||||
DeployProviderTypeGcoreCDN = DeployProviderType("gcore-cdn")
|
ACMEDns01ProviderTypeHuaweiCloud = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeHuaweiCloudDNS]
|
||||||
DeployProviderTypeHuaweiCloudCDN = DeployProviderType("huaweicloud-cdn")
|
ACMEDns01ProviderTypeHuaweiCloudDNS = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud + "-dns")
|
||||||
DeployProviderTypeHuaweiCloudELB = DeployProviderType("huaweicloud-elb")
|
ACMEDns01ProviderTypeJDCloud = ACMEDns01ProviderType(AccessProviderTypeJDCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeJDCloudDNS]
|
||||||
DeployProviderTypeHuaweiCloudWAF = DeployProviderType("huaweicloud-waf")
|
ACMEDns01ProviderTypeJDCloudDNS = ACMEDns01ProviderType(AccessProviderTypeJDCloud + "-dns")
|
||||||
DeployProviderTypeJDCloudALB = DeployProviderType("jdcloud-alb")
|
ACMEDns01ProviderTypeNamecheap = ACMEDns01ProviderType(AccessProviderTypeNamecheap)
|
||||||
DeployProviderTypeJDCloudCDN = DeployProviderType("jdcloud-cdn")
|
ACMEDns01ProviderTypeNameDotCom = ACMEDns01ProviderType(AccessProviderTypeNameDotCom)
|
||||||
DeployProviderTypeJDCloudLive = DeployProviderType("jdcloud-live")
|
ACMEDns01ProviderTypeNameSilo = ACMEDns01ProviderType(AccessProviderTypeNameSilo)
|
||||||
DeployProviderTypeJDCloudVOD = DeployProviderType("jdcloud-vod")
|
ACMEDns01ProviderTypeNetcup = ACMEDns01ProviderType(AccessProviderTypeNetcup)
|
||||||
DeployProviderTypeKubernetesSecret = DeployProviderType("k8s-secret")
|
ACMEDns01ProviderTypeNetlify = ACMEDns01ProviderType(AccessProviderTypeNetlify)
|
||||||
DeployProviderTypeLocal = DeployProviderType("local")
|
ACMEDns01ProviderTypeNS1 = ACMEDns01ProviderType(AccessProviderTypeNS1)
|
||||||
DeployProviderTypeQiniuCDN = DeployProviderType("qiniu-cdn")
|
ACMEDns01ProviderTypePorkbun = ACMEDns01ProviderType(AccessProviderTypePorkbun)
|
||||||
DeployProviderTypeQiniuKodo = DeployProviderType("qiniu-kodo")
|
ACMEDns01ProviderTypePowerDNS = ACMEDns01ProviderType(AccessProviderTypePowerDNS)
|
||||||
DeployProviderTypeQiniuPili = DeployProviderType("qiniu-pili")
|
ACMEDns01ProviderTypeRainYun = ACMEDns01ProviderType(AccessProviderTypeRainYun)
|
||||||
DeployProviderTypeSafeLine = DeployProviderType("safeline")
|
ACMEDns01ProviderTypeTencentCloud = ACMEDns01ProviderType(AccessProviderTypeTencentCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeTencentCloudDNS]
|
||||||
DeployProviderTypeSSH = DeployProviderType("ssh")
|
ACMEDns01ProviderTypeTencentCloudDNS = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-dns")
|
||||||
DeployProviderTypeTencentCloudCDN = DeployProviderType("tencentcloud-cdn")
|
ACMEDns01ProviderTypeTencentCloudEO = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-eo")
|
||||||
DeployProviderTypeTencentCloudCLB = DeployProviderType("tencentcloud-clb")
|
ACMEDns01ProviderTypeUCloudUDNR = ACMEDns01ProviderType(AccessProviderTypeUCloud + "-udnr")
|
||||||
DeployProviderTypeTencentCloudCOS = DeployProviderType("tencentcloud-cos")
|
ACMEDns01ProviderTypeVercel = ACMEDns01ProviderType(AccessProviderTypeVercel)
|
||||||
DeployProviderTypeTencentCloudCSS = DeployProviderType("tencentcloud-css")
|
ACMEDns01ProviderTypeVolcEngine = ACMEDns01ProviderType(AccessProviderTypeVolcEngine) // 兼容旧值,等同于 [ACMEDns01ProviderTypeVolcEngineDNS]
|
||||||
DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn")
|
ACMEDns01ProviderTypeVolcEngineDNS = ACMEDns01ProviderType(AccessProviderTypeVolcEngine + "-dns")
|
||||||
DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo")
|
ACMEDns01ProviderTypeWestcn = ACMEDns01ProviderType(AccessProviderTypeWestcn)
|
||||||
DeployProviderTypeTencentCloudSCF = DeployProviderType("tencentcloud-scf")
|
)
|
||||||
DeployProviderTypeTencentCloudSSL = DeployProviderType("tencentcloud-ssl")
|
|
||||||
DeployProviderTypeTencentCloudSSLDeploy = DeployProviderType("tencentcloud-ssldeploy")
|
type DeploymentProviderType string
|
||||||
DeployProviderTypeTencentCloudVOD = DeployProviderType("tencentcloud-vod")
|
|
||||||
DeployProviderTypeTencentCloudWAF = DeployProviderType("tencentcloud-waf")
|
/*
|
||||||
DeployProviderTypeUCloudUCDN = DeployProviderType("ucloud-ucdn")
|
部署证书主机提供商常量值。
|
||||||
DeployProviderTypeUCloudUS3 = DeployProviderType("ucloud-us3")
|
短横线前的部分始终等于授权提供商类型。
|
||||||
DeployProviderTypeUpyunCDN = DeployProviderType("upyun-cdn")
|
|
||||||
DeployProviderTypeUpyunFile = DeployProviderType("upyun-file")
|
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||||
DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn")
|
NOTICE: If you add new constant, please keep ASCII order.
|
||||||
DeployProviderTypeVolcEngineCLB = DeployProviderType("volcengine-clb")
|
*/
|
||||||
DeployProviderTypeVolcEngineDCDN = DeployProviderType("volcengine-dcdn")
|
const (
|
||||||
DeployProviderTypeVolcEngineImageX = DeployProviderType("volcengine-imagex")
|
DeploymentProviderType1PanelConsole = DeploymentProviderType(AccessProviderType1Panel + "-console")
|
||||||
DeployProviderTypeVolcEngineLive = DeployProviderType("volcengine-live")
|
DeploymentProviderType1PanelSite = DeploymentProviderType(AccessProviderType1Panel + "-site")
|
||||||
DeployProviderTypeVolcEngineTOS = DeployProviderType("volcengine-tos")
|
DeploymentProviderTypeAliyunALB = DeploymentProviderType(AccessProviderTypeAliyun + "-alb")
|
||||||
DeployProviderTypeWebhook = DeployProviderType("webhook")
|
DeploymentProviderTypeAliyunAPIGW = DeploymentProviderType(AccessProviderTypeAliyun + "-apigw")
|
||||||
|
DeploymentProviderTypeAliyunCAS = DeploymentProviderType(AccessProviderTypeAliyun + "-cas")
|
||||||
|
DeploymentProviderTypeAliyunCASDeploy = DeploymentProviderType(AccessProviderTypeAliyun + "-casdeploy")
|
||||||
|
DeploymentProviderTypeAliyunCDN = DeploymentProviderType(AccessProviderTypeAliyun + "-cdn")
|
||||||
|
DeploymentProviderTypeAliyunCLB = DeploymentProviderType(AccessProviderTypeAliyun + "-clb")
|
||||||
|
DeploymentProviderTypeAliyunDCDN = DeploymentProviderType(AccessProviderTypeAliyun + "-dcdn")
|
||||||
|
DeploymentProviderTypeAliyunDDoS = DeploymentProviderType(AccessProviderTypeAliyun + "-ddos")
|
||||||
|
DeploymentProviderTypeAliyunESA = DeploymentProviderType(AccessProviderTypeAliyun + "-esa")
|
||||||
|
DeploymentProviderTypeAliyunFC = DeploymentProviderType(AccessProviderTypeAliyun + "-fc")
|
||||||
|
DeploymentProviderTypeAliyunGA = DeploymentProviderType(AccessProviderTypeAliyun + "-ga")
|
||||||
|
DeploymentProviderTypeAliyunLive = DeploymentProviderType(AccessProviderTypeAliyun + "-live")
|
||||||
|
DeploymentProviderTypeAliyunNLB = DeploymentProviderType(AccessProviderTypeAliyun + "-nlb")
|
||||||
|
DeploymentProviderTypeAliyunOSS = DeploymentProviderType(AccessProviderTypeAliyun + "-oss")
|
||||||
|
DeploymentProviderTypeAliyunVOD = DeploymentProviderType(AccessProviderTypeAliyun + "-vod")
|
||||||
|
DeploymentProviderTypeAliyunWAF = DeploymentProviderType(AccessProviderTypeAliyun + "-waf")
|
||||||
|
DeploymentProviderTypeAPISIX = DeploymentProviderType(AccessProviderTypeAWS + "-apisix")
|
||||||
|
DeploymentProviderTypeAWSACM = DeploymentProviderType(AccessProviderTypeAWS + "-acm")
|
||||||
|
DeploymentProviderTypeAWSCloudFront = DeploymentProviderType(AccessProviderTypeAWS + "-cloudfront")
|
||||||
|
DeploymentProviderTypeAWSIAM = DeploymentProviderType(AccessProviderTypeAWS + "-iam")
|
||||||
|
DeploymentProviderTypeAzureKeyVault = DeploymentProviderType(AccessProviderTypeAzure + "-keyvault")
|
||||||
|
DeploymentProviderTypeBaiduCloudAppBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-appblb")
|
||||||
|
DeploymentProviderTypeBaiduCloudBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-blb")
|
||||||
|
DeploymentProviderTypeBaiduCloudCDN = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-cdn")
|
||||||
|
DeploymentProviderTypeBaiduCloudCert = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-cert")
|
||||||
|
DeploymentProviderTypeBaishanCDN = DeploymentProviderType(AccessProviderTypeBaishan + "-cdn")
|
||||||
|
DeploymentProviderTypeBaotaPanelConsole = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-console")
|
||||||
|
DeploymentProviderTypeBaotaPanelSite = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-site")
|
||||||
|
DeploymentProviderTypeBaotaWAFConsole = DeploymentProviderType(AccessProviderTypeBaotaWAF + "-console")
|
||||||
|
DeploymentProviderTypeBaotaWAFSite = DeploymentProviderType(AccessProviderTypeBaotaWAF + "-site")
|
||||||
|
DeploymentProviderTypeBunnyCDN = DeploymentProviderType(AccessProviderTypeBunny + "-cdn")
|
||||||
|
DeploymentProviderTypeBytePlusCDN = DeploymentProviderType(AccessProviderTypeBytePlus + "-cdn")
|
||||||
|
DeploymentProviderTypeCacheFly = DeploymentProviderType(AccessProviderTypeCacheFly)
|
||||||
|
DeploymentProviderTypeCdnfly = DeploymentProviderType(AccessProviderTypeCdnfly)
|
||||||
|
DeploymentProviderTypeCTCCCloudAO = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ao")
|
||||||
|
DeploymentProviderTypeCTCCCloudCDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cdn")
|
||||||
|
DeploymentProviderTypeCTCCCloudCMS = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cms")
|
||||||
|
DeploymentProviderTypeCTCCCloudELB = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-elb")
|
||||||
|
DeploymentProviderTypeCTCCCloudICDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-icdn")
|
||||||
|
DeploymentProviderTypeCTCCCloudLVDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ldvn")
|
||||||
|
DeploymentProviderTypeDogeCloudCDN = DeploymentProviderType(AccessProviderTypeDogeCloud + "-cdn")
|
||||||
|
DeploymentProviderTypeEdgioApplications = DeploymentProviderType(AccessProviderTypeEdgio + "-applications")
|
||||||
|
DeploymentProviderTypeFlexCDN = DeploymentProviderType(AccessProviderTypeFlexCDN)
|
||||||
|
DeploymentProviderTypeGcoreCDN = DeploymentProviderType(AccessProviderTypeGcore + "-cdn")
|
||||||
|
DeploymentProviderTypeGoEdge = DeploymentProviderType(AccessProviderTypeGoEdge)
|
||||||
|
DeploymentProviderTypeHuaweiCloudCDN = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-cdn")
|
||||||
|
DeploymentProviderTypeHuaweiCloudELB = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-elb")
|
||||||
|
DeploymentProviderTypeHuaweiCloudSCM = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-scm")
|
||||||
|
DeploymentProviderTypeHuaweiCloudWAF = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-waf")
|
||||||
|
DeploymentProviderTypeJDCloudALB = DeploymentProviderType(AccessProviderTypeJDCloud + "-alb")
|
||||||
|
DeploymentProviderTypeJDCloudCDN = DeploymentProviderType(AccessProviderTypeJDCloud + "-cdn")
|
||||||
|
DeploymentProviderTypeJDCloudLive = DeploymentProviderType(AccessProviderTypeJDCloud + "-live")
|
||||||
|
DeploymentProviderTypeJDCloudVOD = DeploymentProviderType(AccessProviderTypeJDCloud + "-vod")
|
||||||
|
DeploymentProviderTypeKubernetesSecret = DeploymentProviderType(AccessProviderTypeKubernetes + "-secret")
|
||||||
|
DeploymentProviderTypeLeCDN = DeploymentProviderType(AccessProviderTypeLeCDN)
|
||||||
|
DeploymentProviderTypeLocal = DeploymentProviderType(AccessProviderTypeLocal)
|
||||||
|
DeploymentProviderTypeNetlifySite = DeploymentProviderType(AccessProviderTypeNetlify + "-site")
|
||||||
|
DeploymentProviderTypeProxmoxVE = DeploymentProviderType(AccessProviderTypeProxmoxVE)
|
||||||
|
DeploymentProviderTypeQiniuCDN = DeploymentProviderType(AccessProviderTypeQiniu + "-cdn")
|
||||||
|
DeploymentProviderTypeQiniuKodo = DeploymentProviderType(AccessProviderTypeQiniu + "-kodo")
|
||||||
|
DeploymentProviderTypeQiniuPili = DeploymentProviderType(AccessProviderTypeQiniu + "-pili")
|
||||||
|
DeploymentProviderTypeRainYunRCDN = DeploymentProviderType(AccessProviderTypeRainYun + "-rcdn")
|
||||||
|
DeploymentProviderTypeRatPanelConsole = DeploymentProviderType(AccessProviderTypeRatPanel + "-console")
|
||||||
|
DeploymentProviderTypeRatPanelSite = DeploymentProviderType(AccessProviderTypeRatPanel + "-site")
|
||||||
|
DeploymentProviderTypeSafeLine = DeploymentProviderType(AccessProviderTypeSafeLine)
|
||||||
|
DeploymentProviderTypeSSH = DeploymentProviderType(AccessProviderTypeSSH)
|
||||||
|
DeploymentProviderTypeTencentCloudCDN = DeploymentProviderType(AccessProviderTypeTencentCloud + "-cdn")
|
||||||
|
DeploymentProviderTypeTencentCloudCLB = DeploymentProviderType(AccessProviderTypeTencentCloud + "-clb")
|
||||||
|
DeploymentProviderTypeTencentCloudCOS = DeploymentProviderType(AccessProviderTypeTencentCloud + "-cos")
|
||||||
|
DeploymentProviderTypeTencentCloudCSS = DeploymentProviderType(AccessProviderTypeTencentCloud + "-css")
|
||||||
|
DeploymentProviderTypeTencentCloudECDN = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ecdn")
|
||||||
|
DeploymentProviderTypeTencentCloudEO = DeploymentProviderType(AccessProviderTypeTencentCloud + "-eo")
|
||||||
|
DeploymentProviderTypeTencentCloudGAAP = DeploymentProviderType(AccessProviderTypeTencentCloud + "-gaap")
|
||||||
|
DeploymentProviderTypeTencentCloudSCF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-scf")
|
||||||
|
DeploymentProviderTypeTencentCloudSSL = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssl")
|
||||||
|
DeploymentProviderTypeTencentCloudSSLDeploy = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssldeploy")
|
||||||
|
DeploymentProviderTypeTencentCloudVOD = DeploymentProviderType(AccessProviderTypeTencentCloud + "-vod")
|
||||||
|
DeploymentProviderTypeTencentCloudWAF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-waf")
|
||||||
|
DeploymentProviderTypeUCloudUCDN = DeploymentProviderType(AccessProviderTypeUCloud + "-ucdn")
|
||||||
|
DeploymentProviderTypeUCloudUS3 = DeploymentProviderType(AccessProviderTypeUCloud + "-us3")
|
||||||
|
DeploymentProviderTypeUniCloudWebHost = DeploymentProviderType(AccessProviderTypeUniCloud + "-webhost")
|
||||||
|
DeploymentProviderTypeUpyunCDN = DeploymentProviderType(AccessProviderTypeUpyun + "-cdn")
|
||||||
|
DeploymentProviderTypeUpyunFile = DeploymentProviderType(AccessProviderTypeUpyun + "-file")
|
||||||
|
DeploymentProviderTypeVolcEngineALB = DeploymentProviderType(AccessProviderTypeVolcEngine + "-alb")
|
||||||
|
DeploymentProviderTypeVolcEngineCDN = DeploymentProviderType(AccessProviderTypeVolcEngine + "-cdn")
|
||||||
|
DeploymentProviderTypeVolcEngineCertCenter = DeploymentProviderType(AccessProviderTypeVolcEngine + "-certcenter")
|
||||||
|
DeploymentProviderTypeVolcEngineCLB = DeploymentProviderType(AccessProviderTypeVolcEngine + "-clb")
|
||||||
|
DeploymentProviderTypeVolcEngineDCDN = DeploymentProviderType(AccessProviderTypeVolcEngine + "-dcdn")
|
||||||
|
DeploymentProviderTypeVolcEngineImageX = DeploymentProviderType(AccessProviderTypeVolcEngine + "-imagex")
|
||||||
|
DeploymentProviderTypeVolcEngineLive = DeploymentProviderType(AccessProviderTypeVolcEngine + "-live")
|
||||||
|
DeploymentProviderTypeVolcEngineTOS = DeploymentProviderType(AccessProviderTypeVolcEngine + "-tos")
|
||||||
|
DeploymentProviderTypeWangsuCDN = DeploymentProviderType(AccessProviderTypeWangsu + "-cdn")
|
||||||
|
DeploymentProviderTypeWangsuCDNPro = DeploymentProviderType(AccessProviderTypeWangsu + "-cdnpro")
|
||||||
|
DeploymentProviderTypeWangsuCertificate = DeploymentProviderType(AccessProviderTypeWangsu + "-certificate")
|
||||||
|
DeploymentProviderTypeWebhook = DeploymentProviderType(AccessProviderTypeWebhook)
|
||||||
|
)
|
||||||
|
|
||||||
|
type NotificationProviderType string
|
||||||
|
|
||||||
|
/*
|
||||||
|
消息通知提供商常量值。
|
||||||
|
短横线前的部分始终等于授权提供商类型。
|
||||||
|
|
||||||
|
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||||
|
NOTICE: If you add new constant, please keep ASCII order.
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
NotificationProviderTypeDingTalkBot = NotificationProviderType(AccessProviderTypeDingTalkBot)
|
||||||
|
NotificationProviderTypeDiscordBot = NotificationProviderType(AccessProviderTypeDiscordBot)
|
||||||
|
NotificationProviderTypeEmail = NotificationProviderType(AccessProviderTypeEmail)
|
||||||
|
NotificationProviderTypeLarkBot = NotificationProviderType(AccessProviderTypeLarkBot)
|
||||||
|
NotificationProviderTypeMattermost = NotificationProviderType(AccessProviderTypeMattermost)
|
||||||
|
NotificationProviderTypeSlackBot = NotificationProviderType(AccessProviderTypeSlackBot)
|
||||||
|
NotificationProviderTypeTelegramBot = NotificationProviderType(AccessProviderTypeTelegramBot)
|
||||||
|
NotificationProviderTypeWebhook = NotificationProviderType(AccessProviderTypeWebhook)
|
||||||
|
NotificationProviderTypeWeComBot = NotificationProviderType(AccessProviderTypeWeComBot)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ type Settings struct {
|
|||||||
Content string `json:"content" db:"content"`
|
Content string `json:"content" db:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
type NotifyTemplatesSettingsContent struct {
|
type NotifyTemplatesSettingsContent struct {
|
||||||
NotifyTemplates []struct {
|
NotifyTemplates []struct {
|
||||||
Subject string `json:"subject"`
|
Subject string `json:"subject"`
|
||||||
@@ -20,8 +21,10 @@ type NotifyTemplatesSettingsContent struct {
|
|||||||
} `json:"notifyTemplates"`
|
} `json:"notifyTemplates"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
type NotifyChannelsSettingsContent map[string]map[string]any
|
type NotifyChannelsSettingsContent map[string]map[string]any
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
func (s *Settings) GetNotifyChannelConfig(channel string) (map[string]any, error) {
|
func (s *Settings) GetNotifyChannelConfig(channel string) (map[string]any, error) {
|
||||||
conf := &NotifyChannelsSettingsContent{}
|
conf := &NotifyChannelsSettingsContent{}
|
||||||
if err := json.Unmarshal([]byte(s.Content), conf); err != nil {
|
if err := json.Unmarshal([]byte(s.Content), conf); err != nil {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/maputil"
|
"github.com/certimate-go/certimate/internal/domain/expr"
|
||||||
|
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
const CollectionNameWorkflow = "workflow"
|
const CollectionNameWorkflow = "workflow"
|
||||||
@@ -30,6 +32,7 @@ const (
|
|||||||
WorkflowNodeTypeEnd = WorkflowNodeType("end")
|
WorkflowNodeTypeEnd = WorkflowNodeType("end")
|
||||||
WorkflowNodeTypeApply = WorkflowNodeType("apply")
|
WorkflowNodeTypeApply = WorkflowNodeType("apply")
|
||||||
WorkflowNodeTypeUpload = WorkflowNodeType("upload")
|
WorkflowNodeTypeUpload = WorkflowNodeType("upload")
|
||||||
|
WorkflowNodeTypeMonitor = WorkflowNodeType("monitor")
|
||||||
WorkflowNodeTypeDeploy = WorkflowNodeType("deploy")
|
WorkflowNodeTypeDeploy = WorkflowNodeType("deploy")
|
||||||
WorkflowNodeTypeNotify = WorkflowNodeType("notify")
|
WorkflowNodeTypeNotify = WorkflowNodeType("notify")
|
||||||
WorkflowNodeTypeBranch = WorkflowNodeType("branch")
|
WorkflowNodeTypeBranch = WorkflowNodeType("branch")
|
||||||
@@ -62,108 +65,135 @@ type WorkflowNode struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WorkflowNodeConfigForApply struct {
|
type WorkflowNodeConfigForApply struct {
|
||||||
Domains string `json:"domains"` // 域名列表,以半角分号分隔
|
Domains string `json:"domains"` // 域名列表,以半角分号分隔
|
||||||
ContactEmail string `json:"contactEmail"` // 联系邮箱
|
ContactEmail string `json:"contactEmail"` // 联系邮箱
|
||||||
ChallengeType string `json:"challengeType"` // TODO: 验证方式。目前仅支持 dns-01
|
ChallengeType string `json:"challengeType"` // TODO: 验证方式。目前仅支持 dns-01
|
||||||
Provider string `json:"provider"` // DNS 提供商
|
Provider string `json:"provider"` // DNS 提供商
|
||||||
ProviderAccessId string `json:"providerAccessId"` // DNS 提供商授权记录 ID
|
ProviderAccessId string `json:"providerAccessId"` // DNS 提供商授权记录 ID
|
||||||
ProviderConfig map[string]any `json:"providerConfig"` // DNS 提供商额外配置
|
ProviderConfig map[string]any `json:"providerConfig"` // DNS 提供商额外配置
|
||||||
KeyAlgorithm string `json:"keyAlgorithm"` // 密钥算法
|
CAProvider string `json:"caProvider,omitempty"` // CA 提供商(零值时使用全局配置)
|
||||||
Nameservers string `json:"nameservers"` // DNS 服务器列表,以半角分号分隔
|
CAProviderAccessId string `json:"caProviderAccessId,omitempty"` // CA 提供商授权记录 ID
|
||||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout"` // DNS 传播超时时间(零值取决于提供商的默认值)
|
CAProviderConfig map[string]any `json:"caProviderConfig,omitempty"` // CA 提供商额外配置
|
||||||
DnsTTL int32 `json:"dnsTTL"` // DNS TTL(零值取决于提供商的默认值)
|
KeyAlgorithm string `json:"keyAlgorithm"` // 证书算法
|
||||||
DisableFollowCNAME bool `json:"disableFollowCNAME"` // 是否关闭 CNAME 跟随
|
Nameservers string `json:"nameservers,omitempty"` // DNS 服务器列表,以半角分号分隔
|
||||||
DisableARI bool `json:"disableARI"` // 是否关闭 ARI
|
DnsPropagationWait int32 `json:"dnsPropagationWait,omitempty"` // DNS 传播等待时间,等同于 lego 的 `--dns-propagation-wait` 参数
|
||||||
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays"` // 证书到期前多少天前跳过续期(零值将使用默认值 30)
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` // DNS 传播检查超时时间(零值时使用提供商的默认值)
|
||||||
|
DnsTTL int32 `json:"dnsTTL,omitempty"` // DNS 解析记录 TTL(零值时使用提供商的默认值)
|
||||||
|
DisableFollowCNAME bool `json:"disableFollowCNAME,omitempty"` // 是否关闭 CNAME 跟随
|
||||||
|
DisableARI bool `json:"disableARI,omitempty"` // 是否关闭 ARI
|
||||||
|
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays,omitempty"` // 证书到期前多少天前跳过续期(零值时默认值 30)
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkflowNodeConfigForUpload struct {
|
type WorkflowNodeConfigForUpload struct {
|
||||||
Certificate string `json:"certificate"`
|
Certificate string `json:"certificate"` // 证书 PEM 内容
|
||||||
PrivateKey string `json:"privateKey"`
|
PrivateKey string `json:"privateKey"` // 私钥 PEM 内容
|
||||||
Domains string `json:"domains"`
|
Domains string `json:"domains,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WorkflowNodeConfigForMonitor struct {
|
||||||
|
Host string `json:"host"` // 主机地址
|
||||||
|
Port int32 `json:"port,omitempty"` // 端口(零值时默认值 443)
|
||||||
|
Domain string `json:"domain,omitempty"` // 域名(零值时默认值 [Host])
|
||||||
|
RequestPath string `json:"requestPath,omitempty"` // 请求路径
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkflowNodeConfigForDeploy struct {
|
type WorkflowNodeConfigForDeploy struct {
|
||||||
Certificate string `json:"certificate"` // 前序节点输出的证书,形如“${NodeId}#certificate”
|
Certificate string `json:"certificate"` // 前序节点输出的证书,形如“${NodeId}#certificate”
|
||||||
Provider string `json:"provider"` // 主机提供商
|
Provider string `json:"provider"` // 主机提供商
|
||||||
ProviderAccessId string `json:"providerAccessId"` // 主机提供商授权记录 ID
|
ProviderAccessId string `json:"providerAccessId,omitempty"` // 主机提供商授权记录 ID
|
||||||
ProviderConfig map[string]any `json:"providerConfig"` // 主机提供商额外配置
|
ProviderConfig map[string]any `json:"providerConfig,omitempty"` // 主机提供商额外配置
|
||||||
SkipOnLastSucceeded bool `json:"skipOnLastSucceeded"` // 上次部署成功时是否跳过
|
SkipOnLastSucceeded bool `json:"skipOnLastSucceeded"` // 上次部署成功时是否跳过
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkflowNodeConfigForNotify struct {
|
type WorkflowNodeConfigForNotify struct {
|
||||||
Channel string `json:"channel"` // 通知渠道
|
Channel string `json:"channel,omitempty"` // Deprecated: v0.4.x 将废弃
|
||||||
Subject string `json:"subject"` // 通知主题
|
Provider string `json:"provider"` // 通知提供商
|
||||||
Message string `json:"message"` // 通知内容
|
ProviderAccessId string `json:"providerAccessId"` // 通知提供商授权记录 ID
|
||||||
|
ProviderConfig map[string]any `json:"providerConfig,omitempty"` // 通知提供商额外配置
|
||||||
|
Subject string `json:"subject"` // 通知主题
|
||||||
|
Message string `json:"message"` // 通知内容
|
||||||
|
SkipOnAllPrevSkipped bool `json:"skipOnAllPrevSkipped"` // 前序节点均已跳过时是否跳过
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *WorkflowNode) getConfigString(key string) string {
|
type WorkflowNodeConfigForCondition struct {
|
||||||
return maputil.GetString(n.Config, key)
|
Expression expr.Expr `json:"expression"` // 条件表达式
|
||||||
}
|
|
||||||
|
|
||||||
func (n *WorkflowNode) getConfigBool(key string) bool {
|
|
||||||
return maputil.GetBool(n.Config, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *WorkflowNode) getConfigInt32(key string) int32 {
|
|
||||||
return maputil.GetInt32(n.Config, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *WorkflowNode) getConfigMap(key string) map[string]any {
|
|
||||||
if val, ok := n.Config[key]; ok {
|
|
||||||
if result, ok := val.(map[string]any); ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return make(map[string]any)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply {
|
func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply {
|
||||||
skipBeforeExpiryDays := n.getConfigInt32("skipBeforeExpiryDays")
|
|
||||||
if skipBeforeExpiryDays == 0 {
|
|
||||||
skipBeforeExpiryDays = 30
|
|
||||||
}
|
|
||||||
|
|
||||||
return WorkflowNodeConfigForApply{
|
return WorkflowNodeConfigForApply{
|
||||||
Domains: n.getConfigString("domains"),
|
Domains: xmaps.GetString(n.Config, "domains"),
|
||||||
ContactEmail: n.getConfigString("contactEmail"),
|
ContactEmail: xmaps.GetString(n.Config, "contactEmail"),
|
||||||
Provider: n.getConfigString("provider"),
|
Provider: xmaps.GetString(n.Config, "provider"),
|
||||||
ProviderAccessId: n.getConfigString("providerAccessId"),
|
ProviderAccessId: xmaps.GetString(n.Config, "providerAccessId"),
|
||||||
ProviderConfig: n.getConfigMap("providerConfig"),
|
ProviderConfig: xmaps.GetKVMapAny(n.Config, "providerConfig"),
|
||||||
KeyAlgorithm: n.getConfigString("keyAlgorithm"),
|
CAProvider: xmaps.GetString(n.Config, "caProvider"),
|
||||||
Nameservers: n.getConfigString("nameservers"),
|
CAProviderAccessId: xmaps.GetString(n.Config, "caProviderAccessId"),
|
||||||
DnsPropagationTimeout: n.getConfigInt32("dnsPropagationTimeout"),
|
CAProviderConfig: xmaps.GetKVMapAny(n.Config, "caProviderConfig"),
|
||||||
DnsTTL: n.getConfigInt32("dnsTTL"),
|
KeyAlgorithm: xmaps.GetOrDefaultString(n.Config, "keyAlgorithm", string(CertificateKeyAlgorithmTypeRSA2048)),
|
||||||
DisableFollowCNAME: n.getConfigBool("disableFollowCNAME"),
|
Nameservers: xmaps.GetString(n.Config, "nameservers"),
|
||||||
DisableARI: n.getConfigBool("disableARI"),
|
DnsPropagationWait: xmaps.GetInt32(n.Config, "dnsPropagationWait"),
|
||||||
SkipBeforeExpiryDays: skipBeforeExpiryDays,
|
DnsPropagationTimeout: xmaps.GetInt32(n.Config, "dnsPropagationTimeout"),
|
||||||
|
DnsTTL: xmaps.GetInt32(n.Config, "dnsTTL"),
|
||||||
|
DisableFollowCNAME: xmaps.GetBool(n.Config, "disableFollowCNAME"),
|
||||||
|
DisableARI: xmaps.GetBool(n.Config, "disableARI"),
|
||||||
|
SkipBeforeExpiryDays: xmaps.GetOrDefaultInt32(n.Config, "skipBeforeExpiryDays", 30),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *WorkflowNode) GetConfigForUpload() WorkflowNodeConfigForUpload {
|
func (n *WorkflowNode) GetConfigForUpload() WorkflowNodeConfigForUpload {
|
||||||
return WorkflowNodeConfigForUpload{
|
return WorkflowNodeConfigForUpload{
|
||||||
Certificate: n.getConfigString("certificate"),
|
Certificate: xmaps.GetString(n.Config, "certificate"),
|
||||||
PrivateKey: n.getConfigString("privateKey"),
|
PrivateKey: xmaps.GetString(n.Config, "privateKey"),
|
||||||
Domains: n.getConfigString("domains"),
|
Domains: xmaps.GetString(n.Config, "domains"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *WorkflowNode) GetConfigForMonitor() WorkflowNodeConfigForMonitor {
|
||||||
|
host := xmaps.GetString(n.Config, "host")
|
||||||
|
return WorkflowNodeConfigForMonitor{
|
||||||
|
Host: host,
|
||||||
|
Port: xmaps.GetOrDefaultInt32(n.Config, "port", 443),
|
||||||
|
Domain: xmaps.GetOrDefaultString(n.Config, "domain", host),
|
||||||
|
RequestPath: xmaps.GetString(n.Config, "path"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy {
|
func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy {
|
||||||
return WorkflowNodeConfigForDeploy{
|
return WorkflowNodeConfigForDeploy{
|
||||||
Certificate: n.getConfigString("certificate"),
|
Certificate: xmaps.GetString(n.Config, "certificate"),
|
||||||
Provider: n.getConfigString("provider"),
|
Provider: xmaps.GetString(n.Config, "provider"),
|
||||||
ProviderAccessId: n.getConfigString("providerAccessId"),
|
ProviderAccessId: xmaps.GetString(n.Config, "providerAccessId"),
|
||||||
ProviderConfig: n.getConfigMap("providerConfig"),
|
ProviderConfig: xmaps.GetKVMapAny(n.Config, "providerConfig"),
|
||||||
SkipOnLastSucceeded: n.getConfigBool("skipOnLastSucceeded"),
|
SkipOnLastSucceeded: xmaps.GetBool(n.Config, "skipOnLastSucceeded"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *WorkflowNode) GetConfigForNotify() WorkflowNodeConfigForNotify {
|
func (n *WorkflowNode) GetConfigForNotify() WorkflowNodeConfigForNotify {
|
||||||
return WorkflowNodeConfigForNotify{
|
return WorkflowNodeConfigForNotify{
|
||||||
Channel: n.getConfigString("channel"),
|
Channel: xmaps.GetString(n.Config, "channel"),
|
||||||
Subject: n.getConfigString("subject"),
|
Provider: xmaps.GetString(n.Config, "provider"),
|
||||||
Message: n.getConfigString("message"),
|
ProviderAccessId: xmaps.GetString(n.Config, "providerAccessId"),
|
||||||
|
ProviderConfig: xmaps.GetKVMapAny(n.Config, "providerConfig"),
|
||||||
|
Subject: xmaps.GetString(n.Config, "subject"),
|
||||||
|
Message: xmaps.GetString(n.Config, "message"),
|
||||||
|
SkipOnAllPrevSkipped: xmaps.GetBool(n.Config, "skipOnAllPrevSkipped"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *WorkflowNode) GetConfigForCondition() WorkflowNodeConfigForCondition {
|
||||||
|
expression := n.Config["expression"]
|
||||||
|
if expression == nil {
|
||||||
|
return WorkflowNodeConfigForCondition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
exprRaw, _ := json.Marshal(expression)
|
||||||
|
expr, err := expr.UnmarshalExpr([]byte(exprRaw))
|
||||||
|
if err != nil {
|
||||||
|
return WorkflowNodeConfigForCondition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WorkflowNodeConfigForCondition{
|
||||||
|
Expression: expr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,9 +206,6 @@ type WorkflowNodeIO struct {
|
|||||||
ValueSelector WorkflowNodeIOValueSelector `json:"valueSelector"`
|
ValueSelector WorkflowNodeIOValueSelector `json:"valueSelector"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkflowNodeIOValueSelector struct {
|
type WorkflowNodeIOValueSelector = expr.ExprValueSelector
|
||||||
Id string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const WorkflowNodeIONameCertificate string = "certificate"
|
const WorkflowNodeIONameCertificate string = "certificate"
|
||||||
|
|||||||
74
internal/notify/notifier.go
Normal file
74
internal/notify/notifier.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/certimate-go/certimate/internal/domain"
|
||||||
|
"github.com/certimate-go/certimate/internal/repository"
|
||||||
|
"github.com/certimate-go/certimate/pkg/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Notifier interface {
|
||||||
|
Notify(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotifierWithWorkflowNodeConfig struct {
|
||||||
|
Node *domain.WorkflowNode
|
||||||
|
Logger *slog.Logger
|
||||||
|
Subject string
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWithWorkflowNode(config NotifierWithWorkflowNodeConfig) (Notifier, error) {
|
||||||
|
if config.Node == nil {
|
||||||
|
return nil, fmt.Errorf("node is nil")
|
||||||
|
}
|
||||||
|
if config.Node.Type != domain.WorkflowNodeTypeNotify {
|
||||||
|
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeNotify))
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeCfg := config.Node.GetConfigForNotify()
|
||||||
|
options := ¬ifierProviderOptions{
|
||||||
|
Provider: domain.NotificationProviderType(nodeCfg.Provider),
|
||||||
|
ProviderAccessConfig: make(map[string]any),
|
||||||
|
ProviderServiceConfig: nodeCfg.ProviderConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
accessRepo := repository.NewAccessRepository()
|
||||||
|
if nodeCfg.ProviderAccessId != "" {
|
||||||
|
access, err := accessRepo.GetById(context.Background(), nodeCfg.ProviderAccessId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.ProviderAccessId, err)
|
||||||
|
} else {
|
||||||
|
options.ProviderAccessConfig = access.Config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notifier, err := createNotifierProvider(options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
notifier.SetLogger(config.Logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ¬ifierImpl{
|
||||||
|
provider: notifier,
|
||||||
|
subject: config.Subject,
|
||||||
|
message: config.Message,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type notifierImpl struct {
|
||||||
|
provider core.Notifier
|
||||||
|
subject string
|
||||||
|
message string
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Notifier = (*notifierImpl)(nil)
|
||||||
|
|
||||||
|
func (n *notifierImpl) Notify(ctx context.Context) error {
|
||||||
|
_, err := n.provider.Notify(ctx, n.subject, n.message)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -7,12 +7,13 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/certimate-go/certimate/internal/domain"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
"github.com/certimate-go/certimate/internal/repository"
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/maputil"
|
"github.com/certimate-go/certimate/pkg/core"
|
||||||
"github.com/usual2970/certimate/internal/repository"
|
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
func SendToAllChannels(subject, message string) error {
|
func SendToAllChannels(subject, message string) error {
|
||||||
notifiers, err := getEnabledNotifiers()
|
notifiers, err := getEnabledNotifiers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -38,8 +39,9 @@ func SendToAllChannels(subject, message string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
func SendToChannel(subject, message string, channel string, channelConfig map[string]any) error {
|
func SendToChannel(subject, message string, channel string, channelConfig map[string]any) error {
|
||||||
notifier, err := createNotifier(domain.NotifyChannelType(channel), channelConfig)
|
notifier, err := createNotifierProviderUseGlobalSettings(domain.NotifyChannelType(channel), channelConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -48,7 +50,8 @@ func SendToChannel(subject, message string, channel string, channelConfig map[st
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEnabledNotifiers() ([]notifier.Notifier, error) {
|
// Deprecated: v0.4.x 将废弃
|
||||||
|
func getEnabledNotifiers() ([]core.Notifier, error) {
|
||||||
settingsRepo := repository.NewSettingsRepository()
|
settingsRepo := repository.NewSettingsRepository()
|
||||||
settings, err := settingsRepo.GetByName(context.Background(), "notifyChannels")
|
settings, err := settingsRepo.GetByName(context.Background(), "notifyChannels")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -60,13 +63,13 @@ func getEnabledNotifiers() ([]notifier.Notifier, error) {
|
|||||||
return nil, fmt.Errorf("unmarshal notifyChannels error: %w", err)
|
return nil, fmt.Errorf("unmarshal notifyChannels error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
notifiers := make([]notifier.Notifier, 0)
|
notifiers := make([]core.Notifier, 0)
|
||||||
for k, v := range rs {
|
for k, v := range rs {
|
||||||
if !maputil.GetBool(v, "enabled") {
|
if !xmaps.GetBool(v, "enabled") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
notifier, err := createNotifier(domain.NotifyChannelType(k), v)
|
notifier, err := createNotifierProviderUseGlobalSettings(domain.NotifyChannelType(k), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,76 +2,181 @@ package notify
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/certimate-go/certimate/internal/domain"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
"github.com/certimate-go/certimate/pkg/core"
|
||||||
pBark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/bark"
|
pDingTalkBot "github.com/certimate-go/certimate/pkg/core/notifier/providers/dingtalkbot"
|
||||||
pDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk"
|
pDiscordBot "github.com/certimate-go/certimate/pkg/core/notifier/providers/discordbot"
|
||||||
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
|
pEmail "github.com/certimate-go/certimate/pkg/core/notifier/providers/email"
|
||||||
pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark"
|
pLarkBot "github.com/certimate-go/certimate/pkg/core/notifier/providers/larkbot"
|
||||||
pServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan"
|
pMattermost "github.com/certimate-go/certimate/pkg/core/notifier/providers/mattermost"
|
||||||
pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram"
|
pSlackBot "github.com/certimate-go/certimate/pkg/core/notifier/providers/slackbot"
|
||||||
pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook"
|
pTelegramBot "github.com/certimate-go/certimate/pkg/core/notifier/providers/telegrambot"
|
||||||
pWeCom "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecom"
|
pWebhook "github.com/certimate-go/certimate/pkg/core/notifier/providers/webhook"
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/maputil"
|
pWeComBot "github.com/certimate-go/certimate/pkg/core/notifier/providers/wecombot"
|
||||||
|
xhttp "github.com/certimate-go/certimate/pkg/utils/http"
|
||||||
|
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]any) (notifier.Notifier, error) {
|
type notifierProviderOptions struct {
|
||||||
|
Provider domain.NotificationProviderType
|
||||||
|
ProviderAccessConfig map[string]any
|
||||||
|
ProviderServiceConfig map[string]any
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNotifierProvider(options *notifierProviderOptions) (core.Notifier, error) {
|
||||||
/*
|
/*
|
||||||
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||||
NOTICE: If you add new constant, please keep ASCII order.
|
NOTICE: If you add new constant, please keep ASCII order.
|
||||||
*/
|
*/
|
||||||
switch channel {
|
switch options.Provider {
|
||||||
case domain.NotifyChannelTypeBark:
|
case domain.NotificationProviderTypeDingTalkBot:
|
||||||
return pBark.NewNotifier(&pBark.NotifierConfig{
|
{
|
||||||
DeviceKey: maputil.GetString(channelConfig, "deviceKey"),
|
access := domain.AccessConfigForDingTalkBot{}
|
||||||
ServerUrl: maputil.GetString(channelConfig, "serverUrl"),
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
})
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
case domain.NotifyChannelTypeDingTalk:
|
return pDingTalkBot.NewNotifierProvider(&pDingTalkBot.NotifierProviderConfig{
|
||||||
return pDingTalk.NewNotifier(&pDingTalk.NotifierConfig{
|
WebhookUrl: access.WebhookUrl,
|
||||||
AccessToken: maputil.GetString(channelConfig, "accessToken"),
|
Secret: access.Secret,
|
||||||
Secret: maputil.GetString(channelConfig, "secret"),
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
case domain.NotifyChannelTypeEmail:
|
case domain.NotificationProviderTypeDiscordBot:
|
||||||
return pEmail.NewNotifier(&pEmail.NotifierConfig{
|
{
|
||||||
SmtpHost: maputil.GetString(channelConfig, "smtpHost"),
|
access := domain.AccessConfigForDiscordBot{}
|
||||||
SmtpPort: maputil.GetInt32(channelConfig, "smtpPort"),
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
SmtpTLS: maputil.GetOrDefaultBool(channelConfig, "smtpTLS", true),
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
Username: maputil.GetOrDefaultString(channelConfig, "username", maputil.GetString(channelConfig, "senderAddress")),
|
}
|
||||||
Password: maputil.GetString(channelConfig, "password"),
|
|
||||||
SenderAddress: maputil.GetString(channelConfig, "senderAddress"),
|
|
||||||
ReceiverAddress: maputil.GetString(channelConfig, "receiverAddress"),
|
|
||||||
})
|
|
||||||
|
|
||||||
case domain.NotifyChannelTypeLark:
|
return pDiscordBot.NewNotifierProvider(&pDiscordBot.NotifierProviderConfig{
|
||||||
return pLark.NewNotifier(&pLark.NotifierConfig{
|
BotToken: access.BotToken,
|
||||||
WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"),
|
ChannelId: xmaps.GetOrDefaultString(options.ProviderServiceConfig, "channelId", access.DefaultChannelId),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
case domain.NotifyChannelTypeServerChan:
|
case domain.NotificationProviderTypeEmail:
|
||||||
return pServerChan.NewNotifier(&pServerChan.NotifierConfig{
|
{
|
||||||
Url: maputil.GetString(channelConfig, "url"),
|
access := domain.AccessConfigForEmail{}
|
||||||
})
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
case domain.NotifyChannelTypeTelegram:
|
return pEmail.NewNotifierProvider(&pEmail.NotifierProviderConfig{
|
||||||
return pTelegram.NewNotifier(&pTelegram.NotifierConfig{
|
SmtpHost: access.SmtpHost,
|
||||||
ApiToken: maputil.GetString(channelConfig, "apiToken"),
|
SmtpPort: access.SmtpPort,
|
||||||
ChatId: maputil.GetInt64(channelConfig, "chatId"),
|
SmtpTls: access.SmtpTls,
|
||||||
})
|
Username: access.Username,
|
||||||
|
Password: access.Password,
|
||||||
|
SenderAddress: xmaps.GetOrDefaultString(options.ProviderServiceConfig, "senderAddress", access.DefaultSenderAddress),
|
||||||
|
SenderName: xmaps.GetOrDefaultString(options.ProviderServiceConfig, "senderName", access.DefaultSenderName),
|
||||||
|
ReceiverAddress: xmaps.GetOrDefaultString(options.ProviderServiceConfig, "receiverAddress", access.DefaultReceiverAddress),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
case domain.NotifyChannelTypeWebhook:
|
case domain.NotificationProviderTypeLarkBot:
|
||||||
return pWebhook.NewNotifier(&pWebhook.NotifierConfig{
|
{
|
||||||
Url: maputil.GetString(channelConfig, "url"),
|
access := domain.AccessConfigForLarkBot{}
|
||||||
AllowInsecureConnections: maputil.GetBool(channelConfig, "allowInsecureConnections"),
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
})
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
case domain.NotifyChannelTypeWeCom:
|
return pLarkBot.NewNotifierProvider(&pLarkBot.NotifierProviderConfig{
|
||||||
return pWeCom.NewNotifier(&pWeCom.NotifierConfig{
|
WebhookUrl: access.WebhookUrl,
|
||||||
WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"),
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
|
case domain.NotificationProviderTypeMattermost:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForMattermost{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pMattermost.NewNotifierProvider(&pMattermost.NotifierProviderConfig{
|
||||||
|
ServerUrl: access.ServerUrl,
|
||||||
|
Username: access.Username,
|
||||||
|
Password: access.Password,
|
||||||
|
ChannelId: xmaps.GetOrDefaultString(options.ProviderServiceConfig, "channelId", access.DefaultChannelId),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.NotificationProviderTypeSlackBot:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForSlackBot{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pSlackBot.NewNotifierProvider(&pSlackBot.NotifierProviderConfig{
|
||||||
|
BotToken: access.BotToken,
|
||||||
|
ChannelId: xmaps.GetOrDefaultString(options.ProviderServiceConfig, "channelId", access.DefaultChannelId),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.NotificationProviderTypeTelegramBot:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForTelegramBot{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pTelegramBot.NewNotifierProvider(&pTelegramBot.NotifierProviderConfig{
|
||||||
|
BotToken: access.BotToken,
|
||||||
|
ChatId: xmaps.GetOrDefaultInt64(options.ProviderServiceConfig, "chatId", access.DefaultChatId),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.NotificationProviderTypeWebhook:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForWebhook{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mergedHeaders := make(map[string]string)
|
||||||
|
if defaultHeadersString := access.HeadersString; defaultHeadersString != "" {
|
||||||
|
h, err := xhttp.ParseHeaders(defaultHeadersString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse webhook headers: %w", err)
|
||||||
|
}
|
||||||
|
for key := range h {
|
||||||
|
mergedHeaders[http.CanonicalHeaderKey(key)] = h.Get(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if extendedHeadersString := xmaps.GetString(options.ProviderServiceConfig, "headers"); extendedHeadersString != "" {
|
||||||
|
h, err := xhttp.ParseHeaders(extendedHeadersString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse webhook headers: %w", err)
|
||||||
|
}
|
||||||
|
for key := range h {
|
||||||
|
mergedHeaders[http.CanonicalHeaderKey(key)] = h.Get(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pWebhook.NewNotifierProvider(&pWebhook.NotifierProviderConfig{
|
||||||
|
WebhookUrl: access.Url,
|
||||||
|
WebhookData: xmaps.GetOrDefaultString(options.ProviderServiceConfig, "webhookData", access.DefaultDataForNotification),
|
||||||
|
Method: access.Method,
|
||||||
|
Headers: mergedHeaders,
|
||||||
|
AllowInsecureConnections: access.AllowInsecureConnections,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.NotificationProviderTypeWeComBot:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForWeComBot{}
|
||||||
|
if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pWeComBot.NewNotifierProvider(&pWeComBot.NotifierProviderConfig{
|
||||||
|
WebhookUrl: access.WebhookUrl,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("unsupported notifier channel: %s", channelConfig)
|
return nil, fmt.Errorf("unsupported notifier provider '%s'", options.Provider)
|
||||||
}
|
}
|
||||||
|
|||||||
108
internal/notify/providers_deprecated.go
Normal file
108
internal/notify/providers_deprecated.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/certimate-go/certimate/internal/domain"
|
||||||
|
"github.com/certimate-go/certimate/pkg/core"
|
||||||
|
pBark "github.com/certimate-go/certimate/pkg/core/notifier/providers/bark"
|
||||||
|
pDingTalk "github.com/certimate-go/certimate/pkg/core/notifier/providers/dingtalkbot"
|
||||||
|
pEmail "github.com/certimate-go/certimate/pkg/core/notifier/providers/email"
|
||||||
|
pGotify "github.com/certimate-go/certimate/pkg/core/notifier/providers/gotify"
|
||||||
|
pLark "github.com/certimate-go/certimate/pkg/core/notifier/providers/larkbot"
|
||||||
|
pMattermost "github.com/certimate-go/certimate/pkg/core/notifier/providers/mattermost"
|
||||||
|
pPushover "github.com/certimate-go/certimate/pkg/core/notifier/providers/pushover"
|
||||||
|
pPushPlus "github.com/certimate-go/certimate/pkg/core/notifier/providers/pushplus"
|
||||||
|
pServerChan "github.com/certimate-go/certimate/pkg/core/notifier/providers/serverchan"
|
||||||
|
pTelegram "github.com/certimate-go/certimate/pkg/core/notifier/providers/telegrambot"
|
||||||
|
pWebhook "github.com/certimate-go/certimate/pkg/core/notifier/providers/webhook"
|
||||||
|
pWeCom "github.com/certimate-go/certimate/pkg/core/notifier/providers/wecombot"
|
||||||
|
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
|
func createNotifierProviderUseGlobalSettings(channel domain.NotifyChannelType, channelConfig map[string]any) (core.Notifier, error) {
|
||||||
|
/*
|
||||||
|
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||||
|
NOTICE: If you add new constant, please keep ASCII order.
|
||||||
|
*/
|
||||||
|
switch channel {
|
||||||
|
case domain.NotifyChannelTypeBark:
|
||||||
|
return pBark.NewNotifierProvider(&pBark.NotifierProviderConfig{
|
||||||
|
DeviceKey: xmaps.GetString(channelConfig, "deviceKey"),
|
||||||
|
ServerUrl: xmaps.GetString(channelConfig, "serverUrl"),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypeDingTalk:
|
||||||
|
return pDingTalk.NewNotifierProvider(&pDingTalk.NotifierProviderConfig{
|
||||||
|
WebhookUrl: "https://oapi.dingtalk.com/robot/send?access_token=" + xmaps.GetString(channelConfig, "accessToken"),
|
||||||
|
Secret: xmaps.GetString(channelConfig, "secret"),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypeEmail:
|
||||||
|
return pEmail.NewNotifierProvider(&pEmail.NotifierProviderConfig{
|
||||||
|
SmtpHost: xmaps.GetString(channelConfig, "smtpHost"),
|
||||||
|
SmtpPort: xmaps.GetInt32(channelConfig, "smtpPort"),
|
||||||
|
SmtpTls: xmaps.GetOrDefaultBool(channelConfig, "smtpTLS", true),
|
||||||
|
Username: xmaps.GetOrDefaultString(channelConfig, "username", xmaps.GetString(channelConfig, "senderAddress")),
|
||||||
|
Password: xmaps.GetString(channelConfig, "password"),
|
||||||
|
SenderAddress: xmaps.GetString(channelConfig, "senderAddress"),
|
||||||
|
ReceiverAddress: xmaps.GetString(channelConfig, "receiverAddress"),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypeGotify:
|
||||||
|
return pGotify.NewNotifierProvider(&pGotify.NotifierProviderConfig{
|
||||||
|
ServerUrl: xmaps.GetString(channelConfig, "url"),
|
||||||
|
Token: xmaps.GetString(channelConfig, "token"),
|
||||||
|
Priority: xmaps.GetOrDefaultInt64(channelConfig, "priority", 1),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypeLark:
|
||||||
|
return pLark.NewNotifierProvider(&pLark.NotifierProviderConfig{
|
||||||
|
WebhookUrl: xmaps.GetString(channelConfig, "webhookUrl"),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypeMattermost:
|
||||||
|
return pMattermost.NewNotifierProvider(&pMattermost.NotifierProviderConfig{
|
||||||
|
ServerUrl: xmaps.GetString(channelConfig, "serverUrl"),
|
||||||
|
ChannelId: xmaps.GetString(channelConfig, "channelId"),
|
||||||
|
Username: xmaps.GetString(channelConfig, "username"),
|
||||||
|
Password: xmaps.GetString(channelConfig, "password"),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypePushover:
|
||||||
|
return pPushover.NewNotifierProvider(&pPushover.NotifierProviderConfig{
|
||||||
|
Token: xmaps.GetString(channelConfig, "token"),
|
||||||
|
User: xmaps.GetString(channelConfig, "user"),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypePushPlus:
|
||||||
|
return pPushPlus.NewNotifierProvider(&pPushPlus.NotifierProviderConfig{
|
||||||
|
Token: xmaps.GetString(channelConfig, "token"),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypeServerChan:
|
||||||
|
return pServerChan.NewNotifierProvider(&pServerChan.NotifierProviderConfig{
|
||||||
|
ServerUrl: xmaps.GetString(channelConfig, "url"),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypeTelegram:
|
||||||
|
return pTelegram.NewNotifierProvider(&pTelegram.NotifierProviderConfig{
|
||||||
|
BotToken: xmaps.GetString(channelConfig, "apiToken"),
|
||||||
|
ChatId: xmaps.GetInt64(channelConfig, "chatId"),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypeWebhook:
|
||||||
|
return pWebhook.NewNotifierProvider(&pWebhook.NotifierProviderConfig{
|
||||||
|
WebhookUrl: xmaps.GetString(channelConfig, "url"),
|
||||||
|
AllowInsecureConnections: xmaps.GetBool(channelConfig, "allowInsecureConnections"),
|
||||||
|
})
|
||||||
|
|
||||||
|
case domain.NotifyChannelTypeWeCom:
|
||||||
|
return pWeCom.NewNotifierProvider(&pWeCom.NotifierProviderConfig{
|
||||||
|
WebhookUrl: xmaps.GetString(channelConfig, "webhookUrl"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("unsupported notifier channel '%s'", channelConfig)
|
||||||
|
}
|
||||||
@@ -4,29 +4,34 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/certimate-go/certimate/internal/domain"
|
||||||
"github.com/usual2970/certimate/internal/domain/dtos"
|
"github.com/certimate-go/certimate/internal/domain/dtos"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
const (
|
const (
|
||||||
notifyTestTitle = "测试通知"
|
notifyTestTitle = "测试通知"
|
||||||
notifyTestBody = "欢迎使用 Certimate ,这是一条测试通知。"
|
notifyTestBody = "欢迎使用 Certimate ,这是一条测试通知。"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
type settingsRepository interface {
|
type settingsRepository interface {
|
||||||
GetByName(ctx context.Context, name string) (*domain.Settings, error)
|
GetByName(ctx context.Context, name string) (*domain.Settings, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
type NotifyService struct {
|
type NotifyService struct {
|
||||||
settingsRepo settingsRepository
|
settingsRepo settingsRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
func NewNotifyService(settingsRepo settingsRepository) *NotifyService {
|
func NewNotifyService(settingsRepo settingsRepository) *NotifyService {
|
||||||
return &NotifyService{
|
return &NotifyService{
|
||||||
settingsRepo: settingsRepo,
|
settingsRepo: settingsRepo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: v0.4.x 将废弃
|
||||||
func (n *NotifyService) Test(ctx context.Context, req *dtos.NotifyTestPushReq) error {
|
func (n *NotifyService) Test(ctx context.Context, req *dtos.NotifyTestPushReq) error {
|
||||||
settings, err := n.settingsRepo.GetByName(ctx, "notifyChannels")
|
settings, err := n.settingsRepo.GetByName(ctx, "notifyChannels")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package deployer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 表示定义证书部署器的抽象类型接口。
|
|
||||||
// 注意与 `Uploader` 区分,“部署”通常为“上传”的后置操作。
|
|
||||||
type Deployer interface {
|
|
||||||
WithLogger(logger *slog.Logger) Deployer
|
|
||||||
|
|
||||||
// 部署证书。
|
|
||||||
//
|
|
||||||
// 入参:
|
|
||||||
// - ctx:上下文。
|
|
||||||
// - certPem:证书 PEM 内容。
|
|
||||||
// - privkeyPem:私钥 PEM 内容。
|
|
||||||
//
|
|
||||||
// 出参:
|
|
||||||
// - res:部署结果。
|
|
||||||
// - err: 错误。
|
|
||||||
Deploy(ctx context.Context, certPem string, privkeyPem string) (res *DeployResult, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 表示证书部署结果的数据结构。
|
|
||||||
type DeployResult struct {
|
|
||||||
ExtendedData map[string]any `json:"extendedData,omitempty"`
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
package onepanelconsole
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
opsdk "github.com/usual2970/certimate/internal/pkg/vendors/1panel-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 1Panel 地址。
|
|
||||||
ApiUrl string `json:"apiUrl"`
|
|
||||||
// 1Panel 接口密钥。
|
|
||||||
ApiKey string `json:"apiKey"`
|
|
||||||
// 是否允许不安全的连接。
|
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
|
||||||
// 是否自动重启。
|
|
||||||
AutoRestart bool `json:"autoRestart"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *opsdk.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 设置面板 SSL 证书
|
|
||||||
updateSystemSSLReq := &opsdk.UpdateSystemSSLRequest{
|
|
||||||
Cert: certPem,
|
|
||||||
Key: privkeyPem,
|
|
||||||
SSL: "enable",
|
|
||||||
SSLType: "import-paste",
|
|
||||||
}
|
|
||||||
if d.config.AutoRestart {
|
|
||||||
updateSystemSSLReq.AutoRestart = "true"
|
|
||||||
} else {
|
|
||||||
updateSystemSSLReq.AutoRestart = "false"
|
|
||||||
}
|
|
||||||
updateSystemSSLResp, err := d.sdkClient.UpdateSystemSSL(updateSystemSSLReq)
|
|
||||||
d.logger.Debug("sdk request '1panel.UpdateSystemSSL'", slog.Any("request", updateSystemSSLReq), slog.Any("response", updateSystemSSLResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UpdateSystemSSL'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) {
|
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
|
||||||
return nil, errors.New("invalid 1panel api url")
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiKey == "" {
|
|
||||||
return nil, errors.New("invalid 1panel api key")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := opsdk.NewClient(apiUrl, apiKey)
|
|
||||||
if allowInsecure {
|
|
||||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
package onepanelsite
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/1panel-ssl"
|
|
||||||
opsdk "github.com/usual2970/certimate/internal/pkg/vendors/1panel-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 1Panel 地址。
|
|
||||||
ApiUrl string `json:"apiUrl"`
|
|
||||||
// 1Panel 接口密钥。
|
|
||||||
ApiKey string `json:"apiKey"`
|
|
||||||
// 是否允许不安全的连接。
|
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
|
||||||
// 网站 ID。
|
|
||||||
WebsiteId int64 `json:"websiteId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *opsdk.Client
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
ApiUrl: config.ApiUrl,
|
|
||||||
ApiKey: config.ApiKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 获取网站 HTTPS 配置
|
|
||||||
getHttpsConfReq := &opsdk.GetHttpsConfRequest{
|
|
||||||
WebsiteID: d.config.WebsiteId,
|
|
||||||
}
|
|
||||||
getHttpsConfResp, err := d.sdkClient.GetHttpsConf(getHttpsConfReq)
|
|
||||||
d.logger.Debug("sdk request '1panel.GetHttpsConf'", slog.Any("request", getHttpsConfReq), slog.Any("response", getHttpsConfResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.GetHttpsConf'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传证书到面板
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改网站 HTTPS 配置
|
|
||||||
certId, _ := strconv.ParseInt(upres.CertId, 10, 64)
|
|
||||||
updateHttpsConfReq := &opsdk.UpdateHttpsConfRequest{
|
|
||||||
WebsiteID: d.config.WebsiteId,
|
|
||||||
Type: "existed",
|
|
||||||
WebsiteSSLID: certId,
|
|
||||||
Enable: getHttpsConfResp.Data.Enable,
|
|
||||||
HttpConfig: getHttpsConfResp.Data.HttpConfig,
|
|
||||||
SSLProtocol: getHttpsConfResp.Data.SSLProtocol,
|
|
||||||
Algorithm: getHttpsConfResp.Data.Algorithm,
|
|
||||||
Hsts: getHttpsConfResp.Data.Hsts,
|
|
||||||
}
|
|
||||||
updateHttpsConfResp, err := d.sdkClient.UpdateHttpsConf(updateHttpsConfReq)
|
|
||||||
d.logger.Debug("sdk request '1panel.UpdateHttpsConf'", slog.Any("request", updateHttpsConfReq), slog.Any("response", updateHttpsConfResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UpdateHttpsConf'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) {
|
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
|
||||||
return nil, errors.New("invalid 1panel api url")
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiKey == "" {
|
|
||||||
return nil, errors.New("invalid 1panel api key")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := opsdk.NewClient(apiUrl, apiKey)
|
|
||||||
if allowInsecure {
|
|
||||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package aliyuncas
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 阿里云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 阿里云 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 阿里云地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
AccessKeySecret: config.AccessKeySecret,
|
|
||||||
Region: config.Region,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 CAS
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
package aliyundcdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
|
||||||
aliyunDcdn "github.com/alibabacloud-go/dcdn-20180115/v3/client"
|
|
||||||
"github.com/alibabacloud-go/tea/tea"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 阿里云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 阿里云 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 加速域名(支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *aliyunDcdn.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// "*.example.com" → ".example.com",适配阿里云 DCDN 要求的泛域名格式
|
|
||||||
domain := strings.TrimPrefix(d.config.Domain, "*")
|
|
||||||
|
|
||||||
// 配置域名证书
|
|
||||||
// REF: https://help.aliyun.com/zh/edge-security-acceleration/dcdn/developer-reference/api-dcdn-2018-01-15-setdcdndomainsslcertificate
|
|
||||||
setDcdnDomainSSLCertificateReq := &aliyunDcdn.SetDcdnDomainSSLCertificateRequest{
|
|
||||||
DomainName: tea.String(domain),
|
|
||||||
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
|
|
||||||
CertType: tea.String("upload"),
|
|
||||||
SSLProtocol: tea.String("on"),
|
|
||||||
SSLPub: tea.String(certPem),
|
|
||||||
SSLPri: tea.String(privkeyPem),
|
|
||||||
}
|
|
||||||
setDcdnDomainSSLCertificateResp, err := d.sdkClient.SetDcdnDomainSSLCertificate(setDcdnDomainSSLCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'dcdn.SetDcdnDomainSSLCertificate'", slog.Any("request", setDcdnDomainSSLCertificateReq), slog.Any("response", setDcdnDomainSSLCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'dcdn.SetDcdnDomainSSLCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret string) (*aliyunDcdn.Client, error) {
|
|
||||||
config := &aliyunOpen.Config{
|
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
|
||||||
Endpoint: tea.String("dcdn.aliyuncs.com"),
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := aliyunDcdn.NewClient(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
package aliyunesa
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
|
||||||
aliyunEsa "github.com/alibabacloud-go/esa-20240910/v2/client"
|
|
||||||
"github.com/alibabacloud-go/tea/tea"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 阿里云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 阿里云 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 阿里云地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 阿里云 ESA 站点 ID。
|
|
||||||
SiteId int64 `json:"siteId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *aliyunEsa.Client
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
if d.config.SiteId == 0 {
|
|
||||||
return nil, errors.New("config `siteId` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传证书到 CAS
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 配置站点证书
|
|
||||||
// REF: https://help.aliyun.com/zh/edge-security-acceleration/esa/api-esa-2024-09-10-setcertificate
|
|
||||||
certId, _ := strconv.ParseInt(upres.CertId, 10, 64)
|
|
||||||
setCertificateReq := &aliyunEsa.SetCertificateRequest{
|
|
||||||
SiteId: tea.Int64(d.config.SiteId),
|
|
||||||
Type: tea.String("cas"),
|
|
||||||
CasId: tea.Int64(certId),
|
|
||||||
}
|
|
||||||
setCertificateResp, err := d.sdkClient.SetCertificate(setCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'esa.SetCertificate'", slog.Any("request", setCertificateReq), slog.Any("response", setCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'esa.SetCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunEsa.Client, error) {
|
|
||||||
// 接入点一览 https://api.aliyun.com/product/ESA
|
|
||||||
config := &aliyunOpen.Config{
|
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
|
||||||
Endpoint: tea.String(fmt.Sprintf("esa.%s.aliyuncs.com", region)),
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := aliyunEsa.NewClient(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
|
||||||
casRegion := region
|
|
||||||
if casRegion != "" {
|
|
||||||
// 阿里云 CAS 服务接入点是独立于 ESA 服务的
|
|
||||||
// 国内版固定接入点:华东一杭州
|
|
||||||
// 国际版固定接入点:亚太东南一新加坡
|
|
||||||
if casRegion != "" && !strings.HasPrefix(casRegion, "cn-") {
|
|
||||||
casRegion = "ap-southeast-1"
|
|
||||||
} else {
|
|
||||||
casRegion = "cn-hangzhou"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: accessKeyId,
|
|
||||||
AccessKeySecret: accessKeySecret,
|
|
||||||
Region: casRegion,
|
|
||||||
})
|
|
||||||
return uploader, err
|
|
||||||
}
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
package aliyunfc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
|
||||||
aliyunFc3 "github.com/alibabacloud-go/fc-20230330/v4/client"
|
|
||||||
aliyunFc2 "github.com/alibabacloud-go/fc-open-20210406/v2/client"
|
|
||||||
"github.com/alibabacloud-go/tea/tea"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 阿里云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 阿里云 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 阿里云地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 服务版本。
|
|
||||||
ServiceVersion string `json:"serviceVersion"`
|
|
||||||
// 自定义域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClients *wSdkClients
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
type wSdkClients struct {
|
|
||||||
fc2 *aliyunFc2.Client
|
|
||||||
fc3 *aliyunFc3.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
clients, err := createSdkClients(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk clients")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClients: clients,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
switch d.config.ServiceVersion {
|
|
||||||
case "3", "3.0":
|
|
||||||
if err := d.deployToFC3(ctx, certPem, privkeyPem); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
case "2", "2.0":
|
|
||||||
if err := d.deployToFC2(ctx, certPem, privkeyPem); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, xerrors.Errorf("unsupported service version: %s", d.config.ServiceVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) deployToFC3(ctx context.Context, certPem string, privkeyPem string) error {
|
|
||||||
// 获取自定义域名
|
|
||||||
// REF: https://help.aliyun.com/zh/functioncompute/fc-3-0/developer-reference/api-fc-2023-03-30-getcustomdomain
|
|
||||||
getCustomDomainResp, err := d.sdkClients.fc3.GetCustomDomain(tea.String(d.config.Domain))
|
|
||||||
d.logger.Debug("sdk request 'fc.GetCustomDomain'", slog.Any("response", getCustomDomainResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'fc.GetCustomDomain'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新自定义域名
|
|
||||||
// REF: https://help.aliyun.com/zh/functioncompute/fc-3-0/developer-reference/api-fc-2023-03-30-updatecustomdomain
|
|
||||||
updateCustomDomainReq := &aliyunFc3.UpdateCustomDomainRequest{
|
|
||||||
Body: &aliyunFc3.UpdateCustomDomainInput{
|
|
||||||
CertConfig: &aliyunFc3.CertConfig{
|
|
||||||
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
|
|
||||||
Certificate: tea.String(certPem),
|
|
||||||
PrivateKey: tea.String(privkeyPem),
|
|
||||||
},
|
|
||||||
Protocol: getCustomDomainResp.Body.Protocol,
|
|
||||||
TlsConfig: getCustomDomainResp.Body.TlsConfig,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
updateCustomDomainResp, err := d.sdkClients.fc3.UpdateCustomDomain(tea.String(d.config.Domain), updateCustomDomainReq)
|
|
||||||
d.logger.Debug("sdk request 'fc.UpdateCustomDomain'", slog.Any("request", updateCustomDomainReq), slog.Any("response", updateCustomDomainResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'fc.UpdateCustomDomain'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) deployToFC2(ctx context.Context, certPem string, privkeyPem string) error {
|
|
||||||
// 获取自定义域名
|
|
||||||
// REF: https://help.aliyun.com/zh/functioncompute/fc-2-0/developer-reference/api-fc-open-2021-04-06-getcustomdomain
|
|
||||||
getCustomDomainResp, err := d.sdkClients.fc2.GetCustomDomain(tea.String(d.config.Domain))
|
|
||||||
d.logger.Debug("sdk request 'fc.GetCustomDomain'", slog.Any("response", getCustomDomainResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'fc.GetCustomDomain'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新自定义域名
|
|
||||||
// REF: https://help.aliyun.com/zh/functioncompute/fc-2-0/developer-reference/api-fc-open-2021-04-06-updatecustomdomain
|
|
||||||
updateCustomDomainReq := &aliyunFc2.UpdateCustomDomainRequest{
|
|
||||||
CertConfig: &aliyunFc2.CertConfig{
|
|
||||||
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
|
|
||||||
Certificate: tea.String(certPem),
|
|
||||||
PrivateKey: tea.String(privkeyPem),
|
|
||||||
},
|
|
||||||
Protocol: getCustomDomainResp.Body.Protocol,
|
|
||||||
TlsConfig: getCustomDomainResp.Body.TlsConfig,
|
|
||||||
}
|
|
||||||
updateCustomDomainResp, err := d.sdkClients.fc2.UpdateCustomDomain(tea.String(d.config.Domain), updateCustomDomainReq)
|
|
||||||
d.logger.Debug("sdk request 'fc.UpdateCustomDomain'", slog.Any("request", updateCustomDomainReq), slog.Any("response", updateCustomDomainResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'fc.UpdateCustomDomain'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients, error) {
|
|
||||||
// 接入点一览 https://api.aliyun.com/product/FC-Open
|
|
||||||
var fc2Endpoint string
|
|
||||||
switch region {
|
|
||||||
case "cn-hangzhou-finance":
|
|
||||||
fc2Endpoint = fmt.Sprintf("%s.fc.aliyuncs.com", region)
|
|
||||||
default:
|
|
||||||
fc2Endpoint = fmt.Sprintf("fc.%s.aliyuncs.com", region)
|
|
||||||
}
|
|
||||||
|
|
||||||
fc2Config := &aliyunOpen.Config{
|
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
|
||||||
Endpoint: tea.String(fc2Endpoint),
|
|
||||||
}
|
|
||||||
fc2Client, err := aliyunFc2.NewClient(fc2Config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 接入点一览 https://api.aliyun.com/product/FC-Open
|
|
||||||
fc3Endpoint := fmt.Sprintf("fcv3.%s.aliyuncs.com", region)
|
|
||||||
fc3Config := &aliyunOpen.Config{
|
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
|
||||||
Endpoint: tea.String(fc3Endpoint),
|
|
||||||
}
|
|
||||||
fc3Client, err := aliyunFc3.NewClient(fc3Config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &wSdkClients{
|
|
||||||
fc2: fc2Client,
|
|
||||||
fc3: fc3Client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
package aliyunvod
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
|
||||||
"github.com/alibabacloud-go/tea/tea"
|
|
||||||
aliyunVod "github.com/alibabacloud-go/vod-20170321/v4/client"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 阿里云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 阿里云 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 阿里云地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 点播加速域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *aliyunVod.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 设置域名证书
|
|
||||||
// REF: https://help.aliyun.com/zh/vod/developer-reference/api-vod-2017-03-21-setvoddomainsslcertificate
|
|
||||||
setVodDomainSSLCertificateReq := &aliyunVod.SetVodDomainSSLCertificateRequest{
|
|
||||||
DomainName: tea.String(d.config.Domain),
|
|
||||||
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
|
|
||||||
CertType: tea.String("upload"),
|
|
||||||
SSLProtocol: tea.String("on"),
|
|
||||||
SSLPub: tea.String(certPem),
|
|
||||||
SSLPri: tea.String(privkeyPem),
|
|
||||||
}
|
|
||||||
setVodDomainSSLCertificateResp, err := d.sdkClient.SetVodDomainSSLCertificate(setVodDomainSSLCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'live.SetVodDomainSSLCertificate'", slog.Any("request", setVodDomainSSLCertificateReq), slog.Any("response", setVodDomainSSLCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.SetVodDomainSSLCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunVod.Client, error) {
|
|
||||||
// 接入点一览 https://api.aliyun.com/product/vod
|
|
||||||
endpoint := fmt.Sprintf("vod.%s.aliyuncs.com", region)
|
|
||||||
|
|
||||||
config := &aliyunOpen.Config{
|
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
|
||||||
Endpoint: tea.String(endpoint),
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := aliyunVod.NewClient(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
package aliyunwaf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
|
||||||
"github.com/alibabacloud-go/tea/tea"
|
|
||||||
aliyunWaf "github.com/alibabacloud-go/waf-openapi-20211001/v5/client"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 阿里云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 阿里云 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 阿里云地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 服务版本。
|
|
||||||
ServiceVersion string `json:"serviceVersion"`
|
|
||||||
// WAF 实例 ID。
|
|
||||||
InstanceId string `json:"instanceId"`
|
|
||||||
// 接入域名(支持泛域名)。
|
|
||||||
Domain string `json:"domain,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *aliyunWaf.Client
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
if d.config.InstanceId == "" {
|
|
||||||
return nil, errors.New("config `instanceId` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch d.config.ServiceVersion {
|
|
||||||
case "3", "3.0":
|
|
||||||
if err := d.deployToWAF3(ctx, certPem, privkeyPem); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, xerrors.Errorf("unsupported service version: %s", d.config.ServiceVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPem string, privkeyPem string) error {
|
|
||||||
// 上传证书到 CAS
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.config.Domain == "" {
|
|
||||||
// 未指定接入域名,只需替换默认证书即可
|
|
||||||
|
|
||||||
// 查询默认 SSL/TLS 设置
|
|
||||||
// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describedefaulthttps
|
|
||||||
describeDefaultHttpsReq := &aliyunWaf.DescribeDefaultHttpsRequest{
|
|
||||||
InstanceId: tea.String(d.config.InstanceId),
|
|
||||||
RegionId: tea.String(d.config.Region),
|
|
||||||
}
|
|
||||||
describeDefaultHttpsResp, err := d.sdkClient.DescribeDefaultHttps(describeDefaultHttpsReq)
|
|
||||||
d.logger.Debug("sdk request 'waf.DescribeDefaultHttps'", slog.Any("request", describeDefaultHttpsReq), slog.Any("response", describeDefaultHttpsResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDefaultHttps'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改默认 SSL/TLS 设置
|
|
||||||
// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifydefaulthttps
|
|
||||||
modifyDefaultHttpsReq := &aliyunWaf.ModifyDefaultHttpsRequest{
|
|
||||||
InstanceId: tea.String(d.config.InstanceId),
|
|
||||||
RegionId: tea.String(d.config.Region),
|
|
||||||
CertId: tea.String(upres.CertId),
|
|
||||||
TLSVersion: tea.String("tlsv1"),
|
|
||||||
EnableTLSv3: tea.Bool(false),
|
|
||||||
}
|
|
||||||
if describeDefaultHttpsResp.Body != nil && describeDefaultHttpsResp.Body.DefaultHttps != nil {
|
|
||||||
modifyDefaultHttpsReq.TLSVersion = describeDefaultHttpsResp.Body.DefaultHttps.TLSVersion
|
|
||||||
modifyDefaultHttpsReq.EnableTLSv3 = describeDefaultHttpsResp.Body.DefaultHttps.EnableTLSv3
|
|
||||||
}
|
|
||||||
modifyDefaultHttpsResp, err := d.sdkClient.ModifyDefaultHttps(modifyDefaultHttpsReq)
|
|
||||||
d.logger.Debug("sdk request 'waf.ModifyDefaultHttps'", slog.Any("request", modifyDefaultHttpsReq), slog.Any("response", modifyDefaultHttpsResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDefaultHttps'")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 指定接入域名
|
|
||||||
|
|
||||||
// 查询 CNAME 接入详情
|
|
||||||
// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describedomaindetail
|
|
||||||
describeDomainDetailReq := &aliyunWaf.DescribeDomainDetailRequest{
|
|
||||||
InstanceId: tea.String(d.config.InstanceId),
|
|
||||||
RegionId: tea.String(d.config.Region),
|
|
||||||
Domain: tea.String(d.config.Domain),
|
|
||||||
}
|
|
||||||
describeDomainDetailResp, err := d.sdkClient.DescribeDomainDetail(describeDomainDetailReq)
|
|
||||||
d.logger.Debug("sdk request 'waf.DescribeDomainDetail'", slog.Any("request", describeDomainDetailReq), slog.Any("response", describeDomainDetailResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDomainDetail'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改 CNAME 接入资源
|
|
||||||
// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifydomain
|
|
||||||
modifyDomainReq := &aliyunWaf.ModifyDomainRequest{
|
|
||||||
InstanceId: tea.String(d.config.InstanceId),
|
|
||||||
RegionId: tea.String(d.config.Region),
|
|
||||||
Domain: tea.String(d.config.Domain),
|
|
||||||
Listen: &aliyunWaf.ModifyDomainRequestListen{
|
|
||||||
CertId: tea.String(upres.CertId),
|
|
||||||
TLSVersion: tea.String("tlsv1"),
|
|
||||||
EnableTLSv3: tea.Bool(false),
|
|
||||||
},
|
|
||||||
Redirect: &aliyunWaf.ModifyDomainRequestRedirect{
|
|
||||||
Loadbalance: tea.String("iphash"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if describeDomainDetailResp.Body != nil && describeDomainDetailResp.Body.Listen != nil {
|
|
||||||
modifyDomainReq.Listen.TLSVersion = describeDomainDetailResp.Body.Listen.TLSVersion
|
|
||||||
modifyDomainReq.Listen.EnableTLSv3 = describeDomainDetailResp.Body.Listen.EnableTLSv3
|
|
||||||
modifyDomainReq.Listen.FocusHttps = describeDomainDetailResp.Body.Listen.FocusHttps
|
|
||||||
}
|
|
||||||
if describeDomainDetailResp.Body != nil && describeDomainDetailResp.Body.Redirect != nil {
|
|
||||||
modifyDomainReq.Redirect.Loadbalance = describeDomainDetailResp.Body.Redirect.Loadbalance
|
|
||||||
modifyDomainReq.Redirect.FocusHttpBackend = describeDomainDetailResp.Body.Redirect.FocusHttpBackend
|
|
||||||
modifyDomainReq.Redirect.SniEnabled = describeDomainDetailResp.Body.Redirect.SniEnabled
|
|
||||||
modifyDomainReq.Redirect.SniHost = describeDomainDetailResp.Body.Redirect.SniHost
|
|
||||||
}
|
|
||||||
modifyDomainResp, err := d.sdkClient.ModifyDomain(modifyDomainReq)
|
|
||||||
d.logger.Debug("sdk request 'waf.ModifyDomain'", slog.Any("request", modifyDomainReq), slog.Any("response", modifyDomainResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDomain'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunWaf.Client, error) {
|
|
||||||
// 接入点一览:https://api.aliyun.com/product/waf-openapi
|
|
||||||
config := &aliyunOpen.Config{
|
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
|
||||||
Endpoint: tea.String(fmt.Sprintf("wafopenapi.%s.aliyuncs.com", region)),
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := aliyunWaf.NewClient(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
|
||||||
casRegion := region
|
|
||||||
if casRegion != "" {
|
|
||||||
// 阿里云 CAS 服务接入点是独立于 WAF 服务的
|
|
||||||
// 国内版固定接入点:华东一杭州
|
|
||||||
// 国际版固定接入点:亚太东南一新加坡
|
|
||||||
if casRegion != "" && !strings.HasPrefix(casRegion, "cn-") {
|
|
||||||
casRegion = "ap-southeast-1"
|
|
||||||
} else {
|
|
||||||
casRegion = "cn-hangzhou"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: accessKeyId,
|
|
||||||
AccessKeySecret: accessKeySecret,
|
|
||||||
Region: casRegion,
|
|
||||||
})
|
|
||||||
return uploader, err
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package awsacm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// AWS AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// AWS SecretAccessKey。
|
|
||||||
SecretAccessKey string `json:"secretAccessKey"`
|
|
||||||
// AWS 区域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
SecretAccessKey: config.SecretAccessKey,
|
|
||||||
Region: config.Region,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 ACM
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
package awscloudfront
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
aws "github.com/aws/aws-sdk-go-v2/aws"
|
|
||||||
awsCfg "github.com/aws/aws-sdk-go-v2/config"
|
|
||||||
awsCred "github.com/aws/aws-sdk-go-v2/credentials"
|
|
||||||
awsCf "github.com/aws/aws-sdk-go-v2/service/cloudfront"
|
|
||||||
awsCfTypes "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// AWS AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// AWS SecretAccessKey。
|
|
||||||
SecretAccessKey string `json:"secretAccessKey"`
|
|
||||||
// AWS 区域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// AWS CloudFront 分配 ID。
|
|
||||||
DistributionId string `json:"distributionId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *awsCf.Client
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
SecretAccessKey: config.SecretAccessKey,
|
|
||||||
Region: config.Region,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
if d.config.DistributionId == "" {
|
|
||||||
return nil, errors.New("config `distribuitionId` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传证书到 ACM
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取分配配置
|
|
||||||
// REF: https://docs.aws.amazon.com/en_us/cloudfront/latest/APIReference/API_GetDistributionConfig.html
|
|
||||||
getDistributionConfigReq := &awsCf.GetDistributionConfigInput{
|
|
||||||
Id: aws.String(d.config.DistributionId),
|
|
||||||
}
|
|
||||||
getDistributionConfigResp, err := d.sdkClient.GetDistributionConfig(context.TODO(), getDistributionConfigReq)
|
|
||||||
d.logger.Debug("sdk request 'cloudfront.GetDistributionConfig'", slog.Any("request", getDistributionConfigReq), slog.Any("response", getDistributionConfigResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cloudfront.GetDistributionConfig'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新分配配置
|
|
||||||
// REF: https://docs.aws.amazon.com/zh_cn/cloudfront/latest/APIReference/API_UpdateDistribution.html
|
|
||||||
updateDistributionReq := &awsCf.UpdateDistributionInput{
|
|
||||||
Id: aws.String(d.config.DistributionId),
|
|
||||||
DistributionConfig: getDistributionConfigResp.DistributionConfig,
|
|
||||||
IfMatch: getDistributionConfigResp.ETag,
|
|
||||||
}
|
|
||||||
if updateDistributionReq.DistributionConfig.ViewerCertificate == nil {
|
|
||||||
updateDistributionReq.DistributionConfig.ViewerCertificate = &awsCfTypes.ViewerCertificate{}
|
|
||||||
}
|
|
||||||
updateDistributionReq.DistributionConfig.ViewerCertificate.CloudFrontDefaultCertificate = aws.Bool(false)
|
|
||||||
updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = aws.String(upres.CertId)
|
|
||||||
updateDistributionResp, err := d.sdkClient.UpdateDistribution(context.TODO(), updateDistributionReq)
|
|
||||||
d.logger.Debug("sdk request 'cloudfront.UpdateDistribution'", slog.Any("request", updateDistributionReq), slog.Any("response", updateDistributionResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cloudfront.UpdateDistribution'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, secretAccessKey, region string) (*awsCf.Client, error) {
|
|
||||||
cfg, err := awsCfg.LoadDefaultConfig(context.TODO())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
client := awsCf.NewFromConfig(cfg, func(o *awsCf.Options) {
|
|
||||||
o.Region = region
|
|
||||||
o.Credentials = aws.NewCredentialsCache(awsCred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, ""))
|
|
||||||
})
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package azurekeyvault
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/azure-keyvault"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// Azure TenantId。
|
|
||||||
TenantId string `json:"tenantId"`
|
|
||||||
// Azure ClientId。
|
|
||||||
ClientId string `json:"clientId"`
|
|
||||||
// Azure ClientSecret。
|
|
||||||
ClientSecret string `json:"clientSecret"`
|
|
||||||
// Azure 主权云环境。
|
|
||||||
CloudName string `json:"cloudName,omitempty"`
|
|
||||||
// Key Vault 名称。
|
|
||||||
KeyVaultName string `json:"keyvaultName"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
TenantId: config.TenantId,
|
|
||||||
ClientId: config.ClientId,
|
|
||||||
ClientSecret: config.ClientSecret,
|
|
||||||
CloudName: config.CloudName,
|
|
||||||
KeyVaultName: config.KeyVaultName,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 KeyVault
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
package baiducloudcdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
bceCdn "github.com/baidubce/bce-sdk-go/services/cdn"
|
|
||||||
bceCdnApi "github.com/baidubce/bce-sdk-go/services/cdn/api"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 百度智能云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 百度智能云 SecretAccessKey。
|
|
||||||
SecretAccessKey string `json:"secretAccessKey"`
|
|
||||||
// 加速域名(支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *bceCdn.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 修改域名证书
|
|
||||||
// REF: https://cloud.baidu.com/doc/CDN/s/qjzuz2hp8
|
|
||||||
putCertResp, err := d.sdkClient.PutCert(
|
|
||||||
d.config.Domain,
|
|
||||||
&bceCdnApi.UserCertificate{
|
|
||||||
CertName: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
|
|
||||||
ServerData: certPem,
|
|
||||||
PrivateData: privkeyPem,
|
|
||||||
},
|
|
||||||
"ON",
|
|
||||||
)
|
|
||||||
d.logger.Debug("sdk request 'cdn.PutCert'", slog.String("request.domain", d.config.Domain), slog.Any("response", putCertResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.PutCert'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, secretAccessKey string) (*bceCdn.Client, error) {
|
|
||||||
client, err := bceCdn.NewClient(accessKeyId, secretAccessKey, "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
package baishancdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
bssdk "github.com/usual2970/certimate/internal/pkg/vendors/baishan-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 白山云 API Token。
|
|
||||||
ApiToken string `json:"apiToken"`
|
|
||||||
// 加速域名(支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *bssdk.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
if d.config.Domain == "" {
|
|
||||||
return nil, errors.New("config `domain` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询域名配置
|
|
||||||
// REF: https://portal.baishancloud.com/track/document/api/1/1065
|
|
||||||
getDomainConfigReq := &bssdk.GetDomainConfigRequest{
|
|
||||||
Domains: d.config.Domain,
|
|
||||||
Config: []string{"https"},
|
|
||||||
}
|
|
||||||
getDomainConfigResp, err := d.sdkClient.GetDomainConfig(getDomainConfigReq)
|
|
||||||
d.logger.Debug("sdk request 'baishan.GetDomainConfig'", slog.Any("request", getDomainConfigReq), slog.Any("response", getDomainConfigResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.GetDomainConfig'")
|
|
||||||
} else if len(getDomainConfigResp.Data) == 0 {
|
|
||||||
return nil, errors.New("domain config not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增证书
|
|
||||||
// REF: https://portal.baishancloud.com/track/document/downloadPdf/1441
|
|
||||||
createCertificateReq := &bssdk.CreateCertificateRequest{
|
|
||||||
Certificate: certPem,
|
|
||||||
Key: privkeyPem,
|
|
||||||
Name: fmt.Sprintf("certimate_%d", time.Now().UnixMilli()),
|
|
||||||
}
|
|
||||||
createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'baishan.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.CreateCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置域名配置
|
|
||||||
// REF: https://portal.baishancloud.com/track/document/api/1/1045
|
|
||||||
setDomainConfigReq := &bssdk.SetDomainConfigRequest{
|
|
||||||
Domains: d.config.Domain,
|
|
||||||
Config: &bssdk.DomainConfig{
|
|
||||||
Https: &bssdk.DomainConfigHttps{
|
|
||||||
CertId: createCertificateResp.Data.CertId,
|
|
||||||
ForceHttps: getDomainConfigResp.Data[0].Config.Https.ForceHttps,
|
|
||||||
EnableHttp2: getDomainConfigResp.Data[0].Config.Https.EnableHttp2,
|
|
||||||
EnableOcsp: getDomainConfigResp.Data[0].Config.Https.EnableOcsp,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
setDomainConfigResp, err := d.sdkClient.SetDomainConfig(setDomainConfigReq)
|
|
||||||
d.logger.Debug("sdk request 'baishan.SetDomainConfig'", slog.Any("request", setDomainConfigReq), slog.Any("response", setDomainConfigResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.SetDomainConfig'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(apiToken string) (*bssdk.Client, error) {
|
|
||||||
if apiToken == "" {
|
|
||||||
return nil, errors.New("invalid baishan api token")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := bssdk.NewClient(apiToken)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
package baotapanelconsole
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
btsdk "github.com/usual2970/certimate/internal/pkg/vendors/btpanel-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 宝塔面板地址。
|
|
||||||
ApiUrl string `json:"apiUrl"`
|
|
||||||
// 宝塔面板接口密钥。
|
|
||||||
ApiKey string `json:"apiKey"`
|
|
||||||
// 是否允许不安全的连接。
|
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
|
||||||
// 是否自动重启。
|
|
||||||
AutoRestart bool `json:"autoRestart"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *btsdk.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 设置面板 SSL 证书
|
|
||||||
configSavePanelSSLReq := &btsdk.ConfigSavePanelSSLRequest{
|
|
||||||
PrivateKey: privkeyPem,
|
|
||||||
Certificate: certPem,
|
|
||||||
}
|
|
||||||
configSavePanelSSLResp, err := d.sdkClient.ConfigSavePanelSSL(configSavePanelSSLReq)
|
|
||||||
d.logger.Debug("sdk request 'bt.ConfigSavePanelSSL'", slog.Any("request", configSavePanelSSLReq), slog.Any("response", configSavePanelSSLResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.ConfigSavePanelSSL'")
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.config.AutoRestart {
|
|
||||||
// 重启面板(无需关心响应,因为宝塔重启时会断开连接产生 error)
|
|
||||||
systemServiceAdminReq := &btsdk.SystemServiceAdminRequest{
|
|
||||||
Name: "nginx",
|
|
||||||
Type: "restart",
|
|
||||||
}
|
|
||||||
systemServiceAdminResp, _ := d.sdkClient.SystemServiceAdmin(systemServiceAdminReq)
|
|
||||||
d.logger.Debug("sdk request 'bt.SystemServiceAdmin'", slog.Any("request", systemServiceAdminReq), slog.Any("response", systemServiceAdminResp))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, error) {
|
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
|
||||||
return nil, errors.New("invalid baota api url")
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiKey == "" {
|
|
||||||
return nil, errors.New("invalid baota api key")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := btsdk.NewClient(apiUrl, apiKey)
|
|
||||||
if allowInsecure {
|
|
||||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
package bytepluscdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
bpCdn "github.com/byteplus-sdk/byteplus-sdk-golang/service/cdn"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/byteplus-cdn"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// BytePlus AccessKey。
|
|
||||||
AccessKey string `json:"accessKey"`
|
|
||||||
// BytePlus SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
// 加速域名(支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *bpCdn.CDN
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := bpCdn.NewInstance()
|
|
||||||
client.Client.SetAccessKey(config.AccessKey)
|
|
||||||
client.Client.SetSecretKey(config.SecretKey)
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKey: config.AccessKey,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 CDN
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
domains := make([]string, 0)
|
|
||||||
if strings.HasPrefix(d.config.Domain, "*.") {
|
|
||||||
// 获取指定证书可关联的域名
|
|
||||||
// REF: https://docs.byteplus.com/en/docs/byteplus-cdn/reference-describecertconfig-9ea17
|
|
||||||
describeCertConfigReq := &bpCdn.DescribeCertConfigRequest{
|
|
||||||
CertId: upres.CertId,
|
|
||||||
}
|
|
||||||
describeCertConfigResp, err := d.sdkClient.DescribeCertConfig(describeCertConfigReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.DescribeCertConfig'", slog.Any("request", describeCertConfigReq), slog.Any("response", describeCertConfigResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeCertConfig'")
|
|
||||||
}
|
|
||||||
|
|
||||||
if describeCertConfigResp.Result.CertNotConfig != nil {
|
|
||||||
for i := range describeCertConfigResp.Result.CertNotConfig {
|
|
||||||
domains = append(domains, describeCertConfigResp.Result.CertNotConfig[i].Domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if describeCertConfigResp.Result.OtherCertConfig != nil {
|
|
||||||
for i := range describeCertConfigResp.Result.OtherCertConfig {
|
|
||||||
domains = append(domains, describeCertConfigResp.Result.OtherCertConfig[i].Domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(domains) == 0 {
|
|
||||||
if len(describeCertConfigResp.Result.SpecifiedCertConfig) > 0 {
|
|
||||||
// 所有可关联的域名都配置了该证书,跳过部署
|
|
||||||
d.logger.Info("no domains to deploy")
|
|
||||||
} else {
|
|
||||||
return nil, errors.New("domain not found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
domains = append(domains, d.config.Domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(domains) > 0 {
|
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for _, domain := range domains {
|
|
||||||
// 关联证书与加速域名
|
|
||||||
// REF: https://docs.byteplus.com/en/docs/byteplus-cdn/reference-batchdeploycert
|
|
||||||
batchDeployCertReq := &bpCdn.BatchDeployCertRequest{
|
|
||||||
CertId: upres.CertId,
|
|
||||||
Domain: domain,
|
|
||||||
}
|
|
||||||
batchDeployCertResp, err := d.sdkClient.BatchDeployCert(batchDeployCertReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.BatchDeployCert'", slog.Any("request", batchDeployCertReq), slog.Any("response", batchDeployCertResp))
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return nil, errors.Join(errs...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package cachefly
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
cfsdk "github.com/usual2970/certimate/internal/pkg/vendors/cachefly-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// CacheFly API Token。
|
|
||||||
ApiToken string `json:"apiToken"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *cfsdk.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书
|
|
||||||
createCertificateReq := &cfsdk.CreateCertificateRequest{
|
|
||||||
Certificate: certPem,
|
|
||||||
CertificateKey: privkeyPem,
|
|
||||||
}
|
|
||||||
createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'cachefly.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cachefly.CreateCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(apiToken string) (*cfsdk.Client, error) {
|
|
||||||
if apiToken == "" {
|
|
||||||
return nil, errors.New("invalid cachefly api token")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := cfsdk.NewClient(apiToken)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
package cdnfly
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/url"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
cfsdk "github.com/usual2970/certimate/internal/pkg/vendors/cdnfly-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// Cdnfly 地址。
|
|
||||||
ApiUrl string `json:"apiUrl"`
|
|
||||||
// Cdnfly 用户端 API Key。
|
|
||||||
ApiKey string `json:"apiKey"`
|
|
||||||
// Cdnfly 用户端 API Secret。
|
|
||||||
ApiSecret string `json:"apiSecret"`
|
|
||||||
// 部署资源类型。
|
|
||||||
ResourceType ResourceType `json:"resourceType"`
|
|
||||||
// 网站 ID。
|
|
||||||
// 部署资源类型为 [RESOURCE_TYPE_SITE] 时必填。
|
|
||||||
SiteId string `json:"siteId,omitempty"`
|
|
||||||
// 证书 ID。
|
|
||||||
// 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。
|
|
||||||
CertificateId string `json:"certificateId,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *cfsdk.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.ApiSecret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 根据部署资源类型决定部署方式
|
|
||||||
switch d.config.ResourceType {
|
|
||||||
case RESOURCE_TYPE_SITE:
|
|
||||||
if err := d.deployToSite(ctx, certPem, privkeyPem); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
case RESOURCE_TYPE_CERTIFICATE:
|
|
||||||
if err := d.deployToCertificate(ctx, certPem, privkeyPem); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported resource type: %s", d.config.ResourceType)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) deployToSite(ctx context.Context, certPem string, privkeyPem string) error {
|
|
||||||
if d.config.SiteId == "" {
|
|
||||||
return errors.New("config `siteId` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取单个网站详情
|
|
||||||
// REF: https://doc.cdnfly.cn/wangzhanguanli-v1-sites.html#%E8%8E%B7%E5%8F%96%E5%8D%95%E4%B8%AA%E7%BD%91%E7%AB%99%E8%AF%A6%E6%83%85
|
|
||||||
getSiteReq := &cfsdk.GetSiteRequest{
|
|
||||||
Id: d.config.SiteId,
|
|
||||||
}
|
|
||||||
getSiteResp, err := d.sdkClient.GetSite(getSiteReq)
|
|
||||||
d.logger.Debug("sdk request 'cdnfly.GetSite'", slog.Any("request", getSiteReq), slog.Any("response", getSiteResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.GetSite'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加单个证书
|
|
||||||
// REF: https://doc.cdnfly.cn/wangzhanzhengshu-v1-certs.html#%E6%B7%BB%E5%8A%A0%E5%8D%95%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%E8%AF%81%E4%B9%A6-%E5%A4%9A%E4%B8%AA%E8%AF%81%E4%B9%A6%E6%97%B6%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F%E4%B8%BA%E6%95%B0%E7%BB%84
|
|
||||||
createCertificateReq := &cfsdk.CreateCertificateRequest{
|
|
||||||
Name: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
|
|
||||||
Type: "custom",
|
|
||||||
Cert: certPem,
|
|
||||||
Key: privkeyPem,
|
|
||||||
}
|
|
||||||
createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'cdnfly.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.CreateCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改单个网站
|
|
||||||
// REF: https://doc.cdnfly.cn/wangzhanguanli-v1-sites.html#%E4%BF%AE%E6%94%B9%E5%8D%95%E4%B8%AA%E7%BD%91%E7%AB%99
|
|
||||||
updateSiteHttpsListenMap := make(map[string]any)
|
|
||||||
_ = json.Unmarshal([]byte(getSiteResp.Data.HttpsListen), &updateSiteHttpsListenMap)
|
|
||||||
updateSiteHttpsListenMap["cert"] = createCertificateResp.Data
|
|
||||||
updateSiteHttpsListenData, _ := json.Marshal(updateSiteHttpsListenMap)
|
|
||||||
updateSiteHttpsListen := string(updateSiteHttpsListenData)
|
|
||||||
updateSiteReq := &cfsdk.UpdateSiteRequest{
|
|
||||||
Id: d.config.SiteId,
|
|
||||||
HttpsListen: &updateSiteHttpsListen,
|
|
||||||
}
|
|
||||||
updateSiteResp, err := d.sdkClient.UpdateSite(updateSiteReq)
|
|
||||||
d.logger.Debug("sdk request 'cdnfly.UpdateSite'", slog.Any("request", updateSiteReq), slog.Any("response", updateSiteResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.UpdateSite'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem string, privkeyPem string) error {
|
|
||||||
if d.config.CertificateId == "" {
|
|
||||||
return errors.New("config `certificateId` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改单个证书
|
|
||||||
// REF: https://doc.cdnfly.cn/wangzhanzhengshu-v1-certs.html#%E4%BF%AE%E6%94%B9%E5%8D%95%E4%B8%AA%E8%AF%81%E4%B9%A6
|
|
||||||
updateCertificateType := "custom"
|
|
||||||
updateCertificateReq := &cfsdk.UpdateCertificateRequest{
|
|
||||||
Id: d.config.CertificateId,
|
|
||||||
Type: &updateCertificateType,
|
|
||||||
Cert: &certPem,
|
|
||||||
Key: &privkeyPem,
|
|
||||||
}
|
|
||||||
updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'cdnfly.UpdateCertificate'", slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.UpdateCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiKey, apiSecret string) (*cfsdk.Client, error) {
|
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
|
||||||
return nil, errors.New("invalid cachefly api url")
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiKey == "" {
|
|
||||||
return nil, errors.New("invalid cachefly api key")
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiSecret == "" {
|
|
||||||
return nil, errors.New("invalid cachefly api secret")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := cfsdk.NewClient(apiUrl, apiKey, apiSecret)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
package dogecloudcdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/dogecloud"
|
|
||||||
dogesdk "github.com/usual2970/certimate/internal/pkg/vendors/dogecloud-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 多吉云 AccessKey。
|
|
||||||
AccessKey string `json:"accessKey"`
|
|
||||||
// 多吉云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
// 加速域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *dogesdk.Client
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := dogesdk.NewClient(config.AccessKey, config.SecretKey)
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKey: config.AccessKey,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 CDN
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绑定证书
|
|
||||||
// REF: https://docs.dogecloud.com/cdn/api-cert-bind
|
|
||||||
bindCdnCertId, _ := strconv.ParseInt(upres.CertId, 10, 64)
|
|
||||||
bindCdnCertResp, err := d.sdkClient.BindCdnCertWithDomain(bindCdnCertId, d.config.Domain)
|
|
||||||
d.logger.Debug("sdk request 'cdn.BindCdnCert'", slog.Int64("request.certId", bindCdnCertId), slog.String("request.domain", d.config.Domain), slog.Any("response", bindCdnCertResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.BindCdnCert'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
package edgioapplications
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/certutil"
|
|
||||||
edgsdk "github.com/usual2970/certimate/internal/pkg/vendors/edgio-sdk/applications/v7"
|
|
||||||
edgsdkDtos "github.com/usual2970/certimate/internal/pkg/vendors/edgio-sdk/applications/v7/dtos"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// Edgio ClientId。
|
|
||||||
ClientId string `json:"clientId"`
|
|
||||||
// Edgio ClientSecret。
|
|
||||||
ClientSecret string `json:"clientSecret"`
|
|
||||||
// Edgio 环境 ID。
|
|
||||||
EnvironmentId string `json:"environmentId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *edgsdk.EdgioClient
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ClientId, config.ClientSecret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 提取 Edgio 所需的服务端证书和中间证书内容
|
|
||||||
privateCertPem, intermediateCertPem, err := certutil.ExtractCertificatesFromPEM(certPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传 TLS 证书
|
|
||||||
// REF: https://docs.edg.io/rest_api/#tag/tls-certs/operation/postConfigV01TlsCerts
|
|
||||||
uploadTlsCertReq := edgsdkDtos.UploadTlsCertRequest{
|
|
||||||
EnvironmentID: d.config.EnvironmentId,
|
|
||||||
PrimaryCert: privateCertPem,
|
|
||||||
IntermediateCert: intermediateCertPem,
|
|
||||||
PrivateKey: privkeyPem,
|
|
||||||
}
|
|
||||||
uploadTlsCertResp, err := d.sdkClient.UploadTlsCert(uploadTlsCertReq)
|
|
||||||
d.logger.Debug("sdk request 'edgio.UploadTlsCert'", slog.Any("request", uploadTlsCertReq), slog.Any("response", uploadTlsCertResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'edgio.UploadTlsCert'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(clientId, clientSecret string) (*edgsdk.EdgioClient, error) {
|
|
||||||
client := edgsdk.NewEdgioClient(clientId, clientSecret, "", "")
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
package gcorecdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
gprovider "github.com/G-Core/gcorelabscdn-go/gcore/provider"
|
|
||||||
gresources "github.com/G-Core/gcorelabscdn-go/resources"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/gcore-cdn"
|
|
||||||
gcoresdk "github.com/usual2970/certimate/internal/pkg/vendors/gcore-sdk/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// Gcore API Token。
|
|
||||||
ApiToken string `json:"apiToken"`
|
|
||||||
// CDN 资源 ID。
|
|
||||||
ResourceId int64 `json:"resourceId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *gresources.Service
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
ApiToken: config.ApiToken,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
if d.config.ResourceId == 0 {
|
|
||||||
return nil, errors.New("config `resourceId` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传证书到 CDN
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取 CDN 资源详情
|
|
||||||
// REF: https://api.gcore.com/docs/cdn#tag/CDN-resources/paths/~1cdn~1resources~1%7Bresource_id%7D/get
|
|
||||||
getResourceResp, err := d.sdkClient.Get(context.TODO(), d.config.ResourceId)
|
|
||||||
d.logger.Debug("sdk request 'resources.Get'", slog.Any("resourceId", d.config.ResourceId), slog.Any("response", getResourceResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'resources.Get'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新 CDN 资源详情
|
|
||||||
// REF: https://api.gcore.com/docs/cdn#tag/CDN-resources/operation/change_cdn_resource
|
|
||||||
updateResourceCertId, _ := strconv.ParseInt(upres.CertId, 10, 64)
|
|
||||||
updateResourceReq := &gresources.UpdateRequest{
|
|
||||||
Description: getResourceResp.Description,
|
|
||||||
Active: getResourceResp.Active,
|
|
||||||
OriginGroup: int(getResourceResp.OriginGroup),
|
|
||||||
OriginProtocol: getResourceResp.OriginProtocol,
|
|
||||||
SecondaryHostnames: getResourceResp.SecondaryHostnames,
|
|
||||||
SSlEnabled: true,
|
|
||||||
SSLData: int(updateResourceCertId),
|
|
||||||
ProxySSLEnabled: getResourceResp.ProxySSLEnabled,
|
|
||||||
ProxySSLCA: &getResourceResp.ProxySSLCA,
|
|
||||||
ProxySSLData: &getResourceResp.ProxySSLData,
|
|
||||||
Options: getResourceResp.Options,
|
|
||||||
}
|
|
||||||
updateResourceResp, err := d.sdkClient.Update(context.TODO(), d.config.ResourceId, updateResourceReq)
|
|
||||||
d.logger.Debug("sdk request 'resources.Update'", slog.Int64("resourceId", d.config.ResourceId), slog.Any("request", updateResourceReq), slog.Any("response", updateResourceResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'resources.Update'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(apiToken string) (*gresources.Service, error) {
|
|
||||||
if apiToken == "" {
|
|
||||||
return nil, errors.New("invalid gcore api token")
|
|
||||||
}
|
|
||||||
|
|
||||||
requester := gprovider.NewClient(
|
|
||||||
gcoresdk.BASE_URL,
|
|
||||||
gprovider.WithSigner(gcoresdk.NewAuthRequestSigner(apiToken)),
|
|
||||||
)
|
|
||||||
service := gresources.NewService(requester)
|
|
||||||
return service, nil
|
|
||||||
}
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
package huaweicloudcdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global"
|
|
||||||
hcCdn "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2"
|
|
||||||
hcCdnModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2/model"
|
|
||||||
hcCdnRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2/region"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/huaweicloud-scm"
|
|
||||||
hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 华为云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 华为云 SecretAccessKey。
|
|
||||||
SecretAccessKey string `json:"secretAccessKey"`
|
|
||||||
// 华为云区域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 加速域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *hcCdn.CdnClient
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(
|
|
||||||
config.AccessKeyId,
|
|
||||||
config.SecretAccessKey,
|
|
||||||
config.Region,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
SecretAccessKey: config.SecretAccessKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 SCM
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询加速域名配置
|
|
||||||
// REF: https://support.huaweicloud.com/api-cdn/ShowDomainFullConfig.html
|
|
||||||
showDomainFullConfigReq := &hcCdnModel.ShowDomainFullConfigRequest{
|
|
||||||
DomainName: d.config.Domain,
|
|
||||||
}
|
|
||||||
showDomainFullConfigResp, err := d.sdkClient.ShowDomainFullConfig(showDomainFullConfigReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.ShowDomainFullConfig'", slog.Any("request", showDomainFullConfigReq), slog.Any("response", showDomainFullConfigResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.ShowDomainFullConfig'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新加速域名配置
|
|
||||||
// REF: https://support.huaweicloud.com/api-cdn/UpdateDomainMultiCertificates.html
|
|
||||||
// REF: https://support.huaweicloud.com/usermanual-cdn/cdn_01_0306.html
|
|
||||||
updateDomainMultiCertificatesReqBodyContent := &hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent{}
|
|
||||||
updateDomainMultiCertificatesReqBodyContent.DomainName = d.config.Domain
|
|
||||||
updateDomainMultiCertificatesReqBodyContent.HttpsSwitch = 1
|
|
||||||
updateDomainMultiCertificatesReqBodyContent.CertificateType = hwsdk.Int32Ptr(2)
|
|
||||||
updateDomainMultiCertificatesReqBodyContent.ScmCertificateId = hwsdk.StringPtr(upres.CertId)
|
|
||||||
updateDomainMultiCertificatesReqBodyContent.CertName = hwsdk.StringPtr(upres.CertName)
|
|
||||||
updateDomainMultiCertificatesReqBodyContent = assign(updateDomainMultiCertificatesReqBodyContent, showDomainFullConfigResp.Configs)
|
|
||||||
updateDomainMultiCertificatesReq := &hcCdnModel.UpdateDomainMultiCertificatesRequest{
|
|
||||||
Body: &hcCdnModel.UpdateDomainMultiCertificatesRequestBody{
|
|
||||||
Https: updateDomainMultiCertificatesReqBodyContent,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
updateDomainMultiCertificatesResp, err := d.sdkClient.UpdateDomainMultiCertificates(updateDomainMultiCertificatesReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.UploadDomainMultiCertificates'", slog.Any("request", updateDomainMultiCertificatesReq), slog.Any("response", updateDomainMultiCertificatesResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.UploadDomainMultiCertificates'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcCdn.CdnClient, error) {
|
|
||||||
if region == "" {
|
|
||||||
region = "cn-north-1" // CDN 服务默认区域:华北一北京
|
|
||||||
}
|
|
||||||
|
|
||||||
auth, err := global.NewCredentialsBuilder().
|
|
||||||
WithAk(accessKeyId).
|
|
||||||
WithSk(secretAccessKey).
|
|
||||||
SafeBuild()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hcRegion, err := hcCdnRegion.SafeValueOf(region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hcClient, err := hcCdn.CdnClientBuilder().
|
|
||||||
WithRegion(hcRegion).
|
|
||||||
WithCredential(auth).
|
|
||||||
SafeBuild()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
client := hcCdn.NewCdnClient(hcClient)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func assign(reqContent *hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent, target *hcCdnModel.ConfigsGetBody) *hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent {
|
|
||||||
if target == nil {
|
|
||||||
return reqContent
|
|
||||||
}
|
|
||||||
|
|
||||||
// 华为云 API 中不传的字段表示使用默认值、而非保留原值,因此这里需要把原配置中的参数重新赋值回去。
|
|
||||||
// 而且蛋疼的是查询接口返回的数据结构和更新接口传入的参数结构不一致,需要做很多转化。
|
|
||||||
|
|
||||||
if *target.OriginProtocol == "follow" {
|
|
||||||
reqContent.AccessOriginWay = hwsdk.Int32Ptr(1)
|
|
||||||
} else if *target.OriginProtocol == "http" {
|
|
||||||
reqContent.AccessOriginWay = hwsdk.Int32Ptr(2)
|
|
||||||
} else if *target.OriginProtocol == "https" {
|
|
||||||
reqContent.AccessOriginWay = hwsdk.Int32Ptr(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.ForceRedirect != nil {
|
|
||||||
reqContent.ForceRedirectConfig = &hcCdnModel.ForceRedirect{}
|
|
||||||
|
|
||||||
if target.ForceRedirect.Status == "on" {
|
|
||||||
reqContent.ForceRedirectConfig.Switch = 1
|
|
||||||
reqContent.ForceRedirectConfig.RedirectType = target.ForceRedirect.Type
|
|
||||||
} else {
|
|
||||||
reqContent.ForceRedirectConfig.Switch = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.Https != nil {
|
|
||||||
if *target.Https.Http2Status == "on" {
|
|
||||||
reqContent.Http2 = hwsdk.Int32Ptr(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reqContent
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
package jdcloudcdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core"
|
|
||||||
jdCdnApi "github.com/jdcloud-api/jdcloud-sdk-go/services/cdn/apis"
|
|
||||||
jdCdnClient "github.com/jdcloud-api/jdcloud-sdk-go/services/cdn/client"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/jdcloud-ssl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 京东云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 京东云 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 加速域名(支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *jdCdnClient.CdnClient
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
AccessKeySecret: config.AccessKeySecret,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 查询域名配置信息
|
|
||||||
// REF: https://docs.jdcloud.com/cn/cdn/api/querydomainconfig
|
|
||||||
queryDomainConfigReq := jdCdnApi.NewQueryDomainConfigRequest(d.config.Domain)
|
|
||||||
queryDomainConfigResp, err := d.sdkClient.QueryDomainConfig(queryDomainConfigReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.QueryDomainConfig'", slog.Any("request", queryDomainConfigReq), slog.Any("response", queryDomainConfigResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.QueryDomainConfig'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传证书到 SSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置通讯协议
|
|
||||||
// REF: https://docs.jdcloud.com/cn/cdn/api/sethttptype
|
|
||||||
setHttpTypeReq := jdCdnApi.NewSetHttpTypeRequest(d.config.Domain)
|
|
||||||
setHttpTypeReq.SetHttpType("https")
|
|
||||||
setHttpTypeReq.SetCertificate(certPem)
|
|
||||||
setHttpTypeReq.SetRsaKey(privkeyPem)
|
|
||||||
setHttpTypeReq.SetCertFrom("ssl")
|
|
||||||
setHttpTypeReq.SetSslCertId(upres.CertId)
|
|
||||||
setHttpTypeReq.SetJumpType(queryDomainConfigResp.Result.HttpsJumpType)
|
|
||||||
setHttpTypeResp, err := d.sdkClient.SetHttpType(setHttpTypeReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.QueryDomainConfig'", slog.Any("request", setHttpTypeReq), slog.Any("response", setHttpTypeResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.SetHttpType'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret string) (*jdCdnClient.CdnClient, error) {
|
|
||||||
clientCredentials := jdCore.NewCredentials(accessKeyId, accessKeySecret)
|
|
||||||
client := jdCdnClient.NewCdnClient(clientCredentials)
|
|
||||||
client.SetLogger(jdCore.NewDefaultLogger(jdCore.LogWarn))
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package jdcloudlive
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core"
|
|
||||||
jdLiveApi "github.com/jdcloud-api/jdcloud-sdk-go/services/live/apis"
|
|
||||||
jdLiveClient "github.com/jdcloud-api/jdcloud-sdk-go/services/live/client"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 京东云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 京东云 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 直播播放域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *jdLiveClient.LiveClient
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 设置直播证书
|
|
||||||
// REF: https://docs.jdcloud.com/cn/live-video/api/setlivedomaincertificate
|
|
||||||
setLiveDomainCertificateReq := jdLiveApi.NewSetLiveDomainCertificateRequest(d.config.Domain, "on")
|
|
||||||
setLiveDomainCertificateReq.SetCert(certPem)
|
|
||||||
setLiveDomainCertificateReq.SetKey(privkeyPem)
|
|
||||||
setLiveDomainCertificateResp, err := d.sdkClient.SetLiveDomainCertificate(setLiveDomainCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'live.SetLiveDomainCertificate'", slog.Any("request", setLiveDomainCertificateReq), slog.Any("response", setLiveDomainCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.SetLiveDomainCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret string) (*jdLiveClient.LiveClient, error) {
|
|
||||||
clientCredentials := jdCore.NewCredentials(accessKeyId, accessKeySecret)
|
|
||||||
client := jdLiveClient.NewLiveClient(clientCredentials)
|
|
||||||
client.SetLogger(jdCore.NewDefaultLogger(jdCore.LogWarn))
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
package local
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/certutil"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/fileutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// Shell 执行环境。
|
|
||||||
// 零值时默认根据操作系统决定。
|
|
||||||
ShellEnv ShellEnvType `json:"shellEnv,omitempty"`
|
|
||||||
// 前置命令。
|
|
||||||
PreCommand string `json:"preCommand,omitempty"`
|
|
||||||
// 后置命令。
|
|
||||||
PostCommand string `json:"postCommand,omitempty"`
|
|
||||||
// 输出证书格式。
|
|
||||||
OutputFormat OutputFormatType `json:"outputFormat,omitempty"`
|
|
||||||
// 输出证书文件路径。
|
|
||||||
OutputCertPath string `json:"outputCertPath,omitempty"`
|
|
||||||
// 输出私钥文件路径。
|
|
||||||
OutputKeyPath string `json:"outputKeyPath,omitempty"`
|
|
||||||
// PFX 导出密码。
|
|
||||||
// 证书格式为 PFX 时必填。
|
|
||||||
PfxPassword string `json:"pfxPassword,omitempty"`
|
|
||||||
// JKS 别名。
|
|
||||||
// 证书格式为 JKS 时必填。
|
|
||||||
JksAlias string `json:"jksAlias,omitempty"`
|
|
||||||
// JKS 密钥密码。
|
|
||||||
// 证书格式为 JKS 时必填。
|
|
||||||
JksKeypass string `json:"jksKeypass,omitempty"`
|
|
||||||
// JKS 存储密码。
|
|
||||||
// 证书格式为 JKS 时必填。
|
|
||||||
JksStorepass string `json:"jksStorepass,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 执行前置命令
|
|
||||||
if d.config.PreCommand != "" {
|
|
||||||
stdout, stderr, err := execCommand(d.config.ShellEnv, d.config.PreCommand)
|
|
||||||
d.logger.Debug("run pre-command", slog.String("stdout", stdout), slog.String("stderr", stderr))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrapf(err, "failed to execute pre-command, stdout: %s, stderr: %s", stdout, stderr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写入证书和私钥文件
|
|
||||||
switch d.config.OutputFormat {
|
|
||||||
case OUTPUT_FORMAT_PEM:
|
|
||||||
if err := fileutil.WriteString(d.config.OutputCertPath, certPem); err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to save certificate file")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl certificate file saved", slog.String("path", d.config.OutputCertPath))
|
|
||||||
|
|
||||||
if err := fileutil.WriteString(d.config.OutputKeyPath, privkeyPem); err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to save private key file")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl private key file saved", slog.String("path", d.config.OutputKeyPath))
|
|
||||||
|
|
||||||
case OUTPUT_FORMAT_PFX:
|
|
||||||
pfxData, err := certutil.TransformCertificateFromPEMToPFX(certPem, privkeyPem, d.config.PfxPassword)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to transform certificate to PFX")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl certificate transformed to pfx")
|
|
||||||
|
|
||||||
if err := fileutil.Write(d.config.OutputCertPath, pfxData); err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to save certificate file")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl certificate file saved", slog.String("path", d.config.OutputCertPath))
|
|
||||||
|
|
||||||
case OUTPUT_FORMAT_JKS:
|
|
||||||
jksData, err := certutil.TransformCertificateFromPEMToJKS(certPem, privkeyPem, d.config.JksAlias, d.config.JksKeypass, d.config.JksStorepass)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to transform certificate to JKS")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl certificate transformed to jks")
|
|
||||||
|
|
||||||
if err := fileutil.Write(d.config.OutputCertPath, jksData); err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to save certificate file")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl certificate file saved", slog.String("path", d.config.OutputCertPath))
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported output format: %s", d.config.OutputFormat)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行后置命令
|
|
||||||
if d.config.PostCommand != "" {
|
|
||||||
stdout, stderr, err := execCommand(d.config.ShellEnv, d.config.PostCommand)
|
|
||||||
d.logger.Debug("run post-command", slog.String("stdout", stdout), slog.String("stderr", stderr))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrapf(err, "failed to execute post-command, stdout: %s, stderr: %s", stdout, stderr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func execCommand(shellEnv ShellEnvType, command string) (string, string, error) {
|
|
||||||
var cmd *exec.Cmd
|
|
||||||
|
|
||||||
switch shellEnv {
|
|
||||||
case SHELL_ENV_SH:
|
|
||||||
cmd = exec.Command("sh", "-c", command)
|
|
||||||
|
|
||||||
case SHELL_ENV_CMD:
|
|
||||||
cmd = exec.Command("cmd", "/C", command)
|
|
||||||
|
|
||||||
case SHELL_ENV_POWERSHELL:
|
|
||||||
cmd = exec.Command("powershell", "-Command", command)
|
|
||||||
|
|
||||||
case ShellEnvType(""):
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
cmd = exec.Command("cmd", "/C", command)
|
|
||||||
} else {
|
|
||||||
cmd = exec.Command("sh", "-c", command)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "", "", fmt.Errorf("unsupported shell env: %s", shellEnv)
|
|
||||||
}
|
|
||||||
|
|
||||||
stdoutBuf := bytes.NewBuffer(nil)
|
|
||||||
cmd.Stdout = stdoutBuf
|
|
||||||
stderrBuf := bytes.NewBuffer(nil)
|
|
||||||
cmd.Stderr = stderrBuf
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return stdoutBuf.String(), stderrBuf.String(), xerrors.Wrap(err, "failed to execute command")
|
|
||||||
}
|
|
||||||
|
|
||||||
return stdoutBuf.String(), stderrBuf.String(), nil
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
package qiniupili
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
"github.com/qiniu/go-sdk/v7/pili"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/qiniu-sslcert"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 七牛云 AccessKey。
|
|
||||||
AccessKey string `json:"accessKey"`
|
|
||||||
// 七牛云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
// 直播空间名。
|
|
||||||
Hub string `json:"hub"`
|
|
||||||
// 直播流域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *pili.Manager
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
manager := pili.NewManager(pili.ManagerConfig{AccessKey: config.AccessKey, SecretKey: config.SecretKey})
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKey: config.AccessKey,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: manager,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 CDN
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改域名证书配置
|
|
||||||
// REF: https://developer.qiniu.com/pili/9910/pili-service-sdk#66
|
|
||||||
setDomainCertReq := pili.SetDomainCertRequest{
|
|
||||||
Hub: d.config.Hub,
|
|
||||||
Domain: d.config.Domain,
|
|
||||||
CertName: upres.CertName,
|
|
||||||
}
|
|
||||||
err = d.sdkClient.SetDomainCert(context.TODO(), setDomainCertReq)
|
|
||||||
d.logger.Debug("sdk request 'pili.SetDomainCert'", slog.Any("request", setDomainCertReq))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'pili.SetDomainCert'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
package safeline
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
safelinesdk "github.com/usual2970/certimate/internal/pkg/vendors/safeline-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 雷池 URL。
|
|
||||||
ApiUrl string `json:"apiUrl"`
|
|
||||||
// 雷池 API Token。
|
|
||||||
ApiToken string `json:"apiToken"`
|
|
||||||
// 是否允许不安全的连接。
|
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
|
||||||
// 部署资源类型。
|
|
||||||
ResourceType ResourceType `json:"resourceType"`
|
|
||||||
// 证书 ID。
|
|
||||||
// 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。
|
|
||||||
CertificateId int32 `json:"certificateId,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *safelinesdk.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiToken, config.AllowInsecureConnections)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 根据部署资源类型决定部署方式
|
|
||||||
switch d.config.ResourceType {
|
|
||||||
case RESOURCE_TYPE_CERTIFICATE:
|
|
||||||
if err := d.deployToCertificate(ctx, certPem, privkeyPem); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported resource type: %s", d.config.ResourceType)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem string, privkeyPem string) error {
|
|
||||||
if d.config.CertificateId == 0 {
|
|
||||||
return errors.New("config `certificateId` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新证书
|
|
||||||
updateCertificateReq := &safelinesdk.UpdateCertificateRequest{
|
|
||||||
Id: d.config.CertificateId,
|
|
||||||
Type: 2,
|
|
||||||
Manual: &safelinesdk.UpdateCertificateRequestBodyManul{
|
|
||||||
Crt: certPem,
|
|
||||||
Key: privkeyPem,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'safeline.UpdateCertificate'", slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'safeline.UpdateCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiToken string, allowInsecure bool) (*safelinesdk.Client, error) {
|
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
|
||||||
return nil, errors.New("invalid safeline api url")
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiToken == "" {
|
|
||||||
return nil, errors.New("invalid safeline api token")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := safelinesdk.NewClient(apiUrl, apiToken)
|
|
||||||
if allowInsecure {
|
|
||||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
package ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
"github.com/pkg/sftp"
|
|
||||||
"github.com/povsister/scp"
|
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/certutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// SSH 主机。
|
|
||||||
// 零值时默认为 "localhost"。
|
|
||||||
SshHost string `json:"sshHost,omitempty"`
|
|
||||||
// SSH 端口。
|
|
||||||
// 零值时默认为 22。
|
|
||||||
SshPort int32 `json:"sshPort,omitempty"`
|
|
||||||
// SSH 登录用户名。
|
|
||||||
SshUsername string `json:"sshUsername,omitempty"`
|
|
||||||
// SSH 登录密码。
|
|
||||||
SshPassword string `json:"sshPassword,omitempty"`
|
|
||||||
// SSH 登录私钥。
|
|
||||||
SshKey string `json:"sshKey,omitempty"`
|
|
||||||
// SSH 登录私钥口令。
|
|
||||||
SshKeyPassphrase string `json:"sshKeyPassphrase,omitempty"`
|
|
||||||
// 是否回退使用 SCP。
|
|
||||||
UseSCP bool `json:"useSCP,omitempty"`
|
|
||||||
// 前置命令。
|
|
||||||
PreCommand string `json:"preCommand,omitempty"`
|
|
||||||
// 后置命令。
|
|
||||||
PostCommand string `json:"postCommand,omitempty"`
|
|
||||||
// 输出证书格式。
|
|
||||||
OutputFormat OutputFormatType `json:"outputFormat,omitempty"`
|
|
||||||
// 输出证书文件路径。
|
|
||||||
OutputCertPath string `json:"outputCertPath,omitempty"`
|
|
||||||
// 输出私钥文件路径。
|
|
||||||
OutputKeyPath string `json:"outputKeyPath,omitempty"`
|
|
||||||
// PFX 导出密码。
|
|
||||||
// 证书格式为 PFX 时必填。
|
|
||||||
PfxPassword string `json:"pfxPassword,omitempty"`
|
|
||||||
// JKS 别名。
|
|
||||||
// 证书格式为 JKS 时必填。
|
|
||||||
JksAlias string `json:"jksAlias,omitempty"`
|
|
||||||
// JKS 密钥密码。
|
|
||||||
// 证书格式为 JKS 时必填。
|
|
||||||
JksKeypass string `json:"jksKeypass,omitempty"`
|
|
||||||
// JKS 存储密码。
|
|
||||||
// 证书格式为 JKS 时必填。
|
|
||||||
JksStorepass string `json:"jksStorepass,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 连接
|
|
||||||
client, err := createSshClient(
|
|
||||||
d.config.SshHost,
|
|
||||||
d.config.SshPort,
|
|
||||||
d.config.SshUsername,
|
|
||||||
d.config.SshPassword,
|
|
||||||
d.config.SshKey,
|
|
||||||
d.config.SshKeyPassphrase,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssh client")
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
|
|
||||||
d.logger.Info("ssh connected")
|
|
||||||
|
|
||||||
// 执行前置命令
|
|
||||||
if d.config.PreCommand != "" {
|
|
||||||
stdout, stderr, err := execSshCommand(client, d.config.PreCommand)
|
|
||||||
d.logger.Debug("run pre-command", slog.String("stdout", stdout), slog.String("stderr", stderr))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrapf(err, "failed to execute pre-command: stdout: %s, stderr: %s", stdout, stderr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传证书和私钥文件
|
|
||||||
switch d.config.OutputFormat {
|
|
||||||
case OUTPUT_FORMAT_PEM:
|
|
||||||
if err := writeFileString(client, d.config.UseSCP, d.config.OutputCertPath, certPem); err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl certificate file uploaded", slog.String("path", d.config.OutputCertPath))
|
|
||||||
|
|
||||||
if err := writeFileString(client, d.config.UseSCP, d.config.OutputKeyPath, privkeyPem); err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload private key file")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl private key file uploaded", slog.String("path", d.config.OutputKeyPath))
|
|
||||||
|
|
||||||
case OUTPUT_FORMAT_PFX:
|
|
||||||
pfxData, err := certutil.TransformCertificateFromPEMToPFX(certPem, privkeyPem, d.config.PfxPassword)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to transform certificate to PFX")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl certificate transformed to pfx")
|
|
||||||
|
|
||||||
if err := writeFile(client, d.config.UseSCP, d.config.OutputCertPath, pfxData); err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl certificate file uploaded", slog.String("path", d.config.OutputCertPath))
|
|
||||||
|
|
||||||
case OUTPUT_FORMAT_JKS:
|
|
||||||
jksData, err := certutil.TransformCertificateFromPEMToJKS(certPem, privkeyPem, d.config.JksAlias, d.config.JksKeypass, d.config.JksStorepass)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to transform certificate to JKS")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl certificate transformed to jks")
|
|
||||||
|
|
||||||
if err := writeFile(client, d.config.UseSCP, d.config.OutputCertPath, jksData); err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
}
|
|
||||||
d.logger.Info("ssl certificate file uploaded", slog.String("path", d.config.OutputCertPath))
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported output format: %s", d.config.OutputFormat)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行后置命令
|
|
||||||
if d.config.PostCommand != "" {
|
|
||||||
stdout, stderr, err := execSshCommand(client, d.config.PostCommand)
|
|
||||||
d.logger.Debug("run post-command", slog.String("stdout", stdout), slog.String("stderr", stderr))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrapf(err, "failed to execute post-command, stdout: %s, stderr: %s", stdout, stderr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSshClient(host string, port int32, username string, password string, key string, keyPassphrase string) (*ssh.Client, error) {
|
|
||||||
if host == "" {
|
|
||||||
host = "localhost"
|
|
||||||
}
|
|
||||||
|
|
||||||
if port == 0 {
|
|
||||||
port = 22
|
|
||||||
}
|
|
||||||
|
|
||||||
var authMethod ssh.AuthMethod
|
|
||||||
if key != "" {
|
|
||||||
var signer ssh.Signer
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if keyPassphrase != "" {
|
|
||||||
signer, err = ssh.ParsePrivateKeyWithPassphrase([]byte(key), []byte(keyPassphrase))
|
|
||||||
} else {
|
|
||||||
signer, err = ssh.ParsePrivateKey([]byte(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
authMethod = ssh.PublicKeys(signer)
|
|
||||||
} else {
|
|
||||||
authMethod = ssh.Password(password)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), &ssh.ClientConfig{
|
|
||||||
User: username,
|
|
||||||
Auth: []ssh.AuthMethod{authMethod},
|
|
||||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func execSshCommand(sshCli *ssh.Client, command string) (string, string, error) {
|
|
||||||
session, err := sshCli.NewSession()
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
defer session.Close()
|
|
||||||
|
|
||||||
stdoutBuf := bytes.NewBuffer(nil)
|
|
||||||
session.Stdout = stdoutBuf
|
|
||||||
stderrBuf := bytes.NewBuffer(nil)
|
|
||||||
session.Stderr = stderrBuf
|
|
||||||
err = session.Run(command)
|
|
||||||
if err != nil {
|
|
||||||
return stdoutBuf.String(), stderrBuf.String(), xerrors.Wrap(err, "failed to execute ssh command")
|
|
||||||
}
|
|
||||||
|
|
||||||
return stdoutBuf.String(), stderrBuf.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFileString(sshCli *ssh.Client, useSCP bool, path string, content string) error {
|
|
||||||
if useSCP {
|
|
||||||
return writeFileStringWithSCP(sshCli, path, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
return writeFileStringWithSFTP(sshCli, path, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFile(sshCli *ssh.Client, useSCP bool, path string, data []byte) error {
|
|
||||||
if useSCP {
|
|
||||||
return writeFileWithSCP(sshCli, path, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return writeFileWithSFTP(sshCli, path, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFileStringWithSCP(sshCli *ssh.Client, path string, content string) error {
|
|
||||||
return writeFileWithSCP(sshCli, path, []byte(content))
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFileWithSCP(sshCli *ssh.Client, path string, data []byte) error {
|
|
||||||
scpCli, err := scp.NewClientFromExistingSSH(sshCli, &scp.ClientOption{})
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to create scp client")
|
|
||||||
}
|
|
||||||
defer scpCli.Close()
|
|
||||||
|
|
||||||
reader := bytes.NewReader(data)
|
|
||||||
err = scpCli.CopyToRemote(reader, path, &scp.FileTransferOption{})
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to write to remote file")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFileStringWithSFTP(sshCli *ssh.Client, path string, content string) error {
|
|
||||||
return writeFileWithSFTP(sshCli, path, []byte(content))
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFileWithSFTP(sshCli *ssh.Client, path string, data []byte) error {
|
|
||||||
sftpCli, err := sftp.NewClient(sshCli)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to create sftp client")
|
|
||||||
}
|
|
||||||
defer sftpCli.Close()
|
|
||||||
|
|
||||||
if err := sftpCli.MkdirAll(filepath.Dir(path)); err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to create remote directory")
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := sftpCli.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to open remote file")
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
_, err = file.Write(data)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to write to remote file")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
package tencentcloudcdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
tcCdn "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn/v20180606"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
|
||||||
tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
|
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 腾讯云 SecretId。
|
|
||||||
SecretId string `json:"secretId"`
|
|
||||||
// 腾讯云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
// 加速域名(支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClients *wSdkClients
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
type wSdkClients struct {
|
|
||||||
ssl *tcSsl.Client
|
|
||||||
cdn *tcCdn.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
clients, err := createSdkClients(config.SecretId, config.SecretKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk clients")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
SecretId: config.SecretId,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClients: clients,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 SSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取待部署的 CDN 实例
|
|
||||||
// 如果是泛域名,根据证书匹配 CDN 实例
|
|
||||||
instanceIds := make([]string, 0)
|
|
||||||
if strings.HasPrefix(d.config.Domain, "*.") {
|
|
||||||
domains, err := d.getDomainsByCertificateId(upres.CertId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
instanceIds = domains
|
|
||||||
} else {
|
|
||||||
instanceIds = append(instanceIds, d.config.Domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跳过已部署的 CDN 实例
|
|
||||||
if len(instanceIds) > 0 {
|
|
||||||
deployedDomains, err := d.getDeployedDomainsByCertificateId(upres.CertId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
temp := make([]string, 0)
|
|
||||||
for _, instanceId := range instanceIds {
|
|
||||||
if !slices.Contains(deployedDomains, instanceId) {
|
|
||||||
temp = append(temp, instanceId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
instanceIds = temp
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(instanceIds) == 0 {
|
|
||||||
d.logger.Info("no cdn instances to deploy")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("found cdn instances to deploy", slog.Any("instanceIds", instanceIds))
|
|
||||||
|
|
||||||
// 证书部署到 CDN 实例
|
|
||||||
// REF: https://cloud.tencent.com/document/product/400/91667
|
|
||||||
deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest()
|
|
||||||
deployCertificateInstanceReq.CertificateId = common.StringPtr(upres.CertId)
|
|
||||||
deployCertificateInstanceReq.ResourceType = common.StringPtr("cdn")
|
|
||||||
deployCertificateInstanceReq.Status = common.Int64Ptr(1)
|
|
||||||
deployCertificateInstanceReq.InstanceIdList = common.StringPtrs(instanceIds)
|
|
||||||
deployCertificateInstanceResp, err := d.sdkClients.ssl.DeployCertificateInstance(deployCertificateInstanceReq)
|
|
||||||
d.logger.Debug("sdk request 'ssl.DeployCertificateInstance'", slog.Any("request", deployCertificateInstanceReq), slog.Any("response", deployCertificateInstanceResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) getDomainsByCertificateId(cloudCertId string) ([]string, error) {
|
|
||||||
// 获取证书中的可用域名
|
|
||||||
// REF: https://cloud.tencent.com/document/product/228/42491
|
|
||||||
describeCertDomainsReq := tcCdn.NewDescribeCertDomainsRequest()
|
|
||||||
describeCertDomainsReq.CertId = common.StringPtr(cloudCertId)
|
|
||||||
describeCertDomainsReq.Product = common.StringPtr("cdn")
|
|
||||||
describeCertDomainsResp, err := d.sdkClients.cdn.DescribeCertDomains(describeCertDomainsReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.DescribeCertDomains'", slog.Any("request", describeCertDomainsReq), slog.Any("response", describeCertDomainsResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeCertDomains'")
|
|
||||||
}
|
|
||||||
|
|
||||||
domains := make([]string, 0)
|
|
||||||
if describeCertDomainsResp.Response.Domains != nil {
|
|
||||||
for _, domain := range describeCertDomainsResp.Response.Domains {
|
|
||||||
domains = append(domains, *domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return domains, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) getDeployedDomainsByCertificateId(cloudCertId string) ([]string, error) {
|
|
||||||
// 根据证书查询关联 CDN 域名
|
|
||||||
// REF: https://cloud.tencent.com/document/product/400/62674
|
|
||||||
describeDeployedResourcesReq := tcSsl.NewDescribeDeployedResourcesRequest()
|
|
||||||
describeDeployedResourcesReq.CertificateIds = common.StringPtrs([]string{cloudCertId})
|
|
||||||
describeDeployedResourcesReq.ResourceType = common.StringPtr("cdn")
|
|
||||||
describeDeployedResourcesResp, err := d.sdkClients.ssl.DescribeDeployedResources(describeDeployedResourcesReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.DescribeDeployedResources'", slog.Any("request", describeDeployedResourcesReq), slog.Any("response", describeDeployedResourcesResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeDeployedResources'")
|
|
||||||
}
|
|
||||||
|
|
||||||
domains := make([]string, 0)
|
|
||||||
if describeDeployedResourcesResp.Response.DeployedResources != nil {
|
|
||||||
for _, deployedResource := range describeDeployedResourcesResp.Response.DeployedResources {
|
|
||||||
for _, resource := range deployedResource.Resources {
|
|
||||||
domains = append(domains, *resource)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return domains, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClients(secretId, secretKey string) (*wSdkClients, error) {
|
|
||||||
credential := common.NewCredential(secretId, secretKey)
|
|
||||||
|
|
||||||
sslClient, err := tcSsl.NewClient(credential, "", profile.NewClientProfile())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cdnClient, err := tcCdn.NewClient(credential, "", profile.NewClientProfile())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &wSdkClients{
|
|
||||||
ssl: sslClient,
|
|
||||||
cdn: cdnClient,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
package tencentcloudcos
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
|
||||||
tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 腾讯云 SecretId。
|
|
||||||
SecretId string `json:"secretId"`
|
|
||||||
// 腾讯云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
// 腾讯云地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 存储桶名。
|
|
||||||
Bucket string `json:"bucket"`
|
|
||||||
// 自定义域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *tcSsl.Client
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.SecretId, config.SecretKey, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
SecretId: config.SecretId,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
if d.config.Bucket == "" {
|
|
||||||
return nil, errors.New("config `bucket` is required")
|
|
||||||
}
|
|
||||||
if d.config.Domain == "" {
|
|
||||||
return nil, errors.New("config `domain` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传证书到 SSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 证书部署到 COS 实例
|
|
||||||
// REF: https://cloud.tencent.com/document/product/400/91667
|
|
||||||
deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest()
|
|
||||||
deployCertificateInstanceReq.CertificateId = common.StringPtr(upres.CertId)
|
|
||||||
deployCertificateInstanceReq.ResourceType = common.StringPtr("cos")
|
|
||||||
deployCertificateInstanceReq.Status = common.Int64Ptr(1)
|
|
||||||
deployCertificateInstanceReq.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s#%s#%s", d.config.Region, d.config.Bucket, d.config.Domain)})
|
|
||||||
deployCertificateInstanceResp, err := d.sdkClient.DeployCertificateInstance(deployCertificateInstanceReq)
|
|
||||||
d.logger.Debug("sdk request 'ssl.DeployCertificateInstance'", slog.Any("request", deployCertificateInstanceReq), slog.Any("response", deployCertificateInstanceResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(secretId, secretKey, region string) (*tcSsl.Client, error) {
|
|
||||||
credential := common.NewCredential(secretId, secretKey)
|
|
||||||
client, err := tcSsl.NewClient(credential, region, profile.NewClientProfile())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
package tencentcloudcss
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
|
||||||
tcLive "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live/v20180801"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 腾讯云 SecretId。
|
|
||||||
SecretId string `json:"secretId"`
|
|
||||||
// 腾讯云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
// 直播播放域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *tcLive.Client
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.SecretId, config.SecretKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
SecretId: config.SecretId,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 SSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绑定证书对应的播放域名
|
|
||||||
// REF: https://cloud.tencent.com/document/product/267/78655
|
|
||||||
modifyLiveDomainCertBindingsReq := &tcLive.ModifyLiveDomainCertBindingsRequest{
|
|
||||||
DomainInfos: []*tcLive.LiveCertDomainInfo{
|
|
||||||
{
|
|
||||||
DomainName: common.StringPtr(d.config.Domain),
|
|
||||||
Status: common.Int64Ptr(1),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CloudCertId: common.StringPtr(upres.CertId),
|
|
||||||
}
|
|
||||||
modifyLiveDomainCertBindingsResp, err := d.sdkClient.ModifyLiveDomainCertBindings(modifyLiveDomainCertBindingsReq)
|
|
||||||
d.logger.Debug("sdk request 'live.ModifyLiveDomainCertBindings'", slog.Any("request", modifyLiveDomainCertBindingsReq), slog.Any("response", modifyLiveDomainCertBindingsResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.ModifyLiveDomainCertBindings'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(secretId, secretKey string) (*tcLive.Client, error) {
|
|
||||||
credential := common.NewCredential(secretId, secretKey)
|
|
||||||
|
|
||||||
client, err := tcLive.NewClient(credential, "", profile.NewClientProfile())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
package tencentcloudecdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
tcCdn "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn/v20180606"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
|
||||||
tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 腾讯云 SecretId。
|
|
||||||
SecretId string `json:"secretId"`
|
|
||||||
// 腾讯云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
// 加速域名(支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClients *wSdkClients
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
type wSdkClients struct {
|
|
||||||
ssl *tcSsl.Client
|
|
||||||
cdn *tcCdn.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
clients, err := createSdkClients(config.SecretId, config.SecretKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk clients")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
SecretId: config.SecretId,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClients: clients,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 SSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取待部署的 CDN 实例
|
|
||||||
// 如果是泛域名,根据证书匹配 CDN 实例
|
|
||||||
instanceIds := make([]string, 0)
|
|
||||||
if strings.HasPrefix(d.config.Domain, "*.") {
|
|
||||||
domains, err := d.getDomainsByCertificateId(upres.CertId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
instanceIds = domains
|
|
||||||
} else {
|
|
||||||
instanceIds = append(instanceIds, d.config.Domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(instanceIds) == 0 {
|
|
||||||
d.logger.Info("no ecdn instances to deploy")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("found ecdn instances to deploy", slog.Any("instanceIds", instanceIds))
|
|
||||||
|
|
||||||
// 证书部署到 ECDN 实例
|
|
||||||
// REF: https://cloud.tencent.com/document/product/400/91667
|
|
||||||
deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest()
|
|
||||||
deployCertificateInstanceReq.CertificateId = common.StringPtr(upres.CertId)
|
|
||||||
deployCertificateInstanceReq.ResourceType = common.StringPtr("ecdn")
|
|
||||||
deployCertificateInstanceReq.Status = common.Int64Ptr(1)
|
|
||||||
deployCertificateInstanceReq.InstanceIdList = common.StringPtrs(instanceIds)
|
|
||||||
deployCertificateInstanceResp, err := d.sdkClients.ssl.DeployCertificateInstance(deployCertificateInstanceReq)
|
|
||||||
d.logger.Debug("sdk request 'ssl.DeployCertificateInstance'", slog.Any("request", deployCertificateInstanceReq), slog.Any("response", deployCertificateInstanceResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) getDomainsByCertificateId(cloudCertId string) ([]string, error) {
|
|
||||||
// 获取证书中的可用域名
|
|
||||||
// REF: https://cloud.tencent.com/document/product/228/42491
|
|
||||||
describeCertDomainsReq := tcCdn.NewDescribeCertDomainsRequest()
|
|
||||||
describeCertDomainsReq.CertId = common.StringPtr(cloudCertId)
|
|
||||||
describeCertDomainsReq.Product = common.StringPtr("ecdn")
|
|
||||||
describeCertDomainsResp, err := d.sdkClients.cdn.DescribeCertDomains(describeCertDomainsReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.DescribeCertDomains'", slog.Any("request", describeCertDomainsReq), slog.Any("response", describeCertDomainsResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeCertDomains'")
|
|
||||||
}
|
|
||||||
|
|
||||||
domains := make([]string, 0)
|
|
||||||
if describeCertDomainsResp.Response.Domains != nil {
|
|
||||||
for _, domain := range describeCertDomainsResp.Response.Domains {
|
|
||||||
domains = append(domains, *domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return domains, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClients(secretId, secretKey string) (*wSdkClients, error) {
|
|
||||||
credential := common.NewCredential(secretId, secretKey)
|
|
||||||
|
|
||||||
sslClient, err := tcSsl.NewClient(credential, "", profile.NewClientProfile())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cdnClient, err := tcCdn.NewClient(credential, "", profile.NewClientProfile())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &wSdkClients{
|
|
||||||
ssl: sslClient,
|
|
||||||
cdn: cdnClient,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
package tencentcloudeo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
|
||||||
tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
|
|
||||||
tcTeo "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo/v20220901"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 腾讯云 SecretId。
|
|
||||||
SecretId string `json:"secretId"`
|
|
||||||
// 腾讯云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
// 站点 ID。
|
|
||||||
ZoneId string `json:"zoneId"`
|
|
||||||
// 加速域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClients *wSdkClients
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
type wSdkClients struct {
|
|
||||||
ssl *tcSsl.Client
|
|
||||||
teo *tcTeo.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
clients, err := createSdkClients(config.SecretId, config.SecretKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk clients")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
SecretId: config.SecretId,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClients: clients,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
if d.config.ZoneId == "" {
|
|
||||||
return nil, errors.New("config `zoneId` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传证书到 SSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 配置域名证书
|
|
||||||
// REF: https://cloud.tencent.com/document/product/1552/80764
|
|
||||||
modifyHostsCertificateReq := tcTeo.NewModifyHostsCertificateRequest()
|
|
||||||
modifyHostsCertificateReq.ZoneId = common.StringPtr(d.config.ZoneId)
|
|
||||||
modifyHostsCertificateReq.Mode = common.StringPtr("sslcert")
|
|
||||||
modifyHostsCertificateReq.Hosts = common.StringPtrs([]string{d.config.Domain})
|
|
||||||
modifyHostsCertificateReq.ServerCertInfo = []*tcTeo.ServerCertInfo{{CertId: common.StringPtr(upres.CertId)}}
|
|
||||||
modifyHostsCertificateResp, err := d.sdkClients.teo.ModifyHostsCertificate(modifyHostsCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'teo.ModifyHostsCertificate'", slog.Any("request", modifyHostsCertificateReq), slog.Any("response", modifyHostsCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'teo.ModifyHostsCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClients(secretId, secretKey string) (*wSdkClients, error) {
|
|
||||||
credential := common.NewCredential(secretId, secretKey)
|
|
||||||
|
|
||||||
sslClient, err := tcSsl.NewClient(credential, "", profile.NewClientProfile())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
teoClient, err := tcTeo.NewClient(credential, "", profile.NewClientProfile())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &wSdkClients{
|
|
||||||
ssl: sslClient,
|
|
||||||
teo: teoClient,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
package tencentcloudscf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
|
||||||
tcScf "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf/v20180416"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 腾讯云 SecretId。
|
|
||||||
SecretId string `json:"secretId"`
|
|
||||||
// 腾讯云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
// 腾讯云地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 自定义域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *tcScf.Client
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.SecretId, config.SecretKey, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
SecretId: config.SecretId,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 查看云函数自定义域名详情
|
|
||||||
// REF: https://cloud.tencent.com/document/product/583/111924
|
|
||||||
getCustomDomainReq := tcScf.NewGetCustomDomainRequest()
|
|
||||||
getCustomDomainReq.Domain = common.StringPtr(d.config.Domain)
|
|
||||||
getCustomDomainResp, err := d.sdkClient.GetCustomDomain(getCustomDomainReq)
|
|
||||||
d.logger.Debug("sdk request 'scf.GetCustomDomain'", slog.Any("request", getCustomDomainReq), slog.Any("response", getCustomDomainResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'scf.GetCustomDomain'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传证书到 SSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新云函数自定义域名
|
|
||||||
// REF: https://cloud.tencent.com/document/product/583/111922
|
|
||||||
updateCustomDomainReq := tcScf.NewUpdateCustomDomainRequest()
|
|
||||||
updateCustomDomainReq.Domain = common.StringPtr(d.config.Domain)
|
|
||||||
updateCustomDomainReq.CertConfig = &tcScf.CertConf{
|
|
||||||
CertificateId: common.StringPtr(upres.CertId),
|
|
||||||
}
|
|
||||||
updateCustomDomainReq.Protocol = getCustomDomainResp.Response.Protocol
|
|
||||||
updateCustomDomainResp, err := d.sdkClient.UpdateCustomDomain(updateCustomDomainReq)
|
|
||||||
d.logger.Debug("sdk request 'scf.UpdateCustomDomain'", slog.Any("request", updateCustomDomainReq), slog.Any("response", updateCustomDomainResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'scf.UpdateCustomDomain'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(secretId, secretKey, region string) (*tcScf.Client, error) {
|
|
||||||
credential := common.NewCredential(secretId, secretKey)
|
|
||||||
client, err := tcScf.NewClient(credential, region, profile.NewClientProfile())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package tencentcloudssl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 腾讯云 SecretId。
|
|
||||||
SecretId string `json:"secretId"`
|
|
||||||
// 腾讯云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
SecretId: config.SecretId,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 SSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
package tencentcloudvod
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
|
||||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
|
||||||
tcVod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod/v20180717"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 腾讯云 SecretId。
|
|
||||||
SecretId string `json:"secretId"`
|
|
||||||
// 腾讯云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
// 点播应用 ID。
|
|
||||||
SubAppId int64 `json:"subAppId"`
|
|
||||||
// 点播加速域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *tcVod.Client
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.SecretId, config.SecretKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
SecretId: config.SecretId,
|
|
||||||
SecretKey: config.SecretKey,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 SSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置点播域名 HTTPS 证书
|
|
||||||
// REF: https://cloud.tencent.com/document/api/266/102015
|
|
||||||
setVodDomainCertificateReq := tcVod.NewSetVodDomainCertificateRequest()
|
|
||||||
setVodDomainCertificateReq.Domain = common.StringPtr(d.config.Domain)
|
|
||||||
setVodDomainCertificateReq.Operation = common.StringPtr("Set")
|
|
||||||
setVodDomainCertificateReq.CertID = common.StringPtr(upres.CertId)
|
|
||||||
if d.config.SubAppId != 0 {
|
|
||||||
setVodDomainCertificateReq.SubAppId = common.Uint64Ptr(uint64(d.config.SubAppId))
|
|
||||||
}
|
|
||||||
setVodDomainCertificateResp, err := d.sdkClient.SetVodDomainCertificate(setVodDomainCertificateReq)
|
|
||||||
d.logger.Debug("sdk request 'vod.SetVodDomainCertificate'", slog.Any("request", setVodDomainCertificateReq), slog.Any("response", setVodDomainCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'vod.SetVodDomainCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(secretId, secretKey string) (*tcVod.Client, error) {
|
|
||||||
credential := common.NewCredential(secretId, secretKey)
|
|
||||||
client, err := tcVod.NewClient(credential, "", profile.NewClientProfile())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
package uclouducdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
uCdn "github.com/ucloud/ucloud-sdk-go/services/ucdn"
|
|
||||||
usdk "github.com/ucloud/ucloud-sdk-go/ucloud"
|
|
||||||
uAuth "github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ucloud-ussl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 优刻得 API 私钥。
|
|
||||||
PrivateKey string `json:"privateKey"`
|
|
||||||
// 优刻得 API 公钥。
|
|
||||||
PublicKey string `json:"publicKey"`
|
|
||||||
// 优刻得项目 ID。
|
|
||||||
ProjectId string `json:"projectId,omitempty"`
|
|
||||||
// 加速域名 ID。
|
|
||||||
DomainId string `json:"domainId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *uCdn.UCDNClient
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.PrivateKey, config.PublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
PrivateKey: config.PrivateKey,
|
|
||||||
PublicKey: config.PublicKey,
|
|
||||||
ProjectId: config.ProjectId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 USSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取加速域名配置
|
|
||||||
// REF: https://docs.ucloud.cn/api/ucdn-api/get_ucdn_domain_config
|
|
||||||
getUcdnDomainConfigReq := d.sdkClient.NewGetUcdnDomainConfigRequest()
|
|
||||||
getUcdnDomainConfigReq.DomainId = []string{d.config.DomainId}
|
|
||||||
if d.config.ProjectId != "" {
|
|
||||||
getUcdnDomainConfigReq.ProjectId = usdk.String(d.config.ProjectId)
|
|
||||||
}
|
|
||||||
getUcdnDomainConfigResp, err := d.sdkClient.GetUcdnDomainConfig(getUcdnDomainConfigReq)
|
|
||||||
d.logger.Debug("sdk request 'ucdn.GetUcdnDomainConfig'", slog.Any("request", getUcdnDomainConfigReq), slog.Any("response", getUcdnDomainConfigResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ucdn.GetUcdnDomainConfig'")
|
|
||||||
} else if len(getUcdnDomainConfigResp.DomainList) == 0 {
|
|
||||||
return nil, errors.New("no domain found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新 HTTPS 加速配置
|
|
||||||
// REF: https://docs.ucloud.cn/api/ucdn-api/update_ucdn_domain_https_config_v2
|
|
||||||
certId, _ := strconv.Atoi(upres.CertId)
|
|
||||||
updateUcdnDomainHttpsConfigV2Req := d.sdkClient.NewUpdateUcdnDomainHttpsConfigV2Request()
|
|
||||||
updateUcdnDomainHttpsConfigV2Req.DomainId = usdk.String(d.config.DomainId)
|
|
||||||
updateUcdnDomainHttpsConfigV2Req.HttpsStatusCn = usdk.String(getUcdnDomainConfigResp.DomainList[0].HttpsStatusCn)
|
|
||||||
updateUcdnDomainHttpsConfigV2Req.HttpsStatusAbroad = usdk.String(getUcdnDomainConfigResp.DomainList[0].HttpsStatusAbroad)
|
|
||||||
updateUcdnDomainHttpsConfigV2Req.HttpsStatusAbroad = usdk.String(getUcdnDomainConfigResp.DomainList[0].HttpsStatusAbroad)
|
|
||||||
updateUcdnDomainHttpsConfigV2Req.CertId = usdk.Int(certId)
|
|
||||||
updateUcdnDomainHttpsConfigV2Req.CertName = usdk.String(upres.CertName)
|
|
||||||
updateUcdnDomainHttpsConfigV2Req.CertType = usdk.String("ussl")
|
|
||||||
if d.config.ProjectId != "" {
|
|
||||||
updateUcdnDomainHttpsConfigV2Req.ProjectId = usdk.String(d.config.ProjectId)
|
|
||||||
}
|
|
||||||
updateUcdnDomainHttpsConfigV2Resp, err := d.sdkClient.UpdateUcdnDomainHttpsConfigV2(updateUcdnDomainHttpsConfigV2Req)
|
|
||||||
d.logger.Debug("sdk request 'ucdn.UpdateUcdnDomainHttpsConfigV2'", slog.Any("request", updateUcdnDomainHttpsConfigV2Req), slog.Any("response", updateUcdnDomainHttpsConfigV2Resp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ucdn.UpdateUcdnDomainHttpsConfigV2'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(privateKey, publicKey string) (*uCdn.UCDNClient, error) {
|
|
||||||
cfg := usdk.NewConfig()
|
|
||||||
|
|
||||||
credential := uAuth.NewCredential()
|
|
||||||
credential.PrivateKey = privateKey
|
|
||||||
credential.PublicKey = publicKey
|
|
||||||
|
|
||||||
client := uCdn.NewClient(&cfg, &credential)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
package ucloudus3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
usdk "github.com/ucloud/ucloud-sdk-go/ucloud"
|
|
||||||
uAuth "github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ucloud-ussl"
|
|
||||||
usdkFile "github.com/usual2970/certimate/internal/pkg/vendors/ucloud-sdk/ufile"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 优刻得 API 私钥。
|
|
||||||
PrivateKey string `json:"privateKey"`
|
|
||||||
// 优刻得 API 公钥。
|
|
||||||
PublicKey string `json:"publicKey"`
|
|
||||||
// 优刻得项目 ID。
|
|
||||||
ProjectId string `json:"projectId,omitempty"`
|
|
||||||
// 优刻得地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 存储桶名。
|
|
||||||
Bucket string `json:"bucket"`
|
|
||||||
// 自定义域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *usdkFile.UFileClient
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.PrivateKey, config.PublicKey, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
PrivateKey: config.PrivateKey,
|
|
||||||
PublicKey: config.PublicKey,
|
|
||||||
ProjectId: config.ProjectId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 USSL
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加 SSL 证书
|
|
||||||
// REF: https://docs.ucloud.cn/api/ufile-api/add_ufile_ssl_cert
|
|
||||||
addUFileSSLCertReq := d.sdkClient.NewAddUFileSSLCertRequest()
|
|
||||||
addUFileSSLCertReq.BucketName = usdk.String(d.config.Bucket)
|
|
||||||
addUFileSSLCertReq.Domain = usdk.String(d.config.Domain)
|
|
||||||
addUFileSSLCertReq.USSLId = usdk.String(upres.CertId)
|
|
||||||
addUFileSSLCertReq.CertificateName = usdk.String(upres.CertName)
|
|
||||||
if d.config.ProjectId != "" {
|
|
||||||
addUFileSSLCertReq.ProjectId = usdk.String(d.config.ProjectId)
|
|
||||||
}
|
|
||||||
addUFileSSLCertResp, err := d.sdkClient.AddUFileSSLCert(addUFileSSLCertReq)
|
|
||||||
d.logger.Debug("sdk request 'us3.AddUFileSSLCert'", slog.Any("request", addUFileSSLCertReq), slog.Any("response", addUFileSSLCertResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'us3.AddUFileSSLCert'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(privateKey, publicKey, region string) (*usdkFile.UFileClient, error) {
|
|
||||||
cfg := usdk.NewConfig()
|
|
||||||
cfg.Region = region
|
|
||||||
|
|
||||||
credential := uAuth.NewCredential()
|
|
||||||
credential.PrivateKey = privateKey
|
|
||||||
credential.PublicKey = publicKey
|
|
||||||
|
|
||||||
client := usdkFile.NewClient(&cfg, &credential)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
package volcenginecdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
veCdn "github.com/volcengine/volc-sdk-golang/service/cdn"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-cdn"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 火山引擎 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 火山引擎 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 加速域名(支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *veCdn.CDN
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := veCdn.NewInstance()
|
|
||||||
client.Client.SetAccessKey(config.AccessKeyId)
|
|
||||||
client.Client.SetSecretKey(config.AccessKeySecret)
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
AccessKeySecret: config.AccessKeySecret,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到 CDN
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
domains := make([]string, 0)
|
|
||||||
if strings.HasPrefix(d.config.Domain, "*.") {
|
|
||||||
// 获取指定证书可关联的域名
|
|
||||||
// REF: https://www.volcengine.com/docs/6454/125711
|
|
||||||
describeCertConfigReq := &veCdn.DescribeCertConfigRequest{
|
|
||||||
CertId: upres.CertId,
|
|
||||||
}
|
|
||||||
describeCertConfigResp, err := d.sdkClient.DescribeCertConfig(describeCertConfigReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.DescribeCertConfig'", slog.Any("request", describeCertConfigReq), slog.Any("response", describeCertConfigResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeCertConfig'")
|
|
||||||
}
|
|
||||||
|
|
||||||
if describeCertConfigResp.Result.CertNotConfig != nil {
|
|
||||||
for i := range describeCertConfigResp.Result.CertNotConfig {
|
|
||||||
domains = append(domains, describeCertConfigResp.Result.CertNotConfig[i].Domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if describeCertConfigResp.Result.OtherCertConfig != nil {
|
|
||||||
for i := range describeCertConfigResp.Result.OtherCertConfig {
|
|
||||||
domains = append(domains, describeCertConfigResp.Result.OtherCertConfig[i].Domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(domains) == 0 {
|
|
||||||
if len(describeCertConfigResp.Result.SpecifiedCertConfig) > 0 {
|
|
||||||
// 所有可关联的域名都配置了该证书,跳过部署
|
|
||||||
d.logger.Info("no domains to deploy")
|
|
||||||
} else {
|
|
||||||
return nil, errors.New("domain not found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
domains = append(domains, d.config.Domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(domains) > 0 {
|
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for _, domain := range domains {
|
|
||||||
// 关联证书与加速域名
|
|
||||||
// REF: https://www.volcengine.com/docs/6454/125712
|
|
||||||
batchDeployCertReq := &veCdn.BatchDeployCertRequest{
|
|
||||||
CertId: upres.CertId,
|
|
||||||
Domain: domain,
|
|
||||||
}
|
|
||||||
batchDeployCertResp, err := d.sdkClient.BatchDeployCert(batchDeployCertReq)
|
|
||||||
d.logger.Debug("sdk request 'cdn.BatchDeployCert'", slog.Any("request", batchDeployCertReq), slog.Any("response", batchDeployCertResp))
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return nil, errors.Join(errs...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
package volcengineclb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
veClb "github.com/volcengine/volcengine-go-sdk/service/clb"
|
|
||||||
ve "github.com/volcengine/volcengine-go-sdk/volcengine"
|
|
||||||
veSession "github.com/volcengine/volcengine-go-sdk/volcengine/session"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-certcenter"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 火山引擎 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 火山引擎 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 火山引擎地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 部署资源类型。
|
|
||||||
ResourceType ResourceType `json:"resourceType"`
|
|
||||||
// 负载均衡监听器 ID。
|
|
||||||
// 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。
|
|
||||||
ListenerId string `json:"listenerId,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *veClb.CLB
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
AccessKeySecret: config.AccessKeySecret,
|
|
||||||
Region: config.Region,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到证书中心
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据部署资源类型决定部署方式
|
|
||||||
switch d.config.ResourceType {
|
|
||||||
case RESOURCE_TYPE_LISTENER:
|
|
||||||
if err := d.deployToListener(ctx, upres.CertId); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported resource type: %s", d.config.ResourceType)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error {
|
|
||||||
if d.config.ListenerId == "" {
|
|
||||||
return errors.New("config `listenerId` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改监听器
|
|
||||||
// REF: https://www.volcengine.com/docs/6406/71775
|
|
||||||
modifyListenerAttributesReq := &veClb.ModifyListenerAttributesInput{
|
|
||||||
ListenerId: ve.String(d.config.ListenerId),
|
|
||||||
CertificateSource: ve.String("cert_center"),
|
|
||||||
CertCenterCertificateId: ve.String(cloudCertId),
|
|
||||||
}
|
|
||||||
modifyListenerAttributesResp, err := d.sdkClient.ModifyListenerAttributes(modifyListenerAttributesReq)
|
|
||||||
d.logger.Debug("sdk request 'clb.ModifyListenerAttributes'", slog.Any("request", modifyListenerAttributesReq), slog.Any("response", modifyListenerAttributesResp))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Wrap(err, "failed to execute sdk request 'clb.ModifyListenerAttributes'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*veClb.CLB, error) {
|
|
||||||
config := ve.NewConfig().WithRegion(region).WithAkSk(accessKeyId, accessKeySecret)
|
|
||||||
|
|
||||||
session, err := veSession.NewSession(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
client := veClb.New(session)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
package volcenginedcdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
veDcdn "github.com/volcengine/volcengine-go-sdk/service/dcdn"
|
|
||||||
ve "github.com/volcengine/volcengine-go-sdk/volcengine"
|
|
||||||
veSession "github.com/volcengine/volcengine-go-sdk/volcengine/session"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-certcenter"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 火山引擎 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 火山引擎 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 火山引擎地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 加速域名(支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *veDcdn.DCDN
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
AccessKeySecret: config.AccessKeySecret,
|
|
||||||
Region: config.Region,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
// 上传证书到证书中心
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// "*.example.com" → ".example.com",适配火山引擎 DCDN 要求的泛域名格式
|
|
||||||
domain := strings.TrimPrefix(d.config.Domain, "*")
|
|
||||||
|
|
||||||
// 绑定证书
|
|
||||||
// REF: https://www.volcengine.com/docs/6559/1250189
|
|
||||||
createCertBindReq := &veDcdn.CreateCertBindInput{
|
|
||||||
CertSource: ve.String("volc"),
|
|
||||||
CertId: ve.String(upres.CertId),
|
|
||||||
DomainNames: ve.StringSlice([]string{domain}),
|
|
||||||
}
|
|
||||||
createCertBindResp, err := d.sdkClient.CreateCertBind(createCertBindReq)
|
|
||||||
d.logger.Debug("sdk request 'dcdn.CreateCertBind'", slog.Any("request", createCertBindReq), slog.Any("response", createCertBindResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'dcdn.CreateCertBind'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*veDcdn.DCDN, error) {
|
|
||||||
if region == "" {
|
|
||||||
region = "cn-beijing" // DCDN 服务默认区域:北京
|
|
||||||
}
|
|
||||||
|
|
||||||
config := ve.NewConfig().WithRegion(region).WithAkSk(accessKeyId, accessKeySecret)
|
|
||||||
|
|
||||||
session, err := veSession.NewSession(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
client := veDcdn.New(session)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
package volcenginetos
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
veTos "github.com/volcengine/ve-tos-golang-sdk/v2/tos"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-certcenter"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// 火山引擎 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 火山引擎 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 火山引擎地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
// 存储桶名。
|
|
||||||
Bucket string `json:"bucket"`
|
|
||||||
// 自定义域名(不支持泛域名)。
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *veTos.ClientV2
|
|
||||||
sslUploader uploader.Uploader
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
AccessKeySecret: config.AccessKeySecret,
|
|
||||||
Region: config.Region,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
sslUploader: uploader,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
d.sslUploader.WithLogger(logger)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
if d.config.Bucket == "" {
|
|
||||||
return nil, errors.New("config `bucket` is required")
|
|
||||||
}
|
|
||||||
if d.config.Domain == "" {
|
|
||||||
return nil, errors.New("config `domain` is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传证书到证书中心
|
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
|
||||||
} else {
|
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置自定义域名
|
|
||||||
// REF: https://www.volcengine.com/docs/6559/1250189
|
|
||||||
putBucketCustomDomainReq := &veTos.PutBucketCustomDomainInput{
|
|
||||||
Bucket: d.config.Bucket,
|
|
||||||
Rule: veTos.CustomDomainRule{
|
|
||||||
Domain: d.config.Domain,
|
|
||||||
CertID: upres.CertId,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
putBucketCustomDomainResp, err := d.sdkClient.PutBucketCustomDomain(context.TODO(), putBucketCustomDomainReq)
|
|
||||||
d.logger.Debug("sdk request 'tos.PutBucketCustomDomain'", slog.Any("request", putBucketCustomDomainReq), slog.Any("response", putBucketCustomDomainResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'tos.PutBucketCustomDomain'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*veTos.ClientV2, error) {
|
|
||||||
endpoint := fmt.Sprintf("tos-%s.ivolces.com", region)
|
|
||||||
|
|
||||||
client, err := veTos.NewClientV2(
|
|
||||||
endpoint,
|
|
||||||
veTos.WithRegion(region),
|
|
||||||
veTos.WithCredentials(veTos.NewStaticCredentials(accessKeyId, accessKeySecret)),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
package webhook
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"encoding/json"
|
|
||||||
"log/slog"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-resty/resty/v2"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/certutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeployerConfig struct {
|
|
||||||
// Webhook URL。
|
|
||||||
WebhookUrl string `json:"webhookUrl"`
|
|
||||||
// Webhook 回调数据(JSON 格式)。
|
|
||||||
WebhookData string `json:"webhookData,omitempty"`
|
|
||||||
// 是否允许不安全的连接。
|
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeployerProvider struct {
|
|
||||||
config *DeployerConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
httpClient *resty.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := resty.New().
|
|
||||||
SetTimeout(30 * time.Second).
|
|
||||||
SetRetryCount(3).
|
|
||||||
SetRetryWaitTime(5 * time.Second)
|
|
||||||
if config.AllowInsecureConnections {
|
|
||||||
client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DeployerProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
httpClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|
||||||
if logger == nil {
|
|
||||||
d.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
|
||||||
certX509, err := certutil.ParseCertificateFromPEM(certPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to parse x509")
|
|
||||||
}
|
|
||||||
|
|
||||||
var webhookData interface{}
|
|
||||||
err = json.Unmarshal([]byte(d.config.WebhookData), &webhookData)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to unmarshall webhook data")
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceJsonValueRecursively(webhookData, "${DOMAIN}", certX509.Subject.CommonName)
|
|
||||||
replaceJsonValueRecursively(webhookData, "${DOMAINS}", strings.Join(certX509.DNSNames, ";"))
|
|
||||||
replaceJsonValueRecursively(webhookData, "${SUBJECT_ALT_NAMES}", strings.Join(certX509.DNSNames, ";"))
|
|
||||||
replaceJsonValueRecursively(webhookData, "${CERTIFICATE}", certPem)
|
|
||||||
replaceJsonValueRecursively(webhookData, "${PRIVATE_KEY}", privkeyPem)
|
|
||||||
|
|
||||||
resp, err := d.httpClient.R().
|
|
||||||
SetContext(ctx).
|
|
||||||
SetHeader("Content-Type", "application/json").
|
|
||||||
SetBody(webhookData).
|
|
||||||
Post(d.config.WebhookUrl)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to send webhook request")
|
|
||||||
} else if resp.StatusCode() != 200 {
|
|
||||||
return nil, xerrors.Errorf("unexpected webhook response status code: %d", resp.StatusCode())
|
|
||||||
}
|
|
||||||
|
|
||||||
d.logger.Debug("webhook responded", slog.Any("response", resp.String()))
|
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func replaceJsonValueRecursively(data interface{}, oldStr, newStr string) interface{} {
|
|
||||||
switch v := data.(type) {
|
|
||||||
case map[string]any:
|
|
||||||
for k, val := range v {
|
|
||||||
v[k] = replaceJsonValueRecursively(val, oldStr, newStr)
|
|
||||||
}
|
|
||||||
case []any:
|
|
||||||
for i, val := range v {
|
|
||||||
v[i] = replaceJsonValueRecursively(val, oldStr, newStr)
|
|
||||||
}
|
|
||||||
case string:
|
|
||||||
return strings.ReplaceAll(v, oldStr, newStr)
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package bark
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/nikoksr/notify"
|
|
||||||
"github.com/nikoksr/notify/service/bark"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NotifierConfig struct {
|
|
||||||
// Bark 服务地址。
|
|
||||||
// 零值时默认使用官方服务器。
|
|
||||||
ServerUrl string `json:"serverUrl"`
|
|
||||||
// Bark 设备密钥。
|
|
||||||
DeviceKey string `json:"deviceKey"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotifierProvider struct {
|
|
||||||
config *NotifierConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ notifier.Notifier = (*NotifierProvider)(nil)
|
|
||||||
|
|
||||||
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &NotifierProvider{
|
|
||||||
config: config,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
|
|
||||||
if logger == nil {
|
|
||||||
n.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
n.logger = logger
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
|
||||||
var srv notify.Notifier
|
|
||||||
if n.config.ServerUrl == "" {
|
|
||||||
srv = bark.New(n.config.DeviceKey)
|
|
||||||
} else {
|
|
||||||
srv = bark.NewWithServers(n.config.DeviceKey, n.config.ServerUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = srv.Send(ctx, subject, message)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ¬ifier.NotifyResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package dingtalk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/nikoksr/notify/service/dingding"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NotifierConfig struct {
|
|
||||||
// 钉钉机器人的 Token。
|
|
||||||
AccessToken string `json:"accessToken"`
|
|
||||||
// 钉钉机器人的 Secret。
|
|
||||||
Secret string `json:"secret"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotifierProvider struct {
|
|
||||||
config *NotifierConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ notifier.Notifier = (*NotifierProvider)(nil)
|
|
||||||
|
|
||||||
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &NotifierProvider{
|
|
||||||
config: config,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
|
|
||||||
if logger == nil {
|
|
||||||
n.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
n.logger = logger
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
|
||||||
srv := dingding.New(&dingding.Config{
|
|
||||||
Token: n.config.AccessToken,
|
|
||||||
Secret: n.config.Secret,
|
|
||||||
})
|
|
||||||
|
|
||||||
err = srv.Send(ctx, subject, message)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ¬ifier.NotifyResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package lark
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/nikoksr/notify/service/lark"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NotifierConfig struct {
|
|
||||||
// 飞书机器人 Webhook 地址。
|
|
||||||
WebhookUrl string `json:"webhookUrl"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotifierProvider struct {
|
|
||||||
config *NotifierConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ notifier.Notifier = (*NotifierProvider)(nil)
|
|
||||||
|
|
||||||
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &NotifierProvider{
|
|
||||||
config: config,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
|
|
||||||
if logger == nil {
|
|
||||||
n.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
n.logger = logger
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
|
||||||
srv := lark.NewWebhookService(n.config.WebhookUrl)
|
|
||||||
|
|
||||||
err = srv.Send(ctx, subject, message)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ¬ifier.NotifyResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
package serverchan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
notifyHttp "github.com/nikoksr/notify/service/http"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NotifierConfig struct {
|
|
||||||
// ServerChan 服务地址。
|
|
||||||
Url string `json:"url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotifierProvider struct {
|
|
||||||
config *NotifierConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ notifier.Notifier = (*NotifierProvider)(nil)
|
|
||||||
|
|
||||||
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &NotifierProvider{
|
|
||||||
config: config,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
|
|
||||||
if logger == nil {
|
|
||||||
n.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
n.logger = logger
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
|
||||||
srv := notifyHttp.New()
|
|
||||||
|
|
||||||
srv.AddReceivers(¬ifyHttp.Webhook{
|
|
||||||
URL: n.config.Url,
|
|
||||||
Header: http.Header{},
|
|
||||||
ContentType: "application/json",
|
|
||||||
Method: http.MethodPost,
|
|
||||||
BuildPayload: func(subject, message string) (payload any) {
|
|
||||||
return map[string]string{
|
|
||||||
"text": subject,
|
|
||||||
"desp": message,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
err = srv.Send(ctx, subject, message)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ¬ifier.NotifyResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
package telegram
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/nikoksr/notify/service/telegram"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NotifierConfig struct {
|
|
||||||
// Telegram API Token。
|
|
||||||
ApiToken string `json:"apiToken"`
|
|
||||||
// Telegram Chat ID。
|
|
||||||
ChatId int64 `json:"chatId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotifierProvider struct {
|
|
||||||
config *NotifierConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ notifier.Notifier = (*NotifierProvider)(nil)
|
|
||||||
|
|
||||||
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &NotifierProvider{
|
|
||||||
config: config,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
|
|
||||||
if logger == nil {
|
|
||||||
n.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
n.logger = logger
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
|
||||||
srv, err := telegram.New(n.config.ApiToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
srv.AddReceivers(n.config.ChatId)
|
|
||||||
|
|
||||||
err = srv.Send(ctx, subject, message)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ¬ifier.NotifyResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
package webhook
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
webhook "github.com/nikoksr/notify/service/http"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NotifierConfig struct {
|
|
||||||
// Webhook URL。
|
|
||||||
Url string `json:"url"`
|
|
||||||
// 是否允许不安全的连接。
|
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotifierProvider struct {
|
|
||||||
config *NotifierConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ notifier.Notifier = (*NotifierProvider)(nil)
|
|
||||||
|
|
||||||
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &NotifierProvider{
|
|
||||||
config: config,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
|
|
||||||
if logger == nil {
|
|
||||||
n.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
n.logger = logger
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
|
||||||
srv := webhook.New()
|
|
||||||
srv.AddReceiversURLs(n.config.Url)
|
|
||||||
|
|
||||||
if n.config.AllowInsecureConnections {
|
|
||||||
tlsConfig := &tls.Config{InsecureSkipVerify: true}
|
|
||||||
transport := &http.Transport{TLSClientConfig: tlsConfig}
|
|
||||||
client := &http.Client{Transport: transport}
|
|
||||||
srv.WithClient(client)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = srv.Send(ctx, subject, message)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ¬ifier.NotifyResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package serverchan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
notifyHttp "github.com/nikoksr/notify/service/http"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NotifierConfig struct {
|
|
||||||
// 企业微信机器人 Webhook 地址。
|
|
||||||
WebhookUrl string `json:"webhookUrl"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotifierProvider struct {
|
|
||||||
config *NotifierConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ notifier.Notifier = (*NotifierProvider)(nil)
|
|
||||||
|
|
||||||
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &NotifierProvider{
|
|
||||||
config: config,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
|
|
||||||
if logger == nil {
|
|
||||||
n.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
n.logger = logger
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
|
||||||
srv := notifyHttp.New()
|
|
||||||
|
|
||||||
srv.AddReceivers(¬ifyHttp.Webhook{
|
|
||||||
URL: n.config.WebhookUrl,
|
|
||||||
Header: http.Header{},
|
|
||||||
ContentType: "application/json",
|
|
||||||
Method: http.MethodPost,
|
|
||||||
BuildPayload: func(subject, message string) (payload any) {
|
|
||||||
return map[string]any{
|
|
||||||
"msgtype": "text",
|
|
||||||
"text": map[string]string{
|
|
||||||
"content": subject + "\n\n" + message,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
err = srv.Send(ctx, subject, message)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ¬ifier.NotifyResult{}, nil
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
package onepanelssl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
opsdk "github.com/usual2970/certimate/internal/pkg/vendors/1panel-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UploaderConfig struct {
|
|
||||||
// 1Panel 地址。
|
|
||||||
ApiUrl string `json:"apiUrl"`
|
|
||||||
// 1Panel 接口密钥。
|
|
||||||
ApiKey string `json:"apiKey"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UploaderProvider struct {
|
|
||||||
config *UploaderConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *opsdk.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ uploader.Uploader = (*UploaderProvider)(nil)
|
|
||||||
|
|
||||||
func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &UploaderProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader {
|
|
||||||
if logger == nil {
|
|
||||||
u.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
u.logger = logger
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
|
||||||
// 遍历证书列表,避免重复上传
|
|
||||||
if res, err := u.getExistCert(ctx, certPem, privkeyPem); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if res != nil {
|
|
||||||
u.logger.Info("ssl certificate already exists")
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成新证书名(需符合 1Panel 命名规则)
|
|
||||||
certName := fmt.Sprintf("certimate-%d", time.Now().UnixMilli())
|
|
||||||
|
|
||||||
// 上传证书
|
|
||||||
uploadWebsiteSSLReq := &opsdk.UploadWebsiteSSLRequest{
|
|
||||||
Type: "paste",
|
|
||||||
Description: certName,
|
|
||||||
Certificate: certPem,
|
|
||||||
PrivateKey: privkeyPem,
|
|
||||||
}
|
|
||||||
uploadWebsiteSSLResp, err := u.sdkClient.UploadWebsiteSSL(uploadWebsiteSSLReq)
|
|
||||||
u.logger.Debug("sdk request '1panel.UploadWebsiteSSL'", slog.Any("request", uploadWebsiteSSLReq), slog.Any("response", uploadWebsiteSSLResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UploadWebsiteSSL'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遍历证书列表,获取刚刚上传证书 ID
|
|
||||||
if res, err := u.getExistCert(ctx, certPem, privkeyPem); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if res == nil {
|
|
||||||
return nil, fmt.Errorf("no ssl certificate found, may be upload failed (code: %d, message: %s)", uploadWebsiteSSLResp.GetCode(), uploadWebsiteSSLResp.GetMessage())
|
|
||||||
} else {
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
|
||||||
searchWebsiteSSLPageNumber := int32(1)
|
|
||||||
searchWebsiteSSLPageSize := int32(100)
|
|
||||||
for {
|
|
||||||
searchWebsiteSSLReq := &opsdk.SearchWebsiteSSLRequest{
|
|
||||||
Page: searchWebsiteSSLPageNumber,
|
|
||||||
PageSize: searchWebsiteSSLPageSize,
|
|
||||||
}
|
|
||||||
searchWebsiteSSLResp, err := u.sdkClient.SearchWebsiteSSL(searchWebsiteSSLReq)
|
|
||||||
u.logger.Debug("sdk request '1panel.SearchWebsiteSSL'", slog.Any("request", searchWebsiteSSLReq), slog.Any("response", searchWebsiteSSLResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.SearchWebsiteSSL'")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, sslItem := range searchWebsiteSSLResp.Data.Items {
|
|
||||||
if strings.TrimSpace(sslItem.PEM) == strings.TrimSpace(certPem) &&
|
|
||||||
strings.TrimSpace(sslItem.PrivateKey) == strings.TrimSpace(privkeyPem) {
|
|
||||||
// 如果已存在相同证书,直接返回
|
|
||||||
return &uploader.UploadResult{
|
|
||||||
CertId: fmt.Sprintf("%d", sslItem.ID),
|
|
||||||
CertName: sslItem.Description,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(searchWebsiteSSLResp.Data.Items) < int(searchWebsiteSSLPageSize) {
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
searchWebsiteSSLPageNumber++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiKey string) (*opsdk.Client, error) {
|
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
|
||||||
return nil, errors.New("invalid 1panel api url")
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiKey == "" {
|
|
||||||
return nil, errors.New("invalid 1panel api key")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := opsdk.NewClient(apiUrl, apiKey)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
package aliyuncas
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
alicas "github.com/alibabacloud-go/cas-20200407/v3/client"
|
|
||||||
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
|
||||||
"github.com/alibabacloud-go/tea/tea"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/certutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UploaderConfig struct {
|
|
||||||
// 阿里云 AccessKeyId。
|
|
||||||
AccessKeyId string `json:"accessKeyId"`
|
|
||||||
// 阿里云 AccessKeySecret。
|
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
|
||||||
// 阿里云地域。
|
|
||||||
Region string `json:"region"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UploaderProvider struct {
|
|
||||||
config *UploaderConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *alicas.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ uploader.Uploader = (*UploaderProvider)(nil)
|
|
||||||
|
|
||||||
func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &UploaderProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader {
|
|
||||||
if logger == nil {
|
|
||||||
u.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
u.logger = logger
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
|
||||||
// 解析证书内容
|
|
||||||
certX509, err := certutil.ParseCertificateFromPEM(certPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询证书列表,避免重复上传
|
|
||||||
// REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-listusercertificateorder
|
|
||||||
// REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-getusercertificatedetail
|
|
||||||
listUserCertificateOrderPage := int64(1)
|
|
||||||
listUserCertificateOrderLimit := int64(50)
|
|
||||||
for {
|
|
||||||
listUserCertificateOrderReq := &alicas.ListUserCertificateOrderRequest{
|
|
||||||
CurrentPage: tea.Int64(listUserCertificateOrderPage),
|
|
||||||
ShowSize: tea.Int64(listUserCertificateOrderLimit),
|
|
||||||
OrderType: tea.String("CERT"),
|
|
||||||
}
|
|
||||||
listUserCertificateOrderResp, err := u.sdkClient.ListUserCertificateOrder(listUserCertificateOrderReq)
|
|
||||||
u.logger.Debug("sdk request 'cas.ListUserCertificateOrder'", slog.Any("request", listUserCertificateOrderReq), slog.Any("response", listUserCertificateOrderResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.ListUserCertificateOrder'")
|
|
||||||
}
|
|
||||||
|
|
||||||
if listUserCertificateOrderResp.Body.CertificateOrderList != nil {
|
|
||||||
for _, certDetail := range listUserCertificateOrderResp.Body.CertificateOrderList {
|
|
||||||
if strings.EqualFold(certX509.SerialNumber.Text(16), *certDetail.SerialNo) {
|
|
||||||
getUserCertificateDetailReq := &alicas.GetUserCertificateDetailRequest{
|
|
||||||
CertId: certDetail.CertificateId,
|
|
||||||
}
|
|
||||||
getUserCertificateDetailResp, err := u.sdkClient.GetUserCertificateDetail(getUserCertificateDetailReq)
|
|
||||||
u.logger.Debug("sdk request 'cas.GetUserCertificateDetail'", slog.Any("request", getUserCertificateDetailReq), slog.Any("response", getUserCertificateDetailResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.GetUserCertificateDetail'")
|
|
||||||
}
|
|
||||||
|
|
||||||
var isSameCert bool
|
|
||||||
if *getUserCertificateDetailResp.Body.Cert == certPem {
|
|
||||||
isSameCert = true
|
|
||||||
} else {
|
|
||||||
oldCertX509, err := certutil.ParseCertificateFromPEM(*getUserCertificateDetailResp.Body.Cert)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
isSameCert = certutil.EqualCertificate(certX509, oldCertX509)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果已存在相同证书,直接返回
|
|
||||||
if isSameCert {
|
|
||||||
u.logger.Info("ssl certificate already exists")
|
|
||||||
return &uploader.UploadResult{
|
|
||||||
CertId: fmt.Sprintf("%d", tea.Int64Value(certDetail.CertificateId)),
|
|
||||||
CertName: *certDetail.Name,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if listUserCertificateOrderResp.Body.CertificateOrderList == nil || len(listUserCertificateOrderResp.Body.CertificateOrderList) < int(listUserCertificateOrderLimit) {
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
listUserCertificateOrderPage++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成新证书名(需符合阿里云命名规则)
|
|
||||||
var certId, certName string
|
|
||||||
certName = fmt.Sprintf("certimate_%d", time.Now().UnixMilli())
|
|
||||||
|
|
||||||
// 上传新证书
|
|
||||||
// REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-uploadusercertificate
|
|
||||||
uploadUserCertificateReq := &alicas.UploadUserCertificateRequest{
|
|
||||||
Name: tea.String(certName),
|
|
||||||
Cert: tea.String(certPem),
|
|
||||||
Key: tea.String(privkeyPem),
|
|
||||||
}
|
|
||||||
uploadUserCertificateResp, err := u.sdkClient.UploadUserCertificate(uploadUserCertificateReq)
|
|
||||||
u.logger.Debug("sdk request 'cas.UploadUserCertificate'", slog.Any("request", uploadUserCertificateReq), slog.Any("response", uploadUserCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.UploadUserCertificate'")
|
|
||||||
}
|
|
||||||
|
|
||||||
certId = fmt.Sprintf("%d", tea.Int64Value(uploadUserCertificateResp.Body.CertId))
|
|
||||||
return &uploader.UploadResult{
|
|
||||||
CertId: certId,
|
|
||||||
CertName: certName,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*alicas.Client, error) {
|
|
||||||
if region == "" {
|
|
||||||
region = "cn-hangzhou" // CAS 服务默认区域:华东一杭州
|
|
||||||
}
|
|
||||||
|
|
||||||
// 接入点一览 https://api.aliyun.com/product/cas
|
|
||||||
var endpoint string
|
|
||||||
switch region {
|
|
||||||
case "cn-hangzhou":
|
|
||||||
endpoint = "cas.aliyuncs.com"
|
|
||||||
default:
|
|
||||||
endpoint = fmt.Sprintf("cas.%s.aliyuncs.com", region)
|
|
||||||
}
|
|
||||||
|
|
||||||
config := &aliopen.Config{
|
|
||||||
Endpoint: tea.String(endpoint),
|
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := alicas.NewClient(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package dogecloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
dogesdk "github.com/usual2970/certimate/internal/pkg/vendors/dogecloud-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UploaderConfig struct {
|
|
||||||
// 多吉云 AccessKey。
|
|
||||||
AccessKey string `json:"accessKey"`
|
|
||||||
// 多吉云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UploaderProvider struct {
|
|
||||||
config *UploaderConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *dogesdk.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ uploader.Uploader = (*UploaderProvider)(nil)
|
|
||||||
|
|
||||||
func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKey, config.SecretKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &UploaderProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader {
|
|
||||||
if logger == nil {
|
|
||||||
u.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
u.logger = logger
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
|
||||||
// 生成新证书名(需符合多吉云命名规则)
|
|
||||||
var certId, certName string
|
|
||||||
certName = fmt.Sprintf("certimate-%d", time.Now().UnixMilli())
|
|
||||||
|
|
||||||
// 上传新证书
|
|
||||||
// REF: https://docs.dogecloud.com/cdn/api-cert-upload
|
|
||||||
uploadSslCertResp, err := u.sdkClient.UploadCdnCert(certName, certPem, privkeyPem)
|
|
||||||
u.logger.Debug("sdk request 'cdn.UploadCdnCert'", slog.Any("response", uploadSslCertResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.UploadCdnCert'")
|
|
||||||
}
|
|
||||||
|
|
||||||
certId = fmt.Sprintf("%d", uploadSslCertResp.Data.Id)
|
|
||||||
return &uploader.UploadResult{
|
|
||||||
CertId: certId,
|
|
||||||
CertName: certName,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKey, secretKey string) (*dogesdk.Client, error) {
|
|
||||||
client := dogesdk.NewClient(accessKey, secretKey)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
package gcorecdn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
gprovider "github.com/G-Core/gcorelabscdn-go/gcore/provider"
|
|
||||||
gsslcerts "github.com/G-Core/gcorelabscdn-go/sslcerts"
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
gcoresdk "github.com/usual2970/certimate/internal/pkg/vendors/gcore-sdk/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UploaderConfig struct {
|
|
||||||
// Gcore API Token。
|
|
||||||
ApiToken string `json:"apiToken"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UploaderProvider struct {
|
|
||||||
config *UploaderConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *gsslcerts.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ uploader.Uploader = (*UploaderProvider)(nil)
|
|
||||||
|
|
||||||
func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &UploaderProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader {
|
|
||||||
if logger == nil {
|
|
||||||
u.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
u.logger = logger
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
|
||||||
// 生成新证书名(需符合 Gcore 命名规则)
|
|
||||||
var certId, certName string
|
|
||||||
certName = fmt.Sprintf("certimate_%d", time.Now().UnixMilli())
|
|
||||||
|
|
||||||
// 新增证书
|
|
||||||
// REF: https://api.gcore.com/docs/cdn#tag/CA-certificates/operation/ca_certificates-add
|
|
||||||
createCertificateReq := &gsslcerts.CreateRequest{
|
|
||||||
Name: certName,
|
|
||||||
Cert: certPem,
|
|
||||||
PrivateKey: privkeyPem,
|
|
||||||
Automated: false,
|
|
||||||
ValidateRootCA: false,
|
|
||||||
}
|
|
||||||
createCertificateResp, err := u.sdkClient.Create(context.TODO(), createCertificateReq)
|
|
||||||
u.logger.Debug("sdk request 'sslcerts.Create'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'sslcerts.Create'")
|
|
||||||
}
|
|
||||||
|
|
||||||
certId = fmt.Sprintf("%d", createCertificateResp.ID)
|
|
||||||
certName = createCertificateResp.Name
|
|
||||||
return &uploader.UploadResult{
|
|
||||||
CertId: certId,
|
|
||||||
CertName: certName,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(apiToken string) (*gsslcerts.Service, error) {
|
|
||||||
if apiToken == "" {
|
|
||||||
return nil, errors.New("invalid gcore api token")
|
|
||||||
}
|
|
||||||
|
|
||||||
requester := gprovider.NewClient(
|
|
||||||
gcoresdk.BASE_URL,
|
|
||||||
gprovider.WithSigner(gcoresdk.NewAuthRequestSigner(apiToken)),
|
|
||||||
)
|
|
||||||
service := gsslcerts.NewService(requester)
|
|
||||||
return service, nil
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
package qiniusslcert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
xerrors "github.com/pkg/errors"
|
|
||||||
"github.com/qiniu/go-sdk/v7/auth"
|
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/certutil"
|
|
||||||
qiniusdk "github.com/usual2970/certimate/internal/pkg/vendors/qiniu-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UploaderConfig struct {
|
|
||||||
// 七牛云 AccessKey。
|
|
||||||
AccessKey string `json:"accessKey"`
|
|
||||||
// 七牛云 SecretKey。
|
|
||||||
SecretKey string `json:"secretKey"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UploaderProvider struct {
|
|
||||||
config *UploaderConfig
|
|
||||||
logger *slog.Logger
|
|
||||||
sdkClient *qiniusdk.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ uploader.Uploader = (*UploaderProvider)(nil)
|
|
||||||
|
|
||||||
func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
panic("config is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := createSdkClient(config.AccessKey, config.SecretKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &UploaderProvider{
|
|
||||||
config: config,
|
|
||||||
logger: slog.Default(),
|
|
||||||
sdkClient: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader {
|
|
||||||
if logger == nil {
|
|
||||||
u.logger = slog.Default()
|
|
||||||
} else {
|
|
||||||
u.logger = logger
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
|
||||||
// 解析证书内容
|
|
||||||
certX509, err := certutil.ParseCertificateFromPEM(certPem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成新证书名(需符合七牛云命名规则)
|
|
||||||
var certId, certName string
|
|
||||||
certName = fmt.Sprintf("certimate-%d", time.Now().UnixMilli())
|
|
||||||
|
|
||||||
// 上传新证书
|
|
||||||
// REF: https://developer.qiniu.com/fusion/8593/interface-related-certificate
|
|
||||||
uploadSslCertResp, err := u.sdkClient.UploadSslCert(context.TODO(), certName, certX509.Subject.CommonName, certPem, privkeyPem)
|
|
||||||
u.logger.Debug("sdk request 'cdn.UploadSslCert'", slog.Any("response", uploadSslCertResp))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.UploadSslCert'")
|
|
||||||
}
|
|
||||||
|
|
||||||
certId = uploadSslCertResp.CertID
|
|
||||||
return &uploader.UploadResult{
|
|
||||||
CertId: certId,
|
|
||||||
CertName: certName,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSdkClient(accessKey, secretKey string) (*qiniusdk.Client, error) {
|
|
||||||
if secretKey == "" {
|
|
||||||
return nil, errors.New("invalid qiniu access key")
|
|
||||||
}
|
|
||||||
|
|
||||||
if secretKey == "" {
|
|
||||||
return nil, errors.New("invalid qiniu secret key")
|
|
||||||
}
|
|
||||||
|
|
||||||
credential := auth.New(accessKey, secretKey)
|
|
||||||
client := qiniusdk.NewClient(credential)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user