Compare commits
176 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
0a73ba1a53 | ||
|
|
a4d397f24b | ||
|
|
809f231981 | ||
|
|
1499c637ee | ||
|
|
e5805a028b | ||
|
|
5cb0463cf6 | ||
|
|
12c208cad4 |
17
.github/ISSUE_TEMPLATE/1-bug_report.yml
vendored
17
.github/ISSUE_TEMPLATE/1-bug_report.yml
vendored
@@ -10,21 +10,23 @@ body:
|
|||||||
## Welcome!
|
## Welcome!
|
||||||
|
|
||||||
**在提交 Issue 之前,请确认以下事项**:
|
**在提交 Issue 之前,请确认以下事项**:
|
||||||
1. 我**确认**已尝试过使用当前最新版本,并能复现问题。
|
1. 我**确认**已尝试过使用当前最新版本,并能复现问题。由于开发者精力有限,非当前最新版本的问题将被直接关闭,感谢理解。
|
||||||
2. 我**确认**已搜索过[已有的 Issues](https://github.com/usual2970/certimate/issues)(包括已关闭的),没有类似的问题。
|
2. 我**确认**已搜索过[已有的 Issues](https://github.com/usual2970/certimate/issues)(包括已关闭的),没有类似的问题。
|
||||||
3. 我**确认**已阅读过[文档](https://docs.certimate.me/),没有类似的问题。
|
3. 我**确认**已阅读过[文档](https://docs.certimate.me/),没有类似的问题。
|
||||||
4. 请**务必**按照模板规范详细描述问题,否则 Issue 将会被直接关闭。
|
4. 请**务必**按照模板规范详细描述问题,否则 Issue 将会被直接关闭。
|
||||||
|
5. 请保持每个 Issue 只包含一个缺陷报告。如果有多个缺陷,请分别提交 Issue。
|
||||||
|
|
||||||
**Before you submit the issue, please make sure of the following checklist**:
|
**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.
|
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/usual2970/certimate/issues) (including closed ones) on GitHub and didn't find any similar.
|
2. Yes, I've searched for [existing issues](https://github.com/usual2970/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.
|
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.
|
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
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: 软件版本 / Release Version
|
label: 软件版本 / Release Version
|
||||||
description: 请提供 Certimate 的具体版本。 / Please provide the specific version of Certimate.
|
description: 请提供 Certimate 的具体版本(请不要填写 `latest` 之类的无效版本号)。 / Please provide the specific version of Certimate.
|
||||||
placeholder: (e.g. v1.0.0)
|
placeholder: (e.g. v1.0.0)
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
@@ -70,8 +72,9 @@ body:
|
|||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
- type: markdown
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
label: 贡献 / Contribution
|
||||||
请保持每个 Issue 只包含一个缺陷报告。
|
options:
|
||||||
Please limit one report per issue.
|
- label: 我乐意为此贡献代码! / I am interested in contributing to this issue!
|
||||||
|
required: false
|
||||||
|
|||||||
12
.github/ISSUE_TEMPLATE/2-feature_request.yml
vendored
12
.github/ISSUE_TEMPLATE/2-feature_request.yml
vendored
@@ -14,12 +14,14 @@ body:
|
|||||||
2. 我**确认**已搜索过[已有的 Issues](https://github.com/usual2970/certimate/issues)(包括已关闭的),没有类似的问题。
|
2. 我**确认**已搜索过[已有的 Issues](https://github.com/usual2970/certimate/issues)(包括已关闭的),没有类似的问题。
|
||||||
3. 我**确认**已阅读过[文档](https://docs.certimate.me/),没有类似的问题。
|
3. 我**确认**已阅读过[文档](https://docs.certimate.me/),没有类似的问题。
|
||||||
4. 请**务必**按照模板规范详细描述问题,否则 Issue 将会被直接关闭。
|
4. 请**务必**按照模板规范详细描述问题,否则 Issue 将会被直接关闭。
|
||||||
|
5. 请保持每个 Issue 只包含一个功能请求。如果有多个需求,请分别提交 Issue。
|
||||||
|
|
||||||
**Before you submit the issue, please make sure of the following checklist**:
|
**Before you submit the issue, please make sure of the following checklist**:
|
||||||
1. Yes, I'm using the latest release.
|
1. Yes, I'm using the latest release.
|
||||||
2. Yes, I've searched for [existing issues](https://github.com/usual2970/certimate/issues) (including closed ones) on GitHub and didn't find any similar.
|
2. Yes, I've searched for [existing issues](https://github.com/usual2970/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.
|
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.
|
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
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
@@ -38,7 +40,7 @@ body:
|
|||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 其他 / Miscellaneous
|
label: 其他 / Miscellaneous
|
||||||
description: 在此处添加关于该 Issue 的任何其他信息。 / Add any other context about the problem here.
|
description: 在此处添加关于该 Issue 的任何其他信息(新增提供商请求请补充 API 文档链接等资料)。 / Add any other context about the problem here.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
@@ -46,11 +48,5 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: 贡献 / Contribution
|
label: 贡献 / Contribution
|
||||||
options:
|
options:
|
||||||
- label: 我乐意为此贡献代码! / I am interested in contributing to this feature!
|
- label: 我乐意为此贡献代码! / I am interested in contributing to this issue!
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
请保持每个 Issue 只包含一个功能请求。
|
|
||||||
Please limit one request per issue.
|
|
||||||
|
|||||||
12
.github/ISSUE_TEMPLATE/3-questions.yml
vendored
12
.github/ISSUE_TEMPLATE/3-questions.yml
vendored
@@ -3,7 +3,7 @@ description: "遇到了困难需要求助? / Have problem in use and need help
|
|||||||
title: "简要描述你遇到的问题"
|
title: "简要描述你遇到的问题"
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
## Welcome!
|
## Welcome!
|
||||||
|
|
||||||
@@ -12,17 +12,19 @@ body:
|
|||||||
2. 我**确认**已搜索过[已有的 Issues](https://github.com/usual2970/certimate/issues)(包括已关闭的),没有类似的问题。
|
2. 我**确认**已搜索过[已有的 Issues](https://github.com/usual2970/certimate/issues)(包括已关闭的),没有类似的问题。
|
||||||
3. 我**确认**已阅读过[文档](https://docs.certimate.me/),没有类似的问题。
|
3. 我**确认**已阅读过[文档](https://docs.certimate.me/),没有类似的问题。
|
||||||
4. 请**务必**按照模板规范详细描述问题,否则 Issue 将会被直接关闭。
|
4. 请**务必**按照模板规范详细描述问题,否则 Issue 将会被直接关闭。
|
||||||
|
5. 请保持每个 Issue 只包含一个问题求助。如果有多个问题,请分别提交 Issue。
|
||||||
|
|
||||||
**Before you submit the issue, please make sure of the following checklist**:
|
**Before you submit the issue, please make sure of the following checklist**:
|
||||||
1. Yes, I'm using the latest release.
|
1. Yes, I'm using the latest release.
|
||||||
2. Yes, I've searched for [existing issues](https://github.com/usual2970/certimate/issues) (including closed ones) on GitHub and didn't find any similar.
|
2. Yes, I've searched for [existing issues](https://github.com/usual2970/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.
|
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.
|
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
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: 软件版本 / Release Version
|
label: 软件版本 / Release Version
|
||||||
description: 请提供 Certimate 的具体版本。 / Please provide the specific version of Certimate.
|
description: 请提供 Certimate 的具体版本(请不要填写 `latest` 之类的无效版本号)。 / Please provide the specific version of Certimate.
|
||||||
placeholder: (e.g. v1.0.0)
|
placeholder: (e.g. v1.0.0)
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
@@ -40,9 +42,3 @@ body:
|
|||||||
description: 在此处添加关于该问题的任何其他信息。 / Add any other context about the problem here.
|
description: 在此处添加关于该问题的任何其他信息。 / Add any other context about the problem here.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
请保持每个 Issue 只包含一个问题求助。
|
|
||||||
Please limit one question per issue.
|
|
||||||
|
|||||||
23
.github/workflows/release.yml
vendored
23
.github/workflows/release.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Base Build
|
name: Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -22,16 +22,31 @@ jobs:
|
|||||||
- 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: Install upx (optional)
|
||||||
|
# run: |
|
||||||
|
# sudo apt-get update
|
||||||
|
# sudo apt-get install -y upx
|
||||||
|
|
||||||
- name: Build WebUI
|
- name: Build WebUI
|
||||||
run: npm --prefix=./ui ci && npm --prefix=./ui run build
|
run: |
|
||||||
|
npm --prefix=./ui ci
|
||||||
|
npm --prefix=./ui run build
|
||||||
|
npm cache clean --force
|
||||||
|
rm -rf ./ui/node_modules
|
||||||
|
|
||||||
|
- name: Check disk usage
|
||||||
|
run: |
|
||||||
|
df -h
|
||||||
|
du -sh /opt/hostedtoolcache/go/*
|
||||||
|
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v3
|
uses: goreleaser/goreleaser-action@v5
|
||||||
with:
|
with:
|
||||||
distribution: goreleaser
|
distribution: goreleaser
|
||||||
version: latest
|
version: latest
|
||||||
args: release --clean
|
args: release --clean
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
|||||||
@@ -30,13 +30,16 @@ 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
|
- CHANGELOG.md
|
||||||
- LICENSE.md
|
- LICENSE.md
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
## 前提条件
|
## 前提条件
|
||||||
|
|
||||||
- Go 1.22+ (用于修改 Go 代码)
|
- Go 1.24+ (用于修改 Go 代码)
|
||||||
- Node 20+ (用于修改 UI)
|
- Node 20+ (用于修改 UI)
|
||||||
|
|
||||||
如果还没有这样做,你可以 fork Certimate 的主仓库,并克隆到本地以便进行修改:
|
如果还没有这样做,你可以 fork Certimate 的主仓库,并克隆到本地以便进行修改:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Thank you for taking the time to improve Certimate! Below is a guide for submitt
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- Go 1.22+ (for Go code changes)
|
- Go 1.24+ (for Go code changes)
|
||||||
- Node 20+ (for Admin UI changes)
|
- 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:
|
If you haven't done so already, you can fork the Certimate repository and clone your fork to work locally:
|
||||||
|
|||||||
@@ -8,12 +8,13 @@ RUN \
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
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=webui-builder /app/ui/dist /app/ui/dist
|
||||||
RUN go build -o certimate
|
ENV CGO_ENABLED=0
|
||||||
|
RUN go build -ldflags="-s -w" -o certimate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
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:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
做个人产品或者在中小企业里负责运维的同学,会遇到要管理多个域名的情况,需要给域名申请证书。但是手动申请证书有以下缺点:
|
做个人产品或者在中小企业里负责运维的同学,会遇到要管理多个域名的情况,需要给域名申请证书。但是手动申请证书有以下缺点:
|
||||||
|
|
||||||
- 😱 麻烦:申请证书并部署到服务的流程虽不复杂,但也挺麻烦的,犹其是你有多个域名需要维护的时候。
|
- 😱 麻烦:申请证书并部署到服务的流程虽不复杂,但也挺麻烦的,尤其是你有多个域名需要维护的时候。
|
||||||
- 😭 易忘:另外当前免费证书的有效期只有 90 天,这就要求你定期的操作,增加了工作量的同时,你也很容易忘掉续期,从而导致网站访问不了。
|
- 😭 易忘:另外当前免费证书的有效期只有 90 天,这就要求你定期的操作,增加了工作量的同时,你也很容易忘掉续期,从而导致网站访问不了。
|
||||||
|
|
||||||
Certimate 就是为了解决上述问题而产生的,它具有以下优势:
|
Certimate 就是为了解决上述问题而产生的,它具有以下优势:
|
||||||
@@ -38,8 +38,8 @@ 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));
|
||||||
- 支持 70+ 部署目标(如 Kubernetes、CDN、WAF、负载均衡等,[点此查看完整清单](https://docs.certimate.me/docs/reference/providers#supported-host-providers));
|
- 支持 90+ 部署目标(如 Kubernetes、CDN、WAF、负载均衡等,[点此查看完整清单](https://docs.certimate.me/docs/reference/providers#supported-hosting-providers));
|
||||||
- 支持邮件、钉钉、飞书、企业微信、Webhook 等多种通知渠道;
|
- 支持邮件、钉钉、飞书、企业微信、Webhook 等多种通知渠道;
|
||||||
- 支持 Let's Encrypt、Buypass、Google Trust Services、SSL.com、ZeroSSL 等多种 ACME 证书颁发机构;
|
- 支持 Let's Encrypt、Buypass、Google Trust Services、SSL.com、ZeroSSL 等多种 ACME 证书颁发机构;
|
||||||
- 更多特性等待探索。
|
- 更多特性等待探索。
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ 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 70+ 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 90+ 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, Buypass, Google Trust Services,SSL.com, ZeroSSL, 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.
|
||||||
|
|||||||
129
go.mod
129
go.mod
@@ -1,69 +1,73 @@
|
|||||||
module github.com/usual2970/certimate
|
module github.com/usual2970/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.18.0
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1
|
||||||
github.com/Edgio/edgio-api v0.0.0-workspace
|
github.com/Edgio/edgio-api v0.0.0-workspace
|
||||||
github.com/G-Core/gcorelabscdn-go v1.0.29
|
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/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/cloudapi-20160714/v5 v5.7.2
|
github.com/alibabacloud-go/cloudapi-20160714/v5 v5.7.4
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7
|
||||||
github.com/alibabacloud-go/esa-20240910/v2 v2.31.1
|
github.com/alibabacloud-go/ddoscoo-20200101/v4 v4.0.0
|
||||||
github.com/alibabacloud-go/fc-20230330/v4 v4.3.4
|
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.9
|
github.com/alibabacloud-go/tea v1.3.9
|
||||||
github.com/alibabacloud-go/vod-20170321/v4 v4.8.3
|
github.com/alibabacloud-go/vod-20170321/v4 v4.8.4
|
||||||
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.1.1
|
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.3
|
github.com/aws/aws-sdk-go-v2/service/acm v1.32.0
|
||||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.3
|
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1
|
||||||
github.com/baidubce/bce-sdk-go v0.9.224
|
github.com/baidubce/bce-sdk-go v0.9.228
|
||||||
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.44
|
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-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.9
|
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.27.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.3
|
github.com/qiniu/go-sdk/v7 v7.25.3
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1136
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1155
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1143
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1166
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1147
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1173
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1143
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1120
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1172
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1169
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1138
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1166
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1136
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1164
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1147
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1170
|
||||||
github.com/ucloud/ucloud-sdk-go v0.22.33
|
github.com/ucloud/ucloud-sdk-go v0.22.41
|
||||||
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.11
|
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.12
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.204
|
github.com/volcengine/volc-sdk-golang v1.0.208
|
||||||
github.com/volcengine/volcengine-go-sdk v1.1.4
|
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.37.0
|
golang.org/x/crypto v0.38.0
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0
|
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
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -77,15 +81,17 @@ require (
|
|||||||
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/iam v1.42.0 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 // 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
|
||||||
@@ -94,19 +100,19 @@ 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.2 // 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-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.7 // 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
|
||||||
@@ -119,8 +125,7 @@ require (
|
|||||||
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
|
||||||
@@ -128,10 +133,11 @@ 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
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -145,7 +151,7 @@ require (
|
|||||||
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.100 // indirect
|
github.com/aliyun/alibaba-cloud-sdk-go v1.63.100 // indirect
|
||||||
github.com/aliyun/credentials-go v1.4.5 // 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.9
|
github.com/aws/aws-sdk-go-v2/config v1.29.9
|
||||||
@@ -168,7 +174,7 @@ require (
|
|||||||
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.5.0 // indirect
|
github.com/ganigeorgiev/fexpr v0.5.0 // indirect
|
||||||
github.com/go-jose/go-jose/v4 v4.0.5 // 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
|
||||||
@@ -188,31 +194,28 @@ require (
|
|||||||
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 // indirect
|
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/stretchr/testify v1.10.0 // indirect
|
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 // indirect
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 // indirect
|
||||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||||
golang.org/x/image v0.26.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.39.0 // indirect
|
golang.org/x/net v0.40.0 // indirect
|
||||||
golang.org/x/oauth2 v0.29.0 // indirect
|
golang.org/x/oauth2 v0.30.0 // indirect
|
||||||
golang.org/x/sync v0.13.0
|
golang.org/x/sync v0.14.0
|
||||||
golang.org/x/sys v0.32.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/term v0.31.0 // indirect
|
golang.org/x/term v0.32.0 // indirect
|
||||||
golang.org/x/text v0.24.0 // indirect
|
golang.org/x/text v0.25.0 // indirect
|
||||||
golang.org/x/time v0.11.0
|
golang.org/x/time v0.11.0
|
||||||
golang.org/x/tools v0.32.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.62.1 // 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.9.1 // indirect
|
modernc.org/memory v1.11.0 // indirect
|
||||||
modernc.org/sqlite v1.37.0 // indirect
|
modernc.org/sqlite v1.37.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/Edgio/edgio-api v0.0.0-workspace => ./internal/pkg/sdk3rd/edgio/edgio-api@v0.0.0-workspace
|
replace github.com/Edgio/edgio-api v0.0.0-workspace => ./internal/pkg/sdk3rd/edgio/edgio-api@v0.0.0-workspace
|
||||||
|
|||||||
292
go.sum
292
go.sum
@@ -36,8 +36,8 @@ filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4
|
|||||||
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.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
|
||||||
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/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g=
|
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.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4=
|
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.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
|
||||||
@@ -67,8 +67,8 @@ github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg
|
|||||||
github.com/BurntSushi/toml v1.5.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.29 h1:9jNCwzNZAgihTPe+nrsLD2c0GHjxvpuV3VEA74L5Kkk=
|
github.com/G-Core/gcorelabscdn-go v1.0.31 h1:0ulvvM3yMDQ+Q5089tLsQxffL7I4pqf2bFCurU+DeHw=
|
||||||
github.com/G-Core/gcorelabscdn-go v1.0.29/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=
|
||||||
@@ -101,8 +101,8 @@ github.com/alibabacloud-go/cas-20200407/v3 v3.0.4 h1:ngRlctbt135zoujwX0lXSv9m4h1
|
|||||||
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.2 h1:Ug50clztqiQAy5t0R9Vejibz2Xgxm1Tpw2Y6A9eAwRE=
|
github.com/alibabacloud-go/cloudapi-20160714/v5 v5.7.4 h1:SsyAoXM1R4J3I4xQdPW/rRW8cTo2KN440/4h/pGiwRQ=
|
||||||
github.com/alibabacloud-go/cloudapi-20160714/v5 v5.7.2/go.mod h1:l9Zd2FanDUO2UqHJSPnOv+cY9DVT+YXcr97zfpSHywo=
|
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=
|
||||||
@@ -112,6 +112,7 @@ 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.0.11/go.mod h1:wHxkgZT1ClZdcwEVP/pDgYK/9HucsnCfMipmJgCz4xY=
|
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.7 h1:ASXSBga98QrGMxbIThCD6jAti09gedLfvry6yJtsoBE=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 h1:ASXSBga98QrGMxbIThCD6jAti09gedLfvry6yJtsoBE=
|
||||||
@@ -122,6 +123,8 @@ github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5
|
|||||||
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=
|
||||||
@@ -129,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.31.1 h1:LACf71RxZjaystAfcWXa3EMtueVKNGxsCR3L+UihKtU=
|
github.com/alibabacloud-go/esa-20240910/v2 v2.33.0 h1:10IWxrMcF1W6/7BUJIJifrofduSG0wRFqDbRfIsR3Zw=
|
||||||
github.com/alibabacloud-go/esa-20240910/v2 v2.31.1/go.mod h1:qa4hC7W/BQOc9liuJckLnBLxILEzYjg2xhAZ+UVeUUQ=
|
github.com/alibabacloud-go/esa-20240910/v2 v2.33.0/go.mod h1:HZS5PmYJvcmH4vrJYuCvK3AnYzD9hLlO8CT0hgRyDXo=
|
||||||
github.com/alibabacloud-go/fc-20230330/v4 v4.3.4 h1:DMUkeW24CWuvChy9uOD1DzMh3ToVARCB6m3xxWBslic=
|
github.com/alibabacloud-go/fc-20230330/v4 v4.3.5 h1:nDNjVzGwkQPbQnAuxAmxvS9x8QGLph8j0ptEdZDPGBA=
|
||||||
github.com/alibabacloud-go/fc-20230330/v4 v4.3.4/go.mod h1:vEJimQ6E/e+m2z0/oXdeQWlFw/Pi/Ar6NKcMrSvcILE=
|
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=
|
||||||
@@ -163,8 +168,9 @@ github.com/alibabacloud-go/tea v1.3.9 h1:bjgt1bvdY780vz/17iWNNtbXl4A77HWntWMeaUF
|
|||||||
github.com/alibabacloud-go/tea v1.3.9/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=
|
||||||
@@ -182,10 +188,10 @@ 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.8.3 h1:IXDfINF3Wc88SKIijYgqy9HF3NiA68F97wgVeiRRwkc=
|
github.com/alibabacloud-go/vod-20170321/v4 v4.8.4 h1:MYP2xfrcud8vlWljQ4lhemNgAgi9/AUAa450n8TUXZo=
|
||||||
github.com/alibabacloud-go/vod-20170321/v4 v4.8.3/go.mod h1:5ocQ6hIc9tpGixD2iy099aOGwIgpzjT2le4Krd4aLn8=
|
github.com/alibabacloud-go/vod-20170321/v4 v4.8.4/go.mod h1:5ocQ6hIc9tpGixD2iy099aOGwIgpzjT2le4Krd4aLn8=
|
||||||
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.1.1 h1:7gHYtb2swx96tG7rflKoiFOdjKZ/W3N7azS6LT1TVFI=
|
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.1.3 h1:25tmcJxIitrk55crBGssPlqRzmFcpGVW5TEFxdUvfg0=
|
||||||
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.1.1/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.100 h1:yUkCbrSM1cWtgBfRVKMQtdt22KhDvKY7g4V+92eG9wA=
|
github.com/aliyun/alibaba-cloud-sdk-go v1.63.100 h1:yUkCbrSM1cWtgBfRVKMQtdt22KhDvKY7g4V+92eG9wA=
|
||||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.100/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=
|
||||||
@@ -194,8 +200,9 @@ github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6q
|
|||||||
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.5 h1:O76WYKgdy1oQYYiJkERjlA2dxGuvLRrzuO2ScrtGWSk=
|
|
||||||
github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
github.com/aliyun/credentials-go v1.4.5/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=
|
||||||
@@ -223,11 +230,13 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0io
|
|||||||
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.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
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.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
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.3 h1:GwlU39usxM7E1LIhZchk93PtTQm2j3jb63of/YkBd+o=
|
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.3/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.3 h1:xQnjN34F4I3a/I3Xj0g9vmD5hAqC7u5y3SC3eC6T1E8=
|
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.3/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/iam v1.42.0 h1:G6+UzGvubaet9QOh0664E9JeT+b6Zvop3AChozRqkrA=
|
||||||
|
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/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
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/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
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/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
|
||||||
@@ -243,8 +252,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.17/go.mod h1:cQnB8CUnxbMU82JvlqjK
|
|||||||
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.224 h1:z2L8alGw/y3IUHjrLRyrxrgCvMssYTjgCd7OQdb4gt0=
|
github.com/baidubce/bce-sdk-go v0.9.228 h1:XEY3/oAxXcsi7+3atib9fMI6YNE9sL5qo+WMZ+iqmNE=
|
||||||
github.com/baidubce/bce-sdk-go v0.9.224/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=
|
||||||
@@ -252,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.44 h1:men5pKZNho+cw9/YU7TFerTspS3lKayS64zctl/D7Fk=
|
github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
|
||||||
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.44/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=
|
||||||
@@ -295,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=
|
||||||
@@ -305,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=
|
||||||
@@ -330,8 +347,8 @@ 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.5.0 h1:XA9JxtTE/Xm+g/JFI6RfZEHSiQlk+1glLvRK1Lpv/Tk=
|
github.com/ganigeorgiev/fexpr v0.5.0 h1:XA9JxtTE/Xm+g/JFI6RfZEHSiQlk+1glLvRK1Lpv/Tk=
|
||||||
github.com/ganigeorgiev/fexpr v0.5.0/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
github.com/ganigeorgiev/fexpr v0.5.0/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
||||||
@@ -348,8 +365,8 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||||||
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=
|
||||||
@@ -388,8 +405,8 @@ 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=
|
||||||
@@ -435,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=
|
||||||
@@ -458,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=
|
||||||
@@ -492,8 +506,14 @@ 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=
|
||||||
@@ -527,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=
|
||||||
@@ -544,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=
|
||||||
@@ -574,6 +594,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
|||||||
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=
|
||||||
@@ -600,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=
|
||||||
@@ -654,8 +680,6 @@ 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/nikoksr/notify v1.3.0/go.mod h1:Xor2hMmkvrCfkCKvXGbcrESez4brac2zQjhd6U2BbeM=
|
|
||||||
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 h1:ouZ2JWDl8IW5k1qugYbmpbmW8hn85Ig6buSMBRlz3KI=
|
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 h1:ouZ2JWDl8IW5k1qugYbmpbmW8hn85Ig6buSMBRlz3KI=
|
||||||
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3/go.mod h1:ZwadWt7mVhMHMbAQ1w8IhDqtWO3eWqWq72W7trnaiE8=
|
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 h1:qrEDiqnsvNU9QE7lXIXi/tIHAfyaFXKxF2/8/52O8uM=
|
||||||
@@ -694,7 +718,10 @@ github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6
|
|||||||
github.com/peterhellberg/link v1.2.0 h1:UA5pg3Gp/E0F2WdX7GERiNrPQrM1K6CVJUUWfHa4t6c=
|
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/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=
|
||||||
@@ -705,17 +732,19 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||||||
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.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
||||||
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
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.27.1 h1:KGCsS8idUVTC5QHxTj91qHDhIXOb5Yb50wwHhNvJRTQ=
|
github.com/pocketbase/pocketbase v0.28.2 h1:b6cfUfr5d4whvUFGFhI8oHRzx/eB76GCUQGftqgv9lM=
|
||||||
github.com/pocketbase/pocketbase v0.27.1/go.mod h1:aTpwwloVJzeJ7MlwTRrbI/x62QNR2/kkCrovmyrXpqs=
|
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=
|
||||||
@@ -744,16 +773,16 @@ 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.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
|
||||||
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
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=
|
||||||
@@ -765,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=
|
||||||
@@ -800,34 +829,34 @@ 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.1136 h1:H1pjtH5uZ4XZPj9qQ9tt9jzeWqZzrd8qYIw01Q60/08=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1166 h1:cEoDsBt7vGh7YtfVHVmgXKQURZANBE8UKK/So84QUdU=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1136/go.mod h1:K6absuzpElv6mw2d7j8xkphOkwd23qvG0Rcmhl4rqlk=
|
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.1143 h1:7OL/ThUCqkntItSiqbY1g3s0Ua26Qr08G8fcSzyrAqA=
|
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1143/go.mod h1:XO18PkKinF17cQOSlhbP7GOnj04N5L2iCaHn64yiMtE=
|
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1120/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.1128/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1128/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1136/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
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.1138/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.1143/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.1147 h1:6v559jM1v6A4KJinNZ28RqVZs+ipKMzCWtYWcWy+zZ4=
|
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.1147/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.1170/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
|
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.1173 h1:W5bzEWiJwiwRZR0/P1l78OYWUXYsXLjhBaQ64c+9+fk=
|
||||||
|
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.1128 h1:mrJ5Fbkd7sZIJ5F6oRfh5zebPQaudPH9Y0+GUmFytYU=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 h1:mrJ5Fbkd7sZIJ5F6oRfh5zebPQaudPH9Y0+GUmFytYU=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128/go.mod h1:zbsYIBT+VTX4z4ocjTAdLBIWyNYj3z0BRqd0iPdnjsk=
|
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.1143 h1:fvK9kOsPquDTWrT2aXLWVnAMUokr4gFK7uYeY3JMB6U=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150 h1:RQQYfZOFYlkxKR2+xp8el3+8xs9DhxBy+ajlHtapqtQ=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1143/go.mod h1:SLYgasv8DdvRnesG+SLdqFdEBIJzietfVDytke8ASKQ=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150/go.mod h1:zpfr6EBWy7ClASTGUgIy01Gn4R79UXf+2QGQeyR124A=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1120 h1:z0t0lb5h1mZirXftO8MRg25COYZHx0ubQjSPhZT/LY0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1172 h1:6SUO0hTie3zxnUEMxmhnS1iRIXpAukSZV27Nrx4NwIk=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1120/go.mod h1:IFZL44Keyl+MHrhpFwUaQmJvMDwGr+t+cUfFAC+74lU=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1172/go.mod h1:tmN4zfu70SD0iee3qfpc09NRLel30zGoAuzIs4X0Kfs=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124 h1:LQKAlxFb0sYiE8ojK5h9+seuFzogoJtYnXmiRF+4F4Q=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1169 h1:oBymtJEmKDnS2NIR0PDLd+xCGQ+7uMoEt7zEB5Q3x8U=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124/go.mod h1:tYbK0FbHVG+78od7eZpzczE8qk0JWKO/osTQWuiJ3Fo=
|
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/teo v1.0.1138 h1:SrQ+rlWLwnXU/6S8ULGhFaiV5faAeqL0ysdsqV6P1AA=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1166 h1:+kIsoG2If/0y15PpZsXfT0QqTuwec9nMgo1JP8KQMkw=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1138/go.mod h1:XvXgF+4yO4Ni6gYoqMszSkNNqFLkOxx2j5F7+u3lpKQ=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1166/go.mod h1:lGmBMXqe3vBg6Bi9h4mVpWLKd7jQIMRbndr8KNHBqSw=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1136 h1:9GqM1URHNySj0f8TkUcKT6qSDiGep3IB1hWWu1ti6rY=
|
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.1136/go.mod h1:b5JZEbM4ROYUSVcgNkDHuHWdTJX5Qe4wC1asq2n0yes=
|
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.1147 h1:SxZsn9N4c1yx40kZOINIh9AnUKcgChUWbZoDiv6VvmQ=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1170 h1:kcQCWuI9zOkZgL5CK66HNAJmSWCSJxRrDxXT+j02CeE=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1147/go.mod h1:T4sxG9+SJ038MBsam2upsEYRpQ82JpX+IkZ08+P9RlE=
|
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=
|
||||||
@@ -836,16 +865,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.33 h1:YKY8VpFNttdnVNb0o3owGeZRoUtRJmoWPJYJPfcCf9A=
|
github.com/ucloud/ucloud-sdk-go v0.22.41 h1:JndTJhCx7A1wggZfVb4KMm7D0Wfvd/HkmQVfSNjClQA=
|
||||||
github.com/ucloud/ucloud-sdk-go v0.22.33/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.11 h1:J4AweXxLqlSwb1Aam9npcb5optZmszDIrKWa/hs+e4U=
|
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.11/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.204 h1:Njid6coReHV2gWc3bsqWMQf+K8jveauzW8zEX08CTzI=
|
github.com/volcengine/volc-sdk-golang v1.0.208 h1:DyGUPjEKhWS08BkptfqenXTuUq+LKb7+gX/RBAtNl8w=
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.204/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.1.4 h1:xPT4KOy8VkXxhY7dbXzzvLvKQXUe4J6AtkQdNQU3wRY=
|
github.com/volcengine/volcengine-go-sdk v1.1.8 h1:/T2p7qeeLWWhGrhtB00b8VNlE32S266LcO+jqFUYwzY=
|
||||||
github.com/volcengine/volcengine-go-sdk v1.1.4/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=
|
||||||
@@ -913,8 +944,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.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
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=
|
||||||
@@ -928,14 +959,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-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
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.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
|
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||||
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
|
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=
|
||||||
@@ -1018,16 +1049,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.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
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.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||||
golang.org/x/oauth2 v0.29.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=
|
||||||
@@ -1045,8 +1076,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.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||||
golang.org/x/sync v0.13.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=
|
||||||
@@ -1099,6 +1130,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=
|
||||||
@@ -1107,6 +1139,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=
|
||||||
@@ -1123,8 +1156,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.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.32.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=
|
||||||
@@ -1140,8 +1173,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.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
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=
|
||||||
@@ -1160,8 +1193,8 @@ 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.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
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=
|
||||||
@@ -1223,8 +1256,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.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
|
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||||
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
|
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=
|
||||||
@@ -1364,39 +1397,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.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic=
|
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
|
||||||
modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||||
modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU=
|
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
|
||||||
modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw=
|
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.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||||
modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s=
|
modernc.org/libc v1.65.7 h1:Ia9Z4yzZtWNtUIuiPuQ7Qf7kxYrxP1/jeHZzG8bFu00=
|
||||||
modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo=
|
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.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g=
|
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||||
modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
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.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI=
|
modernc.org/sqlite v1.37.1 h1:EgHJK/FPoqC+q2YBXg7fUmES37pCHFc97sI7zSayBEs=
|
||||||
modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM=
|
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=
|
||||||
@@ -1407,8 +1440,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=
|
||||||
|
|||||||
@@ -3,25 +3,26 @@ package applicant
|
|||||||
import "github.com/usual2970/certimate/internal/domain"
|
import "github.com/usual2970/certimate/internal/domain"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sslProviderLetsEncrypt = string(domain.CAProviderTypeLetsEncrypt)
|
caLetsEncrypt = string(domain.CAProviderTypeLetsEncrypt)
|
||||||
sslProviderLetsEncryptStaging = string(domain.CAProviderTypeLetsEncryptStaging)
|
caLetsEncryptStaging = string(domain.CAProviderTypeLetsEncryptStaging)
|
||||||
sslProviderBuypass = string(domain.CAProviderTypeBuypass)
|
caBuypass = string(domain.CAProviderTypeBuypass)
|
||||||
sslProviderGoogleTrustServices = string(domain.CAProviderTypeGoogleTrustServices)
|
caGoogleTrustServices = string(domain.CAProviderTypeGoogleTrustServices)
|
||||||
sslProviderSSLCom = string(domain.CAProviderTypeSSLCom)
|
caSSLCom = string(domain.CAProviderTypeSSLCom)
|
||||||
sslProviderZeroSSL = string(domain.CAProviderTypeZeroSSL)
|
caZeroSSL = string(domain.CAProviderTypeZeroSSL)
|
||||||
|
caCustom = string(domain.CAProviderTypeACMECA)
|
||||||
|
|
||||||
sslProviderDefault = sslProviderLetsEncrypt
|
caDefault = caLetsEncrypt
|
||||||
)
|
)
|
||||||
|
|
||||||
var sslProviderUrls = map[string]string{
|
var caDirUrls = map[string]string{
|
||||||
sslProviderLetsEncrypt: "https://acme-v02.api.letsencrypt.org/directory",
|
caLetsEncrypt: "https://acme-v02.api.letsencrypt.org/directory",
|
||||||
sslProviderLetsEncryptStaging: "https://acme-staging-v02.api.letsencrypt.org/directory",
|
caLetsEncryptStaging: "https://acme-staging-v02.api.letsencrypt.org/directory",
|
||||||
sslProviderBuypass: "https://api.buypass.com/acme/directory",
|
caBuypass: "https://api.buypass.com/acme/directory",
|
||||||
sslProviderGoogleTrustServices: "https://dv.acme-v02.api.pki.goog/directory",
|
caGoogleTrustServices: "https://dv.acme-v02.api.pki.goog/directory",
|
||||||
sslProviderSSLCom: "https://acme.ssl.com/sslcom-dv-rsa",
|
caSSLCom: "https://acme.ssl.com/sslcom-dv-rsa",
|
||||||
sslProviderSSLCom + "RSA": "https://acme.ssl.com/sslcom-dv-rsa",
|
caSSLCom + "RSA": "https://acme.ssl.com/sslcom-dv-rsa",
|
||||||
sslProviderSSLCom + "ECC": "https://acme.ssl.com/sslcom-dv-ecc",
|
caSSLCom + "ECC": "https://acme.ssl.com/sslcom-dv-ecc",
|
||||||
sslProviderZeroSSL: "https://acme.zerossl.com/v2/DV90",
|
caZeroSSL: "https://acme.zerossl.com/v2/DV90",
|
||||||
}
|
}
|
||||||
|
|
||||||
type acmeSSLProviderConfig struct {
|
type acmeSSLProviderConfig struct {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ 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"
|
||||||
@@ -19,22 +20,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
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 {
|
||||||
@@ -73,6 +83,10 @@ 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
|
||||||
}
|
}
|
||||||
@@ -94,16 +108,16 @@ func registerAcmeUserWithSingleFlight(client *lego.Client, user *acmeUser, userR
|
|||||||
func registerAcmeUser(client *lego.Client, user *acmeUser, userRegisterOptions map[string]any) (*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 user.CA {
|
switch user.getCAProvider() {
|
||||||
case sslProviderLetsEncrypt, sslProviderLetsEncryptStaging:
|
case caLetsEncrypt, caLetsEncryptStaging:
|
||||||
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
|
|
||||||
case sslProviderBuypass:
|
case caBuypass:
|
||||||
{
|
{
|
||||||
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
case sslProviderGoogleTrustServices:
|
case caGoogleTrustServices:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForGoogleTrustServices{}
|
access := domain.AccessConfigForGoogleTrustServices{}
|
||||||
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
|
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
|
||||||
@@ -117,7 +131,7 @@ func registerAcmeUser(client *lego.Client, user *acmeUser, userRegisterOptions m
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
case sslProviderSSLCom:
|
case caSSLCom:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForSSLCom{}
|
access := domain.AccessConfigForSSLCom{}
|
||||||
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
|
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
|
||||||
@@ -131,7 +145,7 @@ func registerAcmeUser(client *lego.Client, user *acmeUser, userRegisterOptions m
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
case sslProviderZeroSSL:
|
case caZeroSSL:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForZeroSSL{}
|
access := domain.AccessConfigForZeroSSL{}
|
||||||
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
|
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
|
||||||
@@ -145,6 +159,26 @@ func registerAcmeUser(client *lego.Client, user *acmeUser, userRegisterOptions m
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case caCustom:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForACMECA{}
|
||||||
|
if err := maputil.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 ca provider '%s'", user.CA)
|
err = fmt.Errorf("unsupported ca provider '%s'", user.CA)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,18 +20,20 @@ import (
|
|||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/usual2970/certimate/internal/domain"
|
||||||
|
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
|
||||||
sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
|
sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
|
||||||
"github.com/usual2970/certimate/internal/repository"
|
"github.com/usual2970/certimate/internal/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ApplyResult 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 {
|
||||||
@@ -51,36 +53,37 @@ func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, err
|
|||||||
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeApply))
|
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeApply))
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeConfig := config.Node.GetConfigForApply()
|
nodeCfg := config.Node.GetConfigForApply()
|
||||||
options := &applicantProviderOptions{
|
options := &applicantProviderOptions{
|
||||||
Domains: sliceutil.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }),
|
Domains: sliceutil.Filter(strings.Split(nodeCfg.Domains, ";"), func(s string) bool { return s != "" }),
|
||||||
ContactEmail: nodeConfig.ContactEmail,
|
ContactEmail: nodeCfg.ContactEmail,
|
||||||
Provider: domain.ACMEDns01ProviderType(nodeConfig.Provider),
|
Provider: domain.ACMEDns01ProviderType(nodeCfg.Provider),
|
||||||
ProviderAccessConfig: make(map[string]any),
|
ProviderAccessConfig: make(map[string]any),
|
||||||
ProviderExtendedConfig: nodeConfig.ProviderConfig,
|
ProviderServiceConfig: nodeCfg.ProviderConfig,
|
||||||
CAProvider: domain.CAProviderType(nodeConfig.CAProvider),
|
CAProvider: domain.CAProviderType(nodeCfg.CAProvider),
|
||||||
CAProviderAccessConfig: make(map[string]any),
|
CAProviderAccessConfig: make(map[string]any),
|
||||||
CAProviderExtendedConfig: nodeConfig.CAProviderConfig,
|
CAProviderServiceConfig: nodeCfg.CAProviderConfig,
|
||||||
KeyAlgorithm: nodeConfig.KeyAlgorithm,
|
KeyAlgorithm: nodeCfg.KeyAlgorithm,
|
||||||
Nameservers: sliceutil.Filter(strings.Split(nodeConfig.Nameservers, ";"), func(s string) bool { return s != "" }),
|
Nameservers: sliceutil.Filter(strings.Split(nodeCfg.Nameservers, ";"), func(s string) bool { return s != "" }),
|
||||||
DnsPropagationWait: nodeConfig.DnsPropagationWait,
|
DnsPropagationWait: nodeCfg.DnsPropagationWait,
|
||||||
DnsPropagationTimeout: nodeConfig.DnsPropagationTimeout,
|
DnsPropagationTimeout: nodeCfg.DnsPropagationTimeout,
|
||||||
DnsTTL: nodeConfig.DnsTTL,
|
DnsTTL: nodeCfg.DnsTTL,
|
||||||
DisableFollowCNAME: nodeConfig.DisableFollowCNAME,
|
DisableFollowCNAME: nodeCfg.DisableFollowCNAME,
|
||||||
}
|
}
|
||||||
|
|
||||||
accessRepo := repository.NewAccessRepository()
|
accessRepo := repository.NewAccessRepository()
|
||||||
if nodeConfig.ProviderAccessId != "" {
|
if nodeCfg.ProviderAccessId != "" {
|
||||||
if access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId); err != nil {
|
if access, err := accessRepo.GetById(context.Background(), nodeCfg.ProviderAccessId); err != nil {
|
||||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
|
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.ProviderAccessId, err)
|
||||||
} else {
|
} else {
|
||||||
options.ProviderAccessConfig = access.Config
|
options.ProviderAccessConfig = access.Config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if nodeConfig.CAProviderAccessId != "" {
|
if nodeCfg.CAProviderAccessId != "" {
|
||||||
if access, err := accessRepo.GetById(context.Background(), nodeConfig.CAProviderAccessId); err != nil {
|
if access, err := accessRepo.GetById(context.Background(), nodeCfg.CAProviderAccessId); err != nil {
|
||||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.CAProviderAccessId, err)
|
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.CAProviderAccessId, err)
|
||||||
} else {
|
} else {
|
||||||
|
options.CAProviderAccessId = access.Id
|
||||||
options.CAProviderAccessConfig = access.Config
|
options.CAProviderAccessConfig = access.Config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,13 +94,13 @@ func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, err
|
|||||||
|
|
||||||
sslProviderConfig := &acmeSSLProviderConfig{
|
sslProviderConfig := &acmeSSLProviderConfig{
|
||||||
Config: make(map[domain.CAProviderType]map[string]any),
|
Config: make(map[domain.CAProviderType]map[string]any),
|
||||||
Provider: sslProviderDefault,
|
Provider: caDefault,
|
||||||
}
|
}
|
||||||
if settings != nil {
|
if settings != nil {
|
||||||
if err := json.Unmarshal([]byte(settings.Content), sslProviderConfig); err != nil {
|
if err := json.Unmarshal([]byte(settings.Content), sslProviderConfig); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if sslProviderConfig.Provider == "" {
|
} else if sslProviderConfig.Provider == "" {
|
||||||
sslProviderConfig.Provider = sslProviderDefault
|
sslProviderConfig.Provider = caDefault
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +110,7 @@ func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, err
|
|||||||
|
|
||||||
certRepo := repository.NewCertificateRepository()
|
certRepo := repository.NewCertificateRepository()
|
||||||
lastCertificate, _ := certRepo.GetByWorkflowNodeId(context.Background(), config.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)
|
||||||
@@ -117,8 +120,8 @@ func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, err
|
|||||||
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.ReplacedARIAcct = lastCertificate.ACMEAccountUrl
|
options.ARIReplaceAcct = lastCertificate.ACMEAccountUrl
|
||||||
options.ReplacedARICert = replacedARICertId
|
options.ARIReplaceCert = replacedARICertId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,7 +166,7 @@ func getLimiter(key string) *rate.Limiter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOptions) (*ApplyResult, error) {
|
func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOptions) (*ApplyResult, error) {
|
||||||
user, err := newAcmeUser(string(options.CAProvider), options.ContactEmail)
|
user, err := newAcmeUser(string(options.CAProvider), options.CAProviderAccessId, options.ContactEmail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -175,13 +178,26 @@ func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOpt
|
|||||||
// Create an ACME client config
|
// Create an ACME client config
|
||||||
config := lego.NewConfig(user)
|
config := lego.NewConfig(user)
|
||||||
config.Certificate.KeyType = parseLegoKeyAlgorithm(domain.CertificateKeyAlgorithmType(options.KeyAlgorithm))
|
config.Certificate.KeyType = parseLegoKeyAlgorithm(domain.CertificateKeyAlgorithmType(options.KeyAlgorithm))
|
||||||
config.CADirURL = sslProviderUrls[user.CA]
|
switch user.getCAProvider() {
|
||||||
if user.CA == sslProviderSSLCom {
|
case caSSLCom:
|
||||||
if strings.HasPrefix(options.KeyAlgorithm, "RSA") {
|
if strings.HasPrefix(options.KeyAlgorithm, "RSA") {
|
||||||
config.CADirURL = sslProviderUrls[sslProviderSSLCom+"RSA"]
|
config.CADirURL = caDirUrls[caSSLCom+"RSA"]
|
||||||
} else if strings.HasPrefix(options.KeyAlgorithm, "EC") {
|
} else if strings.HasPrefix(options.KeyAlgorithm, "EC") {
|
||||||
config.CADirURL = sslProviderUrls[sslProviderSSLCom+"ECC"]
|
config.CADirURL = caDirUrls[caSSLCom+"ECC"]
|
||||||
|
} else {
|
||||||
|
config.CADirURL = caDirUrls[caSSLCom]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case caCustom:
|
||||||
|
caDirURL := maputil.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
|
||||||
@@ -220,22 +236,24 @@ func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOpt
|
|||||||
Domains: options.Domains,
|
Domains: options.Domains,
|
||||||
Bundle: true,
|
Bundle: true,
|
||||||
}
|
}
|
||||||
if options.ReplacedARIAcct == user.Registration.URI {
|
if options.ARIReplaceAcct == user.Registration.URI {
|
||||||
certRequest.ReplacesCertID = options.ReplacedARICert
|
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 &ApplyResult{
|
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: user.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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/usual2970/certimate/internal/domain"
|
||||||
pACMEHttpReq "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq"
|
pACMEHttpReq "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq"
|
||||||
pAliyun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun"
|
pAliyun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun"
|
||||||
|
pAliyunESA "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun-esa"
|
||||||
pAWSRoute53 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws-route53"
|
pAWSRoute53 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws-route53"
|
||||||
pAzureDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/azure-dns"
|
pAzureDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/azure-dns"
|
||||||
pBaiduCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud"
|
pBaiduCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud"
|
||||||
@@ -15,23 +16,30 @@ import (
|
|||||||
pCloudflare "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare"
|
pCloudflare "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare"
|
||||||
pClouDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudns"
|
pClouDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudns"
|
||||||
pCMCCCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud"
|
pCMCCCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud"
|
||||||
|
pConstellix "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/constellix"
|
||||||
pDeSEC "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/desec"
|
pDeSEC "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/desec"
|
||||||
|
pDigitalOcean "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/digitalocean"
|
||||||
pDNSLA "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla"
|
pDNSLA "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla"
|
||||||
|
pDuckDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/duckdns"
|
||||||
pDynv6 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6"
|
pDynv6 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6"
|
||||||
pGcore "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gcore"
|
pGcore "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gcore"
|
||||||
pGname "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname"
|
pGname "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname"
|
||||||
pGoDaddy "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy"
|
pGoDaddy "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy"
|
||||||
|
pHetzner "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/hetzner"
|
||||||
pHuaweiCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud"
|
pHuaweiCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud"
|
||||||
pJDCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud"
|
pJDCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud"
|
||||||
pNamecheap "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namecheap"
|
pNamecheap "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namecheap"
|
||||||
pNameDotCom "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom"
|
pNameDotCom "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom"
|
||||||
pNameSilo "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo"
|
pNameSilo "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo"
|
||||||
|
pNetcup "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/netcup"
|
||||||
|
pNetlify "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/netlify"
|
||||||
pNS1 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1"
|
pNS1 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1"
|
||||||
pPorkbun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/porkbun"
|
pPorkbun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/porkbun"
|
||||||
pPowerDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns"
|
pPowerDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns"
|
||||||
pRainYun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/rainyun"
|
pRainYun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/rainyun"
|
||||||
pTencentCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud"
|
pTencentCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud"
|
||||||
pTencentCloudEO "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo"
|
pTencentCloudEO "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo"
|
||||||
|
pUCloudUDNR "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ucloud-udnr"
|
||||||
pVercel "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/vercel"
|
pVercel "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/vercel"
|
||||||
pVolcEngine "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine"
|
pVolcEngine "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine"
|
||||||
pWestcn "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/westcn"
|
pWestcn "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/westcn"
|
||||||
@@ -39,22 +47,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type applicantProviderOptions struct {
|
type applicantProviderOptions struct {
|
||||||
Domains []string
|
Domains []string
|
||||||
ContactEmail string
|
ContactEmail string
|
||||||
Provider domain.ACMEDns01ProviderType
|
Provider domain.ACMEDns01ProviderType
|
||||||
ProviderAccessConfig map[string]any
|
ProviderAccessConfig map[string]any
|
||||||
ProviderExtendedConfig map[string]any
|
ProviderServiceConfig map[string]any
|
||||||
CAProvider domain.CAProviderType
|
CAProvider domain.CAProviderType
|
||||||
CAProviderAccessConfig map[string]any
|
CAProviderAccessId string
|
||||||
CAProviderExtendedConfig map[string]any
|
CAProviderAccessConfig map[string]any
|
||||||
KeyAlgorithm string
|
CAProviderServiceConfig map[string]any
|
||||||
Nameservers []string
|
KeyAlgorithm string
|
||||||
DnsPropagationWait int32
|
Nameservers []string
|
||||||
DnsPropagationTimeout int32
|
DnsPropagationWait int32
|
||||||
DnsTTL int32
|
DnsPropagationTimeout int32
|
||||||
DisableFollowCNAME bool
|
DnsTTL int32
|
||||||
ReplacedARIAcct string
|
DisableFollowCNAME bool
|
||||||
ReplacedARICert string
|
ARIReplaceAcct string
|
||||||
|
ARIReplaceCert string
|
||||||
}
|
}
|
||||||
|
|
||||||
func createApplicantProvider(options *applicantProviderOptions) (challenge.Provider, error) {
|
func createApplicantProvider(options *applicantProviderOptions) (challenge.Provider, error) {
|
||||||
@@ -80,20 +89,36 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ACMEDns01ProviderTypeAliyun, domain.ACMEDns01ProviderTypeAliyunDNS:
|
case domain.ACMEDns01ProviderTypeAliyun, domain.ACMEDns01ProviderTypeAliyunDNS, domain.ACMEDns01ProviderTypeAliyunESA:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForAliyun{}
|
access := domain.AccessConfigForAliyun{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := maputil.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: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||||
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.ACMEDns01ProviderTypeAWS, domain.ACMEDns01ProviderTypeAWSRoute53:
|
case domain.ACMEDns01ProviderTypeAWS, domain.ACMEDns01ProviderTypeAWSRoute53:
|
||||||
@@ -106,8 +131,8 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
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.ProviderExtendedConfig, "region"),
|
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||||
HostedZoneId: maputil.GetString(options.ProviderExtendedConfig, "hostedZoneId"),
|
HostedZoneId: maputil.GetString(options.ProviderServiceConfig, "hostedZoneId"),
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
@@ -211,6 +236,22 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeConstellix:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForConstellix{}
|
||||||
|
if err := maputil.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.ACMEDns01ProviderTypeDeSEC:
|
case domain.ACMEDns01ProviderTypeDeSEC:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForDeSEC{}
|
access := domain.AccessConfigForDeSEC{}
|
||||||
@@ -226,6 +267,21 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeDigitalOcean:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForDigitalOcean{}
|
||||||
|
if err := maputil.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:
|
case domain.ACMEDns01ProviderTypeDNSLA:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForDNSLA{}
|
access := domain.AccessConfigForDNSLA{}
|
||||||
@@ -242,6 +298,20 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeDuckDNS:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForDuckDNS{}
|
||||||
|
if err := maputil.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:
|
case domain.ACMEDns01ProviderTypeDynv6:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForDynv6{}
|
access := domain.AccessConfigForDynv6{}
|
||||||
@@ -304,6 +374,21 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeHetzner:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForHetzner{}
|
||||||
|
if err := maputil.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:
|
case domain.ACMEDns01ProviderTypeHuaweiCloud, domain.ACMEDns01ProviderTypeHuaweiCloudDNS:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForHuaweiCloud{}
|
access := domain.AccessConfigForHuaweiCloud{}
|
||||||
@@ -314,7 +399,7 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
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.ProviderExtendedConfig, "region"),
|
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
@@ -331,7 +416,7 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
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.ProviderExtendedConfig, "regionId"),
|
RegionId: maputil.GetString(options.ProviderServiceConfig, "regionId"),
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
@@ -385,6 +470,38 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeNetcup:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForNetcup{}
|
||||||
|
if err := maputil.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 := maputil.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:
|
case domain.ACMEDns01ProviderTypeNS1:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForNS1{}
|
access := domain.AccessConfigForNS1{}
|
||||||
@@ -424,10 +541,11 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
}
|
}
|
||||||
|
|
||||||
applicant, err := pPowerDNS.NewChallengeProvider(&pPowerDNS.ChallengeProviderConfig{
|
applicant, err := pPowerDNS.NewChallengeProvider(&pPowerDNS.ChallengeProviderConfig{
|
||||||
ApiUrl: access.ApiUrl,
|
ServerUrl: access.ServerUrl,
|
||||||
ApiKey: access.ApiKey,
|
ApiKey: access.ApiKey,
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
AllowInsecureConnections: access.AllowInsecureConnections,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
return applicant, err
|
return applicant, err
|
||||||
}
|
}
|
||||||
@@ -468,7 +586,7 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
applicant, err := pTencentCloudEO.NewChallengeProvider(&pTencentCloudEO.ChallengeProviderConfig{
|
applicant, err := pTencentCloudEO.NewChallengeProvider(&pTencentCloudEO.ChallengeProviderConfig{
|
||||||
SecretId: access.SecretId,
|
SecretId: access.SecretId,
|
||||||
SecretKey: access.SecretKey,
|
SecretKey: access.SecretKey,
|
||||||
ZoneId: maputil.GetString(options.ProviderExtendedConfig, "zoneId"),
|
ZoneId: maputil.GetString(options.ProviderServiceConfig, "zoneId"),
|
||||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||||
DnsTTL: options.DnsTTL,
|
DnsTTL: options.DnsTTL,
|
||||||
})
|
})
|
||||||
@@ -479,6 +597,22 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case domain.ACMEDns01ProviderTypeUCloudUDNR:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForUCloud{}
|
||||||
|
if err := maputil.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,
|
||||||
|
DnsTTL: options.DnsTTL,
|
||||||
|
})
|
||||||
|
return applicant, err
|
||||||
|
}
|
||||||
|
|
||||||
case domain.ACMEDns01ProviderTypeVercel:
|
case domain.ACMEDns01ProviderTypeVercel:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForVercel{}
|
access := domain.AccessConfigForVercel{}
|
||||||
|
|||||||
@@ -29,18 +29,18 @@ func NewWithWorkflowNode(config DeployerWithWorkflowNodeConfig) (Deployer, error
|
|||||||
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeDeploy))
|
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeDeploy))
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeConfig := config.Node.GetConfigForDeploy()
|
nodeCfg := config.Node.GetConfigForDeploy()
|
||||||
options := &deployerProviderOptions{
|
options := &deployerProviderOptions{
|
||||||
Provider: domain.DeploymentProviderType(nodeConfig.Provider),
|
Provider: domain.DeploymentProviderType(nodeCfg.Provider),
|
||||||
ProviderAccessConfig: make(map[string]any),
|
ProviderAccessConfig: make(map[string]any),
|
||||||
ProviderExtendedConfig: nodeConfig.ProviderConfig,
|
ProviderServiceConfig: nodeCfg.ProviderConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
accessRepo := repository.NewAccessRepository()
|
accessRepo := repository.NewAccessRepository()
|
||||||
if nodeConfig.ProviderAccessId != "" {
|
if nodeCfg.ProviderAccessId != "" {
|
||||||
access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId)
|
access, err := accessRepo.GetById(context.Background(), nodeCfg.ProviderAccessId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
|
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.ProviderAccessId, err)
|
||||||
} else {
|
} else {
|
||||||
options.ProviderAccessConfig = access.Config
|
options.ProviderAccessConfig = access.Config
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -16,11 +16,18 @@ type Access struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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"`
|
||||||
@@ -31,6 +38,7 @@ 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 AccessConfigForAWS struct {
|
type AccessConfigForAWS struct {
|
||||||
@@ -55,7 +63,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,9 +88,10 @@ type AccessConfigForCacheFly struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
@@ -94,15 +109,29 @@ type AccessConfigForCMCCCloud struct {
|
|||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForConstellix struct {
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
SecretKey string `json:"secretKey"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForDeSEC struct {
|
type AccessConfigForDeSEC struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForDigitalOcean struct {
|
||||||
|
AccessToken string `json:"accessToken"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForDingTalkBot struct {
|
type AccessConfigForDingTalkBot struct {
|
||||||
WebhookUrl string `json:"webhookUrl"`
|
WebhookUrl string `json:"webhookUrl"`
|
||||||
Secret string `json:"secret"`
|
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"`
|
||||||
@@ -113,6 +142,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"`
|
||||||
}
|
}
|
||||||
@@ -132,6 +165,14 @@ type AccessConfigForEmail struct {
|
|||||||
DefaultReceiverAddress string `json:"defaultReceiverAddress,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"`
|
||||||
}
|
}
|
||||||
@@ -146,14 +187,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 {
|
type AccessConfigForGoogleTrustServices struct {
|
||||||
EabKid string `json:"eabKid"`
|
EabKid string `json:"eabKid"`
|
||||||
EabHmacKey string `json:"eabHmacKey"`
|
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 {
|
||||||
@@ -169,6 +223,15 @@ type AccessConfigForLarkBot struct {
|
|||||||
WebhookUrl string `json:"webhookUrl"`
|
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 {
|
type AccessConfigForMattermost struct {
|
||||||
ServerUrl string `json:"serverUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@@ -190,6 +253,16 @@ 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"`
|
||||||
}
|
}
|
||||||
@@ -200,8 +273,16 @@ type AccessConfigForPorkbun struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
@@ -213,19 +294,41 @@ 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 {
|
type AccessConfigForSSLCom struct {
|
||||||
@@ -233,7 +336,7 @@ type AccessConfigForSSLCom struct {
|
|||||||
EabHmacKey string `json:"eabHmacKey"`
|
EabHmacKey string `json:"eabHmacKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForTelegram struct {
|
type AccessConfigForTelegramBot struct {
|
||||||
BotToken string `json:"botToken"`
|
BotToken string `json:"botToken"`
|
||||||
DefaultChatId int64 `json:"defaultChatId,omitempty"`
|
DefaultChatId int64 `json:"defaultChatId,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -249,6 +352,11 @@ 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"`
|
||||||
@@ -285,7 +393,7 @@ type AccessConfigForWeComBot struct {
|
|||||||
|
|
||||||
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 {
|
type AccessConfigForZeroSSL struct {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ type AccessProviderType string
|
|||||||
*/
|
*/
|
||||||
const (
|
const (
|
||||||
AccessProviderType1Panel = AccessProviderType("1panel")
|
AccessProviderType1Panel = AccessProviderType("1panel")
|
||||||
|
AccessProviderTypeACMECA = AccessProviderType("acmeca")
|
||||||
AccessProviderTypeACMEHttpReq = AccessProviderType("acmehttpreq")
|
AccessProviderTypeACMEHttpReq = AccessProviderType("acmehttpreq")
|
||||||
AccessProviderTypeAkamai = AccessProviderType("akamai") // Akamai(预留)
|
AccessProviderTypeAkamai = AccessProviderType("akamai") // Akamai(预留)
|
||||||
AccessProviderTypeAliyun = AccessProviderType("aliyun")
|
AccessProviderTypeAliyun = AccessProviderType("aliyun")
|
||||||
@@ -18,6 +19,7 @@ const (
|
|||||||
AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud")
|
AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud")
|
||||||
AccessProviderTypeBaishan = AccessProviderType("baishan")
|
AccessProviderTypeBaishan = AccessProviderType("baishan")
|
||||||
AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel")
|
AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel")
|
||||||
|
AccessProviderTypeBaotaWAF = AccessProviderType("baotawaf")
|
||||||
AccessProviderTypeBytePlus = AccessProviderType("byteplus")
|
AccessProviderTypeBytePlus = AccessProviderType("byteplus")
|
||||||
AccessProviderTypeBunny = AccessProviderType("bunny")
|
AccessProviderTypeBunny = AccessProviderType("bunny")
|
||||||
AccessProviderTypeBuypass = AccessProviderType("buypass")
|
AccessProviderTypeBuypass = AccessProviderType("buypass")
|
||||||
@@ -26,44 +28,57 @@ const (
|
|||||||
AccessProviderTypeCloudflare = AccessProviderType("cloudflare")
|
AccessProviderTypeCloudflare = AccessProviderType("cloudflare")
|
||||||
AccessProviderTypeClouDNS = AccessProviderType("cloudns")
|
AccessProviderTypeClouDNS = AccessProviderType("cloudns")
|
||||||
AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud")
|
AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud")
|
||||||
AccessProviderTypeCTCCCloud = AccessProviderType("ctcccloud") // 联通云(预留)
|
AccessProviderTypeConstellix = AccessProviderType("constellix")
|
||||||
AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 天翼云(预留)
|
AccessProviderTypeCTCCCloud = AccessProviderType("ctcccloud") // 天翼云(预留)
|
||||||
|
AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 联通云(预留)
|
||||||
AccessProviderTypeDeSEC = AccessProviderType("desec")
|
AccessProviderTypeDeSEC = AccessProviderType("desec")
|
||||||
|
AccessProviderTypeDigitalOcean = AccessProviderType("digitalocean")
|
||||||
AccessProviderTypeDingTalkBot = AccessProviderType("dingtalkbot")
|
AccessProviderTypeDingTalkBot = AccessProviderType("dingtalkbot")
|
||||||
|
AccessProviderTypeDiscordBot = AccessProviderType("discordbot")
|
||||||
AccessProviderTypeDNSLA = AccessProviderType("dnsla")
|
AccessProviderTypeDNSLA = AccessProviderType("dnsla")
|
||||||
AccessProviderTypeDogeCloud = AccessProviderType("dogecloud")
|
AccessProviderTypeDogeCloud = AccessProviderType("dogecloud")
|
||||||
|
AccessProviderTypeDuckDNS = AccessProviderType("duckdns")
|
||||||
AccessProviderTypeDynv6 = AccessProviderType("dynv6")
|
AccessProviderTypeDynv6 = AccessProviderType("dynv6")
|
||||||
AccessProviderTypeEdgio = AccessProviderType("edgio")
|
AccessProviderTypeEdgio = AccessProviderType("edgio")
|
||||||
AccessProviderTypeEmail = AccessProviderType("email")
|
AccessProviderTypeEmail = AccessProviderType("email")
|
||||||
AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly(预留)
|
AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly(预留)
|
||||||
|
AccessProviderTypeFlexCDN = AccessProviderType("flexcdn")
|
||||||
AccessProviderTypeGname = AccessProviderType("gname")
|
AccessProviderTypeGname = AccessProviderType("gname")
|
||||||
AccessProviderTypeGcore = AccessProviderType("gcore")
|
AccessProviderTypeGcore = AccessProviderType("gcore")
|
||||||
AccessProviderTypeGoDaddy = AccessProviderType("godaddy")
|
AccessProviderTypeGoDaddy = AccessProviderType("godaddy")
|
||||||
AccessProviderTypeGoEdge = AccessProviderType("goedge") // GoEdge(预留)
|
AccessProviderTypeGoEdge = AccessProviderType("goedge")
|
||||||
AccessProviderTypeGoogleTrustServices = AccessProviderType("googletrustservices")
|
AccessProviderTypeGoogleTrustServices = AccessProviderType("googletrustservices")
|
||||||
|
AccessProviderTypeHetzner = AccessProviderType("hetzner")
|
||||||
AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud")
|
AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud")
|
||||||
AccessProviderTypeJDCloud = AccessProviderType("jdcloud")
|
AccessProviderTypeJDCloud = AccessProviderType("jdcloud")
|
||||||
AccessProviderTypeKubernetes = AccessProviderType("k8s")
|
AccessProviderTypeKubernetes = AccessProviderType("k8s")
|
||||||
AccessProviderTypeLarkBot = AccessProviderType("larkbot")
|
AccessProviderTypeLarkBot = AccessProviderType("larkbot")
|
||||||
AccessProviderTypeLetsEncrypt = AccessProviderType("letsencrypt")
|
AccessProviderTypeLetsEncrypt = AccessProviderType("letsencrypt")
|
||||||
AccessProviderTypeLetsEncryptStaging = AccessProviderType("letsencryptstaging")
|
AccessProviderTypeLetsEncryptStaging = AccessProviderType("letsencryptstaging")
|
||||||
|
AccessProviderTypeLeCDN = AccessProviderType("lecdn")
|
||||||
AccessProviderTypeLocal = AccessProviderType("local")
|
AccessProviderTypeLocal = AccessProviderType("local")
|
||||||
AccessProviderTypeMattermost = AccessProviderType("mattermost")
|
AccessProviderTypeMattermost = AccessProviderType("mattermost")
|
||||||
AccessProviderTypeNamecheap = AccessProviderType("namecheap")
|
AccessProviderTypeNamecheap = AccessProviderType("namecheap")
|
||||||
AccessProviderTypeNameDotCom = AccessProviderType("namedotcom")
|
AccessProviderTypeNameDotCom = AccessProviderType("namedotcom")
|
||||||
AccessProviderTypeNameSilo = AccessProviderType("namesilo")
|
AccessProviderTypeNameSilo = AccessProviderType("namesilo")
|
||||||
|
AccessProviderTypeNetcup = AccessProviderType("netcup")
|
||||||
|
AccessProviderTypeNetlify = AccessProviderType("netlify")
|
||||||
AccessProviderTypeNS1 = AccessProviderType("ns1")
|
AccessProviderTypeNS1 = AccessProviderType("ns1")
|
||||||
AccessProviderTypePorkbun = AccessProviderType("porkbun")
|
AccessProviderTypePorkbun = AccessProviderType("porkbun")
|
||||||
AccessProviderTypePowerDNS = AccessProviderType("powerdns")
|
AccessProviderTypePowerDNS = AccessProviderType("powerdns")
|
||||||
|
AccessProviderTypeProxmoxVE = AccessProviderType("proxmoxve")
|
||||||
AccessProviderTypeQiniu = AccessProviderType("qiniu")
|
AccessProviderTypeQiniu = AccessProviderType("qiniu")
|
||||||
AccessProviderTypeQingCloud = AccessProviderType("qingcloud") // 青云(预留)
|
AccessProviderTypeQingCloud = AccessProviderType("qingcloud") // 青云(预留)
|
||||||
AccessProviderTypeRainYun = AccessProviderType("rainyun")
|
AccessProviderTypeRainYun = AccessProviderType("rainyun")
|
||||||
|
AccessProviderTypeRatPanel = AccessProviderType("ratpanel")
|
||||||
AccessProviderTypeSafeLine = AccessProviderType("safeline")
|
AccessProviderTypeSafeLine = AccessProviderType("safeline")
|
||||||
|
AccessProviderTypeSlackBot = AccessProviderType("slackbot")
|
||||||
AccessProviderTypeSSH = AccessProviderType("ssh")
|
AccessProviderTypeSSH = AccessProviderType("ssh")
|
||||||
AccessProviderTypeSSLCOM = AccessProviderType("sslcom")
|
AccessProviderTypeSSLCOM = AccessProviderType("sslcom")
|
||||||
AccessProviderTypeTelegram = AccessProviderType("telegram")
|
AccessProviderTypeTelegramBot = AccessProviderType("telegrambot")
|
||||||
AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud")
|
AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud")
|
||||||
AccessProviderTypeUCloud = AccessProviderType("ucloud")
|
AccessProviderTypeUCloud = AccessProviderType("ucloud")
|
||||||
|
AccessProviderTypeUniCloud = AccessProviderType("unicloud")
|
||||||
AccessProviderTypeUpyun = AccessProviderType("upyun")
|
AccessProviderTypeUpyun = AccessProviderType("upyun")
|
||||||
AccessProviderTypeVercel = AccessProviderType("vercel")
|
AccessProviderTypeVercel = AccessProviderType("vercel")
|
||||||
AccessProviderTypeVolcEngine = AccessProviderType("volcengine")
|
AccessProviderTypeVolcEngine = AccessProviderType("volcengine")
|
||||||
@@ -84,6 +99,7 @@ type CAProviderType string
|
|||||||
NOTICE: If you add new constant, please keep ASCII order.
|
NOTICE: If you add new constant, please keep ASCII order.
|
||||||
*/
|
*/
|
||||||
const (
|
const (
|
||||||
|
CAProviderTypeACMECA = CAProviderType(AccessProviderTypeACMECA)
|
||||||
CAProviderTypeBuypass = CAProviderType(AccessProviderTypeBuypass)
|
CAProviderTypeBuypass = CAProviderType(AccessProviderTypeBuypass)
|
||||||
CAProviderTypeGoogleTrustServices = CAProviderType(AccessProviderTypeGoogleTrustServices)
|
CAProviderTypeGoogleTrustServices = CAProviderType(AccessProviderTypeGoogleTrustServices)
|
||||||
CAProviderTypeLetsEncrypt = CAProviderType(AccessProviderTypeLetsEncrypt)
|
CAProviderTypeLetsEncrypt = CAProviderType(AccessProviderTypeLetsEncrypt)
|
||||||
@@ -105,6 +121,7 @@ const (
|
|||||||
ACMEDns01ProviderTypeACMEHttpReq = ACMEDns01ProviderType(AccessProviderTypeACMEHttpReq)
|
ACMEDns01ProviderTypeACMEHttpReq = ACMEDns01ProviderType(AccessProviderTypeACMEHttpReq)
|
||||||
ACMEDns01ProviderTypeAliyun = ACMEDns01ProviderType(AccessProviderTypeAliyun) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAliyunDNS]
|
ACMEDns01ProviderTypeAliyun = ACMEDns01ProviderType(AccessProviderTypeAliyun) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAliyunDNS]
|
||||||
ACMEDns01ProviderTypeAliyunDNS = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-dns")
|
ACMEDns01ProviderTypeAliyunDNS = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-dns")
|
||||||
|
ACMEDns01ProviderTypeAliyunESA = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-esa")
|
||||||
ACMEDns01ProviderTypeAWS = ACMEDns01ProviderType(AccessProviderTypeAWS) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAWSRoute53]
|
ACMEDns01ProviderTypeAWS = ACMEDns01ProviderType(AccessProviderTypeAWS) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAWSRoute53]
|
||||||
ACMEDns01ProviderTypeAWSRoute53 = ACMEDns01ProviderType(AccessProviderTypeAWS + "-route53")
|
ACMEDns01ProviderTypeAWSRoute53 = ACMEDns01ProviderType(AccessProviderTypeAWS + "-route53")
|
||||||
ACMEDns01ProviderTypeAzure = ACMEDns01ProviderType(AccessProviderTypeAzure) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAzure]
|
ACMEDns01ProviderTypeAzure = ACMEDns01ProviderType(AccessProviderTypeAzure) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAzure]
|
||||||
@@ -115,12 +132,16 @@ const (
|
|||||||
ACMEDns01ProviderTypeCloudflare = ACMEDns01ProviderType(AccessProviderTypeCloudflare)
|
ACMEDns01ProviderTypeCloudflare = ACMEDns01ProviderType(AccessProviderTypeCloudflare)
|
||||||
ACMEDns01ProviderTypeClouDNS = ACMEDns01ProviderType(AccessProviderTypeClouDNS)
|
ACMEDns01ProviderTypeClouDNS = ACMEDns01ProviderType(AccessProviderTypeClouDNS)
|
||||||
ACMEDns01ProviderTypeCMCCCloud = ACMEDns01ProviderType(AccessProviderTypeCMCCCloud)
|
ACMEDns01ProviderTypeCMCCCloud = ACMEDns01ProviderType(AccessProviderTypeCMCCCloud)
|
||||||
|
ACMEDns01ProviderTypeConstellix = ACMEDns01ProviderType(AccessProviderTypeConstellix)
|
||||||
ACMEDns01ProviderTypeDeSEC = ACMEDns01ProviderType(AccessProviderTypeDeSEC)
|
ACMEDns01ProviderTypeDeSEC = ACMEDns01ProviderType(AccessProviderTypeDeSEC)
|
||||||
|
ACMEDns01ProviderTypeDigitalOcean = ACMEDns01ProviderType(AccessProviderTypeDigitalOcean)
|
||||||
ACMEDns01ProviderTypeDNSLA = ACMEDns01ProviderType(AccessProviderTypeDNSLA)
|
ACMEDns01ProviderTypeDNSLA = ACMEDns01ProviderType(AccessProviderTypeDNSLA)
|
||||||
|
ACMEDns01ProviderTypeDuckDNS = ACMEDns01ProviderType(AccessProviderTypeDuckDNS)
|
||||||
ACMEDns01ProviderTypeDynv6 = ACMEDns01ProviderType(AccessProviderTypeDynv6)
|
ACMEDns01ProviderTypeDynv6 = ACMEDns01ProviderType(AccessProviderTypeDynv6)
|
||||||
ACMEDns01ProviderTypeGcore = ACMEDns01ProviderType(AccessProviderTypeGcore)
|
ACMEDns01ProviderTypeGcore = ACMEDns01ProviderType(AccessProviderTypeGcore)
|
||||||
ACMEDns01ProviderTypeGname = ACMEDns01ProviderType(AccessProviderTypeGname)
|
ACMEDns01ProviderTypeGname = ACMEDns01ProviderType(AccessProviderTypeGname)
|
||||||
ACMEDns01ProviderTypeGoDaddy = ACMEDns01ProviderType(AccessProviderTypeGoDaddy)
|
ACMEDns01ProviderTypeGoDaddy = ACMEDns01ProviderType(AccessProviderTypeGoDaddy)
|
||||||
|
ACMEDns01ProviderTypeHetzner = ACMEDns01ProviderType(AccessProviderTypeHetzner)
|
||||||
ACMEDns01ProviderTypeHuaweiCloud = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeHuaweiCloudDNS]
|
ACMEDns01ProviderTypeHuaweiCloud = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeHuaweiCloudDNS]
|
||||||
ACMEDns01ProviderTypeHuaweiCloudDNS = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud + "-dns")
|
ACMEDns01ProviderTypeHuaweiCloudDNS = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud + "-dns")
|
||||||
ACMEDns01ProviderTypeJDCloud = ACMEDns01ProviderType(AccessProviderTypeJDCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeJDCloudDNS]
|
ACMEDns01ProviderTypeJDCloud = ACMEDns01ProviderType(AccessProviderTypeJDCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeJDCloudDNS]
|
||||||
@@ -128,6 +149,8 @@ const (
|
|||||||
ACMEDns01ProviderTypeNamecheap = ACMEDns01ProviderType(AccessProviderTypeNamecheap)
|
ACMEDns01ProviderTypeNamecheap = ACMEDns01ProviderType(AccessProviderTypeNamecheap)
|
||||||
ACMEDns01ProviderTypeNameDotCom = ACMEDns01ProviderType(AccessProviderTypeNameDotCom)
|
ACMEDns01ProviderTypeNameDotCom = ACMEDns01ProviderType(AccessProviderTypeNameDotCom)
|
||||||
ACMEDns01ProviderTypeNameSilo = ACMEDns01ProviderType(AccessProviderTypeNameSilo)
|
ACMEDns01ProviderTypeNameSilo = ACMEDns01ProviderType(AccessProviderTypeNameSilo)
|
||||||
|
ACMEDns01ProviderTypeNetcup = ACMEDns01ProviderType(AccessProviderTypeNetcup)
|
||||||
|
ACMEDns01ProviderTypeNetlify = ACMEDns01ProviderType(AccessProviderTypeNetlify)
|
||||||
ACMEDns01ProviderTypeNS1 = ACMEDns01ProviderType(AccessProviderTypeNS1)
|
ACMEDns01ProviderTypeNS1 = ACMEDns01ProviderType(AccessProviderTypeNS1)
|
||||||
ACMEDns01ProviderTypePorkbun = ACMEDns01ProviderType(AccessProviderTypePorkbun)
|
ACMEDns01ProviderTypePorkbun = ACMEDns01ProviderType(AccessProviderTypePorkbun)
|
||||||
ACMEDns01ProviderTypePowerDNS = ACMEDns01ProviderType(AccessProviderTypePowerDNS)
|
ACMEDns01ProviderTypePowerDNS = ACMEDns01ProviderType(AccessProviderTypePowerDNS)
|
||||||
@@ -135,6 +158,7 @@ const (
|
|||||||
ACMEDns01ProviderTypeTencentCloud = ACMEDns01ProviderType(AccessProviderTypeTencentCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeTencentCloudDNS]
|
ACMEDns01ProviderTypeTencentCloud = ACMEDns01ProviderType(AccessProviderTypeTencentCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeTencentCloudDNS]
|
||||||
ACMEDns01ProviderTypeTencentCloudDNS = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-dns")
|
ACMEDns01ProviderTypeTencentCloudDNS = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-dns")
|
||||||
ACMEDns01ProviderTypeTencentCloudEO = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-eo")
|
ACMEDns01ProviderTypeTencentCloudEO = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-eo")
|
||||||
|
ACMEDns01ProviderTypeUCloudUDNR = ACMEDns01ProviderType(AccessProviderTypeUCloud + "-udnr")
|
||||||
ACMEDns01ProviderTypeVercel = ACMEDns01ProviderType(AccessProviderTypeVercel)
|
ACMEDns01ProviderTypeVercel = ACMEDns01ProviderType(AccessProviderTypeVercel)
|
||||||
ACMEDns01ProviderTypeVolcEngine = ACMEDns01ProviderType(AccessProviderTypeVolcEngine) // 兼容旧值,等同于 [ACMEDns01ProviderTypeVolcEngineDNS]
|
ACMEDns01ProviderTypeVolcEngine = ACMEDns01ProviderType(AccessProviderTypeVolcEngine) // 兼容旧值,等同于 [ACMEDns01ProviderTypeVolcEngineDNS]
|
||||||
ACMEDns01ProviderTypeVolcEngineDNS = ACMEDns01ProviderType(AccessProviderTypeVolcEngine + "-dns")
|
ACMEDns01ProviderTypeVolcEngineDNS = ACMEDns01ProviderType(AccessProviderTypeVolcEngine + "-dns")
|
||||||
@@ -160,8 +184,10 @@ const (
|
|||||||
DeploymentProviderTypeAliyunCDN = DeploymentProviderType(AccessProviderTypeAliyun + "-cdn")
|
DeploymentProviderTypeAliyunCDN = DeploymentProviderType(AccessProviderTypeAliyun + "-cdn")
|
||||||
DeploymentProviderTypeAliyunCLB = DeploymentProviderType(AccessProviderTypeAliyun + "-clb")
|
DeploymentProviderTypeAliyunCLB = DeploymentProviderType(AccessProviderTypeAliyun + "-clb")
|
||||||
DeploymentProviderTypeAliyunDCDN = DeploymentProviderType(AccessProviderTypeAliyun + "-dcdn")
|
DeploymentProviderTypeAliyunDCDN = DeploymentProviderType(AccessProviderTypeAliyun + "-dcdn")
|
||||||
|
DeploymentProviderTypeAliyunDDoS = DeploymentProviderType(AccessProviderTypeAliyun + "-ddos")
|
||||||
DeploymentProviderTypeAliyunESA = DeploymentProviderType(AccessProviderTypeAliyun + "-esa")
|
DeploymentProviderTypeAliyunESA = DeploymentProviderType(AccessProviderTypeAliyun + "-esa")
|
||||||
DeploymentProviderTypeAliyunFC = DeploymentProviderType(AccessProviderTypeAliyun + "-fc")
|
DeploymentProviderTypeAliyunFC = DeploymentProviderType(AccessProviderTypeAliyun + "-fc")
|
||||||
|
DeploymentProviderTypeAliyunGA = DeploymentProviderType(AccessProviderTypeAliyun + "-ga")
|
||||||
DeploymentProviderTypeAliyunLive = DeploymentProviderType(AccessProviderTypeAliyun + "-live")
|
DeploymentProviderTypeAliyunLive = DeploymentProviderType(AccessProviderTypeAliyun + "-live")
|
||||||
DeploymentProviderTypeAliyunNLB = DeploymentProviderType(AccessProviderTypeAliyun + "-nlb")
|
DeploymentProviderTypeAliyunNLB = DeploymentProviderType(AccessProviderTypeAliyun + "-nlb")
|
||||||
DeploymentProviderTypeAliyunOSS = DeploymentProviderType(AccessProviderTypeAliyun + "-oss")
|
DeploymentProviderTypeAliyunOSS = DeploymentProviderType(AccessProviderTypeAliyun + "-oss")
|
||||||
@@ -169,6 +195,7 @@ const (
|
|||||||
DeploymentProviderTypeAliyunWAF = DeploymentProviderType(AccessProviderTypeAliyun + "-waf")
|
DeploymentProviderTypeAliyunWAF = DeploymentProviderType(AccessProviderTypeAliyun + "-waf")
|
||||||
DeploymentProviderTypeAWSACM = DeploymentProviderType(AccessProviderTypeAWS + "-acm")
|
DeploymentProviderTypeAWSACM = DeploymentProviderType(AccessProviderTypeAWS + "-acm")
|
||||||
DeploymentProviderTypeAWSCloudFront = DeploymentProviderType(AccessProviderTypeAWS + "-cloudfront")
|
DeploymentProviderTypeAWSCloudFront = DeploymentProviderType(AccessProviderTypeAWS + "-cloudfront")
|
||||||
|
DeploymentProviderTypeAWSIAM = DeploymentProviderType(AccessProviderTypeAWS + "-iam")
|
||||||
DeploymentProviderTypeAzureKeyVault = DeploymentProviderType(AccessProviderTypeAzure + "-keyvault")
|
DeploymentProviderTypeAzureKeyVault = DeploymentProviderType(AccessProviderTypeAzure + "-keyvault")
|
||||||
DeploymentProviderTypeBaiduCloudAppBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-appblb")
|
DeploymentProviderTypeBaiduCloudAppBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-appblb")
|
||||||
DeploymentProviderTypeBaiduCloudBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-blb")
|
DeploymentProviderTypeBaiduCloudBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-blb")
|
||||||
@@ -177,13 +204,17 @@ const (
|
|||||||
DeploymentProviderTypeBaishanCDN = DeploymentProviderType(AccessProviderTypeBaishan + "-cdn")
|
DeploymentProviderTypeBaishanCDN = DeploymentProviderType(AccessProviderTypeBaishan + "-cdn")
|
||||||
DeploymentProviderTypeBaotaPanelConsole = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-console")
|
DeploymentProviderTypeBaotaPanelConsole = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-console")
|
||||||
DeploymentProviderTypeBaotaPanelSite = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-site")
|
DeploymentProviderTypeBaotaPanelSite = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-site")
|
||||||
|
DeploymentProviderTypeBaotaWAFConsole = DeploymentProviderType(AccessProviderTypeBaotaWAF + "-console")
|
||||||
|
DeploymentProviderTypeBaotaWAFSite = DeploymentProviderType(AccessProviderTypeBaotaWAF + "-site")
|
||||||
DeploymentProviderTypeBunnyCDN = DeploymentProviderType(AccessProviderTypeBunny + "-cdn")
|
DeploymentProviderTypeBunnyCDN = DeploymentProviderType(AccessProviderTypeBunny + "-cdn")
|
||||||
DeploymentProviderTypeBytePlusCDN = DeploymentProviderType(AccessProviderTypeBytePlus + "-cdn")
|
DeploymentProviderTypeBytePlusCDN = DeploymentProviderType(AccessProviderTypeBytePlus + "-cdn")
|
||||||
DeploymentProviderTypeCacheFly = DeploymentProviderType(AccessProviderTypeCacheFly)
|
DeploymentProviderTypeCacheFly = DeploymentProviderType(AccessProviderTypeCacheFly)
|
||||||
DeploymentProviderTypeCdnfly = DeploymentProviderType(AccessProviderTypeCdnfly)
|
DeploymentProviderTypeCdnfly = DeploymentProviderType(AccessProviderTypeCdnfly)
|
||||||
DeploymentProviderTypeDogeCloudCDN = DeploymentProviderType(AccessProviderTypeDogeCloud + "-cdn")
|
DeploymentProviderTypeDogeCloudCDN = DeploymentProviderType(AccessProviderTypeDogeCloud + "-cdn")
|
||||||
DeploymentProviderTypeEdgioApplications = DeploymentProviderType(AccessProviderTypeEdgio + "-applications")
|
DeploymentProviderTypeEdgioApplications = DeploymentProviderType(AccessProviderTypeEdgio + "-applications")
|
||||||
|
DeploymentProviderTypeFlexCDN = DeploymentProviderType(AccessProviderTypeFlexCDN)
|
||||||
DeploymentProviderTypeGcoreCDN = DeploymentProviderType(AccessProviderTypeGcore + "-cdn")
|
DeploymentProviderTypeGcoreCDN = DeploymentProviderType(AccessProviderTypeGcore + "-cdn")
|
||||||
|
DeploymentProviderTypeGoEdge = DeploymentProviderType(AccessProviderTypeGoEdge)
|
||||||
DeploymentProviderTypeHuaweiCloudCDN = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-cdn")
|
DeploymentProviderTypeHuaweiCloudCDN = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-cdn")
|
||||||
DeploymentProviderTypeHuaweiCloudELB = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-elb")
|
DeploymentProviderTypeHuaweiCloudELB = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-elb")
|
||||||
DeploymentProviderTypeHuaweiCloudSCM = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-scm")
|
DeploymentProviderTypeHuaweiCloudSCM = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-scm")
|
||||||
@@ -193,11 +224,16 @@ const (
|
|||||||
DeploymentProviderTypeJDCloudLive = DeploymentProviderType(AccessProviderTypeJDCloud + "-live")
|
DeploymentProviderTypeJDCloudLive = DeploymentProviderType(AccessProviderTypeJDCloud + "-live")
|
||||||
DeploymentProviderTypeJDCloudVOD = DeploymentProviderType(AccessProviderTypeJDCloud + "-vod")
|
DeploymentProviderTypeJDCloudVOD = DeploymentProviderType(AccessProviderTypeJDCloud + "-vod")
|
||||||
DeploymentProviderTypeKubernetesSecret = DeploymentProviderType(AccessProviderTypeKubernetes + "-secret")
|
DeploymentProviderTypeKubernetesSecret = DeploymentProviderType(AccessProviderTypeKubernetes + "-secret")
|
||||||
|
DeploymentProviderTypeLeCDN = DeploymentProviderType(AccessProviderTypeLeCDN)
|
||||||
DeploymentProviderTypeLocal = DeploymentProviderType(AccessProviderTypeLocal)
|
DeploymentProviderTypeLocal = DeploymentProviderType(AccessProviderTypeLocal)
|
||||||
|
DeploymentProviderTypeNetlifySite = DeploymentProviderType(AccessProviderTypeNetlify + "-site")
|
||||||
|
DeploymentProviderTypeProxmoxVE = DeploymentProviderType(AccessProviderTypeProxmoxVE)
|
||||||
DeploymentProviderTypeQiniuCDN = DeploymentProviderType(AccessProviderTypeQiniu + "-cdn")
|
DeploymentProviderTypeQiniuCDN = DeploymentProviderType(AccessProviderTypeQiniu + "-cdn")
|
||||||
DeploymentProviderTypeQiniuKodo = DeploymentProviderType(AccessProviderTypeQiniu + "-kodo")
|
DeploymentProviderTypeQiniuKodo = DeploymentProviderType(AccessProviderTypeQiniu + "-kodo")
|
||||||
DeploymentProviderTypeQiniuPili = DeploymentProviderType(AccessProviderTypeQiniu + "-pili")
|
DeploymentProviderTypeQiniuPili = DeploymentProviderType(AccessProviderTypeQiniu + "-pili")
|
||||||
DeploymentProviderTypeRainYunRCDN = DeploymentProviderType(AccessProviderTypeRainYun + "-rcdn")
|
DeploymentProviderTypeRainYunRCDN = DeploymentProviderType(AccessProviderTypeRainYun + "-rcdn")
|
||||||
|
DeploymentProviderTypeRatPanelConsole = DeploymentProviderType(AccessProviderTypeRatPanel + "-console")
|
||||||
|
DeploymentProviderTypeRatPanelSite = DeploymentProviderType(AccessProviderTypeRatPanel + "-site")
|
||||||
DeploymentProviderTypeSafeLine = DeploymentProviderType(AccessProviderTypeSafeLine)
|
DeploymentProviderTypeSafeLine = DeploymentProviderType(AccessProviderTypeSafeLine)
|
||||||
DeploymentProviderTypeSSH = DeploymentProviderType(AccessProviderTypeSSH)
|
DeploymentProviderTypeSSH = DeploymentProviderType(AccessProviderTypeSSH)
|
||||||
DeploymentProviderTypeTencentCloudCDN = DeploymentProviderType(AccessProviderTypeTencentCloud + "-cdn")
|
DeploymentProviderTypeTencentCloudCDN = DeploymentProviderType(AccessProviderTypeTencentCloud + "-cdn")
|
||||||
@@ -213,6 +249,7 @@ const (
|
|||||||
DeploymentProviderTypeTencentCloudWAF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-waf")
|
DeploymentProviderTypeTencentCloudWAF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-waf")
|
||||||
DeploymentProviderTypeUCloudUCDN = DeploymentProviderType(AccessProviderTypeUCloud + "-ucdn")
|
DeploymentProviderTypeUCloudUCDN = DeploymentProviderType(AccessProviderTypeUCloud + "-ucdn")
|
||||||
DeploymentProviderTypeUCloudUS3 = DeploymentProviderType(AccessProviderTypeUCloud + "-us3")
|
DeploymentProviderTypeUCloudUS3 = DeploymentProviderType(AccessProviderTypeUCloud + "-us3")
|
||||||
|
DeploymentProviderTypeUniCloudWebHost = DeploymentProviderType(AccessProviderTypeUniCloud + "-webhost")
|
||||||
DeploymentProviderTypeUpyunCDN = DeploymentProviderType(AccessProviderTypeUpyun + "-cdn")
|
DeploymentProviderTypeUpyunCDN = DeploymentProviderType(AccessProviderTypeUpyun + "-cdn")
|
||||||
DeploymentProviderTypeUpyunFile = DeploymentProviderType(AccessProviderTypeUpyun + "-file")
|
DeploymentProviderTypeUpyunFile = DeploymentProviderType(AccessProviderTypeUpyun + "-file")
|
||||||
DeploymentProviderTypeVolcEngineALB = DeploymentProviderType(AccessProviderTypeVolcEngine + "-alb")
|
DeploymentProviderTypeVolcEngineALB = DeploymentProviderType(AccessProviderTypeVolcEngine + "-alb")
|
||||||
@@ -223,7 +260,9 @@ const (
|
|||||||
DeploymentProviderTypeVolcEngineImageX = DeploymentProviderType(AccessProviderTypeVolcEngine + "-imagex")
|
DeploymentProviderTypeVolcEngineImageX = DeploymentProviderType(AccessProviderTypeVolcEngine + "-imagex")
|
||||||
DeploymentProviderTypeVolcEngineLive = DeploymentProviderType(AccessProviderTypeVolcEngine + "-live")
|
DeploymentProviderTypeVolcEngineLive = DeploymentProviderType(AccessProviderTypeVolcEngine + "-live")
|
||||||
DeploymentProviderTypeVolcEngineTOS = DeploymentProviderType(AccessProviderTypeVolcEngine + "-tos")
|
DeploymentProviderTypeVolcEngineTOS = DeploymentProviderType(AccessProviderTypeVolcEngine + "-tos")
|
||||||
|
DeploymentProviderTypeWangsuCDN = DeploymentProviderType(AccessProviderTypeWangsu + "-cdn")
|
||||||
DeploymentProviderTypeWangsuCDNPro = DeploymentProviderType(AccessProviderTypeWangsu + "-cdnpro")
|
DeploymentProviderTypeWangsuCDNPro = DeploymentProviderType(AccessProviderTypeWangsu + "-cdnpro")
|
||||||
|
DeploymentProviderTypeWangsuCertificate = DeploymentProviderType(AccessProviderTypeWangsu + "-certificate")
|
||||||
DeploymentProviderTypeWebhook = DeploymentProviderType(AccessProviderTypeWebhook)
|
DeploymentProviderTypeWebhook = DeploymentProviderType(AccessProviderTypeWebhook)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -238,10 +277,12 @@ type NotificationProviderType string
|
|||||||
*/
|
*/
|
||||||
const (
|
const (
|
||||||
NotificationProviderTypeDingTalkBot = NotificationProviderType(AccessProviderTypeDingTalkBot)
|
NotificationProviderTypeDingTalkBot = NotificationProviderType(AccessProviderTypeDingTalkBot)
|
||||||
|
NotificationProviderTypeDiscordBot = NotificationProviderType(AccessProviderTypeDiscordBot)
|
||||||
NotificationProviderTypeEmail = NotificationProviderType(AccessProviderTypeEmail)
|
NotificationProviderTypeEmail = NotificationProviderType(AccessProviderTypeEmail)
|
||||||
NotificationProviderTypeLarkBot = NotificationProviderType(AccessProviderTypeLarkBot)
|
NotificationProviderTypeLarkBot = NotificationProviderType(AccessProviderTypeLarkBot)
|
||||||
NotificationProviderTypeMattermost = NotificationProviderType(AccessProviderTypeMattermost)
|
NotificationProviderTypeMattermost = NotificationProviderType(AccessProviderTypeMattermost)
|
||||||
NotificationProviderTypeTelegram = NotificationProviderType(AccessProviderTypeTelegram)
|
NotificationProviderTypeSlackBot = NotificationProviderType(AccessProviderTypeSlackBot)
|
||||||
|
NotificationProviderTypeTelegramBot = NotificationProviderType(AccessProviderTypeTelegramBot)
|
||||||
NotificationProviderTypeWebhook = NotificationProviderType(AccessProviderTypeWebhook)
|
NotificationProviderTypeWebhook = NotificationProviderType(AccessProviderTypeWebhook)
|
||||||
NotificationProviderTypeWeComBot = NotificationProviderType(AccessProviderTypeWeComBot)
|
NotificationProviderTypeWeComBot = NotificationProviderType(AccessProviderTypeWeComBot)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/usual2970/certimate/internal/domain/expr"
|
||||||
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
|
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -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")
|
||||||
@@ -68,23 +71,30 @@ type WorkflowNodeConfigForApply struct {
|
|||||||
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 提供商额外配置
|
||||||
CAProvider string `json:"caProvider,omitempty"` // CA 提供商(零值将使用全局配置)
|
CAProvider string `json:"caProvider,omitempty"` // CA 提供商(零值时使用全局配置)
|
||||||
CAProviderAccessId string `json:"caProviderAccessId,omitempty"` // CA 提供商授权记录 ID
|
CAProviderAccessId string `json:"caProviderAccessId,omitempty"` // CA 提供商授权记录 ID
|
||||||
CAProviderConfig map[string]any `json:"caProviderConfig,omitempty"` // CA 提供商额外配置
|
CAProviderConfig map[string]any `json:"caProviderConfig,omitempty"` // CA 提供商额外配置
|
||||||
KeyAlgorithm string `json:"keyAlgorithm"` // 证书算法
|
KeyAlgorithm string `json:"keyAlgorithm"` // 证书算法
|
||||||
Nameservers string `json:"nameservers,omitempty"` // DNS 服务器列表,以半角分号分隔
|
Nameservers string `json:"nameservers,omitempty"` // DNS 服务器列表,以半角分号分隔
|
||||||
DnsPropagationWait int32 `json:"dnsPropagationWait,omitempty"` // DNS 传播等待时间,等同于 lego 的 `--dns-propagation-wait` 参数
|
DnsPropagationWait int32 `json:"dnsPropagationWait,omitempty"` // DNS 传播等待时间,等同于 lego 的 `--dns-propagation-wait` 参数
|
||||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` // DNS 传播检查超时时间(零值取决于提供商的默认值)
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` // DNS 传播检查超时时间(零值时使用提供商的默认值)
|
||||||
DnsTTL int32 `json:"dnsTTL,omitempty"` // DNS 解析记录 TTL(零值取决于提供商的默认值)
|
DnsTTL int32 `json:"dnsTTL,omitempty"` // DNS 解析记录 TTL(零值时使用提供商的默认值)
|
||||||
DisableFollowCNAME bool `json:"disableFollowCNAME,omitempty"` // 是否关闭 CNAME 跟随
|
DisableFollowCNAME bool `json:"disableFollowCNAME,omitempty"` // 是否关闭 CNAME 跟随
|
||||||
DisableARI bool `json:"disableARI,omitempty"` // 是否关闭 ARI
|
DisableARI bool `json:"disableARI,omitempty"` // 是否关闭 ARI
|
||||||
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays,omitempty"` // 证书到期前多少天前跳过续期(零值将使用默认值 30)
|
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 {
|
||||||
@@ -104,12 +114,11 @@ type WorkflowNodeConfigForNotify struct {
|
|||||||
Message string `json:"message"` // 通知内容
|
Message string `json:"message"` // 通知内容
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply {
|
type WorkflowNodeConfigForCondition struct {
|
||||||
skipBeforeExpiryDays := maputil.GetInt32(n.Config, "skipBeforeExpiryDays")
|
Expression expr.Expr `json:"expression"` // 条件表达式
|
||||||
if skipBeforeExpiryDays == 0 {
|
}
|
||||||
skipBeforeExpiryDays = 30
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply {
|
||||||
return WorkflowNodeConfigForApply{
|
return WorkflowNodeConfigForApply{
|
||||||
Domains: maputil.GetString(n.Config, "domains"),
|
Domains: maputil.GetString(n.Config, "domains"),
|
||||||
ContactEmail: maputil.GetString(n.Config, "contactEmail"),
|
ContactEmail: maputil.GetString(n.Config, "contactEmail"),
|
||||||
@@ -126,7 +135,7 @@ func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply {
|
|||||||
DnsTTL: maputil.GetInt32(n.Config, "dnsTTL"),
|
DnsTTL: maputil.GetInt32(n.Config, "dnsTTL"),
|
||||||
DisableFollowCNAME: maputil.GetBool(n.Config, "disableFollowCNAME"),
|
DisableFollowCNAME: maputil.GetBool(n.Config, "disableFollowCNAME"),
|
||||||
DisableARI: maputil.GetBool(n.Config, "disableARI"),
|
DisableARI: maputil.GetBool(n.Config, "disableARI"),
|
||||||
SkipBeforeExpiryDays: skipBeforeExpiryDays,
|
SkipBeforeExpiryDays: maputil.GetOrDefaultInt32(n.Config, "skipBeforeExpiryDays", 30),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +147,16 @@ func (n *WorkflowNode) GetConfigForUpload() WorkflowNodeConfigForUpload {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *WorkflowNode) GetConfigForMonitor() WorkflowNodeConfigForMonitor {
|
||||||
|
host := maputil.GetString(n.Config, "host")
|
||||||
|
return WorkflowNodeConfigForMonitor{
|
||||||
|
Host: host,
|
||||||
|
Port: maputil.GetOrDefaultInt32(n.Config, "port", 443),
|
||||||
|
Domain: maputil.GetOrDefaultString(n.Config, "domain", host),
|
||||||
|
RequestPath: maputil.GetString(n.Config, "path"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy {
|
func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy {
|
||||||
return WorkflowNodeConfigForDeploy{
|
return WorkflowNodeConfigForDeploy{
|
||||||
Certificate: maputil.GetString(n.Config, "certificate"),
|
Certificate: maputil.GetString(n.Config, "certificate"),
|
||||||
@@ -159,6 +178,23 @@ func (n *WorkflowNode) GetConfigForNotify() WorkflowNodeConfigForNotify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type WorkflowNodeIO struct {
|
type WorkflowNodeIO struct {
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@@ -168,9 +204,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"
|
||||||
|
|||||||
@@ -29,18 +29,18 @@ func NewWithWorkflowNode(config NotifierWithWorkflowNodeConfig) (Notifier, error
|
|||||||
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeNotify))
|
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeNotify))
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeConfig := config.Node.GetConfigForNotify()
|
nodeCfg := config.Node.GetConfigForNotify()
|
||||||
options := ¬ifierProviderOptions{
|
options := ¬ifierProviderOptions{
|
||||||
Provider: domain.NotificationProviderType(nodeConfig.Provider),
|
Provider: domain.NotificationProviderType(nodeCfg.Provider),
|
||||||
ProviderAccessConfig: make(map[string]any),
|
ProviderAccessConfig: make(map[string]any),
|
||||||
ProviderExtendedConfig: nodeConfig.ProviderConfig,
|
ProviderServiceConfig: nodeCfg.ProviderConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
accessRepo := repository.NewAccessRepository()
|
accessRepo := repository.NewAccessRepository()
|
||||||
if nodeConfig.ProviderAccessId != "" {
|
if nodeCfg.ProviderAccessId != "" {
|
||||||
access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId)
|
access, err := accessRepo.GetById(context.Background(), nodeCfg.ProviderAccessId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
|
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.ProviderAccessId, err)
|
||||||
} else {
|
} else {
|
||||||
options.ProviderAccessConfig = access.Config
|
options.ProviderAccessConfig = access.Config
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,21 +6,23 @@ import (
|
|||||||
|
|
||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/usual2970/certimate/internal/domain"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
||||||
pDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk"
|
pDingTalkBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalkbot"
|
||||||
|
pDiscordBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/discordbot"
|
||||||
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
|
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
|
||||||
pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark"
|
pLarkBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/larkbot"
|
||||||
pMattermost "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
|
pMattermost "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
|
||||||
pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram"
|
pSlackBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/slackbot"
|
||||||
|
pTelegramBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegrambot"
|
||||||
pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook"
|
pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook"
|
||||||
pWeCom "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecom"
|
pWeComBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecombot"
|
||||||
httputil "github.com/usual2970/certimate/internal/pkg/utils/http"
|
httputil "github.com/usual2970/certimate/internal/pkg/utils/http"
|
||||||
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
|
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
|
||||||
)
|
)
|
||||||
|
|
||||||
type notifierProviderOptions struct {
|
type notifierProviderOptions struct {
|
||||||
Provider domain.NotificationProviderType
|
Provider domain.NotificationProviderType
|
||||||
ProviderAccessConfig map[string]any
|
ProviderAccessConfig map[string]any
|
||||||
ProviderExtendedConfig map[string]any
|
ProviderServiceConfig map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier, error) {
|
func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier, error) {
|
||||||
@@ -36,12 +38,25 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
|
|||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pDingTalk.NewNotifier(&pDingTalk.NotifierConfig{
|
return pDingTalkBot.NewNotifier(&pDingTalkBot.NotifierConfig{
|
||||||
WebhookUrl: access.WebhookUrl,
|
WebhookUrl: access.WebhookUrl,
|
||||||
Secret: access.Secret,
|
Secret: access.Secret,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case domain.NotificationProviderTypeDiscordBot:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForDiscordBot{}
|
||||||
|
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pDiscordBot.NewNotifier(&pDiscordBot.NotifierConfig{
|
||||||
|
BotToken: access.BotToken,
|
||||||
|
ChannelId: maputil.GetOrDefaultString(options.ProviderServiceConfig, "channelId", access.DefaultChannelId),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
case domain.NotificationProviderTypeEmail:
|
case domain.NotificationProviderTypeEmail:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForEmail{}
|
access := domain.AccessConfigForEmail{}
|
||||||
@@ -55,8 +70,8 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
|
|||||||
SmtpTls: access.SmtpTls,
|
SmtpTls: access.SmtpTls,
|
||||||
Username: access.Username,
|
Username: access.Username,
|
||||||
Password: access.Password,
|
Password: access.Password,
|
||||||
SenderAddress: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "senderAddress", access.DefaultSenderAddress),
|
SenderAddress: maputil.GetOrDefaultString(options.ProviderServiceConfig, "senderAddress", access.DefaultSenderAddress),
|
||||||
ReceiverAddress: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "receiverAddress", access.DefaultReceiverAddress),
|
ReceiverAddress: maputil.GetOrDefaultString(options.ProviderServiceConfig, "receiverAddress", access.DefaultReceiverAddress),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +82,7 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
|
|||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pLark.NewNotifier(&pLark.NotifierConfig{
|
return pLarkBot.NewNotifier(&pLarkBot.NotifierConfig{
|
||||||
WebhookUrl: access.WebhookUrl,
|
WebhookUrl: access.WebhookUrl,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -83,20 +98,33 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
|
|||||||
ServerUrl: access.ServerUrl,
|
ServerUrl: access.ServerUrl,
|
||||||
Username: access.Username,
|
Username: access.Username,
|
||||||
Password: access.Password,
|
Password: access.Password,
|
||||||
ChannelId: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "channelId", access.DefaultChannelId),
|
ChannelId: maputil.GetOrDefaultString(options.ProviderServiceConfig, "channelId", access.DefaultChannelId),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.NotificationProviderTypeTelegram:
|
case domain.NotificationProviderTypeSlackBot:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForTelegram{}
|
access := domain.AccessConfigForSlackBot{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := maputil.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pTelegram.NewNotifier(&pTelegram.NotifierConfig{
|
return pSlackBot.NewNotifier(&pSlackBot.NotifierConfig{
|
||||||
|
BotToken: access.BotToken,
|
||||||
|
ChannelId: maputil.GetOrDefaultString(options.ProviderServiceConfig, "channelId", access.DefaultChannelId),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
case domain.NotificationProviderTypeTelegramBot:
|
||||||
|
{
|
||||||
|
access := domain.AccessConfigForTelegramBot{}
|
||||||
|
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pTelegramBot.NewNotifier(&pTelegramBot.NotifierConfig{
|
||||||
BotToken: access.BotToken,
|
BotToken: access.BotToken,
|
||||||
ChatId: maputil.GetOrDefaultInt64(options.ProviderExtendedConfig, "chatId", access.DefaultChatId),
|
ChatId: maputil.GetOrDefaultInt64(options.ProviderServiceConfig, "chatId", access.DefaultChatId),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +145,7 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
|
|||||||
mergedHeaders[http.CanonicalHeaderKey(key)] = h.Get(key)
|
mergedHeaders[http.CanonicalHeaderKey(key)] = h.Get(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if extendedHeadersString := maputil.GetString(options.ProviderExtendedConfig, "headers"); extendedHeadersString != "" {
|
if extendedHeadersString := maputil.GetString(options.ProviderServiceConfig, "headers"); extendedHeadersString != "" {
|
||||||
h, err := httputil.ParseHeaders(extendedHeadersString)
|
h, err := httputil.ParseHeaders(extendedHeadersString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse webhook headers: %w", err)
|
return nil, fmt.Errorf("failed to parse webhook headers: %w", err)
|
||||||
@@ -129,7 +157,7 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
|
|||||||
|
|
||||||
return pWebhook.NewNotifier(&pWebhook.NotifierConfig{
|
return pWebhook.NewNotifier(&pWebhook.NotifierConfig{
|
||||||
WebhookUrl: access.Url,
|
WebhookUrl: access.Url,
|
||||||
WebhookData: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "webhookData", access.DefaultDataForNotification),
|
WebhookData: maputil.GetOrDefaultString(options.ProviderServiceConfig, "webhookData", access.DefaultDataForNotification),
|
||||||
Method: access.Method,
|
Method: access.Method,
|
||||||
Headers: mergedHeaders,
|
Headers: mergedHeaders,
|
||||||
AllowInsecureConnections: access.AllowInsecureConnections,
|
AllowInsecureConnections: access.AllowInsecureConnections,
|
||||||
@@ -143,7 +171,7 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
|
|||||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pWeCom.NewNotifier(&pWeCom.NotifierConfig{
|
return pWeComBot.NewNotifier(&pWeComBot.NotifierConfig{
|
||||||
WebhookUrl: access.WebhookUrl,
|
WebhookUrl: access.WebhookUrl,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ import (
|
|||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/usual2970/certimate/internal/domain"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
||||||
pBark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/bark"
|
pBark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/bark"
|
||||||
pDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk"
|
pDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalkbot"
|
||||||
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
|
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
|
||||||
pGotify "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/gotify"
|
pGotify "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/gotify"
|
||||||
pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark"
|
pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/larkbot"
|
||||||
pMattermost "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
|
pMattermost "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
|
||||||
pPushover "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushover"
|
pPushover "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushover"
|
||||||
pPushPlus "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushplus"
|
pPushPlus "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushplus"
|
||||||
pServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan"
|
pServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan"
|
||||||
pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram"
|
pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegrambot"
|
||||||
pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook"
|
pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook"
|
||||||
pWeCom "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecom"
|
pWeCom "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecombot"
|
||||||
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
|
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -52,9 +52,9 @@ func createNotifierProviderUseGlobalSettings(channel domain.NotifyChannelType, c
|
|||||||
|
|
||||||
case domain.NotifyChannelTypeGotify:
|
case domain.NotifyChannelTypeGotify:
|
||||||
return pGotify.NewNotifier(&pGotify.NotifierConfig{
|
return pGotify.NewNotifier(&pGotify.NotifierConfig{
|
||||||
Url: maputil.GetString(channelConfig, "url"),
|
ServerUrl: maputil.GetString(channelConfig, "url"),
|
||||||
Token: maputil.GetString(channelConfig, "token"),
|
Token: maputil.GetString(channelConfig, "token"),
|
||||||
Priority: maputil.GetOrDefaultInt64(channelConfig, "priority", 1),
|
Priority: maputil.GetOrDefaultInt64(channelConfig, "priority", 1),
|
||||||
})
|
})
|
||||||
|
|
||||||
case domain.NotifyChannelTypeLark:
|
case domain.NotifyChannelTypeLark:
|
||||||
@@ -83,7 +83,7 @@ func createNotifierProviderUseGlobalSettings(channel domain.NotifyChannelType, c
|
|||||||
|
|
||||||
case domain.NotifyChannelTypeServerChan:
|
case domain.NotifyChannelTypeServerChan:
|
||||||
return pServerChan.NewNotifier(&pServerChan.NotifierConfig{
|
return pServerChan.NewNotifier(&pServerChan.NotifierConfig{
|
||||||
Url: maputil.GetString(channelConfig, "url"),
|
ServerUrl: maputil.GetString(channelConfig, "url"),
|
||||||
})
|
})
|
||||||
|
|
||||||
case domain.NotifyChannelTypeTelegram:
|
case domain.NotifyChannelTypeTelegram:
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package aliyunesa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
|
||||||
|
internal "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun-esa/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChallengeProviderConfig struct {
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
Region string `json:"region"`
|
||||||
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||||
|
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||||
|
if config == nil {
|
||||||
|
panic("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
providerConfig := internal.NewDefaultConfig()
|
||||||
|
providerConfig.SecretID = config.AccessKeyId
|
||||||
|
providerConfig.SecretKey = config.AccessKeySecret
|
||||||
|
providerConfig.RegionID = config.Region
|
||||||
|
if config.DnsPropagationTimeout != 0 {
|
||||||
|
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||||
|
}
|
||||||
|
if config.DnsTTL != 0 {
|
||||||
|
providerConfig.TTL = config.DnsTTL
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := internal.NewDNSProviderConfig(providerConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,271 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||||
|
aliesa "github.com/alibabacloud-go/esa-20240910/v2/client"
|
||||||
|
"github.com/alibabacloud-go/tea/tea"
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||||
|
"github.com/go-acme/lego/v4/platform/config/env"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
envNamespace = "ALICLOUDESA_"
|
||||||
|
|
||||||
|
EnvAccessKey = envNamespace + "ACCESS_KEY"
|
||||||
|
EnvSecretKey = envNamespace + "SECRET_KEY"
|
||||||
|
EnvRegionID = envNamespace + "REGION_ID"
|
||||||
|
|
||||||
|
EnvTTL = envNamespace + "TTL"
|
||||||
|
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||||
|
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
||||||
|
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
SecretID string
|
||||||
|
SecretKey string
|
||||||
|
RegionID string
|
||||||
|
|
||||||
|
PropagationTimeout time.Duration
|
||||||
|
PollingInterval time.Duration
|
||||||
|
TTL int32
|
||||||
|
HTTPTimeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type DNSProvider struct {
|
||||||
|
client *aliesa.Client
|
||||||
|
config *Config
|
||||||
|
|
||||||
|
siteIDs map[string]int64
|
||||||
|
siteIDsMtx sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
TTL: int32(env.GetOrDefaultInt(EnvTTL, 300)),
|
||||||
|
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
|
||||||
|
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
|
||||||
|
HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDNSProvider() (*DNSProvider, error) {
|
||||||
|
values, err := env.Get(EnvAccessKey, EnvSecretKey, EnvRegionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("alicloud-esa: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
config.SecretID = values[EnvAccessKey]
|
||||||
|
config.SecretKey = values[EnvSecretKey]
|
||||||
|
config.RegionID = values[EnvRegionID]
|
||||||
|
|
||||||
|
return NewDNSProviderConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("alicloud-esa: the configuration of the DNS provider is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := aliesa.NewClient(&aliopen.Config{
|
||||||
|
AccessKeyId: tea.String(config.SecretID),
|
||||||
|
AccessKeySecret: tea.String(config.SecretKey),
|
||||||
|
Endpoint: tea.String(fmt.Sprintf("esa.%s.aliyuncs.com", config.RegionID)),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("alicloud-esa: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DNSProvider{
|
||||||
|
client: client,
|
||||||
|
config: config,
|
||||||
|
|
||||||
|
siteIDs: make(map[string]int64),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
|
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||||
|
|
||||||
|
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("alicloud-esa: could not find zone for domain %q: %w", domain, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
siteName := dns01.UnFqdn(authZone)
|
||||||
|
siteId, err := d.getSiteId(siteName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("alicloud-esa: could not find site for zone %q: %w", siteName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.addOrUpdateDNSRecord(siteId, dns01.UnFqdn(info.EffectiveFQDN), info.Value); err != nil {
|
||||||
|
return fmt.Errorf("alicloud-esa: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
|
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||||
|
|
||||||
|
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("alicloud-esa: could not find zone for domain %q: %w", domain, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
siteName := dns01.UnFqdn(authZone)
|
||||||
|
siteId, err := d.getSiteId(siteName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("alicloud-esa: could not find site for zone %q: %w", siteName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.removeDNSRecord(siteId, dns01.UnFqdn(info.EffectiveFQDN)); err != nil {
|
||||||
|
return fmt.Errorf("alicloud-esa: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||||
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) getSiteId(siteName string) (int64, error) {
|
||||||
|
d.siteIDsMtx.Lock()
|
||||||
|
siteID, ok := d.siteIDs[siteName]
|
||||||
|
d.siteIDsMtx.Unlock()
|
||||||
|
if ok {
|
||||||
|
return siteID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pageNumber := 1
|
||||||
|
pageSize := 500
|
||||||
|
for {
|
||||||
|
request := &aliesa.ListSitesRequest{
|
||||||
|
SiteName: tea.String(siteName),
|
||||||
|
SiteSearchType: tea.String("exact"),
|
||||||
|
PageNumber: tea.Int32(int32(pageNumber)),
|
||||||
|
PageSize: tea.Int32(int32(pageSize)),
|
||||||
|
AccessType: tea.String("NS"),
|
||||||
|
}
|
||||||
|
response, err := d.client.ListSites(request)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.Body == nil {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
for _, record := range response.Body.Sites {
|
||||||
|
if tea.StringValue(record.SiteName) == siteName {
|
||||||
|
d.siteIDsMtx.Lock()
|
||||||
|
d.siteIDs[siteName] = *record.SiteId
|
||||||
|
d.siteIDsMtx.Unlock()
|
||||||
|
return *record.SiteId, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(response.Body.Sites) < pageSize {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
pageNumber++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, errors.New("site not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) findDNSRecord(siteId int64, effectiveFQDN string) (*aliesa.ListRecordsResponseBodyRecords, error) {
|
||||||
|
pageNumber := 1
|
||||||
|
pageSize := 500
|
||||||
|
for {
|
||||||
|
request := &aliesa.ListRecordsRequest{
|
||||||
|
SiteId: tea.Int64(siteId),
|
||||||
|
Type: tea.String("TXT"),
|
||||||
|
RecordName: tea.String(effectiveFQDN),
|
||||||
|
RecordMatchType: tea.String("exact"),
|
||||||
|
PageNumber: tea.Int32(int32(pageNumber)),
|
||||||
|
PageSize: tea.Int32(int32(pageSize)),
|
||||||
|
}
|
||||||
|
response, err := d.client.ListRecords(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.Body == nil {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
for _, record := range response.Body.Records {
|
||||||
|
if tea.StringValue(record.RecordName) == effectiveFQDN {
|
||||||
|
return record, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(response.Body.Records) < pageSize {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
pageNumber++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) addOrUpdateDNSRecord(siteId int64, effectiveFQDN, value string) error {
|
||||||
|
record, err := d.findDNSRecord(siteId, effectiveFQDN)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if record == nil {
|
||||||
|
request := &aliesa.CreateRecordRequest{
|
||||||
|
SiteId: tea.Int64(siteId),
|
||||||
|
Type: tea.String("TXT"),
|
||||||
|
RecordName: tea.String(effectiveFQDN),
|
||||||
|
Data: &aliesa.CreateRecordRequestData{
|
||||||
|
Value: tea.String(value),
|
||||||
|
},
|
||||||
|
Ttl: tea.Int32(d.config.TTL),
|
||||||
|
}
|
||||||
|
_, err := d.client.CreateRecord(request)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
request := &aliesa.UpdateRecordRequest{
|
||||||
|
RecordId: record.RecordId,
|
||||||
|
Ttl: tea.Int32(d.config.TTL),
|
||||||
|
Data: &aliesa.UpdateRecordRequestData{
|
||||||
|
Value: tea.String(value),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := d.client.UpdateRecord(request)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) removeDNSRecord(siteId int64, effectiveFQDN string) error {
|
||||||
|
record, err := d.findDNSRecord(siteId, effectiveFQDN)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if record == nil {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
request := &aliesa.DeleteRecordRequest{
|
||||||
|
RecordId: record.RecordId,
|
||||||
|
}
|
||||||
|
_, err = d.client.DeleteRecord(request)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package lego_baiducloud
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -128,7 +128,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*bcedns.Record, error) {
|
func (d *DNSProvider) findDNSRecord(zoneName, subDomain string) (*bcedns.Record, error) {
|
||||||
pageMarker := ""
|
pageMarker := ""
|
||||||
pageSize := 1000
|
pageSize := 1000
|
||||||
for {
|
for {
|
||||||
@@ -159,7 +159,7 @@ func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*bcedns.Record,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error {
|
func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error {
|
||||||
record, err := d.getDNSRecord(zoneName, subDomain)
|
record, err := d.findDNSRecord(zoneName, subDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error {
|
func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error {
|
||||||
record, err := d.getDNSRecord(zoneName, subDomain)
|
record, err := d.findDNSRecord(zoneName, subDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package cloudns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/constellix"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChallengeProviderConfig struct {
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
SecretKey string `json:"secretKey"`
|
||||||
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||||
|
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||||
|
if config == nil {
|
||||||
|
panic("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
providerConfig := constellix.NewDefaultConfig()
|
||||||
|
providerConfig.APIKey = config.ApiKey
|
||||||
|
providerConfig.SecretKey = config.SecretKey
|
||||||
|
if config.DnsPropagationTimeout != 0 {
|
||||||
|
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||||
|
}
|
||||||
|
if config.DnsTTL != 0 {
|
||||||
|
providerConfig.TTL = int(config.DnsTTL)
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := constellix.NewDNSProviderConfig(providerConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package namedotcom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/digitalocean"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChallengeProviderConfig struct {
|
||||||
|
AccessToken string `json:"accessToken"`
|
||||||
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||||
|
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||||
|
if config == nil {
|
||||||
|
panic("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
providerConfig := digitalocean.NewDefaultConfig()
|
||||||
|
providerConfig.AuthToken = config.AccessToken
|
||||||
|
if config.DnsPropagationTimeout != 0 {
|
||||||
|
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||||
|
}
|
||||||
|
if config.DnsTTL != 0 {
|
||||||
|
providerConfig.TTL = int(config.DnsTTL)
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := digitalocean.NewDNSProviderConfig(providerConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package lego_dnsla
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package namedotcom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/duckdns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChallengeProviderConfig struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||||
|
if config == nil {
|
||||||
|
panic("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
providerConfig := duckdns.NewDefaultConfig()
|
||||||
|
providerConfig.Token = config.Token
|
||||||
|
if config.DnsPropagationTimeout != 0 {
|
||||||
|
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := duckdns.NewDNSProviderConfig(providerConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package lego_dynv6
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -115,7 +115,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*libdns.Record, error) {
|
func (d *DNSProvider) findDNSRecord(zoneName, subDomain string) (*libdns.Record, error) {
|
||||||
records, err := d.client.GetRecords(context.Background(), zoneName)
|
records, err := d.client.GetRecords(context.Background(), zoneName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -131,7 +131,7 @@ func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*libdns.Record,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error {
|
func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error {
|
||||||
record, err := d.getDNSRecord(zoneName, subDomain)
|
record, err := d.findDNSRecord(zoneName, subDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error {
|
func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error {
|
||||||
record, err := d.getDNSRecord(zoneName, subDomain)
|
record, err := d.findDNSRecord(zoneName, subDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package lego_gname
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -121,7 +121,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*gnamesdk.ResolutionRecord, error) {
|
func (d *DNSProvider) findDNSRecord(zoneName, subDomain string) (*gnamesdk.ResolutionRecord, error) {
|
||||||
page := int32(1)
|
page := int32(1)
|
||||||
pageSize := int32(20)
|
pageSize := int32(20)
|
||||||
for {
|
for {
|
||||||
@@ -155,7 +155,7 @@ func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*gnamesdk.Resolu
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error {
|
func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error {
|
||||||
record, err := d.getDNSRecord(zoneName, subDomain)
|
record, err := d.findDNSRecord(zoneName, subDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error {
|
func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error {
|
||||||
record, err := d.getDNSRecord(zoneName, subDomain)
|
record, err := d.findDNSRecord(zoneName, subDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package namedotcom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/hetzner"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChallengeProviderConfig struct {
|
||||||
|
ApiToken string `json:"apiToken"`
|
||||||
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||||
|
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||||
|
if config == nil {
|
||||||
|
panic("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
providerConfig := hetzner.NewDefaultConfig()
|
||||||
|
providerConfig.APIKey = config.ApiToken
|
||||||
|
if config.DnsPropagationTimeout != 0 {
|
||||||
|
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||||
|
}
|
||||||
|
if config.DnsTTL != 0 {
|
||||||
|
providerConfig.TTL = int(config.DnsTTL)
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := hetzner.NewDNSProviderConfig(providerConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package lego_jdcloud
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package netcup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/netcup"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChallengeProviderConfig struct {
|
||||||
|
CustomerNumber string `json:"customerNumber"`
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
ApiPassword string `json:"apiPassword"`
|
||||||
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||||
|
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||||
|
if config == nil {
|
||||||
|
panic("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
providerConfig := netcup.NewDefaultConfig()
|
||||||
|
providerConfig.Customer = config.CustomerNumber
|
||||||
|
providerConfig.Key = config.ApiKey
|
||||||
|
providerConfig.Password = config.ApiPassword
|
||||||
|
if config.DnsPropagationTimeout != 0 {
|
||||||
|
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||||
|
}
|
||||||
|
if config.DnsTTL != 0 {
|
||||||
|
providerConfig.TTL = int(config.DnsTTL)
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := netcup.NewDNSProviderConfig(providerConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package netcup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/netlify"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChallengeProviderConfig struct {
|
||||||
|
ApiToken string `json:"apiToken"`
|
||||||
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||||
|
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||||
|
if config == nil {
|
||||||
|
panic("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
providerConfig := netlify.NewDefaultConfig()
|
||||||
|
providerConfig.Token = config.ApiToken
|
||||||
|
if config.DnsPropagationTimeout != 0 {
|
||||||
|
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||||
|
}
|
||||||
|
if config.DnsTTL != 0 {
|
||||||
|
providerConfig.TTL = int(config.DnsTTL)
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := netlify.NewDNSProviderConfig(providerConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package powerdns
|
package powerdns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -9,10 +11,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ChallengeProviderConfig struct {
|
type ChallengeProviderConfig struct {
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||||
|
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||||
@@ -20,10 +23,18 @@ func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider,
|
|||||||
panic("config is nil")
|
panic("config is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
host, _ := url.Parse(config.ApiUrl)
|
serverUrl, _ := url.Parse(config.ServerUrl)
|
||||||
providerConfig := pdns.NewDefaultConfig()
|
providerConfig := pdns.NewDefaultConfig()
|
||||||
providerConfig.Host = host
|
providerConfig.Host = serverUrl
|
||||||
providerConfig.APIKey = config.ApiKey
|
providerConfig.APIKey = config.ApiKey
|
||||||
|
if config.AllowInsecureConnections {
|
||||||
|
providerConfig.HTTPClient.Transport = &http.Transport{
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
if config.DnsPropagationTimeout != 0 {
|
if config.DnsPropagationTimeout != 0 {
|
||||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
package lego_tencentcloudeo
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/challenge"
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
@@ -20,7 +19,7 @@ const (
|
|||||||
|
|
||||||
EnvSecretID = envNamespace + "SECRET_ID"
|
EnvSecretID = envNamespace + "SECRET_ID"
|
||||||
EnvSecretKey = envNamespace + "SECRET_KEY"
|
EnvSecretKey = envNamespace + "SECRET_KEY"
|
||||||
EnvZoneId = envNamespace + "ZONE_ID"
|
EnvZoneID = envNamespace + "ZONE_ID"
|
||||||
|
|
||||||
EnvTTL = envNamespace + "TTL"
|
EnvTTL = envNamespace + "TTL"
|
||||||
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||||
@@ -33,7 +32,7 @@ var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
SecretID string
|
SecretID string
|
||||||
SecretKey string
|
SecretKey string
|
||||||
ZoneId string
|
ZoneID string
|
||||||
|
|
||||||
PropagationTimeout time.Duration
|
PropagationTimeout time.Duration
|
||||||
PollingInterval time.Duration
|
PollingInterval time.Duration
|
||||||
@@ -56,7 +55,7 @@ func NewDefaultConfig() *Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewDNSProvider() (*DNSProvider, error) {
|
func NewDNSProvider() (*DNSProvider, error) {
|
||||||
values, err := env.Get(EnvSecretID, EnvSecretKey, EnvZoneId)
|
values, err := env.Get(EnvSecretID, EnvSecretKey, EnvZoneID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("tencentcloud-eo: %w", err)
|
return nil, fmt.Errorf("tencentcloud-eo: %w", err)
|
||||||
}
|
}
|
||||||
@@ -64,7 +63,7 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||||||
config := NewDefaultConfig()
|
config := NewDefaultConfig()
|
||||||
config.SecretID = values[EnvSecretID]
|
config.SecretID = values[EnvSecretID]
|
||||||
config.SecretKey = values[EnvSecretKey]
|
config.SecretKey = values[EnvSecretKey]
|
||||||
config.ZoneId = values[EnvSecretKey]
|
config.ZoneID = values[EnvSecretKey]
|
||||||
|
|
||||||
return NewDNSProviderConfig(config)
|
return NewDNSProviderConfig(config)
|
||||||
}
|
}
|
||||||
@@ -91,7 +90,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||||
|
|
||||||
if err := d.addOrUpdateDNSRecord(strings.TrimRight(info.EffectiveFQDN, "."), info.Value); err != nil {
|
if err := d.addOrUpdateDNSRecord(dns01.UnFqdn(info.EffectiveFQDN), info.Value); err != nil {
|
||||||
return fmt.Errorf("tencentcloud-eo: %w", err)
|
return fmt.Errorf("tencentcloud-eo: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +100,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||||
|
|
||||||
if err := d.removeDNSRecord(strings.TrimRight(info.EffectiveFQDN, ".")); err != nil {
|
if err := d.removeDNSRecord(dns01.UnFqdn(info.EffectiveFQDN)); err != nil {
|
||||||
return fmt.Errorf("tencentcloud-eo: %w", err)
|
return fmt.Errorf("tencentcloud-eo: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,12 +111,12 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) getDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error) {
|
func (d *DNSProvider) findDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error) {
|
||||||
pageOffset := 0
|
pageOffset := 0
|
||||||
pageLimit := 1000
|
pageLimit := 1000
|
||||||
for {
|
for {
|
||||||
request := teo.NewDescribeDnsRecordsRequest()
|
request := teo.NewDescribeDnsRecordsRequest()
|
||||||
request.ZoneId = common.StringPtr(d.config.ZoneId)
|
request.ZoneId = common.StringPtr(d.config.ZoneID)
|
||||||
request.Offset = common.Int64Ptr(int64(pageOffset))
|
request.Offset = common.Int64Ptr(int64(pageOffset))
|
||||||
request.Limit = common.Int64Ptr(int64(pageLimit))
|
request.Limit = common.Int64Ptr(int64(pageLimit))
|
||||||
request.Filters = []*teo.AdvancedFilter{
|
request.Filters = []*teo.AdvancedFilter{
|
||||||
@@ -141,7 +140,7 @@ func (d *DNSProvider) getDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(response.Response.DnsRecords) < int(pageLimit) {
|
if len(response.Response.DnsRecords) < pageLimit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,14 +152,14 @@ func (d *DNSProvider) getDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) addOrUpdateDNSRecord(effectiveFQDN, value string) error {
|
func (d *DNSProvider) addOrUpdateDNSRecord(effectiveFQDN, value string) error {
|
||||||
record, err := d.getDNSRecord(effectiveFQDN)
|
record, err := d.findDNSRecord(effectiveFQDN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if record == nil {
|
if record == nil {
|
||||||
request := teo.NewCreateDnsRecordRequest()
|
request := teo.NewCreateDnsRecordRequest()
|
||||||
request.ZoneId = common.StringPtr(d.config.ZoneId)
|
request.ZoneId = common.StringPtr(d.config.ZoneID)
|
||||||
request.Name = common.StringPtr(effectiveFQDN)
|
request.Name = common.StringPtr(effectiveFQDN)
|
||||||
request.Type = common.StringPtr("TXT")
|
request.Type = common.StringPtr("TXT")
|
||||||
request.Content = common.StringPtr(value)
|
request.Content = common.StringPtr(value)
|
||||||
@@ -169,8 +168,9 @@ func (d *DNSProvider) addOrUpdateDNSRecord(effectiveFQDN, value string) error {
|
|||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
record.Content = common.StringPtr(value)
|
record.Content = common.StringPtr(value)
|
||||||
|
record.TTL = common.Int64Ptr(int64(d.config.TTL))
|
||||||
request := teo.NewModifyDnsRecordsRequest()
|
request := teo.NewModifyDnsRecordsRequest()
|
||||||
request.ZoneId = common.StringPtr(d.config.ZoneId)
|
request.ZoneId = common.StringPtr(d.config.ZoneID)
|
||||||
request.DnsRecords = []*teo.DnsRecord{record}
|
request.DnsRecords = []*teo.DnsRecord{record}
|
||||||
if _, err := d.client.ModifyDnsRecords(request); err != nil {
|
if _, err := d.client.ModifyDnsRecords(request); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -178,7 +178,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(effectiveFQDN, value string) error {
|
|||||||
|
|
||||||
if *record.Status == "disable" {
|
if *record.Status == "disable" {
|
||||||
request := teo.NewModifyDnsRecordsStatusRequest()
|
request := teo.NewModifyDnsRecordsStatusRequest()
|
||||||
request.ZoneId = common.StringPtr(d.config.ZoneId)
|
request.ZoneId = common.StringPtr(d.config.ZoneID)
|
||||||
request.RecordsToEnable = []*string{record.RecordId}
|
request.RecordsToEnable = []*string{record.RecordId}
|
||||||
if _, err = d.client.ModifyDnsRecordsStatus(request); err != nil {
|
if _, err = d.client.ModifyDnsRecordsStatus(request); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -190,7 +190,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(effectiveFQDN, value string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) removeDNSRecord(effectiveFQDN string) error {
|
func (d *DNSProvider) removeDNSRecord(effectiveFQDN string) error {
|
||||||
record, err := d.getDNSRecord(effectiveFQDN)
|
record, err := d.findDNSRecord(effectiveFQDN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ func (d *DNSProvider) removeDNSRecord(effectiveFQDN string) error {
|
|||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
request := teo.NewDeleteDnsRecordsRequest()
|
request := teo.NewDeleteDnsRecordsRequest()
|
||||||
request.ZoneId = common.StringPtr(d.config.ZoneId)
|
request.ZoneId = common.StringPtr(d.config.ZoneID)
|
||||||
request.RecordIds = []*string{record.RecordId}
|
request.RecordIds = []*string{record.RecordId}
|
||||||
_, err = d.client.DeleteDnsRecords(request)
|
_, err = d.client.DeleteDnsRecords(request)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider,
|
|||||||
providerConfig := internal.NewDefaultConfig()
|
providerConfig := internal.NewDefaultConfig()
|
||||||
providerConfig.SecretID = config.SecretId
|
providerConfig.SecretID = config.SecretId
|
||||||
providerConfig.SecretKey = config.SecretKey
|
providerConfig.SecretKey = config.SecretKey
|
||||||
providerConfig.ZoneId = config.ZoneId
|
providerConfig.ZoneID = config.ZoneId
|
||||||
if config.DnsPropagationTimeout != 0 {
|
if config.DnsPropagationTimeout != 0 {
|
||||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,165 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||||
|
"github.com/go-acme/lego/v4/platform/config/env"
|
||||||
|
"github.com/ucloud/ucloud-sdk-go/ucloud"
|
||||||
|
"github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
||||||
|
|
||||||
|
"github.com/usual2970/certimate/internal/pkg/sdk3rd/ucloud/udnr"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
envNamespace = "UCLOUDUDNR_"
|
||||||
|
|
||||||
|
EnvPublicKey = envNamespace + "PUBLIC_KEY"
|
||||||
|
EnvPrivateKey = envNamespace + "PRIVATE_KEY"
|
||||||
|
|
||||||
|
EnvTTL = envNamespace + "TTL"
|
||||||
|
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||||
|
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
||||||
|
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
PrivateKey string
|
||||||
|
PublicKey string
|
||||||
|
|
||||||
|
PropagationTimeout time.Duration
|
||||||
|
PollingInterval time.Duration
|
||||||
|
TTL int32
|
||||||
|
HTTPTimeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type DNSProvider struct {
|
||||||
|
client *udnr.UDNRClient
|
||||||
|
config *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
TTL: int32(env.GetOrDefaultInt(EnvTTL, 300)),
|
||||||
|
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
|
||||||
|
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
|
||||||
|
HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDNSProvider() (*DNSProvider, error) {
|
||||||
|
values, err := env.Get(EnvPrivateKey, EnvPublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ucloud-udnr: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
config.PrivateKey = values[EnvPrivateKey]
|
||||||
|
config.PublicKey = values[EnvPublicKey]
|
||||||
|
|
||||||
|
return NewDNSProviderConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("ucloud-udnr: the configuration of the DNS provider is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := ucloud.NewConfig()
|
||||||
|
credential := auth.NewCredential()
|
||||||
|
credential.PrivateKey = config.PrivateKey
|
||||||
|
credential.PublicKey = config.PublicKey
|
||||||
|
client := udnr.NewClient(&cfg, &credential)
|
||||||
|
|
||||||
|
return &DNSProvider{
|
||||||
|
client: client,
|
||||||
|
config: config,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
|
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||||
|
|
||||||
|
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ucloud-udnr: could not find zone for domain %q: %w", domain, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ucloud-udnr: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
udnrDomainDNSQueryReq := d.client.NewQueryDomainDNSRequest()
|
||||||
|
udnrDomainDNSQueryReq.Dn = ucloud.String(authZone)
|
||||||
|
if udnrDomainDNSQueryResp, err := d.client.QueryDomainDNS(udnrDomainDNSQueryReq); err != nil {
|
||||||
|
return fmt.Errorf("ucloud-udnr: %w", err)
|
||||||
|
} else {
|
||||||
|
for _, record := range udnrDomainDNSQueryResp.Data {
|
||||||
|
if record.DnsType == "TXT" && record.RecordName == subDomain {
|
||||||
|
udnrDomainDNSDeleteReq := d.client.NewDeleteDomainDNSRequest()
|
||||||
|
udnrDomainDNSDeleteReq.Dn = ucloud.String(authZone)
|
||||||
|
udnrDomainDNSDeleteReq.DnsType = ucloud.String(record.DnsType)
|
||||||
|
udnrDomainDNSDeleteReq.RecordName = ucloud.String(record.RecordName)
|
||||||
|
udnrDomainDNSDeleteReq.Content = ucloud.String(record.Content)
|
||||||
|
d.client.DeleteDomainDNS(udnrDomainDNSDeleteReq)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
udnrDomainDNSAddReq := d.client.NewAddDomainDNSRequest()
|
||||||
|
udnrDomainDNSAddReq.Dn = ucloud.String(authZone)
|
||||||
|
udnrDomainDNSAddReq.DnsType = ucloud.String("TXT")
|
||||||
|
udnrDomainDNSAddReq.RecordName = ucloud.String(subDomain)
|
||||||
|
udnrDomainDNSAddReq.Content = ucloud.String(info.Value)
|
||||||
|
udnrDomainDNSAddReq.TTL = ucloud.Int(int(d.config.TTL))
|
||||||
|
if _, err := d.client.AddDomainDNS(udnrDomainDNSAddReq); err != nil {
|
||||||
|
return fmt.Errorf("ucloud-udnr: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
|
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||||
|
|
||||||
|
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ucloud-udnr: could not find zone for domain %q: %w", domain, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ucloud-udnr: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
udnrDomainDNSQueryReq := d.client.NewQueryDomainDNSRequest()
|
||||||
|
udnrDomainDNSQueryReq.Dn = ucloud.String(authZone)
|
||||||
|
if udnrDomainDNSQueryResp, err := d.client.QueryDomainDNS(udnrDomainDNSQueryReq); err != nil {
|
||||||
|
return fmt.Errorf("ucloud-udnr: %w", err)
|
||||||
|
} else {
|
||||||
|
for _, record := range udnrDomainDNSQueryResp.Data {
|
||||||
|
if record.DnsType == "TXT" && record.RecordName == subDomain {
|
||||||
|
udnrDomainDNSDeleteReq := d.client.NewDeleteDomainDNSRequest()
|
||||||
|
udnrDomainDNSDeleteReq.Dn = ucloud.String(authZone)
|
||||||
|
udnrDomainDNSDeleteReq.DnsType = ucloud.String(record.DnsType)
|
||||||
|
udnrDomainDNSDeleteReq.RecordName = ucloud.String(record.RecordName)
|
||||||
|
udnrDomainDNSDeleteReq.Content = ucloud.String(record.Content)
|
||||||
|
d.client.DeleteDomainDNS(udnrDomainDNSDeleteReq)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||||
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package ucloududnr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
|
||||||
|
"github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ucloud-udnr/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChallengeProviderConfig struct {
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
PublicKey string `json:"publicKey"`
|
||||||
|
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||||
|
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
providerConfig := internal.NewDefaultConfig()
|
||||||
|
providerConfig.PrivateKey = config.PrivateKey
|
||||||
|
providerConfig.PublicKey = config.PublicKey
|
||||||
|
if config.DnsTTL != 0 {
|
||||||
|
providerConfig.TTL = config.DnsTTL
|
||||||
|
}
|
||||||
|
if config.DnsPropagationTimeout != 0 {
|
||||||
|
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := internal.NewDNSProviderConfig(providerConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ type Deployer interface {
|
|||||||
// 出参:
|
// 出参:
|
||||||
// - res:部署结果。
|
// - res:部署结果。
|
||||||
// - err: 错误。
|
// - err: 错误。
|
||||||
Deploy(ctx context.Context, certPEM string, privkeyPEM string) (res *DeployResult, err error)
|
Deploy(ctx context.Context, certPEM string, privkeyPEM string) (_res *DeployResult, _err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表示证书部署结果的数据结构。
|
// 表示证书部署结果的数据结构。
|
||||||
|
|||||||
@@ -9,12 +9,15 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||||
opsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
|
onepanelsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeployerConfig struct {
|
type DeployerConfig struct {
|
||||||
// 1Panel 地址。
|
// 1Panel 服务地址。
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
// 1Panel 版本。
|
||||||
|
// 可取值 "v1"、"v2"。
|
||||||
|
ApiVersion string `json:"apiVersion"`
|
||||||
// 1Panel 接口密钥。
|
// 1Panel 接口密钥。
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
// 是否允许不安全的连接。
|
// 是否允许不安全的连接。
|
||||||
@@ -26,7 +29,7 @@ type DeployerConfig struct {
|
|||||||
type DeployerProvider struct {
|
type DeployerProvider struct {
|
||||||
config *DeployerConfig
|
config *DeployerConfig
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
sdkClient *opsdk.Client
|
sdkClient *onepanelsdk.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||||
@@ -36,7 +39,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
panic("config is nil")
|
panic("config is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
client, err := createSdkClient(config.ServerUrl, config.ApiVersion, config.ApiKey, config.AllowInsecureConnections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
@@ -50,7 +53,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -59,7 +62,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||||
// 设置面板 SSL 证书
|
// 设置面板 SSL 证书
|
||||||
updateSystemSSLReq := &opsdk.UpdateSystemSSLRequest{
|
updateSystemSSLReq := &onepanelsdk.UpdateSystemSSLRequest{
|
||||||
Cert: certPEM,
|
Cert: certPEM,
|
||||||
Key: privkeyPEM,
|
Key: privkeyPEM,
|
||||||
SSL: "enable",
|
SSL: "enable",
|
||||||
@@ -79,17 +82,21 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
return &deployer.DeployResult{}, nil
|
return &deployer.DeployResult{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) {
|
func createSdkClient(serverUrl, apiVersion, apiKey string, skipTlsVerify bool) (*onepanelsdk.Client, error) {
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
if _, err := url.Parse(serverUrl); err != nil {
|
||||||
return nil, errors.New("invalid 1panel api url")
|
return nil, errors.New("invalid 1panel server url")
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiVersion == "" {
|
||||||
|
return nil, errors.New("invalid 1panel api version")
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiKey == "" {
|
if apiKey == "" {
|
||||||
return nil, errors.New("invalid 1panel api key")
|
return nil, errors.New("invalid 1panel api key")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := opsdk.NewClient(apiUrl, apiKey)
|
client := onepanelsdk.NewClient(serverUrl, apiVersion, apiKey)
|
||||||
if allowInsecure {
|
if skipTlsVerify {
|
||||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import (
|
|||||||
var (
|
var (
|
||||||
fInputCertPath string
|
fInputCertPath string
|
||||||
fInputKeyPath string
|
fInputKeyPath string
|
||||||
fApiUrl string
|
fServerUrl string
|
||||||
|
fApiVersion string
|
||||||
fApiKey string
|
fApiKey string
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,7 +24,8 @@ func init() {
|
|||||||
|
|
||||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
|
||||||
|
flag.StringVar(&fApiVersion, argsPrefix+"APIVERSION", "v1", "")
|
||||||
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +35,8 @@ Shell command to run this test:
|
|||||||
go test -v ./1panel_console_test.go -args \
|
go test -v ./1panel_console_test.go -args \
|
||||||
--CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
--CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
--CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
--CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIURL="http://127.0.0.1:20410" \
|
--CERTIMATE_DEPLOYER_1PANELCONSOLE_SERVERURL="http://127.0.0.1:20410" \
|
||||||
|
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIVERSION="v1" \
|
||||||
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIKEY="your-api-key"
|
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIKEY="your-api-key"
|
||||||
*/
|
*/
|
||||||
func TestDeploy(t *testing.T) {
|
func TestDeploy(t *testing.T) {
|
||||||
@@ -44,12 +47,14 @@ func TestDeploy(t *testing.T) {
|
|||||||
"args:",
|
"args:",
|
||||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
fmt.Sprintf("SERVERURL: %v", fServerUrl),
|
||||||
|
fmt.Sprintf("APIVERSION: %v", fApiVersion),
|
||||||
fmt.Sprintf("APIKEY: %v", fApiKey),
|
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||||
}, "\n"))
|
}, "\n"))
|
||||||
|
|
||||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
ApiUrl: fApiUrl,
|
ServerUrl: fServerUrl,
|
||||||
|
ApiVersion: fApiVersion,
|
||||||
ApiKey: fApiKey,
|
ApiKey: fApiKey,
|
||||||
AllowInsecureConnections: true,
|
AllowInsecureConnections: true,
|
||||||
AutoRestart: true,
|
AutoRestart: true,
|
||||||
|
|||||||
@@ -12,12 +12,15 @@ import (
|
|||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/1panel-ssl"
|
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/1panel-ssl"
|
||||||
opsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
|
onepanelsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeployerConfig struct {
|
type DeployerConfig struct {
|
||||||
// 1Panel 地址。
|
// 1Panel 服务地址。
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
// 1Panel 版本。
|
||||||
|
// 可取值 "v1"、"v2"。
|
||||||
|
ApiVersion string `json:"apiVersion"`
|
||||||
// 1Panel 接口密钥。
|
// 1Panel 接口密钥。
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
// 是否允许不安全的连接。
|
// 是否允许不安全的连接。
|
||||||
@@ -35,7 +38,7 @@ type DeployerConfig struct {
|
|||||||
type DeployerProvider struct {
|
type DeployerProvider struct {
|
||||||
config *DeployerConfig
|
config *DeployerConfig
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
sdkClient *opsdk.Client
|
sdkClient *onepanelsdk.Client
|
||||||
sslUploader uploader.Uploader
|
sslUploader uploader.Uploader
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,14 +49,16 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
panic("config is nil")
|
panic("config is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
client, err := createSdkClient(config.ServerUrl, config.ApiVersion, config.ApiKey, config.AllowInsecureConnections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
ApiUrl: config.ApiUrl,
|
ServerUrl: config.ServerUrl,
|
||||||
ApiKey: config.ApiKey,
|
ApiVersion: config.ApiVersion,
|
||||||
|
ApiKey: config.ApiKey,
|
||||||
|
AllowInsecureConnections: config.AllowInsecureConnections,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
@@ -69,7 +74,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -103,7 +108,7 @@ func (d *DeployerProvider) deployToWebsite(ctx context.Context, certPEM string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取网站 HTTPS 配置
|
// 获取网站 HTTPS 配置
|
||||||
getHttpsConfReq := &opsdk.GetHttpsConfRequest{
|
getHttpsConfReq := &onepanelsdk.GetHttpsConfRequest{
|
||||||
WebsiteID: d.config.WebsiteId,
|
WebsiteID: d.config.WebsiteId,
|
||||||
}
|
}
|
||||||
getHttpsConfResp, err := d.sdkClient.GetHttpsConf(getHttpsConfReq)
|
getHttpsConfResp, err := d.sdkClient.GetHttpsConf(getHttpsConfReq)
|
||||||
@@ -122,7 +127,7 @@ func (d *DeployerProvider) deployToWebsite(ctx context.Context, certPEM string,
|
|||||||
|
|
||||||
// 修改网站 HTTPS 配置
|
// 修改网站 HTTPS 配置
|
||||||
certId, _ := strconv.ParseInt(upres.CertId, 10, 64)
|
certId, _ := strconv.ParseInt(upres.CertId, 10, 64)
|
||||||
updateHttpsConfReq := &opsdk.UpdateHttpsConfRequest{
|
updateHttpsConfReq := &onepanelsdk.UpdateHttpsConfRequest{
|
||||||
WebsiteID: d.config.WebsiteId,
|
WebsiteID: d.config.WebsiteId,
|
||||||
Type: "existed",
|
Type: "existed",
|
||||||
WebsiteSSLID: certId,
|
WebsiteSSLID: certId,
|
||||||
@@ -147,7 +152,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取证书详情
|
// 获取证书详情
|
||||||
getWebsiteSSLReq := &opsdk.GetWebsiteSSLRequest{
|
getWebsiteSSLReq := &onepanelsdk.GetWebsiteSSLRequest{
|
||||||
SSLID: d.config.CertificateId,
|
SSLID: d.config.CertificateId,
|
||||||
}
|
}
|
||||||
getWebsiteSSLResp, err := d.sdkClient.GetWebsiteSSL(getWebsiteSSLReq)
|
getWebsiteSSLResp, err := d.sdkClient.GetWebsiteSSL(getWebsiteSSLReq)
|
||||||
@@ -157,7 +162,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新证书
|
// 更新证书
|
||||||
uploadWebsiteSSLReq := &opsdk.UploadWebsiteSSLRequest{
|
uploadWebsiteSSLReq := &onepanelsdk.UploadWebsiteSSLRequest{
|
||||||
Type: "paste",
|
Type: "paste",
|
||||||
SSLID: d.config.CertificateId,
|
SSLID: d.config.CertificateId,
|
||||||
Description: getWebsiteSSLResp.Data.Description,
|
Description: getWebsiteSSLResp.Data.Description,
|
||||||
@@ -173,17 +178,21 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) {
|
func createSdkClient(serverUrl, apiVersion, apiKey string, skipTlsVerify bool) (*onepanelsdk.Client, error) {
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
if _, err := url.Parse(serverUrl); err != nil {
|
||||||
return nil, errors.New("invalid 1panel api url")
|
return nil, errors.New("invalid 1panel server url")
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiVersion == "" {
|
||||||
|
return nil, errors.New("invalid 1panel api version")
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiKey == "" {
|
if apiKey == "" {
|
||||||
return nil, errors.New("invalid 1panel api key")
|
return nil, errors.New("invalid 1panel api key")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := opsdk.NewClient(apiUrl, apiKey)
|
client := onepanelsdk.NewClient(serverUrl, apiVersion, apiKey)
|
||||||
if allowInsecure {
|
if skipTlsVerify {
|
||||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import (
|
|||||||
var (
|
var (
|
||||||
fInputCertPath string
|
fInputCertPath string
|
||||||
fInputKeyPath string
|
fInputKeyPath string
|
||||||
fApiUrl string
|
fServerUrl string
|
||||||
|
fApiVersion string
|
||||||
fApiKey string
|
fApiKey string
|
||||||
fWebsiteId int64
|
fWebsiteId int64
|
||||||
)
|
)
|
||||||
@@ -24,7 +25,8 @@ func init() {
|
|||||||
|
|
||||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
|
||||||
|
flag.StringVar(&fApiVersion, argsPrefix+"APIVERSION", "v1", "")
|
||||||
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||||
flag.Int64Var(&fWebsiteId, argsPrefix+"WEBSITEID", 0, "")
|
flag.Int64Var(&fWebsiteId, argsPrefix+"WEBSITEID", 0, "")
|
||||||
}
|
}
|
||||||
@@ -35,7 +37,8 @@ Shell command to run this test:
|
|||||||
go test -v ./1panel_site_test.go -args \
|
go test -v ./1panel_site_test.go -args \
|
||||||
--CERTIMATE_DEPLOYER_1PANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
--CERTIMATE_DEPLOYER_1PANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
--CERTIMATE_DEPLOYER_1PANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
--CERTIMATE_DEPLOYER_1PANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
--CERTIMATE_DEPLOYER_1PANELSITE_APIURL="http://127.0.0.1:20410" \
|
--CERTIMATE_DEPLOYER_1PANELSITE_SERVERURL="http://127.0.0.1:20410" \
|
||||||
|
--CERTIMATE_DEPLOYER_1PANELSITE_APIVERSION="v1" \
|
||||||
--CERTIMATE_DEPLOYER_1PANELSITE_APIKEY="your-api-key" \
|
--CERTIMATE_DEPLOYER_1PANELSITE_APIKEY="your-api-key" \
|
||||||
--CERTIMATE_DEPLOYER_1PANELSITE_WEBSITEID="your-website-id"
|
--CERTIMATE_DEPLOYER_1PANELSITE_WEBSITEID="your-website-id"
|
||||||
*/
|
*/
|
||||||
@@ -47,13 +50,15 @@ func TestDeploy(t *testing.T) {
|
|||||||
"args:",
|
"args:",
|
||||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
fmt.Sprintf("SERVERURL: %v", fServerUrl),
|
||||||
|
fmt.Sprintf("APIVERSION: %v", fApiVersion),
|
||||||
fmt.Sprintf("APIKEY: %v", fApiKey),
|
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||||
fmt.Sprintf("WEBSITEID: %v", fWebsiteId),
|
fmt.Sprintf("WEBSITEID: %v", fWebsiteId),
|
||||||
}, "\n"))
|
}, "\n"))
|
||||||
|
|
||||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
ApiUrl: fApiUrl,
|
ServerUrl: fServerUrl,
|
||||||
|
ApiVersion: fApiVersion,
|
||||||
ApiKey: fApiKey,
|
ApiKey: fApiKey,
|
||||||
AllowInsecureConnections: true,
|
AllowInsecureConnections: true,
|
||||||
ResourceType: provider.RESOURCE_TYPE_WEBSITE,
|
ResourceType: provider.RESOURCE_TYPE_WEBSITE,
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 部署资源类型。
|
// 部署资源类型。
|
||||||
@@ -64,7 +66,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
return nil, fmt.Errorf("failed to create sdk clients: %w", err)
|
return nil, fmt.Errorf("failed to create sdk clients: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
}
|
}
|
||||||
@@ -79,7 +81,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -157,7 +159,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
|||||||
|
|
||||||
if listListenersResp.Body.Listeners != nil {
|
if listListenersResp.Body.Listeners != nil {
|
||||||
for _, listener := range listListenersResp.Body.Listeners {
|
for _, listener := range listListenersResp.Body.Listeners {
|
||||||
listenerIds = append(listenerIds, *listener.ListenerId)
|
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +194,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
|||||||
|
|
||||||
if listListenersResp.Body.Listeners != nil {
|
if listListenersResp.Body.Listeners != nil {
|
||||||
for _, listener := range listListenersResp.Body.Listeners {
|
for _, listener := range listListenersResp.Body.Listeners {
|
||||||
listenerIds = append(listenerIds, *listener.ListenerId)
|
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,8 +213,13 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
|||||||
d.logger.Info("found https/quic listeners to deploy", slog.Any("listenerIds", listenerIds))
|
d.logger.Info("found https/quic listeners to deploy", slog.Any("listenerIds", listenerIds))
|
||||||
|
|
||||||
for _, listenerId := range listenerIds {
|
for _, listenerId := range listenerIds {
|
||||||
if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
|
select {
|
||||||
errs = append(errs, err)
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +425,7 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
|||||||
// 接入点一览 https://api.aliyun.com/product/Alb
|
// 接入点一览 https://api.aliyun.com/product/Alb
|
||||||
var albEndpoint string
|
var albEndpoint string
|
||||||
switch region {
|
switch region {
|
||||||
case "cn-hangzhou-finance":
|
case "", "cn-hangzhou-finance":
|
||||||
albEndpoint = "alb.cn-hangzhou.aliyuncs.com"
|
albEndpoint = "alb.cn-hangzhou.aliyuncs.com"
|
||||||
default:
|
default:
|
||||||
albEndpoint = fmt.Sprintf("alb.%s.aliyuncs.com", region)
|
albEndpoint = fmt.Sprintf("alb.%s.aliyuncs.com", region)
|
||||||
@@ -458,13 +465,13 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||||
casRegion := region
|
casRegion := region
|
||||||
if casRegion != "" {
|
if casRegion != "" {
|
||||||
// 阿里云 CAS 服务接入点是独立于 ALB 服务的
|
// 阿里云 CAS 服务接入点是独立于 ALB 服务的
|
||||||
// 国内版固定接入点:华东一杭州
|
// 国内版固定接入点:华东一杭州
|
||||||
// 国际版固定接入点:亚太东南一新加坡
|
// 国际版固定接入点:亚太东南一新加坡
|
||||||
if casRegion != "" && !strings.HasPrefix(casRegion, "cn-") {
|
if !strings.HasPrefix(casRegion, "cn-") {
|
||||||
casRegion = "ap-southeast-1"
|
casRegion = "ap-southeast-1"
|
||||||
} else {
|
} else {
|
||||||
casRegion = "cn-hangzhou"
|
casRegion = "cn-hangzhou"
|
||||||
@@ -474,6 +481,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
|||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
AccessKeyId: accessKeyId,
|
AccessKeyId: accessKeyId,
|
||||||
AccessKeySecret: accessKeySecret,
|
AccessKeySecret: accessKeySecret,
|
||||||
|
ResourceGroupId: resourceGroupId,
|
||||||
Region: casRegion,
|
Region: casRegion,
|
||||||
})
|
})
|
||||||
return uploader, err
|
return uploader, err
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ func TestDeploy(t *testing.T) {
|
|||||||
fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
|
fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
|
||||||
fmt.Sprintf("REGION: %v", fRegion),
|
fmt.Sprintf("REGION: %v", fRegion),
|
||||||
fmt.Sprintf("LISTENERID: %v", fListenerId),
|
fmt.Sprintf("LISTENERID: %v", fListenerId),
|
||||||
|
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||||
}, "\n"))
|
}, "\n"))
|
||||||
|
|
||||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas"
|
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas"
|
||||||
|
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeployerConfig struct {
|
type DeployerConfig struct {
|
||||||
@@ -23,6 +24,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 服务类型。
|
// 服务类型。
|
||||||
@@ -61,7 +64,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
return nil, fmt.Errorf("failed to create sdk clients: %w", err)
|
return nil, fmt.Errorf("failed to create sdk clients: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
}
|
}
|
||||||
@@ -76,7 +79,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -149,10 +152,11 @@ func (d *DeployerProvider) deployToCloudNative(ctx context.Context, certPEM stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
listDomainsReq := &aliapig.ListDomainsRequest{
|
listDomainsReq := &aliapig.ListDomainsRequest{
|
||||||
GatewayId: tea.String(d.config.GatewayId),
|
ResourceGroupId: typeutil.ToPtrOrZeroNil(d.config.ResourceGroupId),
|
||||||
NameLike: tea.String(d.config.Domain),
|
GatewayId: tea.String(d.config.GatewayId),
|
||||||
PageNumber: tea.Int32(listDomainsPageNumber),
|
NameLike: tea.String(d.config.Domain),
|
||||||
PageSize: tea.Int32(listDomainsPageSize),
|
PageNumber: tea.Int32(listDomainsPageNumber),
|
||||||
|
PageSize: tea.Int32(listDomainsPageSize),
|
||||||
}
|
}
|
||||||
listDomainsResp, err := d.sdkClients.CloudNativeAPIGateway.ListDomains(listDomainsReq)
|
listDomainsResp, err := d.sdkClients.CloudNativeAPIGateway.ListDomains(listDomainsReq)
|
||||||
d.logger.Debug("sdk request 'apig.ListDomains'", slog.Any("request", listDomainsReq), slog.Any("response", listDomainsResp))
|
d.logger.Debug("sdk request 'apig.ListDomains'", slog.Any("request", listDomainsReq), slog.Any("response", listDomainsResp))
|
||||||
@@ -223,7 +227,7 @@ func (d *DeployerProvider) deployToCloudNative(ctx context.Context, certPEM stri
|
|||||||
|
|
||||||
func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients, error) {
|
func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients, error) {
|
||||||
// 接入点一览 https://api.aliyun.com/product/APIG
|
// 接入点一览 https://api.aliyun.com/product/APIG
|
||||||
cloudNativeAPIGEndpoint := fmt.Sprintf("apig.%s.aliyuncs.com", region)
|
cloudNativeAPIGEndpoint := strings.ReplaceAll(fmt.Sprintf("apig.%s.aliyuncs.com", region), "..", ".")
|
||||||
cloudNativeAPIGConfig := &aliopen.Config{
|
cloudNativeAPIGConfig := &aliopen.Config{
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
@@ -235,7 +239,7 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 接入点一览 https://api.aliyun.com/product/CloudAPI
|
// 接入点一览 https://api.aliyun.com/product/CloudAPI
|
||||||
traditionalAPIGEndpoint := fmt.Sprintf("apigateway.%s.aliyuncs.com", region)
|
traditionalAPIGEndpoint := strings.ReplaceAll(fmt.Sprintf("apigateway.%s.aliyuncs.com", region), "..", ".")
|
||||||
traditionalAPIGConfig := &aliopen.Config{
|
traditionalAPIGConfig := &aliopen.Config{
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
@@ -252,13 +256,13 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||||
casRegion := region
|
casRegion := region
|
||||||
if casRegion != "" {
|
if casRegion != "" {
|
||||||
// 阿里云 CAS 服务接入点是独立于 APIGateway 服务的
|
// 阿里云 CAS 服务接入点是独立于 APIGateway 服务的
|
||||||
// 国内版固定接入点:华东一杭州
|
// 国内版固定接入点:华东一杭州
|
||||||
// 国际版固定接入点:亚太东南一新加坡
|
// 国际版固定接入点:亚太东南一新加坡
|
||||||
if casRegion != "" && !strings.HasPrefix(casRegion, "cn-") {
|
if !strings.HasPrefix(casRegion, "cn-") {
|
||||||
casRegion = "ap-southeast-1"
|
casRegion = "ap-southeast-1"
|
||||||
} else {
|
} else {
|
||||||
casRegion = "cn-hangzhou"
|
casRegion = "cn-hangzhou"
|
||||||
@@ -268,6 +272,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
|||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
AccessKeyId: accessKeyId,
|
AccessKeyId: accessKeyId,
|
||||||
AccessKeySecret: accessKeySecret,
|
AccessKeySecret: accessKeySecret,
|
||||||
|
ResourceGroupId: resourceGroupId,
|
||||||
Region: casRegion,
|
Region: casRegion,
|
||||||
})
|
})
|
||||||
return uploader, err
|
return uploader, err
|
||||||
|
|||||||
@@ -22,12 +22,14 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 阿里云云产品资源 ID 数组。
|
// 阿里云云产品资源 ID 数组。
|
||||||
ResourceIds []string `json:"resourceIds"`
|
ResourceIds []string `json:"resourceIds"`
|
||||||
// 阿里云云联系人 ID 数组。
|
// 阿里云云联系人 ID 数组。
|
||||||
// 零值时默认使用账号下第一个联系人。
|
// 零值时使用账号下第一个联系人。
|
||||||
ContactIds []string `json:"contactIds"`
|
ContactIds []string `json:"contactIds"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,11 +52,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
AccessKeySecret: config.AccessKeySecret,
|
|
||||||
Region: config.Region,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
}
|
}
|
||||||
@@ -69,7 +67,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -94,9 +92,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
if len(contactIds) == 0 {
|
if len(contactIds) == 0 {
|
||||||
// 获取联系人列表
|
// 获取联系人列表
|
||||||
// REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-listcontact
|
// REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-listcontact
|
||||||
listContactReq := &alicas.ListContactRequest{}
|
listContactReq := &alicas.ListContactRequest{
|
||||||
listContactReq.ShowSize = tea.Int32(1)
|
ShowSize: tea.Int32(1),
|
||||||
listContactReq.CurrentPage = tea.Int32(1)
|
CurrentPage: tea.Int32(1),
|
||||||
|
}
|
||||||
listContactResp, err := d.sdkClient.ListContact(listContactReq)
|
listContactResp, err := d.sdkClient.ListContact(listContactReq)
|
||||||
d.logger.Debug("sdk request 'cas.ListContact'", slog.Any("request", listContactReq), slog.Any("response", listContactResp))
|
d.logger.Debug("sdk request 'cas.ListContact'", slog.Any("request", listContactReq), slog.Any("response", listContactResp))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -157,14 +156,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*alicas.Client, error) {
|
func createSdkClient(accessKeyId, accessKeySecret, region string) (*alicas.Client, error) {
|
||||||
if region == "" {
|
|
||||||
region = "cn-hangzhou" // CAS 服务默认区域:华东一杭州
|
|
||||||
}
|
|
||||||
|
|
||||||
// 接入点一览 https://api.aliyun.com/product/cas
|
// 接入点一览 https://api.aliyun.com/product/cas
|
||||||
var endpoint string
|
var endpoint string
|
||||||
switch region {
|
switch region {
|
||||||
case "cn-hangzhou":
|
case "", "cn-hangzhou":
|
||||||
endpoint = "cas.aliyuncs.com"
|
endpoint = "cas.aliyuncs.com"
|
||||||
default:
|
default:
|
||||||
endpoint = fmt.Sprintf("cas.%s.aliyuncs.com", region)
|
endpoint = fmt.Sprintf("cas.%s.aliyuncs.com", region)
|
||||||
@@ -183,3 +178,25 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alicas.Clien
|
|||||||
|
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||||
|
casRegion := region
|
||||||
|
if casRegion != "" {
|
||||||
|
// 阿里云 CAS 服务接入点是独立于其他服务的
|
||||||
|
// 国内版固定接入点:华东一杭州
|
||||||
|
// 国际版固定接入点:亚太东南一新加坡
|
||||||
|
if !strings.HasPrefix(casRegion, "cn-") {
|
||||||
|
casRegion = "ap-southeast-1"
|
||||||
|
} else {
|
||||||
|
casRegion = "cn-hangzhou"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
|
AccessKeyId: accessKeyId,
|
||||||
|
AccessKeySecret: accessKeySecret,
|
||||||
|
ResourceGroupId: resourceGroupId,
|
||||||
|
Region: casRegion,
|
||||||
|
})
|
||||||
|
return uploader, err
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
}
|
}
|
||||||
@@ -35,6 +37,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
AccessKeyId: config.AccessKeyId,
|
AccessKeyId: config.AccessKeyId,
|
||||||
AccessKeySecret: config.AccessKeySecret,
|
AccessKeySecret: config.AccessKeySecret,
|
||||||
|
ResourceGroupId: config.ResourceGroupId,
|
||||||
Region: config.Region,
|
Region: config.Region,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -50,7 +53,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 加速域名(支持泛域名)。
|
// 加速域名(支持泛域名)。
|
||||||
Domain string `json:"domain"`
|
Domain string `json:"domain"`
|
||||||
}
|
}
|
||||||
@@ -50,7 +52,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 部署资源类型。
|
// 部署资源类型。
|
||||||
@@ -54,11 +56,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||||
AccessKeyId: config.AccessKeyId,
|
|
||||||
AccessKeySecret: config.AccessKeySecret,
|
|
||||||
Region: config.Region,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
}
|
}
|
||||||
@@ -73,7 +71,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -175,7 +173,6 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
|||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listenerPort, cloudCertId); err != nil {
|
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listenerPort, cloudCertId); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
@@ -288,7 +285,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alislb.Clien
|
|||||||
// 接入点一览 https://api.aliyun.com/product/Slb
|
// 接入点一览 https://api.aliyun.com/product/Slb
|
||||||
var endpoint string
|
var endpoint string
|
||||||
switch region {
|
switch region {
|
||||||
case
|
case "",
|
||||||
"cn-hangzhou",
|
"cn-hangzhou",
|
||||||
"cn-hangzhou-finance",
|
"cn-hangzhou-finance",
|
||||||
"cn-shanghai-finance-1",
|
"cn-shanghai-finance-1",
|
||||||
@@ -311,3 +308,13 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alislb.Clien
|
|||||||
|
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||||
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
|
AccessKeyId: accessKeyId,
|
||||||
|
AccessKeySecret: accessKeySecret,
|
||||||
|
ResourceGroupId: resourceGroupId,
|
||||||
|
Region: region,
|
||||||
|
})
|
||||||
|
return uploader, err
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ var (
|
|||||||
fAccessKeySecret string
|
fAccessKeySecret string
|
||||||
fRegion string
|
fRegion string
|
||||||
fLoadbalancerId string
|
fLoadbalancerId string
|
||||||
fListenerPort int
|
fListenerPort int64
|
||||||
fDomain string
|
fDomain string
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ func init() {
|
|||||||
flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
|
flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
|
||||||
flag.StringVar(&fRegion, argsPrefix+"REGION", "", "")
|
flag.StringVar(&fRegion, argsPrefix+"REGION", "", "")
|
||||||
flag.StringVar(&fLoadbalancerId, argsPrefix+"LOADBALANCERID", "", "")
|
flag.StringVar(&fLoadbalancerId, argsPrefix+"LOADBALANCERID", "", "")
|
||||||
flag.IntVar(&fListenerPort, argsPrefix+"LISTENERPORT", 443, "")
|
flag.Int64Var(&fListenerPort, argsPrefix+"LISTENERPORT", 443, "")
|
||||||
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 加速域名(支持泛域名)。
|
// 加速域名(支持泛域名)。
|
||||||
Domain string `json:"domain"`
|
Domain string `json:"domain"`
|
||||||
}
|
}
|
||||||
@@ -50,7 +52,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
140
internal/pkg/core/deployer/providers/aliyun-ddos/aliyun_ddos.go
Normal file
140
internal/pkg/core/deployer/providers/aliyun-ddos/aliyun_ddos.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
package aliyunddos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||||
|
aliddos "github.com/alibabacloud-go/ddoscoo-20200101/v4/client"
|
||||||
|
"github.com/alibabacloud-go/tea/tea"
|
||||||
|
|
||||||
|
"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-slb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeployerConfig struct {
|
||||||
|
// 阿里云 AccessKeyId。
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
// 阿里云 AccessKeySecret。
|
||||||
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
|
// 阿里云地域。
|
||||||
|
Region string `json:"region"`
|
||||||
|
// 网站域名(支持泛域名)。
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeployerProvider struct {
|
||||||
|
config *DeployerConfig
|
||||||
|
logger *slog.Logger
|
||||||
|
sdkClient *aliddos.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, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.New(slog.DiscardHandler)
|
||||||
|
} 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.Domain == "" {
|
||||||
|
return nil, errors.New("config `domain` is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传证书到 CAS
|
||||||
|
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||||
|
} else {
|
||||||
|
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为网站业务转发规则关联 SSL 证书
|
||||||
|
// REF: https://help.aliyun.com/zh/anti-ddos/anti-ddos-pro-and-premium/developer-reference/api-ddoscoo-2020-01-01-associatewebcert
|
||||||
|
certId, _ := strconv.Atoi(upres.CertId)
|
||||||
|
associateWebCertReq := &aliddos.AssociateWebCertRequest{
|
||||||
|
Domain: tea.String(d.config.Domain),
|
||||||
|
CertId: tea.Int32(int32(certId)),
|
||||||
|
}
|
||||||
|
associateWebCertResp, err := d.sdkClient.AssociateWebCert(associateWebCertReq)
|
||||||
|
d.logger.Debug("sdk request 'dcdn.AssociateWebCert'", slog.Any("request", associateWebCertReq), slog.Any("response", associateWebCertResp))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute sdk request 'dcdn.AssociateWebCert': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &deployer.DeployResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliddos.Client, error) {
|
||||||
|
// 接入点一览 https://api.aliyun.com/product/ddoscoo
|
||||||
|
config := &aliopen.Config{
|
||||||
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
|
Endpoint: tea.String(strings.ReplaceAll(fmt.Sprintf("ddoscoo.%s.aliyuncs.com", region), "..", ".")),
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := aliddos.NewClient(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||||
|
casRegion := region
|
||||||
|
if casRegion != "" {
|
||||||
|
// 阿里云 CAS 服务接入点是独立于 Anti-DDoS 服务的
|
||||||
|
// 国内版固定接入点:华东一杭州
|
||||||
|
// 国际版固定接入点:亚太东南一新加坡
|
||||||
|
if !strings.HasPrefix(casRegion, "cn-") {
|
||||||
|
casRegion = "ap-southeast-1"
|
||||||
|
} else {
|
||||||
|
casRegion = "cn-hangzhou"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
|
AccessKeyId: accessKeyId,
|
||||||
|
AccessKeySecret: accessKeySecret,
|
||||||
|
ResourceGroupId: resourceGroupId,
|
||||||
|
Region: casRegion,
|
||||||
|
})
|
||||||
|
return uploader, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package aliyunddos_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-ddos"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fInputCertPath string
|
||||||
|
fInputKeyPath string
|
||||||
|
fAccessKeyId string
|
||||||
|
fAccessKeySecret string
|
||||||
|
fRegion string
|
||||||
|
fDomain string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
argsPrefix := "CERTIMATE_DEPLOYER_ALIYUNDDOS_"
|
||||||
|
|
||||||
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
|
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||||
|
flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
|
||||||
|
flag.StringVar(&fRegion, argsPrefix+"REGION", "", "")
|
||||||
|
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shell command to run this test:
|
||||||
|
|
||||||
|
go test -v ./aliyun_ddos_test.go -args \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNDDOS_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNDDOS_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNDDOS_ACCESSKEYID="your-access-key-id" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNDDOS_ACCESSKEYSECRET="your-access-key-secret" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNDDOS_REGION="cn-hangzhou" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNDDOS_DOMAIN="example.com"
|
||||||
|
*/
|
||||||
|
func TestDeploy(t *testing.T) {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
t.Run("Deploy", func(t *testing.T) {
|
||||||
|
t.Log(strings.Join([]string{
|
||||||
|
"args:",
|
||||||
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
|
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||||
|
fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
|
||||||
|
fmt.Sprintf("REGION: %v", fRegion),
|
||||||
|
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||||
|
}, "\n"))
|
||||||
|
|
||||||
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
|
AccessKeyId: fAccessKeyId,
|
||||||
|
AccessKeySecret: fAccessKeySecret,
|
||||||
|
Region: fRegion,
|
||||||
|
Domain: fDomain,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||||
|
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||||
|
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("ok: %v", res)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -22,6 +22,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 阿里云 ESA 站点 ID。
|
// 阿里云 ESA 站点 ID。
|
||||||
@@ -47,7 +49,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
}
|
}
|
||||||
@@ -62,7 +64,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -105,7 +107,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliesa.Clien
|
|||||||
config := &aliopen.Config{
|
config := &aliopen.Config{
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
Endpoint: tea.String(fmt.Sprintf("esa.%s.aliyuncs.com", region)),
|
Endpoint: tea.String(strings.ReplaceAll(fmt.Sprintf("esa.%s.aliyuncs.com", region), "..", ".")),
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := aliesa.NewClient(config)
|
client, err := aliesa.NewClient(config)
|
||||||
@@ -116,13 +118,13 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliesa.Clien
|
|||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||||
casRegion := region
|
casRegion := region
|
||||||
if casRegion != "" {
|
if casRegion != "" {
|
||||||
// 阿里云 CAS 服务接入点是独立于 ESA 服务的
|
// 阿里云 CAS 服务接入点是独立于 ESA 服务的
|
||||||
// 国内版固定接入点:华东一杭州
|
// 国内版固定接入点:华东一杭州
|
||||||
// 国际版固定接入点:亚太东南一新加坡
|
// 国际版固定接入点:亚太东南一新加坡
|
||||||
if casRegion != "" && !strings.HasPrefix(casRegion, "cn-") {
|
if !strings.HasPrefix(casRegion, "cn-") {
|
||||||
casRegion = "ap-southeast-1"
|
casRegion = "ap-southeast-1"
|
||||||
} else {
|
} else {
|
||||||
casRegion = "cn-hangzhou"
|
casRegion = "cn-hangzhou"
|
||||||
@@ -132,6 +134,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
|||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
AccessKeyId: accessKeyId,
|
AccessKeyId: accessKeyId,
|
||||||
AccessKeySecret: accessKeySecret,
|
AccessKeySecret: accessKeySecret,
|
||||||
|
ResourceGroupId: resourceGroupId,
|
||||||
Region: casRegion,
|
Region: casRegion,
|
||||||
})
|
})
|
||||||
return uploader, err
|
return uploader, err
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||||
@@ -19,9 +20,12 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 服务版本。
|
// 服务版本。
|
||||||
|
// 可取值 "2.0"、"3.0"。
|
||||||
ServiceVersion string `json:"serviceVersion"`
|
ServiceVersion string `json:"serviceVersion"`
|
||||||
// 自定义域名(支持泛域名)。
|
// 自定义域名(支持泛域名)。
|
||||||
Domain string `json:"domain"`
|
Domain string `json:"domain"`
|
||||||
@@ -59,7 +63,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -107,6 +111,9 @@ func (d *DeployerProvider) deployToFC3(ctx context.Context, certPEM string, priv
|
|||||||
TlsConfig: getCustomDomainResp.Body.TlsConfig,
|
TlsConfig: getCustomDomainResp.Body.TlsConfig,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if tea.StringValue(updateCustomDomainReq.Body.Protocol) == "HTTP" {
|
||||||
|
updateCustomDomainReq.Body.Protocol = tea.String("HTTP,HTTPS")
|
||||||
|
}
|
||||||
updateCustomDomainResp, err := d.sdkClients.FC3.UpdateCustomDomain(tea.String(d.config.Domain), updateCustomDomainReq)
|
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))
|
d.logger.Debug("sdk request 'fc.UpdateCustomDomain'", slog.Any("request", updateCustomDomainReq), slog.Any("response", updateCustomDomainResp))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -136,6 +143,9 @@ func (d *DeployerProvider) deployToFC2(ctx context.Context, certPEM string, priv
|
|||||||
Protocol: getCustomDomainResp.Body.Protocol,
|
Protocol: getCustomDomainResp.Body.Protocol,
|
||||||
TlsConfig: getCustomDomainResp.Body.TlsConfig,
|
TlsConfig: getCustomDomainResp.Body.TlsConfig,
|
||||||
}
|
}
|
||||||
|
if tea.StringValue(updateCustomDomainReq.Protocol) == "HTTP" {
|
||||||
|
updateCustomDomainReq.Protocol = tea.String("HTTP,HTTPS")
|
||||||
|
}
|
||||||
updateCustomDomainResp, err := d.sdkClients.FC2.UpdateCustomDomain(tea.String(d.config.Domain), updateCustomDomainReq)
|
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))
|
d.logger.Debug("sdk request 'fc.UpdateCustomDomain'", slog.Any("request", updateCustomDomainReq), slog.Any("response", updateCustomDomainResp))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -149,6 +159,8 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
|||||||
// 接入点一览 https://api.aliyun.com/product/FC-Open
|
// 接入点一览 https://api.aliyun.com/product/FC-Open
|
||||||
var fc2Endpoint string
|
var fc2Endpoint string
|
||||||
switch region {
|
switch region {
|
||||||
|
case "":
|
||||||
|
fc2Endpoint = "fc.aliyuncs.com"
|
||||||
case "cn-hangzhou-finance":
|
case "cn-hangzhou-finance":
|
||||||
fc2Endpoint = fmt.Sprintf("%s.fc.aliyuncs.com", region)
|
fc2Endpoint = fmt.Sprintf("%s.fc.aliyuncs.com", region)
|
||||||
default:
|
default:
|
||||||
@@ -166,7 +178,7 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 接入点一览 https://api.aliyun.com/product/FC-Open
|
// 接入点一览 https://api.aliyun.com/product/FC-Open
|
||||||
fc3Endpoint := fmt.Sprintf("fcv3.%s.aliyuncs.com", region)
|
fc3Endpoint := strings.ReplaceAll(fmt.Sprintf("fcv3.%s.aliyuncs.com", region), "..", ".")
|
||||||
fc3Config := &aliopen.Config{
|
fc3Config := &aliopen.Config{
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
|
|||||||
325
internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga.go
Normal file
325
internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga.go
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
package aliyunga
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||||
|
aliga "github.com/alibabacloud-go/ga-20191120/v3/client"
|
||||||
|
"github.com/alibabacloud-go/tea/tea"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeployerConfig struct {
|
||||||
|
// 阿里云 AccessKeyId。
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
// 阿里云 AccessKeySecret。
|
||||||
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
|
// 部署资源类型。
|
||||||
|
ResourceType ResourceType `json:"resourceType"`
|
||||||
|
// 全球加速实例 ID。
|
||||||
|
AcceleratorId string `json:"acceleratorId"`
|
||||||
|
// 全球加速监听 ID。
|
||||||
|
// 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。
|
||||||
|
ListenerId string `json:"listenerId,omitempty"`
|
||||||
|
// SNI 域名(不支持泛域名)。
|
||||||
|
// 部署资源类型为 [RESOURCE_TYPE_ACCELERATOR]、[RESOURCE_TYPE_LISTENER] 时选填。
|
||||||
|
Domain string `json:"domain,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeployerProvider struct {
|
||||||
|
config *DeployerConfig
|
||||||
|
logger *slog.Logger
|
||||||
|
sdkClient *aliga.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)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.New(slog.DiscardHandler)
|
||||||
|
} 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, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||||
|
} else {
|
||||||
|
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据部署资源类型决定部署方式
|
||||||
|
switch d.config.ResourceType {
|
||||||
|
case RESOURCE_TYPE_ACCELERATOR:
|
||||||
|
if err := d.deployToAccelerator(ctx, upres.ExtendedData["certIdentifier"].(string)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case RESOURCE_TYPE_LISTENER:
|
||||||
|
if err := d.deployToListener(ctx, upres.ExtendedData["certIdentifier"].(string)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &deployer.DeployResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeployerProvider) deployToAccelerator(ctx context.Context, cloudCertId string) error {
|
||||||
|
if d.config.AcceleratorId == "" {
|
||||||
|
return errors.New("config `acceleratorId` is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询 HTTPS 监听列表
|
||||||
|
// REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-listlisteners
|
||||||
|
listenerIds := make([]string, 0)
|
||||||
|
listListenersPageNumber := int32(1)
|
||||||
|
listListenersPageSize := int32(50)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
listListenersReq := &aliga.ListListenersRequest{
|
||||||
|
RegionId: tea.String("cn-hangzhou"),
|
||||||
|
AcceleratorId: tea.String(d.config.AcceleratorId),
|
||||||
|
PageNumber: tea.Int32(listListenersPageNumber),
|
||||||
|
PageSize: tea.Int32(listListenersPageSize),
|
||||||
|
}
|
||||||
|
listListenersResp, err := d.sdkClient.ListListeners(listListenersReq)
|
||||||
|
d.logger.Debug("sdk request 'ga.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute sdk request 'ga.ListListeners': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if listListenersResp.Body.Listeners != nil {
|
||||||
|
for _, listener := range listListenersResp.Body.Listeners {
|
||||||
|
if strings.EqualFold(tea.StringValue(listener.Protocol), "https") {
|
||||||
|
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(listListenersResp.Body.Listeners) < int(listListenersPageSize) {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
listListenersPageNumber++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历更新监听证书
|
||||||
|
if len(listenerIds) == 0 {
|
||||||
|
d.logger.Info("no ga listeners to deploy")
|
||||||
|
} else {
|
||||||
|
var errs []error
|
||||||
|
d.logger.Info("found https listeners to deploy", slog.Any("listenerIds", listenerIds))
|
||||||
|
|
||||||
|
for _, listenerId := range listenerIds {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
if err := d.updateListenerCertificate(ctx, d.config.AcceleratorId, listenerId, cloudCertId); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return errors.Join(errs...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error {
|
||||||
|
if d.config.AcceleratorId == "" {
|
||||||
|
return errors.New("config `acceleratorId` is required")
|
||||||
|
}
|
||||||
|
if d.config.ListenerId == "" {
|
||||||
|
return errors.New("config `listenerId` is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新监听
|
||||||
|
if err := d.updateListenerCertificate(ctx, d.config.AcceleratorId, d.config.ListenerId, cloudCertId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudAcceleratorId string, cloudListenerId string, cloudCertId string) error {
|
||||||
|
// 查询监听绑定的证书列表
|
||||||
|
// REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-listlistenercertificates
|
||||||
|
var listenerDefaultCertificate *aliga.ListListenerCertificatesResponseBodyCertificates
|
||||||
|
var listenerAdditionalCertificates []*aliga.ListListenerCertificatesResponseBodyCertificates = make([]*aliga.ListListenerCertificatesResponseBodyCertificates, 0)
|
||||||
|
var listListenerCertificatesNextToken *string
|
||||||
|
for {
|
||||||
|
listListenerCertificatesReq := &aliga.ListListenerCertificatesRequest{
|
||||||
|
RegionId: tea.String("cn-hangzhou"),
|
||||||
|
AcceleratorId: tea.String(d.config.AcceleratorId),
|
||||||
|
NextToken: listListenerCertificatesNextToken,
|
||||||
|
MaxResults: tea.Int32(20),
|
||||||
|
}
|
||||||
|
listListenerCertificatesResp, err := d.sdkClient.ListListenerCertificates(listListenerCertificatesReq)
|
||||||
|
d.logger.Debug("sdk request 'ga.ListListenerCertificates'", slog.Any("request", listListenerCertificatesReq), slog.Any("response", listListenerCertificatesResp))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute sdk request 'ga.ListListenerCertificates': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if listListenerCertificatesResp.Body.Certificates != nil {
|
||||||
|
for _, certificate := range listListenerCertificatesResp.Body.Certificates {
|
||||||
|
if tea.BoolValue(certificate.IsDefault) {
|
||||||
|
listenerDefaultCertificate = certificate
|
||||||
|
} else {
|
||||||
|
listenerAdditionalCertificates = append(listenerAdditionalCertificates, certificate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if listListenerCertificatesResp.Body.NextToken == nil {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
listListenerCertificatesNextToken = listListenerCertificatesResp.Body.NextToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.config.Domain == "" {
|
||||||
|
// 未指定 SNI,只需部署到监听器
|
||||||
|
if listenerDefaultCertificate != nil && tea.StringValue(listenerDefaultCertificate.CertificateId) == cloudCertId {
|
||||||
|
d.logger.Info("no need to update ga listener default certificate")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改监听的属性
|
||||||
|
// REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-updatelistener
|
||||||
|
updateListenerReq := &aliga.UpdateListenerRequest{
|
||||||
|
RegionId: tea.String("cn-hangzhou"),
|
||||||
|
ListenerId: tea.String(cloudListenerId),
|
||||||
|
Certificates: []*aliga.UpdateListenerRequestCertificates{{
|
||||||
|
Id: tea.String(cloudCertId),
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
updateListenerResp, err := d.sdkClient.UpdateListener(updateListenerReq)
|
||||||
|
d.logger.Debug("sdk request 'ga.UpdateListener'", slog.Any("request", updateListenerReq), slog.Any("response", updateListenerResp))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute sdk request 'ga.UpdateListener': %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 指定 SNI,需部署到扩展域名
|
||||||
|
if sliceutil.Some(listenerAdditionalCertificates, func(item *aliga.ListListenerCertificatesResponseBodyCertificates) bool {
|
||||||
|
return tea.StringValue(item.CertificateId) == cloudCertId
|
||||||
|
}) {
|
||||||
|
d.logger.Info("no need to update ga listener additional certificate")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if sliceutil.Some(listenerAdditionalCertificates, func(item *aliga.ListListenerCertificatesResponseBodyCertificates) bool {
|
||||||
|
return tea.StringValue(item.Domain) == d.config.Domain
|
||||||
|
}) {
|
||||||
|
// 为监听替换扩展证书
|
||||||
|
// REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-updateadditionalcertificatewithlistener
|
||||||
|
updateAdditionalCertificateWithListenerReq := &aliga.UpdateAdditionalCertificateWithListenerRequest{
|
||||||
|
RegionId: tea.String("cn-hangzhou"),
|
||||||
|
AcceleratorId: tea.String(cloudAcceleratorId),
|
||||||
|
ListenerId: tea.String(cloudListenerId),
|
||||||
|
CertificateId: tea.String(cloudCertId),
|
||||||
|
Domain: tea.String(d.config.Domain),
|
||||||
|
}
|
||||||
|
updateAdditionalCertificateWithListenerResp, err := d.sdkClient.UpdateAdditionalCertificateWithListener(updateAdditionalCertificateWithListenerReq)
|
||||||
|
d.logger.Debug("sdk request 'ga.UpdateAdditionalCertificateWithListener'", slog.Any("request", updateAdditionalCertificateWithListenerReq), slog.Any("response", updateAdditionalCertificateWithListenerResp))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute sdk request 'ga.UpdateAdditionalCertificateWithListener': %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 为监听绑定扩展证书
|
||||||
|
// REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-associateadditionalcertificateswithlistener
|
||||||
|
associateAdditionalCertificatesWithListenerReq := &aliga.AssociateAdditionalCertificatesWithListenerRequest{
|
||||||
|
RegionId: tea.String("cn-hangzhou"),
|
||||||
|
AcceleratorId: tea.String(cloudAcceleratorId),
|
||||||
|
ListenerId: tea.String(cloudListenerId),
|
||||||
|
Certificates: []*aliga.AssociateAdditionalCertificatesWithListenerRequestCertificates{{
|
||||||
|
Id: tea.String(cloudCertId),
|
||||||
|
Domain: tea.String(d.config.Domain),
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
associateAdditionalCertificatesWithListenerResp, err := d.sdkClient.AssociateAdditionalCertificatesWithListener(associateAdditionalCertificatesWithListenerReq)
|
||||||
|
d.logger.Debug("sdk request 'ga.AssociateAdditionalCertificatesWithListener'", slog.Any("request", associateAdditionalCertificatesWithListenerReq), slog.Any("response", associateAdditionalCertificatesWithListenerResp))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute sdk request 'ga.AssociateAdditionalCertificatesWithListener': %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSdkClient(accessKeyId, accessKeySecret string) (*aliga.Client, error) {
|
||||||
|
// 接入点一览 https://api.aliyun.com/product/Ga
|
||||||
|
config := &aliopen.Config{
|
||||||
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
|
Endpoint: tea.String("ga.cn-hangzhou.aliyuncs.com"),
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := aliga.NewClient(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId string) (uploader.Uploader, error) {
|
||||||
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
|
AccessKeyId: accessKeyId,
|
||||||
|
AccessKeySecret: accessKeySecret,
|
||||||
|
ResourceGroupId: resourceGroupId,
|
||||||
|
Region: "cn-hangzhou",
|
||||||
|
})
|
||||||
|
return uploader, err
|
||||||
|
}
|
||||||
118
internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga_test.go
Normal file
118
internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga_test.go
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package aliyunga_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-ga"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fInputCertPath string
|
||||||
|
fInputKeyPath string
|
||||||
|
fAccessKeyId string
|
||||||
|
fAccessKeySecret string
|
||||||
|
fAcceleratorId string
|
||||||
|
fListenerId string
|
||||||
|
fDomain string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
argsPrefix := "CERTIMATE_DEPLOYER_ALIYUNGA_"
|
||||||
|
|
||||||
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
|
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||||
|
flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
|
||||||
|
flag.StringVar(&fAcceleratorId, argsPrefix+"ACCELERATORID", "", "")
|
||||||
|
flag.StringVar(&fListenerId, argsPrefix+"LISTENERID", "", "")
|
||||||
|
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shell command to run this test:
|
||||||
|
|
||||||
|
go test -v ./aliyun_ga_test.go -args \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNGA_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNGA_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNGA_ACCESSKEYID="your-access-key-id" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNGA_ACCESSKEYSECRET="your-access-key-secret" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNGA_ACCELERATORID="your-ga-accelerator-id" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNGA_LISTENERID="your-ga-listener-id" \
|
||||||
|
--CERTIMATE_DEPLOYER_ALIYUNGA_DOMAIN="your-ga-sni-domain"
|
||||||
|
*/
|
||||||
|
func TestDeploy(t *testing.T) {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
t.Run("Deploy_ToAccelerator", func(t *testing.T) {
|
||||||
|
t.Log(strings.Join([]string{
|
||||||
|
"args:",
|
||||||
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
|
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||||
|
fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
|
||||||
|
fmt.Sprintf("ACCELERATORID: %v", fAcceleratorId),
|
||||||
|
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||||
|
}, "\n"))
|
||||||
|
|
||||||
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
|
AccessKeyId: fAccessKeyId,
|
||||||
|
AccessKeySecret: fAccessKeySecret,
|
||||||
|
ResourceType: provider.RESOURCE_TYPE_ACCELERATOR,
|
||||||
|
AcceleratorId: fAcceleratorId,
|
||||||
|
Domain: fDomain,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||||
|
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||||
|
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("ok: %v", res)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Deploy_ToListener", func(t *testing.T) {
|
||||||
|
t.Log(strings.Join([]string{
|
||||||
|
"args:",
|
||||||
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
|
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||||
|
fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
|
||||||
|
fmt.Sprintf("LISTENERID: %v", fListenerId),
|
||||||
|
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||||
|
}, "\n"))
|
||||||
|
|
||||||
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
|
AccessKeyId: fAccessKeyId,
|
||||||
|
AccessKeySecret: fAccessKeySecret,
|
||||||
|
ResourceType: provider.RESOURCE_TYPE_LISTENER,
|
||||||
|
ListenerId: fListenerId,
|
||||||
|
Domain: fDomain,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||||
|
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||||
|
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("ok: %v", res)
|
||||||
|
})
|
||||||
|
}
|
||||||
10
internal/pkg/core/deployer/providers/aliyun-ga/consts.go
Normal file
10
internal/pkg/core/deployer/providers/aliyun-ga/consts.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package aliyunga
|
||||||
|
|
||||||
|
type ResourceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 资源类型:部署到指定全球加速器。
|
||||||
|
RESOURCE_TYPE_ACCELERATOR = ResourceType("accelerator")
|
||||||
|
// 资源类型:部署到指定监听器。
|
||||||
|
RESOURCE_TYPE_LISTENER = ResourceType("listener")
|
||||||
|
)
|
||||||
@@ -19,6 +19,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 直播流域名(支持泛域名)。
|
// 直播流域名(支持泛域名)。
|
||||||
@@ -52,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -86,7 +88,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alilive.Clie
|
|||||||
// 接入点一览 https://api.aliyun.com/product/live
|
// 接入点一览 https://api.aliyun.com/product/live
|
||||||
var endpoint string
|
var endpoint string
|
||||||
switch region {
|
switch region {
|
||||||
case
|
case "",
|
||||||
"cn-qingdao",
|
"cn-qingdao",
|
||||||
"cn-beijing",
|
"cn-beijing",
|
||||||
"cn-shanghai",
|
"cn-shanghai",
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 部署资源类型。
|
// 部署资源类型。
|
||||||
@@ -52,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
}
|
}
|
||||||
@@ -67,7 +69,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -145,7 +147,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
|||||||
|
|
||||||
if listListenersResp.Body.Listeners != nil {
|
if listListenersResp.Body.Listeners != nil {
|
||||||
for _, listener := range listListenersResp.Body.Listeners {
|
for _, listener := range listListenersResp.Body.Listeners {
|
||||||
listenerIds = append(listenerIds, *listener.ListenerId)
|
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +169,6 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
|||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
|
if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
@@ -225,12 +226,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
|
|||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*alinlb.Client, error) {
|
func createSdkClient(accessKeyId, accessKeySecret, region string) (*alinlb.Client, error) {
|
||||||
// 接入点一览 https://api.aliyun.com/product/Nlb
|
// 接入点一览 https://api.aliyun.com/product/Nlb
|
||||||
var endpoint string
|
endpoint := strings.ReplaceAll(fmt.Sprintf("nlb.%s.aliyuncs.com", region), "..", ".")
|
||||||
switch region {
|
|
||||||
default:
|
|
||||||
endpoint = fmt.Sprintf("nlb.%s.aliyuncs.com", region)
|
|
||||||
}
|
|
||||||
|
|
||||||
config := &aliopen.Config{
|
config := &aliopen.Config{
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
@@ -245,13 +241,13 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alinlb.Clien
|
|||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||||
casRegion := region
|
casRegion := region
|
||||||
if casRegion != "" {
|
if casRegion != "" {
|
||||||
// 阿里云 CAS 服务接入点是独立于 NLB 服务的
|
// 阿里云 CAS 服务接入点是独立于 NLB 服务的
|
||||||
// 国内版固定接入点:华东一杭州
|
// 国内版固定接入点:华东一杭州
|
||||||
// 国际版固定接入点:亚太东南一新加坡
|
// 国际版固定接入点:亚太东南一新加坡
|
||||||
if casRegion != "" && !strings.HasPrefix(casRegion, "cn-") {
|
if !strings.HasPrefix(casRegion, "cn-") {
|
||||||
casRegion = "ap-southeast-1"
|
casRegion = "ap-southeast-1"
|
||||||
} else {
|
} else {
|
||||||
casRegion = "cn-hangzhou"
|
casRegion = "cn-hangzhou"
|
||||||
@@ -261,6 +257,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
|||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
AccessKeyId: accessKeyId,
|
AccessKeyId: accessKeyId,
|
||||||
AccessKeySecret: accessKeySecret,
|
AccessKeySecret: accessKeySecret,
|
||||||
|
ResourceGroupId: resourceGroupId,
|
||||||
Region: casRegion,
|
Region: casRegion,
|
||||||
})
|
})
|
||||||
return uploader, err
|
return uploader, err
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 存储桶名。
|
// 存储桶名。
|
||||||
@@ -51,7 +53,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||||
@@ -18,6 +19,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 点播加速域名(不支持泛域名)。
|
// 点播加速域名(不支持泛域名)。
|
||||||
@@ -51,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -80,8 +83,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*alivod.Client, error) {
|
func createSdkClient(accessKeyId, accessKeySecret, region string) (*alivod.Client, error) {
|
||||||
// 接入点一览 https://api.aliyun.com/product/vod
|
// 接入点一览 https://api.aliyun.com/product/vod
|
||||||
endpoint := fmt.Sprintf("vod.%s.aliyuncs.com", region)
|
endpoint := strings.ReplaceAll(fmt.Sprintf("vod.%s.aliyuncs.com", region), "..", ".")
|
||||||
|
|
||||||
config := &aliopen.Config{
|
config := &aliopen.Config{
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas"
|
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas"
|
||||||
sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
|
sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
|
||||||
|
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeployerConfig struct {
|
type DeployerConfig struct {
|
||||||
@@ -22,6 +23,8 @@ type DeployerConfig struct {
|
|||||||
AccessKeyId string `json:"accessKeyId"`
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
// 阿里云 AccessKeySecret。
|
// 阿里云 AccessKeySecret。
|
||||||
AccessKeySecret string `json:"accessKeySecret"`
|
AccessKeySecret string `json:"accessKeySecret"`
|
||||||
|
// 阿里云资源组 ID。
|
||||||
|
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||||
// 阿里云地域。
|
// 阿里云地域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// 服务版本。
|
// 服务版本。
|
||||||
@@ -51,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
}
|
}
|
||||||
@@ -66,7 +69,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -107,8 +110,9 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPEM string, pri
|
|||||||
// 查询默认 SSL/TLS 设置
|
// 查询默认 SSL/TLS 设置
|
||||||
// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describedefaulthttps
|
// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describedefaulthttps
|
||||||
describeDefaultHttpsReq := &aliwaf.DescribeDefaultHttpsRequest{
|
describeDefaultHttpsReq := &aliwaf.DescribeDefaultHttpsRequest{
|
||||||
InstanceId: tea.String(d.config.InstanceId),
|
ResourceManagerResourceGroupId: typeutil.ToPtrOrZeroNil(d.config.ResourceGroupId),
|
||||||
RegionId: tea.String(d.config.Region),
|
InstanceId: tea.String(d.config.InstanceId),
|
||||||
|
RegionId: tea.String(d.config.Region),
|
||||||
}
|
}
|
||||||
describeDefaultHttpsResp, err := d.sdkClient.DescribeDefaultHttps(describeDefaultHttpsReq)
|
describeDefaultHttpsResp, err := d.sdkClient.DescribeDefaultHttps(describeDefaultHttpsReq)
|
||||||
d.logger.Debug("sdk request 'waf.DescribeDefaultHttps'", slog.Any("request", describeDefaultHttpsReq), slog.Any("response", describeDefaultHttpsResp))
|
d.logger.Debug("sdk request 'waf.DescribeDefaultHttps'", slog.Any("request", describeDefaultHttpsReq), slog.Any("response", describeDefaultHttpsResp))
|
||||||
@@ -119,11 +123,12 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPEM string, pri
|
|||||||
// 修改默认 SSL/TLS 设置
|
// 修改默认 SSL/TLS 设置
|
||||||
// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifydefaulthttps
|
// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifydefaulthttps
|
||||||
modifyDefaultHttpsReq := &aliwaf.ModifyDefaultHttpsRequest{
|
modifyDefaultHttpsReq := &aliwaf.ModifyDefaultHttpsRequest{
|
||||||
InstanceId: tea.String(d.config.InstanceId),
|
ResourceManagerResourceGroupId: typeutil.ToPtrOrZeroNil(d.config.ResourceGroupId),
|
||||||
RegionId: tea.String(d.config.Region),
|
InstanceId: tea.String(d.config.InstanceId),
|
||||||
CertId: tea.String(upres.CertId),
|
RegionId: tea.String(d.config.Region),
|
||||||
TLSVersion: tea.String("tlsv1"),
|
CertId: tea.String(upres.CertId),
|
||||||
EnableTLSv3: tea.Bool(false),
|
TLSVersion: tea.String("tlsv1"),
|
||||||
|
EnableTLSv3: tea.Bool(false),
|
||||||
}
|
}
|
||||||
if describeDefaultHttpsResp.Body != nil && describeDefaultHttpsResp.Body.DefaultHttps != nil {
|
if describeDefaultHttpsResp.Body != nil && describeDefaultHttpsResp.Body.DefaultHttps != nil {
|
||||||
modifyDefaultHttpsReq.TLSVersion = describeDefaultHttpsResp.Body.DefaultHttps.TLSVersion
|
modifyDefaultHttpsReq.TLSVersion = describeDefaultHttpsResp.Body.DefaultHttps.TLSVersion
|
||||||
@@ -172,10 +177,11 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPEM string, pri
|
|||||||
|
|
||||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliwaf.Client, error) {
|
func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliwaf.Client, error) {
|
||||||
// 接入点一览:https://api.aliyun.com/product/waf-openapi
|
// 接入点一览:https://api.aliyun.com/product/waf-openapi
|
||||||
|
endpoint := strings.ReplaceAll(fmt.Sprintf("wafopenapi.%s.aliyuncs.com", region), "..", ".")
|
||||||
config := &aliopen.Config{
|
config := &aliopen.Config{
|
||||||
AccessKeyId: tea.String(accessKeyId),
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
AccessKeySecret: tea.String(accessKeySecret),
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
Endpoint: tea.String(fmt.Sprintf("wafopenapi.%s.aliyuncs.com", region)),
|
Endpoint: tea.String(endpoint),
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := aliwaf.NewClient(config)
|
client, err := aliwaf.NewClient(config)
|
||||||
@@ -186,13 +192,13 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliwaf.Clien
|
|||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||||
casRegion := region
|
casRegion := region
|
||||||
if casRegion != "" {
|
if casRegion != "" {
|
||||||
// 阿里云 CAS 服务接入点是独立于 WAF 服务的
|
// 阿里云 CAS 服务接入点是独立于 WAF 服务的
|
||||||
// 国内版固定接入点:华东一杭州
|
// 国内版固定接入点:华东一杭州
|
||||||
// 国际版固定接入点:亚太东南一新加坡
|
// 国际版固定接入点:亚太东南一新加坡
|
||||||
if casRegion != "" && !strings.HasPrefix(casRegion, "cn-") {
|
if !strings.HasPrefix(casRegion, "cn-") {
|
||||||
casRegion = "ap-southeast-1"
|
casRegion = "ap-southeast-1"
|
||||||
} else {
|
} else {
|
||||||
casRegion = "cn-hangzhou"
|
casRegion = "cn-hangzhou"
|
||||||
@@ -202,6 +208,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
|||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
AccessKeyId: accessKeyId,
|
AccessKeyId: accessKeyId,
|
||||||
AccessKeySecret: accessKeySecret,
|
AccessKeySecret: accessKeySecret,
|
||||||
|
ResourceGroupId: resourceGroupId,
|
||||||
Region: casRegion,
|
Region: casRegion,
|
||||||
})
|
})
|
||||||
return uploader, err
|
return uploader, err
|
||||||
|
|||||||
@@ -5,9 +5,15 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"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"
|
||||||
|
awsacm "github.com/aws/aws-sdk-go-v2/service/acm"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm"
|
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm"
|
||||||
|
certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeployerConfig struct {
|
type DeployerConfig struct {
|
||||||
@@ -17,11 +23,15 @@ type DeployerConfig struct {
|
|||||||
SecretAccessKey string `json:"secretAccessKey"`
|
SecretAccessKey string `json:"secretAccessKey"`
|
||||||
// AWS 区域。
|
// AWS 区域。
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
|
// ACM 证书 ARN。
|
||||||
|
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||||
|
CertificateArn string `json:"certificateArn,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeployerProvider struct {
|
type DeployerProvider struct {
|
||||||
config *DeployerConfig
|
config *DeployerConfig
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
|
sdkClient *awsacm.Client
|
||||||
sslUploader uploader.Uploader
|
sslUploader uploader.Uploader
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +42,11 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
panic("config is nil")
|
panic("config is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
AccessKeyId: config.AccessKeyId,
|
AccessKeyId: config.AccessKeyId,
|
||||||
SecretAccessKey: config.SecretAccessKey,
|
SecretAccessKey: config.SecretAccessKey,
|
||||||
@@ -44,13 +59,14 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
return &DeployerProvider{
|
return &DeployerProvider{
|
||||||
config: config,
|
config: config,
|
||||||
logger: slog.Default(),
|
logger: slog.Default(),
|
||||||
|
sdkClient: client,
|
||||||
sslUploader: uploader,
|
sslUploader: uploader,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -59,13 +75,48 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||||
// 上传证书到 ACM
|
if d.config.CertificateArn == "" {
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
// 上传证书到 ACM
|
||||||
if err != nil {
|
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||||
|
} else {
|
||||||
|
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
// 提取服务器证书
|
||||||
|
serverCertPEM, intermediaCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to extract certs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导入证书
|
||||||
|
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ImportCertificate.html
|
||||||
|
importCertificateReq := &awsacm.ImportCertificateInput{
|
||||||
|
CertificateArn: aws.String(d.config.CertificateArn),
|
||||||
|
Certificate: ([]byte)(serverCertPEM),
|
||||||
|
CertificateChain: ([]byte)(intermediaCertPEM),
|
||||||
|
PrivateKey: ([]byte)(privkeyPEM),
|
||||||
|
}
|
||||||
|
importCertificateResp, err := d.sdkClient.ImportCertificate(context.TODO(), importCertificateReq)
|
||||||
|
d.logger.Debug("sdk request 'acm.ImportCertificate'", slog.Any("request", importCertificateReq), slog.Any("response", importCertificateResp))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute sdk request 'acm.ImportCertificate': %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &deployer.DeployResult{}, nil
|
return &deployer.DeployResult{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createSdkClient(accessKeyId, secretAccessKey, region string) (*awsacm.Client, error) {
|
||||||
|
cfg, err := awscfg.LoadDefaultConfig(context.TODO())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := awsacm.NewFromConfig(cfg, func(o *awsacm.Options) {
|
||||||
|
o.Region = region
|
||||||
|
o.Credentials = aws.NewCredentialsCache(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, ""))
|
||||||
|
})
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import (
|
|||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm"
|
uploaderspacm "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm"
|
||||||
|
uploaderspiam "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-iam"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeployerConfig struct {
|
type DeployerConfig struct {
|
||||||
@@ -26,6 +27,9 @@ type DeployerConfig struct {
|
|||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
// AWS CloudFront 分配 ID。
|
// AWS CloudFront 分配 ID。
|
||||||
DistributionId string `json:"distributionId"`
|
DistributionId string `json:"distributionId"`
|
||||||
|
// AWS CloudFront 证书来源。
|
||||||
|
// 可取值 "ACM"、"IAM"。
|
||||||
|
CertificateSource string `json:"certificateSource"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeployerProvider struct {
|
type DeployerProvider struct {
|
||||||
@@ -47,13 +51,28 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
var uploader uploader.Uploader
|
||||||
AccessKeyId: config.AccessKeyId,
|
if config.CertificateSource == "ACM" {
|
||||||
SecretAccessKey: config.SecretAccessKey,
|
uploader, err = uploaderspacm.NewUploader(&uploaderspacm.UploaderConfig{
|
||||||
Region: config.Region,
|
AccessKeyId: config.AccessKeyId,
|
||||||
})
|
SecretAccessKey: config.SecretAccessKey,
|
||||||
if err != nil {
|
Region: config.Region,
|
||||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
|
}
|
||||||
|
} else if config.CertificateSource == "IAM" {
|
||||||
|
uploader, err = uploaderspiam.NewUploader(&uploaderspiam.UploaderConfig{
|
||||||
|
AccessKeyId: config.AccessKeyId,
|
||||||
|
SecretAccessKey: config.SecretAccessKey,
|
||||||
|
Region: config.Region,
|
||||||
|
CertificatePath: "/cloudfront/",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("unsupported certificate source: '%s'", config.CertificateSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &DeployerProvider{
|
return &DeployerProvider{
|
||||||
@@ -66,7 +85,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -79,7 +98,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
return nil, errors.New("config `distribuitionId` is required")
|
return nil, errors.New("config `distribuitionId` is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传证书到 ACM
|
// 上传证书到 ACM/IAM
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||||
@@ -109,7 +128,19 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
updateDistributionReq.DistributionConfig.ViewerCertificate = &types.ViewerCertificate{}
|
updateDistributionReq.DistributionConfig.ViewerCertificate = &types.ViewerCertificate{}
|
||||||
}
|
}
|
||||||
updateDistributionReq.DistributionConfig.ViewerCertificate.CloudFrontDefaultCertificate = aws.Bool(false)
|
updateDistributionReq.DistributionConfig.ViewerCertificate.CloudFrontDefaultCertificate = aws.Bool(false)
|
||||||
updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = aws.String(upres.CertId)
|
if d.config.CertificateSource == "ACM" {
|
||||||
|
updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = aws.String(upres.CertId)
|
||||||
|
updateDistributionReq.DistributionConfig.ViewerCertificate.IAMCertificateId = nil
|
||||||
|
} else if d.config.CertificateSource == "IAM" {
|
||||||
|
updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = nil
|
||||||
|
updateDistributionReq.DistributionConfig.ViewerCertificate.IAMCertificateId = aws.String(upres.CertId)
|
||||||
|
if updateDistributionReq.DistributionConfig.ViewerCertificate.MinimumProtocolVersion == "" {
|
||||||
|
updateDistributionReq.DistributionConfig.ViewerCertificate.MinimumProtocolVersion = types.MinimumProtocolVersionTLSv1
|
||||||
|
}
|
||||||
|
if updateDistributionReq.DistributionConfig.ViewerCertificate.SSLSupportMethod == "" {
|
||||||
|
updateDistributionReq.DistributionConfig.ViewerCertificate.SSLSupportMethod = types.SSLSupportMethodSniOnly
|
||||||
|
}
|
||||||
|
}
|
||||||
updateDistributionResp, err := d.sdkClient.UpdateDistribution(context.TODO(), updateDistributionReq)
|
updateDistributionResp, err := d.sdkClient.UpdateDistribution(context.TODO(), updateDistributionReq)
|
||||||
d.logger.Debug("sdk request 'cloudfront.UpdateDistribution'", slog.Any("request", updateDistributionReq), slog.Any("response", updateDistributionResp))
|
d.logger.Debug("sdk request 'cloudfront.UpdateDistribution'", slog.Any("request", updateDistributionReq), slog.Any("response", updateDistributionResp))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
75
internal/pkg/core/deployer/providers/aws-iam/aws_iam.go
Normal file
75
internal/pkg/core/deployer/providers/aws-iam/aws_iam.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package awsiam
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"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-iam"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeployerConfig struct {
|
||||||
|
// AWS AccessKeyId。
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
// AWS SecretAccessKey。
|
||||||
|
SecretAccessKey string `json:"secretAccessKey"`
|
||||||
|
// AWS 区域。
|
||||||
|
Region string `json:"region"`
|
||||||
|
// IAM 证书路径。
|
||||||
|
// 选填。
|
||||||
|
CertificatePath string `json:"certificatePath,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
CertificatePath: config.CertificatePath,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.New(slog.DiscardHandler)
|
||||||
|
} else {
|
||||||
|
d.logger = logger
|
||||||
|
}
|
||||||
|
d.sslUploader.WithLogger(logger)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||||
|
// 上传证书到 IAM
|
||||||
|
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||||
|
} else {
|
||||||
|
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &deployer.DeployResult{}, nil
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ type DeployerConfig struct {
|
|||||||
// Key Vault 名称。
|
// Key Vault 名称。
|
||||||
KeyVaultName string `json:"keyvaultName"`
|
KeyVaultName string `json:"keyvaultName"`
|
||||||
// Key Vault 证书名称。
|
// Key Vault 证书名称。
|
||||||
// 选填。
|
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||||
CertificateName string `json:"certificateName,omitempty"`
|
CertificateName string `json:"certificateName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type DeployerConfig struct {
|
|||||||
// 加速域名(支持泛域名)。
|
// 加速域名(支持泛域名)。
|
||||||
Domain string `json:"domain"`
|
Domain string `json:"domain"`
|
||||||
// 证书 ID。
|
// 证书 ID。
|
||||||
// 选填。
|
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||||
CertificateId string `json:"certificateId,omitempty"`
|
CertificateId string `json:"certificateId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -63,6 +63,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
return nil, errors.New("config `domain` is required")
|
return nil, errors.New("config `domain` is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果原证书 ID 为空,则新增证书;否则替换证书。
|
||||||
if d.config.CertificateId == "" {
|
if d.config.CertificateId == "" {
|
||||||
// 新增证书
|
// 新增证书
|
||||||
// REF: https://portal.baishancloud.com/track/document/downloadPdf/1441
|
// REF: https://portal.baishancloud.com/track/document/downloadPdf/1441
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DeployerConfig struct {
|
type DeployerConfig struct {
|
||||||
// 宝塔面板地址。
|
// 宝塔面板服务地址。
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
// 宝塔面板接口密钥。
|
// 宝塔面板接口密钥。
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
// 是否允许不安全的连接。
|
// 是否允许不安全的连接。
|
||||||
@@ -36,7 +36,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
panic("config is nil")
|
panic("config is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
client, err := createSdkClient(config.ServerUrl, config.ApiKey, config.AllowInsecureConnections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -82,17 +82,17 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
return &deployer.DeployResult{}, nil
|
return &deployer.DeployResult{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, error) {
|
func createSdkClient(serverUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
if _, err := url.Parse(serverUrl); err != nil {
|
||||||
return nil, errors.New("invalid baota api url")
|
return nil, errors.New("invalid baota server url")
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiKey == "" {
|
if apiKey == "" {
|
||||||
return nil, errors.New("invalid baota api key")
|
return nil, errors.New("invalid baota api key")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := btsdk.NewClient(apiUrl, apiKey)
|
client := btsdk.NewClient(serverUrl, apiKey)
|
||||||
if allowInsecure {
|
if skipTlsVerify {
|
||||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
fInputCertPath string
|
fInputCertPath string
|
||||||
fInputKeyPath string
|
fInputKeyPath string
|
||||||
fApiUrl string
|
fServerUrl string
|
||||||
fApiKey string
|
fApiKey string
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ func init() {
|
|||||||
|
|
||||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
|
||||||
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ Shell command to run this test:
|
|||||||
go test -v ./baotapanel_console_test.go -args \
|
go test -v ./baotapanel_console_test.go -args \
|
||||||
--CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
--CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
--CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
--CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
--CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_APIURL="http://127.0.0.1:8888" \
|
--CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_SERVERURL="http://127.0.0.1:8888" \
|
||||||
--CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_APIKEY="your-api-key"
|
--CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_APIKEY="your-api-key"
|
||||||
*/
|
*/
|
||||||
func TestDeploy(t *testing.T) {
|
func TestDeploy(t *testing.T) {
|
||||||
@@ -44,12 +44,12 @@ func TestDeploy(t *testing.T) {
|
|||||||
"args:",
|
"args:",
|
||||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
fmt.Sprintf("SERVERURL: %v", fServerUrl),
|
||||||
fmt.Sprintf("APIKEY: %v", fApiKey),
|
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||||
}, "\n"))
|
}, "\n"))
|
||||||
|
|
||||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
ApiUrl: fApiUrl,
|
ServerUrl: fServerUrl,
|
||||||
ApiKey: fApiKey,
|
ApiKey: fApiKey,
|
||||||
AllowInsecureConnections: true,
|
AllowInsecureConnections: true,
|
||||||
AutoRestart: true,
|
AutoRestart: true,
|
||||||
|
|||||||
@@ -14,17 +14,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DeployerConfig struct {
|
type DeployerConfig struct {
|
||||||
// 宝塔面板地址。
|
// 宝塔面板服务地址。
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
// 宝塔面板接口密钥。
|
// 宝塔面板接口密钥。
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
// 是否允许不安全的连接。
|
// 是否允许不安全的连接。
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
// 站点类型。
|
// 网站类型。
|
||||||
SiteType string `json:"siteType"`
|
SiteType string `json:"siteType"`
|
||||||
// 站点名称(单个)。
|
// 网站名称(单个)。
|
||||||
SiteName string `json:"siteName,omitempty"`
|
SiteName string `json:"siteName,omitempty"`
|
||||||
// 站点名称(多个)。
|
// 网站名称(多个)。
|
||||||
SiteNames []string `json:"siteNames,omitempty"`
|
SiteNames []string `json:"siteNames,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
panic("config is nil")
|
panic("config is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
client, err := createSdkClient(config.ServerUrl, config.ApiKey, config.AllowInsecureConnections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -124,17 +124,17 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
return &deployer.DeployResult{}, nil
|
return &deployer.DeployResult{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, error) {
|
func createSdkClient(serverUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
if _, err := url.Parse(serverUrl); err != nil {
|
||||||
return nil, errors.New("invalid baota api url")
|
return nil, errors.New("invalid baota server url")
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiKey == "" {
|
if apiKey == "" {
|
||||||
return nil, errors.New("invalid baota api key")
|
return nil, errors.New("invalid baota api key")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := btsdk.NewClient(apiUrl, apiKey)
|
client := btsdk.NewClient(serverUrl, apiKey)
|
||||||
if allowInsecure {
|
if skipTlsVerify {
|
||||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
fInputCertPath string
|
fInputCertPath string
|
||||||
fInputKeyPath string
|
fInputKeyPath string
|
||||||
fApiUrl string
|
fServerUrl string
|
||||||
fApiKey string
|
fApiKey string
|
||||||
fSiteType string
|
fSiteType string
|
||||||
fSiteName string
|
fSiteName string
|
||||||
@@ -25,7 +25,7 @@ func init() {
|
|||||||
|
|
||||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
|
||||||
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||||
flag.StringVar(&fSiteType, argsPrefix+"SITETYPE", "", "")
|
flag.StringVar(&fSiteType, argsPrefix+"SITETYPE", "", "")
|
||||||
flag.StringVar(&fSiteName, argsPrefix+"SITENAME", "", "")
|
flag.StringVar(&fSiteName, argsPrefix+"SITENAME", "", "")
|
||||||
@@ -37,7 +37,7 @@ Shell command to run this test:
|
|||||||
go test -v ./baotapanel_site_test.go -args \
|
go test -v ./baotapanel_site_test.go -args \
|
||||||
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIURL="http://127.0.0.1:8888" \
|
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_SERVERURL="http://127.0.0.1:8888" \
|
||||||
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIKEY="your-api-key" \
|
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIKEY="your-api-key" \
|
||||||
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITETYPE="php" \
|
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITETYPE="php" \
|
||||||
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITENAME="your-site-name"
|
--CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITENAME="your-site-name"
|
||||||
@@ -50,14 +50,14 @@ func TestDeploy(t *testing.T) {
|
|||||||
"args:",
|
"args:",
|
||||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
fmt.Sprintf("SERVERURL: %v", fServerUrl),
|
||||||
fmt.Sprintf("APIKEY: %v", fApiKey),
|
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||||
fmt.Sprintf("SITETYPE: %v", fSiteType),
|
fmt.Sprintf("SITETYPE: %v", fSiteType),
|
||||||
fmt.Sprintf("SITENAME: %v", fSiteName),
|
fmt.Sprintf("SITENAME: %v", fSiteName),
|
||||||
}, "\n"))
|
}, "\n"))
|
||||||
|
|
||||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
ApiUrl: fApiUrl,
|
ServerUrl: fServerUrl,
|
||||||
ApiKey: fApiKey,
|
ApiKey: fApiKey,
|
||||||
AllowInsecureConnections: true,
|
AllowInsecureConnections: true,
|
||||||
SiteType: fSiteType,
|
SiteType: fSiteType,
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package baotapanelconsole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||||
|
btsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/btwaf"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeployerConfig struct {
|
||||||
|
// 堡塔云 WAF 服务地址。
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
// 堡塔云 WAF 接口密钥。
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
// 是否允许不安全的连接。
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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.ServerUrl, config.ApiKey, config.AllowInsecureConnections)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.New(slog.DiscardHandler)
|
||||||
|
} else {
|
||||||
|
d.logger = logger
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||||
|
// 设置面板 SSL
|
||||||
|
configSetSSLReq := &btsdk.ConfigSetSSLRequest{
|
||||||
|
CertContent: certPEM,
|
||||||
|
KeyContent: privkeyPEM,
|
||||||
|
}
|
||||||
|
configSetSSLResp, err := d.sdkClient.ConfigSetSSL(configSetSSLReq)
|
||||||
|
d.logger.Debug("sdk request 'bt.ConfigSetSSL'", slog.Any("request", configSetSSLReq), slog.Any("response", configSetSSLResp))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute sdk request 'bt.ConfigSetSSL': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &deployer.DeployResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSdkClient(serverUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
|
||||||
|
if _, err := url.Parse(serverUrl); err != nil {
|
||||||
|
return nil, errors.New("invalid baota server url")
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiKey == "" {
|
||||||
|
return nil, errors.New("invalid baota api key")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := btsdk.NewClient(serverUrl, apiKey)
|
||||||
|
if skipTlsVerify {
|
||||||
|
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package baotapanelconsole_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-console"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fInputCertPath string
|
||||||
|
fInputKeyPath string
|
||||||
|
fServerUrl string
|
||||||
|
fApiKey string
|
||||||
|
fSiteName string
|
||||||
|
fSitePort int64
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
argsPrefix := "CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_"
|
||||||
|
|
||||||
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
|
flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
|
||||||
|
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shell command to run this test:
|
||||||
|
|
||||||
|
go test -v ./baotawaf_console_test.go -args \
|
||||||
|
--CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_SERVERURL="http://127.0.0.1:8888" \
|
||||||
|
--CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_APIKEY="your-api-key"
|
||||||
|
*/
|
||||||
|
func TestDeploy(t *testing.T) {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
t.Run("Deploy", func(t *testing.T) {
|
||||||
|
t.Log(strings.Join([]string{
|
||||||
|
"args:",
|
||||||
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
|
fmt.Sprintf("SERVERURL: %v", fServerUrl),
|
||||||
|
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||||
|
}, "\n"))
|
||||||
|
|
||||||
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
|
ServerUrl: fServerUrl,
|
||||||
|
ApiKey: fApiKey,
|
||||||
|
AllowInsecureConnections: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||||
|
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||||
|
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("ok: %v", res)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
package baotapanelwaf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||||
|
btsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/btwaf"
|
||||||
|
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeployerConfig struct {
|
||||||
|
// 堡塔云 WAF 服务地址。
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
// 堡塔云 WAF 接口密钥。
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
// 是否允许不安全的连接。
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
|
// 网站名称。
|
||||||
|
SiteName string `json:"siteName"`
|
||||||
|
// 网站 SSL 端口。
|
||||||
|
// 零值时默认值 443。
|
||||||
|
SitePort int32 `json:"sitePort,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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.ServerUrl, config.ApiKey, config.AllowInsecureConnections)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.New(slog.DiscardHandler)
|
||||||
|
} else {
|
||||||
|
d.logger = logger
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||||
|
if d.config.SiteName == "" {
|
||||||
|
return nil, errors.New("config `siteName` is required")
|
||||||
|
}
|
||||||
|
if d.config.SitePort == 0 {
|
||||||
|
d.config.SitePort = 443
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历获取网站列表,获取网站 ID
|
||||||
|
// REF: https://support.huaweicloud.com/api-waf/ListHost.html
|
||||||
|
siteId := ""
|
||||||
|
getSitListPage := int32(1)
|
||||||
|
getSitListPageSize := int32(100)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
getSiteListReq := &btsdk.GetSiteListRequest{
|
||||||
|
SiteName: typeutil.ToPtr(d.config.SiteName),
|
||||||
|
Page: typeutil.ToPtr(getSitListPage),
|
||||||
|
PageSize: typeutil.ToPtr(getSitListPageSize),
|
||||||
|
}
|
||||||
|
getSiteListResp, err := d.sdkClient.GetSiteList(getSiteListReq)
|
||||||
|
d.logger.Debug("sdk request 'bt.GetSiteList'", slog.Any("request", getSiteListReq), slog.Any("response", getSiteListResp))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute sdk request 'bt.GetSiteList': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if getSiteListResp.Result != nil && getSiteListResp.Result.List != nil {
|
||||||
|
for _, siteItem := range getSiteListResp.Result.List {
|
||||||
|
if siteItem.SiteName == d.config.SiteName {
|
||||||
|
siteId = siteItem.SiteId
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if getSiteListResp.Result == nil || len(getSiteListResp.Result.List) < int(getSitListPageSize) {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
getSitListPage++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if siteId == "" {
|
||||||
|
return nil, errors.New("site not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改站点配置
|
||||||
|
modifySiteReq := &btsdk.ModifySiteRequest{
|
||||||
|
SiteId: siteId,
|
||||||
|
Type: typeutil.ToPtr("openCert"),
|
||||||
|
Server: &btsdk.SiteServerInfo{
|
||||||
|
ListenSSLPorts: typeutil.ToPtr([]int32{d.config.SitePort}),
|
||||||
|
SSL: &btsdk.SiteServerSSLInfo{
|
||||||
|
IsSSL: typeutil.ToPtr(int32(1)),
|
||||||
|
FullChain: typeutil.ToPtr(certPEM),
|
||||||
|
PrivateKey: typeutil.ToPtr(privkeyPEM),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
modifySiteResp, err := d.sdkClient.ModifySite(modifySiteReq)
|
||||||
|
d.logger.Debug("sdk request 'bt.ModifySite'", slog.Any("request", modifySiteReq), slog.Any("response", modifySiteResp))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute sdk request 'bt.ModifySite': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &deployer.DeployResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSdkClient(serverUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
|
||||||
|
if _, err := url.Parse(serverUrl); err != nil {
|
||||||
|
return nil, errors.New("invalid baota server url")
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiKey == "" {
|
||||||
|
return nil, errors.New("invalid baota api key")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := btsdk.NewClient(serverUrl, apiKey)
|
||||||
|
if skipTlsVerify {
|
||||||
|
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package baotapanelwaf_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-site"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fInputCertPath string
|
||||||
|
fInputKeyPath string
|
||||||
|
fServerUrl string
|
||||||
|
fApiKey string
|
||||||
|
fSiteName string
|
||||||
|
fSitePort int64
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
argsPrefix := "CERTIMATE_DEPLOYER_BAOTAWAFSITE_"
|
||||||
|
|
||||||
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
|
flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
|
||||||
|
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||||
|
flag.StringVar(&fSiteName, argsPrefix+"SITENAME", "", "")
|
||||||
|
flag.Int64Var(&fSitePort, argsPrefix+"SITEPORT", 0, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shell command to run this test:
|
||||||
|
|
||||||
|
go test -v ./baotawaf_site_test.go -args \
|
||||||
|
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_SERVERURL="http://127.0.0.1:8888" \
|
||||||
|
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_APIKEY="your-api-key" \
|
||||||
|
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_SITENAME="your-site-name" \
|
||||||
|
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_SITEPORT=443
|
||||||
|
*/
|
||||||
|
func TestDeploy(t *testing.T) {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
t.Run("Deploy", func(t *testing.T) {
|
||||||
|
t.Log(strings.Join([]string{
|
||||||
|
"args:",
|
||||||
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
|
fmt.Sprintf("SERVERURL: %v", fServerUrl),
|
||||||
|
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||||
|
fmt.Sprintf("SITENAME: %v", fSiteName),
|
||||||
|
fmt.Sprintf("SITEPORT: %v", fSitePort),
|
||||||
|
}, "\n"))
|
||||||
|
|
||||||
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
|
ServerUrl: fServerUrl,
|
||||||
|
ApiKey: fApiKey,
|
||||||
|
AllowInsecureConnections: true,
|
||||||
|
SiteName: fSiteName,
|
||||||
|
SitePort: int32(fSitePort),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||||
|
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||||
|
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("ok: %v", res)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -51,6 +51,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||||
// 上传证书
|
// 上传证书
|
||||||
|
// REF: https://api.cachefly.com/api/2.5/docs#tag/Certificates/paths/~1certificates/post
|
||||||
createCertificateReq := &cfsdk.CreateCertificateRequest{
|
createCertificateReq := &cfsdk.CreateCertificateRequest{
|
||||||
Certificate: certPEM,
|
Certificate: certPEM,
|
||||||
CertificateKey: privkeyPEM,
|
CertificateKey: privkeyPEM,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package cdnfly
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -14,12 +15,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DeployerConfig struct {
|
type DeployerConfig struct {
|
||||||
// Cdnfly 地址。
|
// Cdnfly 服务地址。
|
||||||
ApiUrl string `json:"apiUrl"`
|
ServerUrl string `json:"serverUrl"`
|
||||||
// Cdnfly 用户端 API Key。
|
// Cdnfly 用户端 API Key。
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
// Cdnfly 用户端 API Secret。
|
// Cdnfly 用户端 API Secret。
|
||||||
ApiSecret string `json:"apiSecret"`
|
ApiSecret string `json:"apiSecret"`
|
||||||
|
// 是否允许不安全的连接。
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
// 部署资源类型。
|
// 部署资源类型。
|
||||||
ResourceType ResourceType `json:"resourceType"`
|
ResourceType ResourceType `json:"resourceType"`
|
||||||
// 网站 ID。
|
// 网站 ID。
|
||||||
@@ -43,7 +46,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
panic("config is nil")
|
panic("config is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.ApiSecret)
|
client, err := createSdkClient(config.ServerUrl, config.ApiKey, config.ApiSecret, config.AllowInsecureConnections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
}
|
}
|
||||||
@@ -57,7 +60,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -157,9 +160,9 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSdkClient(apiUrl, apiKey, apiSecret string) (*cfsdk.Client, error) {
|
func createSdkClient(serverUrl, apiKey, apiSecret string, skipTlsVerify bool) (*cfsdk.Client, error) {
|
||||||
if _, err := url.Parse(apiUrl); err != nil {
|
if _, err := url.Parse(serverUrl); err != nil {
|
||||||
return nil, errors.New("invalid cachefly api url")
|
return nil, errors.New("invalid cachefly server url")
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiKey == "" {
|
if apiKey == "" {
|
||||||
@@ -170,6 +173,10 @@ func createSdkClient(apiUrl, apiKey, apiSecret string) (*cfsdk.Client, error) {
|
|||||||
return nil, errors.New("invalid cachefly api secret")
|
return nil, errors.New("invalid cachefly api secret")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := cfsdk.NewClient(apiUrl, apiKey, apiSecret)
|
client := cfsdk.NewClient(serverUrl, apiKey, apiSecret)
|
||||||
|
if skipTlsVerify {
|
||||||
|
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
}
|
||||||
|
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
fInputCertPath string
|
fInputCertPath string
|
||||||
fInputKeyPath string
|
fInputKeyPath string
|
||||||
fApiUrl string
|
fServerUrl string
|
||||||
fApiKey string
|
fApiKey string
|
||||||
fApiSecret string
|
fApiSecret string
|
||||||
fCertificateId string
|
fCertificateId string
|
||||||
@@ -25,7 +25,7 @@ func init() {
|
|||||||
|
|
||||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
|
||||||
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||||
flag.StringVar(&fApiSecret, argsPrefix+"APISECRET", "", "")
|
flag.StringVar(&fApiSecret, argsPrefix+"APISECRET", "", "")
|
||||||
flag.StringVar(&fCertificateId, argsPrefix+"CERTIFICATEID", "", "")
|
flag.StringVar(&fCertificateId, argsPrefix+"CERTIFICATEID", "", "")
|
||||||
@@ -37,7 +37,7 @@ Shell command to run this test:
|
|||||||
go test -v ./cdnfly_test.go -args \
|
go test -v ./cdnfly_test.go -args \
|
||||||
--CERTIMATE_DEPLOYER_CDNFLY_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
--CERTIMATE_DEPLOYER_CDNFLY_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
--CERTIMATE_DEPLOYER_CDNFLY_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
--CERTIMATE_DEPLOYER_CDNFLY_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
--CERTIMATE_DEPLOYER_CDNFLY_APIURL="http://127.0.0.1:88" \
|
--CERTIMATE_DEPLOYER_CDNFLY_SERVERURL="http://127.0.0.1:88" \
|
||||||
--CERTIMATE_DEPLOYER_CDNFLY_APIKEY="your-api-key" \
|
--CERTIMATE_DEPLOYER_CDNFLY_APIKEY="your-api-key" \
|
||||||
--CERTIMATE_DEPLOYER_CDNFLY_APISECRET="your-api-secret" \
|
--CERTIMATE_DEPLOYER_CDNFLY_APISECRET="your-api-secret" \
|
||||||
--CERTIMATE_DEPLOYER_CDNFLY_CERTIFICATEID="your-cert-id"
|
--CERTIMATE_DEPLOYER_CDNFLY_CERTIFICATEID="your-cert-id"
|
||||||
@@ -50,18 +50,19 @@ func TestDeploy(t *testing.T) {
|
|||||||
"args:",
|
"args:",
|
||||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
fmt.Sprintf("SERVERURL: %v", fServerUrl),
|
||||||
fmt.Sprintf("APIKEY: %v", fApiKey),
|
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||||
fmt.Sprintf("APISECRET: %v", fApiSecret),
|
fmt.Sprintf("APISECRET: %v", fApiSecret),
|
||||||
fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
|
fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
|
||||||
}, "\n"))
|
}, "\n"))
|
||||||
|
|
||||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
ApiUrl: fApiUrl,
|
ServerUrl: fServerUrl,
|
||||||
ApiKey: fApiKey,
|
ApiKey: fApiKey,
|
||||||
ApiSecret: fApiSecret,
|
ApiSecret: fApiSecret,
|
||||||
ResourceType: provider.RESOURCE_TYPE_CERTIFICATE,
|
AllowInsecureConnections: true,
|
||||||
CertificateId: fCertificateId,
|
ResourceType: provider.RESOURCE_TYPE_CERTIFICATE,
|
||||||
|
CertificateId: fCertificateId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("err: %+v", err)
|
t.Errorf("err: %+v", err)
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -56,18 +56,18 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||||
// 提取 Edgio 所需的服务端证书和中间证书内容
|
// 提取服务器证书和中间证书
|
||||||
privateCertPEM, intermediateCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
|
serverCertPEM, intermediaCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to extract certs: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传 TLS 证书
|
// 上传 TLS 证书
|
||||||
// REF: https://docs.edg.io/rest_api/#tag/tls-certs/operation/postConfigV01TlsCerts
|
// REF: https://docs.edg.io/rest_api/#tag/tls-certs/operation/postConfigV01TlsCerts
|
||||||
uploadTlsCertReq := edgiodtos.UploadTlsCertRequest{
|
uploadTlsCertReq := edgiodtos.UploadTlsCertRequest{
|
||||||
EnvironmentID: d.config.EnvironmentId,
|
EnvironmentID: d.config.EnvironmentId,
|
||||||
PrimaryCert: privateCertPEM,
|
PrimaryCert: serverCertPEM,
|
||||||
IntermediateCert: intermediateCertPEM,
|
IntermediateCert: intermediaCertPEM,
|
||||||
PrivateKey: privkeyPEM,
|
PrivateKey: privkeyPEM,
|
||||||
}
|
}
|
||||||
uploadTlsCertResp, err := d.sdkClient.UploadTlsCert(uploadTlsCertReq)
|
uploadTlsCertResp, err := d.sdkClient.UploadTlsCert(uploadTlsCertReq)
|
||||||
|
|||||||
8
internal/pkg/core/deployer/providers/flexcdn/consts.go
Normal file
8
internal/pkg/core/deployer/providers/flexcdn/consts.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package flexcdn
|
||||||
|
|
||||||
|
type ResourceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 资源类型:替换指定证书。
|
||||||
|
RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate")
|
||||||
|
)
|
||||||
145
internal/pkg/core/deployer/providers/flexcdn/flexcdn.go
Normal file
145
internal/pkg/core/deployer/providers/flexcdn/flexcdn.go
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
package flexcdn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||||
|
flexcdnsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/flexcdn"
|
||||||
|
certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeployerConfig struct {
|
||||||
|
// FlexCDN 服务地址。
|
||||||
|
ServerUrl string `json:"serverUrl"`
|
||||||
|
// FlexCDN 用户角色。
|
||||||
|
// 可取值 "user"、"admin"。
|
||||||
|
ApiRole string `json:"apiRole"`
|
||||||
|
// FlexCDN AccessKeyId。
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
// FlexCDN AccessKey。
|
||||||
|
AccessKey string `json:"accessKey"`
|
||||||
|
// 是否允许不安全的连接。
|
||||||
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
|
// 部署资源类型。
|
||||||
|
ResourceType ResourceType `json:"resourceType"`
|
||||||
|
// 证书 ID。
|
||||||
|
// 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。
|
||||||
|
CertificateId int64 `json:"certificateId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeployerProvider struct {
|
||||||
|
config *DeployerConfig
|
||||||
|
logger *slog.Logger
|
||||||
|
sdkClient *flexcdnsdk.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||||
|
|
||||||
|
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||||
|
if config == nil {
|
||||||
|
panic("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := createSdkClient(config.ServerUrl, config.ApiRole, config.AccessKeyId, config.AccessKey, config.AllowInsecureConnections)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.New(slog.DiscardHandler)
|
||||||
|
} 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析证书内容
|
||||||
|
certX509, err := certutil.ParseCertificateFromPEM(certPEM)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改证书
|
||||||
|
// REF: https://flexcdn.cloud/dev/api/service/SSLCertService?role=user#updateSSLCert
|
||||||
|
updateSSLCertReq := &flexcdnsdk.UpdateSSLCertRequest{
|
||||||
|
SSLCertId: d.config.CertificateId,
|
||||||
|
IsOn: true,
|
||||||
|
Name: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
|
||||||
|
Description: "upload from certimate",
|
||||||
|
ServerName: certX509.Subject.CommonName,
|
||||||
|
IsCA: false,
|
||||||
|
CertData: base64.StdEncoding.EncodeToString([]byte(certPEM)),
|
||||||
|
KeyData: base64.StdEncoding.EncodeToString([]byte(privkeyPEM)),
|
||||||
|
TimeBeginAt: certX509.NotBefore.Unix(),
|
||||||
|
TimeEndAt: certX509.NotAfter.Unix(),
|
||||||
|
DNSNames: certX509.DNSNames,
|
||||||
|
CommonNames: []string{certX509.Subject.CommonName},
|
||||||
|
}
|
||||||
|
updateSSLCertResp, err := d.sdkClient.UpdateSSLCert(updateSSLCertReq)
|
||||||
|
d.logger.Debug("sdk request 'flexcdn.UpdateSSLCert'", slog.Any("request", updateSSLCertReq), slog.Any("response", updateSSLCertResp))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute sdk request 'flexcdn.UpdateSSLCert': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSdkClient(serverUrl, apiRole, accessKeyId, accessKey string, skipTlsVerify bool) (*flexcdnsdk.Client, error) {
|
||||||
|
if _, err := url.Parse(serverUrl); err != nil {
|
||||||
|
return nil, errors.New("invalid flexcdn server url")
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiRole != "user" && apiRole != "admin" {
|
||||||
|
return nil, errors.New("invalid flexcdn api role")
|
||||||
|
}
|
||||||
|
|
||||||
|
if accessKeyId == "" {
|
||||||
|
return nil, errors.New("invalid flexcdn access key id")
|
||||||
|
}
|
||||||
|
|
||||||
|
if accessKey == "" {
|
||||||
|
return nil, errors.New("invalid flexcdn access key")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := flexcdnsdk.NewClient(serverUrl, apiRole, accessKeyId, accessKey)
|
||||||
|
if skipTlsVerify {
|
||||||
|
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
83
internal/pkg/core/deployer/providers/flexcdn/flexcdn_test.go
Normal file
83
internal/pkg/core/deployer/providers/flexcdn/flexcdn_test.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package flexcdn_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/flexcdn"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fInputCertPath string
|
||||||
|
fInputKeyPath string
|
||||||
|
fServerUrl string
|
||||||
|
fAccessKeyId string
|
||||||
|
fAccessKey string
|
||||||
|
fCertificateId int64
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
argsPrefix := "CERTIMATE_DEPLOYER_FLEXCDN_"
|
||||||
|
|
||||||
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
|
flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
|
||||||
|
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||||
|
flag.StringVar(&fAccessKey, argsPrefix+"ACCESSKEY", "", "")
|
||||||
|
flag.Int64Var(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shell command to run this test:
|
||||||
|
|
||||||
|
go test -v ./flexcdn_test.go -args \
|
||||||
|
--CERTIMATE_DEPLOYER_FLEXCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_FLEXCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_FLEXCDN_SERVERURL="http://127.0.0.1:7788" \
|
||||||
|
--CERTIMATE_DEPLOYER_FLEXCDN_ACCESSKEYID="your-access-key-id" \
|
||||||
|
--CERTIMATE_DEPLOYER_FLEXCDN_ACCESSKEY="your-access-key" \
|
||||||
|
--CERTIMATE_DEPLOYER_FLEXCDN_CERTIFICATEID="your-cerficiate-id"
|
||||||
|
*/
|
||||||
|
func TestDeploy(t *testing.T) {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
t.Run("Deploy_ToCertificate", func(t *testing.T) {
|
||||||
|
t.Log(strings.Join([]string{
|
||||||
|
"args:",
|
||||||
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
|
fmt.Sprintf("SERVERURL: %v", fServerUrl),
|
||||||
|
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||||
|
fmt.Sprintf("ACCESSKEY: %v", fAccessKey),
|
||||||
|
fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
|
||||||
|
}, "\n"))
|
||||||
|
|
||||||
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
|
ServerUrl: fServerUrl,
|
||||||
|
ApiRole: "user",
|
||||||
|
AccessKeyId: fAccessKeyId,
|
||||||
|
AccessKey: fAccessKey,
|
||||||
|
AllowInsecureConnections: true,
|
||||||
|
ResourceType: provider.RESOURCE_TYPE_CERTIFICATE,
|
||||||
|
CertificateId: fCertificateId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||||
|
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||||
|
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("ok: %v", res)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -7,8 +7,10 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
gprovider "github.com/G-Core/gcorelabscdn-go/gcore/provider"
|
"github.com/G-Core/gcorelabscdn-go/gcore"
|
||||||
gresources "github.com/G-Core/gcorelabscdn-go/resources"
|
"github.com/G-Core/gcorelabscdn-go/gcore/provider"
|
||||||
|
"github.com/G-Core/gcorelabscdn-go/resources"
|
||||||
|
"github.com/G-Core/gcorelabscdn-go/sslcerts"
|
||||||
|
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||||
@@ -21,25 +23,33 @@ type DeployerConfig struct {
|
|||||||
ApiToken string `json:"apiToken"`
|
ApiToken string `json:"apiToken"`
|
||||||
// CDN 资源 ID。
|
// CDN 资源 ID。
|
||||||
ResourceId int64 `json:"resourceId"`
|
ResourceId int64 `json:"resourceId"`
|
||||||
|
// 证书 ID。
|
||||||
|
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||||
|
CertificateId int64 `json:"certificateId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeployerProvider struct {
|
type DeployerProvider struct {
|
||||||
config *DeployerConfig
|
config *DeployerConfig
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
sdkClient *gresources.Service
|
sdkClients *wSdkClients
|
||||||
sslUploader uploader.Uploader
|
sslUploader uploader.Uploader
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||||
|
|
||||||
|
type wSdkClients struct {
|
||||||
|
Resources *resources.Service
|
||||||
|
SSLCerts *sslcerts.Service
|
||||||
|
}
|
||||||
|
|
||||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||||
if config == nil {
|
if config == nil {
|
||||||
panic("config is nil")
|
panic("config is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := createSdkClient(config.ApiToken)
|
clients, err := createSdkClients(config.ApiToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
return nil, fmt.Errorf("failed to create sdk clients: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
@@ -52,14 +62,14 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
|||||||
return &DeployerProvider{
|
return &DeployerProvider{
|
||||||
config: config,
|
config: config,
|
||||||
logger: slog.Default(),
|
logger: slog.Default(),
|
||||||
sdkClient: client,
|
sdkClients: clients,
|
||||||
sslUploader: uploader,
|
sslUploader: uploader,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
d.logger = slog.Default()
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
} else {
|
} else {
|
||||||
d.logger = logger
|
d.logger = logger
|
||||||
}
|
}
|
||||||
@@ -72,17 +82,47 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
return nil, errors.New("config `resourceId` is required")
|
return nil, errors.New("config `resourceId` is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传证书到 CDN
|
// 如果原证书 ID 为空,则创建证书;否则更新证书。
|
||||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
var cloudCertId int64
|
||||||
if err != nil {
|
if d.config.CertificateId == 0 {
|
||||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
// 上传证书到 CDN
|
||||||
|
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||||
|
} else {
|
||||||
|
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||||
|
}
|
||||||
|
|
||||||
|
cloudCertId, _ = strconv.ParseInt(upres.CertId, 10, 64)
|
||||||
} else {
|
} else {
|
||||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
// 获取证书
|
||||||
|
// REF: https://api.gcore.com/docs/cdn#tag/SSL-certificates/paths/~1cdn~1sslData~1%7Bssl_id%7D/get
|
||||||
|
getCertificateDetailResp, err := d.sdkClients.SSLCerts.Get(context.TODO(), d.config.CertificateId)
|
||||||
|
d.logger.Debug("sdk request 'sslcerts.Get'", slog.Any("sslId", d.config.CertificateId), slog.Any("response", getCertificateDetailResp))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute sdk request 'sslcerts.Get': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新证书
|
||||||
|
// REF: https://api.gcore.com/docs/cdn#tag/SSL-certificates/paths/~1cdn~1sslData~1%7Bssl_id%7D/get
|
||||||
|
changeCertificateReq := &sslcerts.UpdateRequest{
|
||||||
|
Name: getCertificateDetailResp.Name,
|
||||||
|
Cert: certPEM,
|
||||||
|
PrivateKey: privkeyPEM,
|
||||||
|
ValidateRootCA: false,
|
||||||
|
}
|
||||||
|
changeCertificateResp, err := d.sdkClients.SSLCerts.Update(context.TODO(), getCertificateDetailResp.ID, changeCertificateReq)
|
||||||
|
d.logger.Debug("sdk request 'sslcerts.Update'", slog.Any("sslId", getCertificateDetailResp.ID), slog.Any("request", changeCertificateReq), slog.Any("response", changeCertificateResp))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute sdk request 'sslcerts.Update': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cloudCertId = changeCertificateResp.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取 CDN 资源详情
|
// 获取 CDN 资源详情
|
||||||
// REF: https://api.gcore.com/docs/cdn#tag/CDN-resources/paths/~1cdn~1resources~1%7Bresource_id%7D/get
|
// 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)
|
getResourceResp, err := d.sdkClients.Resources.Get(context.TODO(), d.config.ResourceId)
|
||||||
d.logger.Debug("sdk request 'resources.Get'", slog.Any("resourceId", d.config.ResourceId), slog.Any("response", getResourceResp))
|
d.logger.Debug("sdk request 'resources.Get'", slog.Any("resourceId", d.config.ResourceId), slog.Any("response", getResourceResp))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to execute sdk request 'resources.Get': %w", err)
|
return nil, fmt.Errorf("failed to execute sdk request 'resources.Get': %w", err)
|
||||||
@@ -90,16 +130,16 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
|
|
||||||
// 更新 CDN 资源详情
|
// 更新 CDN 资源详情
|
||||||
// REF: https://api.gcore.com/docs/cdn#tag/CDN-resources/operation/change_cdn_resource
|
// REF: https://api.gcore.com/docs/cdn#tag/CDN-resources/operation/change_cdn_resource
|
||||||
updateResourceCertId, _ := strconv.ParseInt(upres.CertId, 10, 64)
|
updateResourceReq := &resources.UpdateRequest{
|
||||||
updateResourceReq := &gresources.UpdateRequest{
|
|
||||||
Description: getResourceResp.Description,
|
Description: getResourceResp.Description,
|
||||||
Active: getResourceResp.Active,
|
Active: getResourceResp.Active,
|
||||||
OriginGroup: int(getResourceResp.OriginGroup),
|
OriginGroup: int(getResourceResp.OriginGroup),
|
||||||
OriginProtocol: getResourceResp.OriginProtocol,
|
OriginProtocol: getResourceResp.OriginProtocol,
|
||||||
SecondaryHostnames: getResourceResp.SecondaryHostnames,
|
SecondaryHostnames: getResourceResp.SecondaryHostnames,
|
||||||
SSlEnabled: true,
|
SSlEnabled: true,
|
||||||
SSLData: int(updateResourceCertId),
|
SSLData: int(cloudCertId),
|
||||||
ProxySSLEnabled: getResourceResp.ProxySSLEnabled,
|
ProxySSLEnabled: getResourceResp.ProxySSLEnabled,
|
||||||
|
Options: &gcore.Options{},
|
||||||
}
|
}
|
||||||
if getResourceResp.ProxySSLCA != 0 {
|
if getResourceResp.ProxySSLCA != 0 {
|
||||||
updateResourceReq.ProxySSLCA = &getResourceResp.ProxySSLCA
|
updateResourceReq.ProxySSLCA = &getResourceResp.ProxySSLCA
|
||||||
@@ -107,10 +147,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
if getResourceResp.ProxySSLData != 0 {
|
if getResourceResp.ProxySSLData != 0 {
|
||||||
updateResourceReq.ProxySSLData = &getResourceResp.ProxySSLData
|
updateResourceReq.ProxySSLData = &getResourceResp.ProxySSLData
|
||||||
}
|
}
|
||||||
if getResourceResp.Options != nil {
|
updateResourceResp, err := d.sdkClients.Resources.Update(context.TODO(), d.config.ResourceId, updateResourceReq)
|
||||||
updateResourceReq.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))
|
d.logger.Debug("sdk request 'resources.Update'", slog.Int64("resourceId", d.config.ResourceId), slog.Any("request", updateResourceReq), slog.Any("response", updateResourceResp))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to execute sdk request 'resources.Update': %w", err)
|
return nil, fmt.Errorf("failed to execute sdk request 'resources.Update': %w", err)
|
||||||
@@ -119,15 +156,19 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
return &deployer.DeployResult{}, nil
|
return &deployer.DeployResult{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSdkClient(apiToken string) (*gresources.Service, error) {
|
func createSdkClients(apiToken string) (*wSdkClients, error) {
|
||||||
if apiToken == "" {
|
if apiToken == "" {
|
||||||
return nil, errors.New("invalid gcore api token")
|
return nil, errors.New("invalid gcore api token")
|
||||||
}
|
}
|
||||||
|
|
||||||
requester := gprovider.NewClient(
|
requester := provider.NewClient(
|
||||||
gcoresdk.BASE_URL,
|
gcoresdk.BASE_URL,
|
||||||
gprovider.WithSigner(gcoresdk.NewAuthRequestSigner(apiToken)),
|
provider.WithSigner(gcoresdk.NewAuthRequestSigner(apiToken)),
|
||||||
)
|
)
|
||||||
service := gresources.NewService(requester)
|
resourcesSrv := resources.NewService(requester)
|
||||||
return service, nil
|
sslCertsSrv := sslcerts.NewService(requester)
|
||||||
|
return &wSdkClients{
|
||||||
|
Resources: resourcesSrv,
|
||||||
|
SSLCerts: sslCertsSrv,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user