This commit is contained in:
wood chen 2025-05-12 13:22:26 +08:00
commit 04bfd94243
529 changed files with 15241 additions and 4460 deletions

View File

@ -10,5 +10,7 @@ trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
[*.go] [*.go]
charset = utf-8
end_of_line = lf
indent_size = 2 indent_size = 2
indent_style = tab indent_style = tab

View File

@ -1,6 +1,6 @@
name: "❓ Questions" name: "❓ Questions"
description: "遇到了困难需要求助? / Have problem in use and need help?" description: "遇到了困难需要求助? / Have problem in use and need help?"
title: "[Feature] 简要描述你遇到的问题" title: "简要描述你遇到的问题"
body: body:
- type: markdown - type: markdown
attributes: attributes:
@ -19,6 +19,14 @@ body:
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.
- type: input
attributes:
label: 软件版本 / Release Version
description: 请提供 Certimate 的具体版本。 / Please provide the specific version of Certimate.
placeholder: (e.g. v1.0.0)
validations:
required: true
- type: textarea - type: textarea
attributes: attributes:
label: 问题描述 / Description label: 问题描述 / Description

View File

@ -41,7 +41,7 @@ Certimate 旨在为用户提供一个安全、简便的 SSL 证书管理解决
- 支持 20+ 域名托管商如阿里云、腾讯云、Cloudflare 等,[点此查看完整清单](https://docs.certimate.me/docs/reference/providers#supported-dns-providers) - 支持 20+ 域名托管商如阿里云、腾讯云、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) - 支持 70+ 部署目标(如 Kubernetes、CDN、WAF、负载均衡等[点此查看完整清单](https://docs.certimate.me/docs/reference/providers#supported-host-providers)
- 支持邮件、钉钉、飞书、企业微信、Webhook 等多种通知渠道; - 支持邮件、钉钉、飞书、企业微信、Webhook 等多种通知渠道;
- 支持 Let's Encrypt、ZeroSSL、Google Trust Services 等多种 ACME 证书颁发机构; - 支持 Let's Encrypt、Buypass、Google Trust Services、SSL.com、ZeroSSL 等多种 ACME 证书颁发机构;
- 更多特性等待探索。 - 更多特性等待探索。
## ⏱️ 快速启动 ## ⏱️ 快速启动

View File

@ -41,7 +41,7 @@ Certimate aims to provide users with a secure and user-friendly SSL certificate
- 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 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 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 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 multiple notification channels including email, DingTalk, Feishu, WeCom, Webhook, and more; - Supports multiple notification channels including email, DingTalk, Feishu, WeCom, Webhook, and more;
- Supports multiple ACME CAs including Let's Encrypt, ZeroSSL, Google Trust Services, and more; - Supports multiple ACME CAs including Let's Encrypt, Buypass, Google Trust ServicesSSL.com, ZeroSSL, and more;
- More features waiting to be discovered. - More features waiting to be discovered.
## ⏱️ Fast Track ## ⏱️ Fast Track

156
go.mod
View File

@ -5,29 +5,32 @@ go 1.23.0
toolchain go1.23.2 toolchain go1.23.2
require ( require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1
github.com/G-Core/gcorelabscdn-go v1.0.28 github.com/Edgio/edgio-api v0.0.0-workspace
github.com/G-Core/gcorelabscdn-go v1.0.29
github.com/alibabacloud-go/alb-20200616/v2 v2.2.8 github.com/alibabacloud-go/alb-20200616/v2 v2.2.8
github.com/alibabacloud-go/apig-20240327/v3 v3.2.2
github.com/alibabacloud-go/cas-20200407/v3 v3.0.4 github.com/alibabacloud-go/cas-20200407/v3 v3.0.4
github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2 github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4 github.com/alibabacloud-go/cloudapi-20160714/v5 v5.7.2
github.com/alibabacloud-go/esa-20240910/v2 v2.23.0 github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7
github.com/alibabacloud-go/fc-20230330/v4 v4.1.7 github.com/alibabacloud-go/esa-20240910/v2 v2.31.1
github.com/alibabacloud-go/fc-20230330/v4 v4.3.4
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/live-20161101 v1.1.1 github.com/alibabacloud-go/live-20161101 v1.1.1
github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3 github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3
github.com/alibabacloud-go/slb-20140515/v4 v4.0.10 github.com/alibabacloud-go/slb-20140515/v4 v4.0.10
github.com/alibabacloud-go/tea v1.3.4 github.com/alibabacloud-go/tea v1.3.9
github.com/alibabacloud-go/vod-20170321/v4 v4.7.0 github.com/alibabacloud-go/vod-20170321/v4 v4.8.3
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5 github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.1.1
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
github.com/aws/aws-sdk-go-v2/service/acm v1.31.1 github.com/aws/aws-sdk-go-v2/service/acm v1.31.3
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.2 github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.3
github.com/baidubce/bce-sdk-go v0.9.221 github.com/baidubce/bce-sdk-go v0.9.224
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.42 github.com/byteplus-sdk/byteplus-sdk-golang v1.0.44
github.com/go-acme/lego/v4 v4.22.2 github.com/go-acme/lego/v4 v4.23.1
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.141
@ -36,28 +39,28 @@ require (
github.com/libdns/libdns v0.2.3 github.com/libdns/libdns v0.2.3
github.com/nikoksr/notify v1.3.0 github.com/nikoksr/notify v1.3.0
github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0
github.com/pkg/sftp v1.13.8 github.com/pkg/sftp v1.13.9
github.com/pocketbase/dbx v1.11.0 github.com/pocketbase/dbx v1.11.0
github.com/pocketbase/pocketbase v0.26.1 github.com/pocketbase/pocketbase v0.27.1
github.com/povsister/scp v0.0.0-20240802064259-28781e87b246 github.com/povsister/scp v0.0.0-20240802064259-28781e87b246
github.com/qiniu/go-sdk/v7 v7.25.2 github.com/qiniu/go-sdk/v7 v7.25.3
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1136
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1127 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1143
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1127 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1147
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1117 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1143
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1120
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1126 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1138
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1115 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1136
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1125 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1147
github.com/ucloud/ucloud-sdk-go v0.22.31 github.com/ucloud/ucloud-sdk-go v0.22.33
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9 github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.11
github.com/volcengine/volc-sdk-golang v1.0.199 github.com/volcengine/volc-sdk-golang v1.0.204
github.com/volcengine/volcengine-go-sdk v1.0.187 github.com/volcengine/volcengine-go-sdk v1.1.4
gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1
gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0
golang.org/x/crypto v0.36.0 golang.org/x/crypto v0.37.0
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0
k8s.io/api v0.32.3 k8s.io/api v0.32.3
k8s.io/apimachinery v0.32.3 k8s.io/apimachinery v0.32.3
k8s.io/client-go v0.32.3 k8s.io/client-go v0.32.3
@ -65,21 +68,25 @@ require (
) )
require ( require (
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.7 // indirect github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.7 // indirect
github.com/alibabacloud-go/ddoscoo-20200101/v4 v4.0.0 // 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.3 // indirect
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect
github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/avast/retry-go v3.0.0+incompatible // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1 // indirect github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 // indirect
github.com/blinkbean/dingtalk v1.1.3 // indirect github.com/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-lark/lark v1.15.1 // indirect
@ -94,19 +101,24 @@ require (
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/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.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect github.com/google/gofuzz v1.2.0 // indirect
github.com/gorilla/websocket v1.5.3 // 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/luthermonson/go-proxmox v0.2.2 // indirect
github.com/magefile/mage v1.14.0 // indirect
github.com/mailru/easyjson v0.9.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 // indirect
github.com/nrdcg/desec v0.10.0 // indirect github.com/nrdcg/desec v0.10.0 // indirect
github.com/nrdcg/mailinabox v0.2.0 // indirect github.com/nrdcg/mailinabox v0.2.0 // indirect
github.com/nrdcg/porkbun v0.4.0 // indirect github.com/nrdcg/porkbun v0.4.0 // indirect
@ -115,7 +127,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/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
@ -132,7 +144,7 @@ require (
) )
require ( require (
github.com/BurntSushi/toml v1.4.0 // indirect github.com/BurntSushi/toml v1.5.0 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0 github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0
github.com/alibabacloud-go/debug v1.0.1 // indirect github.com/alibabacloud-go/debug v1.0.1 // indirect
@ -140,35 +152,35 @@ require (
github.com/alibabacloud-go/openapi-util v0.1.1 // indirect github.com/alibabacloud-go/openapi-util v0.1.1 // indirect
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.63.83 // indirect github.com/aliyun/alibaba-cloud-sdk-go v1.63.100 // indirect
github.com/aliyun/credentials-go v1.4.3 // indirect github.com/aliyun/credentials-go v1.4.5 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2 v1.36.3 github.com/aws/aws-sdk-go-v2 v1.36.3
github.com/aws/aws-sdk-go-v2/config v1.29.5 github.com/aws/aws-sdk-go-v2/config v1.29.9
github.com/aws/aws-sdk-go-v2/credentials v1.17.58 github.com/aws/aws-sdk-go-v2/credentials v1.17.62
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect
github.com/aws/smithy-go v1.22.2 // indirect github.com/aws/smithy-go v1.22.2 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/cloudflare/cloudflare-go v0.114.0 // indirect github.com/cloudflare/cloudflare-go v0.115.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/disintegration/imaging v1.6.2 // indirect github.com/disintegration/imaging v1.6.2 // indirect
github.com/domodwyer/mailyak/v3 v3.6.2 github.com/domodwyer/mailyak/v3 v3.6.2
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.18.0 // indirect github.com/fatih/color v1.18.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/ganigeorgiev/fexpr v0.4.1 // indirect github.com/ganigeorgiev/fexpr v0.5.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.4 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
github.com/goccy/go-json v0.10.4 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
@ -177,40 +189,42 @@ require (
github.com/kr/fs v0.1.0 // indirect github.com/kr/fs v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/miekg/dns v1.1.62 // indirect github.com/miekg/dns v1.1.64 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/nrdcg/namesilo v0.2.1 // indirect github.com/nrdcg/namesilo v0.2.1 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/spf13/cast v1.7.1 // 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/objx v0.5.2 // indirect
github.com/stretchr/testify v1.10.0 // indirect github.com/stretchr/testify v1.10.0 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084 // 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.25.0 // indirect golang.org/x/image v0.26.0 // indirect
golang.org/x/mod v0.24.0 // indirect golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.37.0 // indirect golang.org/x/net v0.39.0 // indirect
golang.org/x/oauth2 v0.28.0 // indirect golang.org/x/oauth2 v0.29.0 // indirect
golang.org/x/sync v0.12.0 golang.org/x/sync v0.13.0
golang.org/x/sys v0.31.0 // indirect golang.org/x/sys v0.32.0 // indirect
golang.org/x/term v0.30.0 // indirect golang.org/x/term v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect golang.org/x/text v0.24.0 // indirect
golang.org/x/time v0.9.0 golang.org/x/time v0.11.0
golang.org/x/tools v0.31.0 // indirect golang.org/x/tools v0.32.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.61.13 // indirect modernc.org/libc v1.62.1 // indirect
modernc.org/mathutil v1.7.1 // indirect modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.8.2 // indirect modernc.org/memory v1.9.1 // indirect
modernc.org/sqlite v1.36.1 // indirect modernc.org/sqlite v1.37.0 // indirect
) )
replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 => ./internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0 replace github.com/Edgio/edgio-api v0.0.0-workspace => ./internal/pkg/sdk3rd/edgio/edgio-api@v0.0.0-workspace
replace gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 => ./internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1 replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 => ./internal/pkg/sdk3rd/cmcc/ecloudsdkcore@v1.0.0
replace gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 => ./internal/pkg/sdk3rd/cmcc/ecloudsdkclouddns@v1.0.1

333
go.sum
View File

@ -34,18 +34,14 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 h1:btEsytNrA4TG3edZnnUnzOz8W2MjOd6Bu3/7xyOXSOY=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0/go.mod h1:5SlTxxL1U4LLipEr7pAbnu6Ck5y3aIEu4L/tVbGmpsY=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0 h1:2qsIIvxVT+uE6yrNldntJKlLRgxGbZ85kgtz5SNBhMw= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0 h1:2qsIIvxVT+uE6yrNldntJKlLRgxGbZ85kgtz5SNBhMw=
@ -56,19 +52,23 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourceg
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1 h1:HUJQzFYTv7t3V1dxPms52eEgl0l9xCNqutDrY45Lvmw=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1/go.mod h1:ig/8nSkzmfxm5QGeIy5JYIEj8JEFy5JxvY3OB1YNRC4=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 h1:bFWuoEKg+gImo7pvkiQEFAc8ocibADgXeiLAxWhWmkI=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1/go.mod h1:Vih/3yc6yac2JzU4hzpaDupBJP0Flaia9rXXrU8xyww=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4= github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/G-Core/gcorelabscdn-go v1.0.28 h1:6ymVMV3HPTICO5BWJCEcZZzgY+Pc/+/TQMzeXMN77GQ= github.com/G-Core/gcorelabscdn-go v1.0.29 h1:9jNCwzNZAgihTPe+nrsLD2c0GHjxvpuV3VEA74L5Kkk=
github.com/G-Core/gcorelabscdn-go v1.0.28/go.mod h1:iSGXaTvZBzDHQW+rKFS918BgFVpONcyLEijwh8WsXpE= github.com/G-Core/gcorelabscdn-go v1.0.29/go.mod h1:iSGXaTvZBzDHQW+rKFS918BgFVpONcyLEijwh8WsXpE=
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
@ -95,10 +95,14 @@ github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do2
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
github.com/alibabacloud-go/apig-20240327/v3 v3.2.2 h1:yH84ePgqtA2tF3ly7Tf3AA5ogl2SC8kqCNG4+zz4yo4=
github.com/alibabacloud-go/apig-20240327/v3 v3.2.2/go.mod h1:XLaCapbSH7olJTs42wisDO9JvX9BGy5acZk0bLNejDs=
github.com/alibabacloud-go/cas-20200407/v3 v3.0.4 h1:ngRlctbt135zoujwX0lXSv9m4h1/bmg/yalQS0z1EWc= github.com/alibabacloud-go/cas-20200407/v3 v3.0.4 h1:ngRlctbt135zoujwX0lXSv9m4h1/bmg/yalQS0z1EWc=
github.com/alibabacloud-go/cas-20200407/v3 v3.0.4/go.mod h1:6n9MZ9SH3HlSzfe2oKwjOqhJx3dxvW2gMDO+lq8t9U4= github.com/alibabacloud-go/cas-20200407/v3 v3.0.4/go.mod h1:6n9MZ9SH3HlSzfe2oKwjOqhJx3dxvW2gMDO+lq8t9U4=
github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2 h1:+KJOPukTM+xMyiLOW5qBwYKG2df3Ar7coRsqc1juKO8= github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2 h1:+KJOPukTM+xMyiLOW5qBwYKG2df3Ar7coRsqc1juKO8=
github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2/go.mod h1:GnPiPL3HlzCi8SGiLiVgKrAFkP1vTtcF4yGtjsl4wfo= github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2/go.mod h1:GnPiPL3HlzCi8SGiLiVgKrAFkP1vTtcF4yGtjsl4wfo=
github.com/alibabacloud-go/cloudapi-20160714/v5 v5.7.2 h1:Ug50clztqiQAy5t0R9Vejibz2Xgxm1Tpw2Y6A9eAwRE=
github.com/alibabacloud-go/cloudapi-20160714/v5 v5.7.2/go.mod h1:l9Zd2FanDUO2UqHJSPnOv+cY9DVT+YXcr97zfpSHywo=
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=
@ -109,14 +113,17 @@ github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNd
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.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4 h1:IGSZHlOnWwBbLtX5xDplQvZOH0nkrV7Wmq+Fto7JK5w= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.11/go.mod h1:wHxkgZT1ClZdcwEVP/pDgYK/9HucsnCfMipmJgCz4xY=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4/go.mod h1:Wxis0IBFusdbo44HO6KYYCJR1rRkoh47QQOYWvaheSU= github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 h1:ASXSBga98QrGMxbIThCD6jAti09gedLfvry6yJtsoBE=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7/go.mod h1:TBpgqm3XofZz2LCYjZhektGPU7ArEgascyzbm4SjFo4=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg= github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ= github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo= github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0 h1:EQmKhYju6y38kJ1ZvZROeJG2Q1Wk6hlc8KQrVhvGyaw= github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0 h1:EQmKhYju6y38kJ1ZvZROeJG2Q1Wk6hlc8KQrVhvGyaw=
github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0/go.mod h1:b9qzvr/2V1f0r1Z6xUmkLqEouKcPGy4LCC22yV+6HQo= github.com/alibabacloud-go/dcdn-20180115/v3 v3.5.0/go.mod h1:b9qzvr/2V1f0r1Z6xUmkLqEouKcPGy4LCC22yV+6HQo=
github.com/alibabacloud-go/ddoscoo-20200101/v4 v4.0.0 h1:z9dPOvBRxzpD+FQ2uu/p2Z92I+PY9MUZMauwC+8AC6M=
github.com/alibabacloud-go/ddoscoo-20200101/v4 v4.0.0/go.mod h1:Cdg3Fu4jFByamRzt3AkeiBssoVPRNDs+EPYMP2fIj78=
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg= github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
@ -124,10 +131,10 @@ github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/ql
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8= github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8=
github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
github.com/alibabacloud-go/esa-20240910/v2 v2.23.0 h1:Z/AALmxhOfzN+35tNCvm62/pET4IlxhDQn4nsdLqNzk= github.com/alibabacloud-go/esa-20240910/v2 v2.31.1 h1:LACf71RxZjaystAfcWXa3EMtueVKNGxsCR3L+UihKtU=
github.com/alibabacloud-go/esa-20240910/v2 v2.23.0/go.mod h1:P1w/+i7dE2xSXVHJznEOVImlLtqqrzUJQQk2AsyBJ6o= github.com/alibabacloud-go/esa-20240910/v2 v2.31.1/go.mod h1:qa4hC7W/BQOc9liuJckLnBLxILEzYjg2xhAZ+UVeUUQ=
github.com/alibabacloud-go/fc-20230330/v4 v4.1.7 h1:rQvPfzPaouL/WGNgMDMCplA4wDscmVFff7aLCUkjv4g= github.com/alibabacloud-go/fc-20230330/v4 v4.3.4 h1:DMUkeW24CWuvChy9uOD1DzMh3ToVARCB6m3xxWBslic=
github.com/alibabacloud-go/fc-20230330/v4 v4.1.7/go.mod h1:ssEfKO6MskPtq7QaQnyiOHGWLXOZcl7a8YIf8u56DGc= github.com/alibabacloud-go/fc-20230330/v4 v4.3.4/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/live-20161101 v1.1.1 h1:rUGfA8RHmCMtQ5M3yMSyRde+yRXWqVecmiXBU3XrGJ8= github.com/alibabacloud-go/live-20161101 v1.1.1 h1:rUGfA8RHmCMtQ5M3yMSyRde+yRXWqVecmiXBU3XrGJ8=
@ -153,9 +160,9 @@ github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA= github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA=
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
github.com/alibabacloud-go/tea v1.3.2/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg= github.com/alibabacloud-go/tea v1.3.8/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
github.com/alibabacloud-go/tea v1.3.4 h1:QGTns2930y+ANmoNcUS74TgYpsoqusSrLIyYDOvIFFI= github.com/alibabacloud-go/tea v1.3.9 h1:bjgt1bvdY780vz/17iWNNtbXl4A77HWntWMeaUF3So0=
github.com/alibabacloud-go/tea v1.3.4/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg= github.com/alibabacloud-go/tea v1.3.9/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
github.com/alibabacloud-go/tea-fileform v1.1.1 h1:1YG6erAP3joQ0XdCXYIotuD7zyOM6qCR49xkp5FZDeU= github.com/alibabacloud-go/tea-fileform v1.1.1 h1:1YG6erAP3joQ0XdCXYIotuD7zyOM6qCR49xkp5FZDeU=
github.com/alibabacloud-go/tea-fileform v1.1.1/go.mod h1:ZeCV91o4ISmxidd686f0ebdS5EDHWU+vW+TkjLhrsFE= github.com/alibabacloud-go/tea-fileform v1.1.1/go.mod h1:ZeCV91o4ISmxidd686f0ebdS5EDHWU+vW+TkjLhrsFE=
github.com/alibabacloud-go/tea-oss-sdk v1.1.3 h1:EhAHI6edMeqgkZEqP7r4nc9iMWAUBKGxJHoBsOSKTtU= github.com/alibabacloud-go/tea-oss-sdk v1.1.3 h1:EhAHI6edMeqgkZEqP7r4nc9iMWAUBKGxJHoBsOSKTtU=
@ -177,20 +184,20 @@ github.com/alibabacloud-go/tea-xml v1.1.1/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCE
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0= github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
github.com/alibabacloud-go/vod-20170321/v4 v4.7.0 h1:hpsnJBX5EeMrFujopMCjfq+p8XbNvPhFw6LOTV/WHd8= github.com/alibabacloud-go/vod-20170321/v4 v4.8.3 h1:IXDfINF3Wc88SKIijYgqy9HF3NiA68F97wgVeiRRwkc=
github.com/alibabacloud-go/vod-20170321/v4 v4.7.0/go.mod h1:TkgLKMSLu0qZN8Qdcu8svfHREyI64kjFvrp/GhrD4VQ= github.com/alibabacloud-go/vod-20170321/v4 v4.8.3/go.mod h1:5ocQ6hIc9tpGixD2iy099aOGwIgpzjT2le4Krd4aLn8=
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5 h1:ldAm1nvsCq66igjtcZyGhAoLClr+2eZ/pMIBUdKCOMM= github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.1.1 h1:7gHYtb2swx96tG7rflKoiFOdjKZ/W3N7azS6LT1TVFI=
github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5/go.mod h1:DohGoS8BnMxHXghHebtjPP7+GMdxPsRN19T3nn2HcCU= github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.1.1/go.mod h1:DohGoS8BnMxHXghHebtjPP7+GMdxPsRN19T3nn2HcCU=
github.com/aliyun/alibaba-cloud-sdk-go v1.63.83 h1:YBkf7H5CSgrlb3C1aWcpDt7Vk8UEGFPeD2OOirtt6IM= github.com/aliyun/alibaba-cloud-sdk-go v1.63.100 h1:yUkCbrSM1cWtgBfRVKMQtdt22KhDvKY7g4V+92eG9wA=
github.com/aliyun/alibaba-cloud-sdk-go v1.63.83/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/aliyun/alibaba-cloud-sdk-go v1.63.100/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM= github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
github.com/aliyun/credentials-go v1.4.3 h1:N3iHyvHRMyOwY1+0qBLSf3hb5JFiOujVSVuEpgeGttY= github.com/aliyun/credentials-go v1.4.5 h1:O76WYKgdy1oQYYiJkERjlA2dxGuvLRrzuO2ScrtGWSk=
github.com/aliyun/credentials-go v1.4.3/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@ -206,40 +213,40 @@ github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
github.com/aws/aws-sdk-go-v2/config v1.29.5 h1:4lS2IB+wwkj5J43Tq/AwvnscBerBJtQQ6YS7puzCI1k= github.com/aws/aws-sdk-go-v2/config v1.29.9 h1:Kg+fAYNaJeGXp1vmjtidss8O2uXIsXwaRqsQJKXVr+0=
github.com/aws/aws-sdk-go-v2/config v1.29.5/go.mod h1:SNzldMlDVbN6nWxM7XsUiNXPSa1LWlqiXtvh/1PrJGg= github.com/aws/aws-sdk-go-v2/config v1.29.9/go.mod h1:oU3jj2O53kgOU4TXq/yipt6ryiooYjlkqqVaZk7gY/U=
github.com/aws/aws-sdk-go-v2/credentials v1.17.58 h1:/d7FUpAPU8Lf2KUdjniQvfNdlMID0Sd9pS23FJ3SS9Y= github.com/aws/aws-sdk-go-v2/credentials v1.17.62 h1:fvtQY3zFzYJ9CfixuAQ96IxDrBajbBWGqjNTCa79ocU=
github.com/aws/aws-sdk-go-v2/credentials v1.17.58/go.mod h1:aVYW33Ow10CyMQGFgC0ptMRIqJWvJ4nxZb0sUiuQT/A= github.com/aws/aws-sdk-go-v2/credentials v1.17.62/go.mod h1:ElETBxIQqcxej++Cs8GyPBbgMys5DgQPTwo7cUPDKt8=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 h1:KwsodFKVQTlI5EyhRSugALzsV6mG/SGrdjlMXSZSdso= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28/go.mod h1:EY3APf9MzygVhKuPXAc5H+MkGb8k/DOSQjWS0LgkKqI= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
github.com/aws/aws-sdk-go-v2/service/acm v1.31.1 h1:FB1PgU6vlXbqehxZiHuYQRWo5Ou6sQrFJcUaRe27lRo= github.com/aws/aws-sdk-go-v2/service/acm v1.31.3 h1:GwlU39usxM7E1LIhZchk93PtTQm2j3jb63of/YkBd+o=
github.com/aws/aws-sdk-go-v2/service/acm v1.31.1/go.mod h1:3sKYAgRbuBa2QMYGh/WEclwnmfx+QoPhhX25PdSQSQM= github.com/aws/aws-sdk-go-v2/service/acm v1.31.3/go.mod h1:3sKYAgRbuBa2QMYGh/WEclwnmfx+QoPhhX25PdSQSQM=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.2 h1:S3JpsBLyn/jqSJ6GgsbDQHubmop6fshQk/iOaOeotsc= github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.3 h1:xQnjN34F4I3a/I3Xj0g9vmD5hAqC7u5y3SC3eC6T1E8=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.2/go.mod h1:FIBJ48TS+qJb+Ne4qJ+0NeIhtPTVXItXooTeNeVI4Po= github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.3/go.mod h1:FIBJ48TS+qJb+Ne4qJ+0NeIhtPTVXItXooTeNeVI4Po=
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= github.com/aws/aws-sdk-go-v2/service/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.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= 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.13 h1:SYVGSFQHlchIcy6e7x12bsrxClCXSP5et8cqVhL8cuw= 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.13/go.mod h1:kizuDaLX37bG5WZaoxGPQR/LNFXpxp0vsUnqfkWXfNE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1 h1:njgAP7Rtt4DGdTGFPhJ4gaZXCD1CDj/SZDa5W4ZgSTs= github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 h1:/nkJHXtJXJeelXHqG0898+fWKgvfaXBhGzbCsSmn9j8=
github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1/go.mod h1:TN4PcCL0lvqmYcv+AV8iZFC4Sd0FM06QDaoBXrFEftU= github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0/go.mod h1:kGYOjvTa0Vw0qxrqrOLut1vMnui6qLxqv/SX3vYeM8Y=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 h1:/eE3DogBjYlvlbhd2ssWyeuovWunHLxfgw3s/OJa4GQ= github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 h1:8JdC7Gr9NROg1Rusk25IcZeTO59zLxsKgE0gkh5O6h0=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.15/go.mod h1:2PCJYpi7EKeA5SkStAmZlF6fi0uUABuhtF8ILHjGc3Y= github.com/aws/aws-sdk-go-v2/service/sso v1.25.1/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 h1:M/zwXiL2iXUrHputuXgmO94TVNmcenPHxgLXLutodKE= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 h1:KwuLovgQPcdjNMfFt9OhUd9a2OwcOKhxfvF4glTzLuA=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14/go.mod h1:RVwIw3y/IqxC2YEXSIkAzRDdEU1iRabDPaYjpGCbCGQ= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 h1:TzeR06UCMUq+KA3bDkujxK1GVGy+G8qQN/QVYzGLkQE= github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 h1:PZV5W8yk4OtH1JAuhV2PXwwO9v5G5Aoj+eMCn4T+1Kc=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.14/go.mod h1:dspXf/oYWGWo6DEvj98wpaTeqt5+DMidZD0A9BYTizc= github.com/aws/aws-sdk-go-v2/service/sts v1.33.17/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/baidubce/bce-sdk-go v0.9.221 h1:x5uTXND33m5TE3UBXYhlePuXcJi5rxNnBBt+bP7kPe0= github.com/baidubce/bce-sdk-go v0.9.224 h1:z2L8alGw/y3IUHjrLRyrxrgCvMssYTjgCd7OQdb4gt0=
github.com/baidubce/bce-sdk-go v0.9.221/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= github.com/baidubce/bce-sdk-go v0.9.224/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@ -247,8 +254,10 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/blinkbean/dingtalk v1.1.3 h1:MbidFZYom7DTFHD/YIs+eaI7kRy52kmWE/sy0xjo6E4= github.com/blinkbean/dingtalk v1.1.3 h1:MbidFZYom7DTFHD/YIs+eaI7kRy52kmWE/sy0xjo6E4=
github.com/blinkbean/dingtalk v1.1.3/go.mod h1:9BaLuGSBqY3vT5hstValh48DbsKO7vaHaJnG9pXwbto= github.com/blinkbean/dingtalk v1.1.3/go.mod h1:9BaLuGSBqY3vT5hstValh48DbsKO7vaHaJnG9pXwbto=
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.42 h1:Dm9FDjQP2SlAjUH7WAV7DFYDBFQz2uBxX6JULs0Sxs0= github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.42/go.mod h1:CIL/T2dxgbIA79os+wl0Fq0vCbADTZNIddV6PNYB6DY= github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE=
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.44 h1:men5pKZNho+cw9/YU7TFerTspS3lKayS64zctl/D7Fk=
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.44/go.mod h1:CIL/T2dxgbIA79os+wl0Fq0vCbADTZNIddV6PNYB6DY=
github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
@ -271,8 +280,8 @@ github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.114.0 h1:ucoti4/7Exo0XQ+rzpn1H+IfVVe++zgiM+tyKtf0HUA= github.com/cloudflare/cloudflare-go v0.115.0 h1:84/dxeeXweCc0PN5Cto44iTA8AkG1fyT11yPO5ZB7sM=
github.com/cloudflare/cloudflare-go v0.114.0/go.mod h1:O7fYfFfA6wKqKFn2QIR9lhj7FDw6VQCGOY6hd2TBtd0= github.com/cloudflare/cloudflare-go v0.115.0/go.mod h1:Ds6urDwn/TF2uIU24mu7H91xkKP8gSAHxQ44DSZgVmU=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
@ -290,6 +299,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=
@ -328,16 +341,16 @@ github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXE
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw= github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw=
github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k= github.com/ganigeorgiev/fexpr v0.5.0 h1:XA9JxtTE/Xm+g/JFI6RfZEHSiQlk+1glLvRK1Lpv/Tk=
github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE= github.com/ganigeorgiev/fexpr v0.5.0/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-acme/lego/v4 v4.22.2 h1:ck+HllWrV/rZGeYohsKQ5iKNnU/WAZxwOdiu6cxky+0= github.com/go-acme/lego/v4 v4.23.1 h1:lZ5fGtGESA2L9FB8dNTvrQUq3/X4QOb8ExkKyY7LSV4=
github.com/go-acme/lego/v4 v4.22.2/go.mod h1:E2FndyI3Ekv0usNJt46mFb9LVpV/XBYT+4E3tz02Tzo= github.com/go-acme/lego/v4 v4.23.1/go.mod h1:7UMVR7oQbIYw6V7mTgGwi4Er7B6Ww0c+c8feiBM0EgI=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
@ -388,8 +401,8 @@ github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
@ -399,8 +412,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -470,8 +483,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20250315033105-103756e64e1d h1:tx51Lf+wdE+aavqH8TcPJoCjTf4cE8hrMzROghCely0= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
github.com/google/pprof v0.0.0-20250315033105-103756e64e1d/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -487,6 +500,8 @@ 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.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
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/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=
@ -498,6 +513,8 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
@ -537,6 +554,8 @@ 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=
@ -560,8 +579,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
@ -593,6 +612,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=
@ -613,8 +636,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= github.com/miekg/dns v1.1.64 h1:wuZgD9wwCE6XMT05UU/mlSko71eRSXEAm2EbjQXLKnQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/miekg/dns v1.1.64/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
@ -649,6 +672,8 @@ github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJm
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 h1:UxzfxzAYGQD9a5JYLBTVx0lFMxeHCke3rPCkfWdPgLs=
github.com/nikoksr/notify v1.3.0/go.mod h1:Xor2hMmkvrCfkCKvXGbcrESez4brac2zQjhd6U2BbeM= 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/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=
github.com/nrdcg/desec v0.10.0/go.mod h1:5+4vyhMRTs49V9CNoODF/HwT8Mwxv9DJ6j+7NekUnBs= github.com/nrdcg/desec v0.10.0/go.mod h1:5+4vyhMRTs49V9CNoODF/HwT8Mwxv9DJ6j+7NekUnBs=
github.com/nrdcg/mailinabox v0.2.0 h1:IKq8mfKiVwNW2hQii/ng1dJ4yYMMv3HAP3fMFIq2CFk= github.com/nrdcg/mailinabox v0.2.0 h1:IKq8mfKiVwNW2hQii/ng1dJ4yYMMv3HAP3fMFIq2CFk=
@ -694,15 +719,15 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.13.8 h1:Xt7eJ/xqXv7s0VuzFw7JXhZj6Oc1zI6l4GK8KP9sFB0= github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
github.com/pkg/sftp v1.13.8/go.mod h1:DmvEkvKE2lshEeuo2JMp06yqcx9HVnR7e3zqQl42F3U= github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU= github.com/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU=
github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs= github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
github.com/pocketbase/pocketbase v0.26.1 h1:0WBqIRKKPCqp+xHPVLB4fevkoT9HVlR4BSuNwAt5oJ0= github.com/pocketbase/pocketbase v0.27.1 h1:KGCsS8idUVTC5QHxTj91qHDhIXOb5Yb50wwHhNvJRTQ=
github.com/pocketbase/pocketbase v0.26.1/go.mod h1:t5y5pfnhrEg//RuSzSg0a926OLZ0oQj66jYs3BzDJwA= github.com/pocketbase/pocketbase v0.27.1/go.mod h1:aTpwwloVJzeJ7MlwTRrbI/x62QNR2/kkCrovmyrXpqs=
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-20240802064259-28781e87b246 h1:c4D8BPWLOxxdaxQLfLKQXH2YXY/E9yo3jrDSL54XrTw=
@ -729,14 +754,14 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/qiniu/dyn v1.3.0 h1:s+xPTeV0H8yikgM4ZMBc7Rrefam8UNI3asBlkaOQg5o= github.com/qiniu/dyn v1.3.0 h1:s+xPTeV0H8yikgM4ZMBc7Rrefam8UNI3asBlkaOQg5o=
github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk= github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk=
github.com/qiniu/go-sdk/v7 v7.25.2 h1:URwgZpxySdiwu2yQpHk93X4LXWHyFRp1x3Vmlk/YWvo= github.com/qiniu/go-sdk/v7 v7.25.3 h1:eYHh02q4i5MrlEn3qy823w7moieymFzb4dsP38Y43AI=
github.com/qiniu/go-sdk/v7 v7.25.2/go.mod h1:dmKtJ2ahhPWFVi9o1D5GemmWoh/ctuB9peqTowyTO8o= github.com/qiniu/go-sdk/v7 v7.25.3/go.mod h1:dmKtJ2ahhPWFVi9o1D5GemmWoh/ctuB9peqTowyTO8o=
github.com/qiniu/x v1.10.5 h1:7V/CYWEmo9axJULvrJN6sMYh2FdY+esN5h8jwDkA4b0= github.com/qiniu/x v1.10.5 h1:7V/CYWEmo9axJULvrJN6sMYh2FdY+esN5h8jwDkA4b0=
github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs= github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
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=
@ -758,6 +783,8 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
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.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0=
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=
@ -793,32 +820,32 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
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/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115 h1:HsrXyqKQB2mKfGq+ZkbylRCMrbtPCmmUBrwA8MhhEX0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1136 h1:H1pjtH5uZ4XZPj9qQ9tt9jzeWqZzrd8qYIw01Q60/08=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115/go.mod h1:5cz1DtLlXK98U1Hh36oW4PjVOU+mbKg5wtCDmCc9Fcs= 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.1127 h1:PiLZflqaW0690YsqIM/hqaVYjZJ3+cCJp4NHfw7h/uw= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1143 h1:7OL/ThUCqkntItSiqbY1g3s0Ua26Qr08G8fcSzyrAqA=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1127/go.mod h1:V1+julLUOH0jKoVH6o6xgM4STWowzAL57M4VanUEEag= 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.1084/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= 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.1115/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1117/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1124/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.1125/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.1126/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.1127 h1:1uG8zc0b9gLbyTr27T0CzGtcdrL86CGGJ6Flkq867f4= 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.1127/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/dnspod v1.0.1084 h1:kwctN0WQYt8/iKP+iRCTCwdzEMIXsXklbRIib5rjeQ8= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1147 h1:6v559jM1v6A4KJinNZ28RqVZs+ipKMzCWtYWcWy+zZ4=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084/go.mod h1:qE67ApiBzeRvzeDsV+GxyIDbVIDemsKpHXllQATz/Vw= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1147/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1117 h1:Yc/r5zUAyukVI3huIuwE7koowCjDjOWqeRpBILCvOSE= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 h1:mrJ5Fbkd7sZIJ5F6oRfh5zebPQaudPH9Y0+GUmFytYU=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1117/go.mod h1:YxsorHl3sTRw+2GsUObMqcumDqAQ3zo9rLMtf3Cxj8U= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128/go.mod h1:zbsYIBT+VTX4z4ocjTAdLBIWyNYj3z0BRqd0iPdnjsk=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115 h1:Qi7VWmJ0AQxEMlwKpbWfnsLA5QdNxekdcLJTBVdO85U= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1143 h1:fvK9kOsPquDTWrT2aXLWVnAMUokr4gFK7uYeY3JMB6U=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115/go.mod h1:P16nIMvmpSY+arTc2m2HyJmrYQP6CFnr48glz0+abyw= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1143/go.mod h1:SLYgasv8DdvRnesG+SLdqFdEBIJzietfVDytke8ASKQ=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1120 h1:z0t0lb5h1mZirXftO8MRg25COYZHx0ubQjSPhZT/LY0=
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/ssl v1.0.1124 h1:LQKAlxFb0sYiE8ojK5h9+seuFzogoJtYnXmiRF+4F4Q= 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.1124/go.mod h1:tYbK0FbHVG+78od7eZpzczE8qk0JWKO/osTQWuiJ3Fo= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124/go.mod h1:tYbK0FbHVG+78od7eZpzczE8qk0JWKO/osTQWuiJ3Fo=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1126 h1:+CJQNXLdLP0GLaz2fnPECQsU+WdOmW3BQ54cNoQgMKA= 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.1126/go.mod h1:eY3GoWilNoCPOEw2Lp4o+h02nEfc+BoZnqK3TlK6F7I= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1138/go.mod h1:XvXgF+4yO4Ni6gYoqMszSkNNqFLkOxx2j5F7+u3lpKQ=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1115 h1:rO0LdbcNtT5VlL9sB/K3Ve848uLp1rgg3R8igT9xsFQ= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1136 h1:9GqM1URHNySj0f8TkUcKT6qSDiGep3IB1hWWu1ti6rY=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1115/go.mod h1:jJR8Y5sHuujSXZy0cpCgBk180TvPNsLw9hEoSH9w7iA= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1136/go.mod h1:b5JZEbM4ROYUSVcgNkDHuHWdTJX5Qe4wC1asq2n0yes=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1125 h1:IR9pJqHjHr7KyncRVxld9iltfnmy9sCC+0USZrs3rOw= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1147 h1:SxZsn9N4c1yx40kZOINIh9AnUKcgChUWbZoDiv6VvmQ=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1125/go.mod h1:5+5QrF7x+AW1KPM7F+YRzD74L88RXHZ6BxDF07b8QkE= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1147/go.mod h1:T4sxG9+SJ038MBsam2upsEYRpQ82JpX+IkZ08+P9RlE=
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=
@ -827,16 +854,16 @@ github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaO
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ucloud/ucloud-sdk-go v0.22.31 h1:izZK+Re9ZkJAd1fHSVpFzgh8uKda4f5G6++iUw4n/mE= github.com/ucloud/ucloud-sdk-go v0.22.33 h1:YKY8VpFNttdnVNb0o3owGeZRoUtRJmoWPJYJPfcCf9A=
github.com/ucloud/ucloud-sdk-go v0.22.31/go.mod h1:dyLmFHmUfgb4RZKYQP9IArlvQ2pxzFthfhwxRzOEPIw= github.com/ucloud/ucloud-sdk-go v0.22.33/go.mod h1:dyLmFHmUfgb4RZKYQP9IArlvQ2pxzFthfhwxRzOEPIw=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9 h1:fEnScn2dXfvfNcFnvJnpf/cYdj8kLIe5QC5qORlFO2c= github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.11 h1:J4AweXxLqlSwb1Aam9npcb5optZmszDIrKWa/hs+e4U=
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9/go.mod h1:IrjK84IJJTuOZOTMv/P18Ydjy/x+ow7fF7q11jAxXLM= github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.11/go.mod h1:IrjK84IJJTuOZOTMv/P18Ydjy/x+ow7fF7q11jAxXLM=
github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU= github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU=
github.com/volcengine/volc-sdk-golang v1.0.199 h1:zv9QOqTl/IsLwtfC37GlJtcz6vMAHi+pjq8ILWjLYUc= github.com/volcengine/volc-sdk-golang v1.0.204 h1:Njid6coReHV2gWc3bsqWMQf+K8jveauzW8zEX08CTzI=
github.com/volcengine/volc-sdk-golang v1.0.199/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ= github.com/volcengine/volc-sdk-golang v1.0.204/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
github.com/volcengine/volcengine-go-sdk v1.0.187 h1:YpZjydoyHDA/ofnF6mYCelbOoo9pJsBEiQOOSJzGSOY= github.com/volcengine/volcengine-go-sdk v1.1.4 h1:xPT4KOy8VkXxhY7dbXzzvLvKQXUe4J6AtkQdNQU3wRY=
github.com/volcengine/volcengine-go-sdk v1.0.187/go.mod h1:gfEDc1s7SYaGoY+WH2dRrS3qiuDJMkwqyfXWCa7+7oA= github.com/volcengine/volcengine-go-sdk v1.1.4/go.mod h1:gfEDc1s7SYaGoY+WH2dRrS3qiuDJMkwqyfXWCa7+7oA=
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=
@ -904,8 +931,8 @@ golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOM
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
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=
@ -919,14 +946,14 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
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=
@ -1009,16 +1036,16 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
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=
@ -1036,8 +1063,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.13.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=
@ -1090,6 +1117,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=
@ -1098,6 +1126,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=
@ -1114,8 +1143,8 @@ golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.32.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=
@ -1131,8 +1160,8 @@ golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
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=
@ -1151,15 +1180,15 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -1214,8 +1243,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
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=
@ -1367,27 +1396,27 @@ k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8X
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas= k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas=
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0= modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic=
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo= modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU=
modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo= modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw=
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.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8= modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s=
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E= modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI= modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g=
modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU= modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.36.1 h1:bDa8BJUH4lg6EGkLbahKe/8QqoF8p9gArSc6fTqYhyQ= modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI=
modernc.org/sqlite v1.36.1/go.mod h1:7MPwH7Z6bREicF9ZVUR78P1IKuxfZ8mRIDHD0iD+8TU= modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM=
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=

View File

@ -1,38 +1,30 @@
package applicant package applicant
import "github.com/usual2970/certimate/internal/domain"
const ( const (
sslProviderLetsEncrypt = "letsencrypt" sslProviderLetsEncrypt = string(domain.CAProviderTypeLetsEncrypt)
sslProviderLetsEncryptStaging = "letsencrypt_staging" sslProviderLetsEncryptStaging = string(domain.CAProviderTypeLetsEncryptStaging)
sslProviderZeroSSL = "zerossl" sslProviderBuypass = string(domain.CAProviderTypeBuypass)
sslProviderGoogleTrustServices = "gts" sslProviderGoogleTrustServices = string(domain.CAProviderTypeGoogleTrustServices)
) sslProviderSSLCom = string(domain.CAProviderTypeSSLCom)
const defaultSSLProvider = sslProviderLetsEncrypt sslProviderZeroSSL = string(domain.CAProviderTypeZeroSSL)
const ( sslProviderDefault = sslProviderLetsEncrypt
letsencryptUrl = "https://acme-v02.api.letsencrypt.org/directory"
letsencryptStagingUrl = "https://acme-staging-v02.api.letsencrypt.org/directory"
zerosslUrl = "https://acme.zerossl.com/v2/DV90"
gtsUrl = "https://dv.acme-v02.api.pki.goog/directory"
) )
var sslProviderUrls = map[string]string{ var sslProviderUrls = map[string]string{
sslProviderLetsEncrypt: letsencryptUrl, sslProviderLetsEncrypt: "https://acme-v02.api.letsencrypt.org/directory",
sslProviderLetsEncryptStaging: letsencryptStagingUrl, sslProviderLetsEncryptStaging: "https://acme-staging-v02.api.letsencrypt.org/directory",
sslProviderZeroSSL: zerosslUrl, sslProviderBuypass: "https://api.buypass.com/acme/directory",
sslProviderGoogleTrustServices: gtsUrl, sslProviderGoogleTrustServices: "https://dv.acme-v02.api.pki.goog/directory",
sslProviderSSLCom: "https://acme.ssl.com/sslcom-dv-rsa",
sslProviderSSLCom + "RSA": "https://acme.ssl.com/sslcom-dv-rsa",
sslProviderSSLCom + "ECC": "https://acme.ssl.com/sslcom-dv-ecc",
sslProviderZeroSSL: "https://acme.zerossl.com/v2/DV90",
} }
type acmeSSLProviderConfig struct { type acmeSSLProviderConfig struct {
Config acmeSSLProviderConfigContent `json:"config"` Config map[domain.CAProviderType]map[string]any `json:"config"`
Provider string `json:"provider"` Provider string `json:"provider"`
}
type acmeSSLProviderConfigContent struct {
ZeroSSL acmeSSLProviderEabConfig `json:"zerossl"`
GoogleTrustServices acmeSSLProviderEabConfig `json:"gts"`
}
type acmeSSLProviderEabConfig struct {
EabHmacKey string `json:"eabHmacKey"`
EabKid string `json:"eabKid"`
} }

View File

@ -1,4 +1,4 @@
package applicant package applicant
import ( import (
"context" "context"
@ -13,7 +13,8 @@ import (
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
"github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/domain"
"github.com/usual2970/certimate/internal/pkg/utils/certutil" certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
"github.com/usual2970/certimate/internal/repository" "github.com/usual2970/certimate/internal/repository"
) )
@ -76,16 +77,11 @@ func (u *acmeUser) getPrivateKeyPEM() string {
return u.privkey return u.privkey
} }
type acmeAccountRepository interface {
GetByCAAndEmail(ca, email string) (*domain.AcmeAccount, error)
Save(ca, email, key string, resource *registration.Resource) error
}
var registerGroup singleflight.Group var registerGroup singleflight.Group
func registerAcmeUserWithSingleFlight(client *lego.Client, sslProviderConfig *acmeSSLProviderConfig, user *acmeUser) (*registration.Resource, error) { func registerAcmeUserWithSingleFlight(client *lego.Client, user *acmeUser, userRegisterOptions map[string]any) (*registration.Resource, error) {
resp, err, _ := registerGroup.Do(fmt.Sprintf("register_acme_user_%s_%s", sslProviderConfig.Provider, user.GetEmail()), func() (interface{}, error) { resp, err, _ := registerGroup.Do(fmt.Sprintf("register_acme_user_%s_%s", user.CA, user.Email), func() (interface{}, error) {
return registerAcmeUser(client, sslProviderConfig, user) return registerAcmeUser(client, user, userRegisterOptions)
}) })
if err != nil { if err != nil {
@ -95,45 +91,81 @@ func registerAcmeUserWithSingleFlight(client *lego.Client, sslProviderConfig *ac
return resp.(*registration.Resource), nil return resp.(*registration.Resource), nil
} }
func registerAcmeUser(client *lego.Client, sslProviderConfig *acmeSSLProviderConfig, user *acmeUser) (*registration.Resource, error) { func registerAcmeUser(client *lego.Client, user *acmeUser, userRegisterOptions map[string]any) (*registration.Resource, error) {
var reg *registration.Resource var reg *registration.Resource
var err error var err error
switch sslProviderConfig.Provider { switch user.CA {
case sslProviderZeroSSL:
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
TermsOfServiceAgreed: true,
Kid: sslProviderConfig.Config.ZeroSSL.EabKid,
HmacEncoded: sslProviderConfig.Config.ZeroSSL.EabHmacKey,
})
case sslProviderGoogleTrustServices:
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
TermsOfServiceAgreed: true,
Kid: sslProviderConfig.Config.GoogleTrustServices.EabKid,
HmacEncoded: sslProviderConfig.Config.GoogleTrustServices.EabHmacKey,
})
case sslProviderLetsEncrypt, sslProviderLetsEncryptStaging: case sslProviderLetsEncrypt, sslProviderLetsEncryptStaging:
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
case sslProviderBuypass:
{
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
}
case sslProviderGoogleTrustServices:
{
access := domain.AccessConfigForGoogleTrustServices{}
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
TermsOfServiceAgreed: true,
Kid: access.EabKid,
HmacEncoded: access.EabHmacKey,
})
}
case sslProviderSSLCom:
{
access := domain.AccessConfigForSSLCom{}
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
TermsOfServiceAgreed: true,
Kid: access.EabKid,
HmacEncoded: access.EabHmacKey,
})
}
case sslProviderZeroSSL:
{
access := domain.AccessConfigForZeroSSL{}
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
TermsOfServiceAgreed: true,
Kid: access.EabKid,
HmacEncoded: access.EabHmacKey,
})
}
default: default:
err = fmt.Errorf("unsupported ssl provider: %s", sslProviderConfig.Provider) err = fmt.Errorf("unsupported ca provider '%s'", user.CA)
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
repo := repository.NewAcmeAccountRepository() repo := repository.NewAcmeAccountRepository()
resp, err := repo.GetByCAAndEmail(sslProviderConfig.Provider, user.GetEmail()) resp, err := repo.GetByCAAndEmail(user.CA, user.Email)
if err == nil { if err == nil {
user.privkey = resp.Key user.privkey = resp.Key
return resp.Resource, nil return resp.Resource, nil
} }
if _, err := repo.Save(context.Background(), &domain.AcmeAccount{ if _, err := repo.Save(context.Background(), &domain.AcmeAccount{
CA: sslProviderConfig.Provider, CA: user.CA,
Email: user.GetEmail(), Email: user.Email,
Key: user.getPrivateKeyPEM(), Key: user.getPrivateKeyPEM(),
Resource: reg, Resource: reg,
}); err != nil { }); err != nil {
return nil, fmt.Errorf("failed to save registration: %w", err) return nil, fmt.Errorf("failed to save acme account registration: %w", err)
} }
return reg, nil return reg, nil

View File

@ -4,10 +4,12 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log/slog"
"os" "os"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time"
"github.com/go-acme/lego/v4/certcrypto" "github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/certificate" "github.com/go-acme/lego/v4/certificate"
@ -18,11 +20,11 @@ import (
"golang.org/x/time/rate" "golang.org/x/time/rate"
"github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/domain"
"github.com/usual2970/certimate/internal/pkg/utils/sliceutil" sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
"github.com/usual2970/certimate/internal/repository" "github.com/usual2970/certimate/internal/repository"
) )
type ApplyCertResult struct { type ApplyResult struct {
CertificateFullChain string CertificateFullChain string
IssuerCertificate string IssuerCertificate string
PrivateKey string PrivateKey string
@ -33,51 +35,78 @@ type ApplyCertResult struct {
} }
type Applicant interface { type Applicant interface {
Apply() (*ApplyCertResult, error) Apply(ctx context.Context) (*ApplyResult, error)
} }
type applicantOptions struct { type ApplicantWithWorkflowNodeConfig struct {
Domains []string Node *domain.WorkflowNode
ContactEmail string Logger *slog.Logger
Provider domain.ApplyDNSProviderType
ProviderAccessConfig map[string]any
ProviderApplyConfig map[string]any
KeyAlgorithm string
Nameservers []string
DnsPropagationTimeout int32
DnsTTL int32
DisableFollowCNAME bool
ReplacedARIAcctId string
ReplacedARICertId string
} }
func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) { func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, error) {
if node.Type != domain.WorkflowNodeTypeApply { if config.Node == nil {
return nil, fmt.Errorf("node type is not apply") return nil, fmt.Errorf("node is nil")
}
if config.Node.Type != domain.WorkflowNodeTypeApply {
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeApply))
} }
nodeConfig := node.GetConfigForApply() nodeConfig := config.Node.GetConfigForApply()
options := &applicantOptions{ options := &applicantProviderOptions{
Domains: sliceutil.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }), Domains: sliceutil.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }),
ContactEmail: nodeConfig.ContactEmail, ContactEmail: nodeConfig.ContactEmail,
Provider: domain.ApplyDNSProviderType(nodeConfig.Provider), Provider: domain.ACMEDns01ProviderType(nodeConfig.Provider),
ProviderApplyConfig: nodeConfig.ProviderConfig, ProviderAccessConfig: make(map[string]any),
KeyAlgorithm: nodeConfig.KeyAlgorithm, ProviderExtendedConfig: nodeConfig.ProviderConfig,
Nameservers: sliceutil.Filter(strings.Split(nodeConfig.Nameservers, ";"), func(s string) bool { return s != "" }), CAProvider: domain.CAProviderType(nodeConfig.CAProvider),
DnsPropagationTimeout: nodeConfig.DnsPropagationTimeout, CAProviderAccessConfig: make(map[string]any),
DnsTTL: nodeConfig.DnsTTL, CAProviderExtendedConfig: nodeConfig.CAProviderConfig,
DisableFollowCNAME: nodeConfig.DisableFollowCNAME, KeyAlgorithm: nodeConfig.KeyAlgorithm,
Nameservers: sliceutil.Filter(strings.Split(nodeConfig.Nameservers, ";"), func(s string) bool { return s != "" }),
DnsPropagationWait: nodeConfig.DnsPropagationWait,
DnsPropagationTimeout: nodeConfig.DnsPropagationTimeout,
DnsTTL: nodeConfig.DnsTTL,
DisableFollowCNAME: nodeConfig.DisableFollowCNAME,
} }
accessRepo := repository.NewAccessRepository() accessRepo := repository.NewAccessRepository()
if access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId); err != nil { if nodeConfig.ProviderAccessId != "" {
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err) if access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId); err != nil {
} else { return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
options.ProviderAccessConfig = access.Config } else {
options.ProviderAccessConfig = access.Config
}
}
if nodeConfig.CAProviderAccessId != "" {
if access, err := accessRepo.GetById(context.Background(), nodeConfig.CAProviderAccessId); err != nil {
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.CAProviderAccessId, err)
} else {
options.CAProviderAccessConfig = access.Config
}
}
settingsRepo := repository.NewSettingsRepository()
if string(options.CAProvider) == "" {
settings, _ := settingsRepo.GetByName(context.Background(), "sslProvider")
sslProviderConfig := &acmeSSLProviderConfig{
Config: make(map[domain.CAProviderType]map[string]any),
Provider: sslProviderDefault,
}
if settings != nil {
if err := json.Unmarshal([]byte(settings.Content), sslProviderConfig); err != nil {
return nil, err
} else if sslProviderConfig.Provider == "" {
sslProviderConfig.Provider = sslProviderDefault
}
}
options.CAProvider = domain.CAProviderType(sslProviderConfig.Provider)
options.CAProviderAccessConfig = sslProviderConfig.Config[options.CAProvider]
} }
certRepo := repository.NewCertificateRepository() certRepo := repository.NewCertificateRepository()
lastCertificate, _ := certRepo.GetByWorkflowNodeId(context.Background(), node.Id) lastCertificate, _ := certRepo.GetByWorkflowNodeId(context.Background(), config.Node.Id)
if lastCertificate != nil { if lastCertificate != nil {
newCertSan := slices.Clone(options.Domains) newCertSan := slices.Clone(options.Domains)
oldCertSan := strings.Split(lastCertificate.SubjectAltNames, ";") oldCertSan := strings.Split(lastCertificate.SubjectAltNames, ";")
@ -88,42 +117,53 @@ func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
lastCertX509, _ := certcrypto.ParsePEMCertificate([]byte(lastCertificate.Certificate)) lastCertX509, _ := certcrypto.ParsePEMCertificate([]byte(lastCertificate.Certificate))
if lastCertX509 != nil { if lastCertX509 != nil {
replacedARICertId, _ := certificate.MakeARICertID(lastCertX509) replacedARICertId, _ := certificate.MakeARICertID(lastCertX509)
options.ReplacedARIAcctId = lastCertificate.ACMEAccountUrl options.ReplacedARIAcct = lastCertificate.ACMEAccountUrl
options.ReplacedARICertId = replacedARICertId options.ReplacedARICert = replacedARICertId
} }
} }
} }
applicant, err := createApplicant(options) applicant, err := createApplicantProvider(options)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &proxyApplicant{ return &applicantImpl{
applicant: applicant, applicant: applicant,
options: options, options: options,
}, nil }, nil
} }
func apply(challengeProvider challenge.Provider, options *applicantOptions) (*ApplyCertResult, error) { type applicantImpl struct {
settingsRepo := repository.NewSettingsRepository() applicant challenge.Provider
settings, _ := settingsRepo.GetByName(context.Background(), "sslProvider") options *applicantProviderOptions
}
sslProviderConfig := &acmeSSLProviderConfig{ var _ Applicant = (*applicantImpl)(nil)
Config: acmeSSLProviderConfigContent{},
Provider: defaultSSLProvider, func (d *applicantImpl) Apply(ctx context.Context) (*ApplyResult, error) {
} limiter := getLimiter(fmt.Sprintf("apply_%s", d.options.ContactEmail))
if settings != nil { if err := limiter.Wait(ctx); err != nil {
if err := json.Unmarshal([]byte(settings.Content), sslProviderConfig); err != nil { return nil, err
return nil, err
}
} }
if sslProviderConfig.Provider == "" { return applyUseLego(d.applicant, d.options)
sslProviderConfig.Provider = defaultSSLProvider }
}
acmeUser, err := newAcmeUser(sslProviderConfig.Provider, options.ContactEmail) const (
limitBurst = 300
limitRate float64 = float64(1) / float64(36)
)
var limiters sync.Map
func getLimiter(key string) *rate.Limiter {
limiter, _ := limiters.LoadOrStore(key, rate.NewLimiter(rate.Limit(limitRate), 300))
return limiter.(*rate.Limiter)
}
func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOptions) (*ApplyResult, error) {
user, err := newAcmeUser(string(options.CAProvider), options.ContactEmail)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -133,9 +173,16 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", strconv.FormatBool(options.DisableFollowCNAME)) os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", strconv.FormatBool(options.DisableFollowCNAME))
// Create an ACME client config // Create an ACME client config
config := lego.NewConfig(acmeUser) config := lego.NewConfig(user)
config.CADirURL = sslProviderUrls[sslProviderConfig.Provider] config.Certificate.KeyType = parseLegoKeyAlgorithm(domain.CertificateKeyAlgorithmType(options.KeyAlgorithm))
config.Certificate.KeyType = parseKeyAlgorithm(domain.CertificateKeyAlgorithmType(options.KeyAlgorithm)) config.CADirURL = sslProviderUrls[user.CA]
if user.CA == sslProviderSSLCom {
if strings.HasPrefix(options.KeyAlgorithm, "RSA") {
config.CADirURL = sslProviderUrls[sslProviderSSLCom+"RSA"]
} else if strings.HasPrefix(options.KeyAlgorithm, "EC") {
config.CADirURL = sslProviderUrls[sslProviderSSLCom+"ECC"]
}
}
// Create an ACME client // Create an ACME client
client, err := lego.NewClient(config) client, err := lego.NewClient(config)
@ -144,20 +191,28 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
} }
// Set the DNS01 challenge provider // Set the DNS01 challenge provider
challengeOptions := make([]dns01.ChallengeOption, 0) client.Challenge.SetDNS01Provider(legoProvider,
if len(options.Nameservers) > 0 { dns01.CondOption(
challengeOptions = append(challengeOptions, dns01.AddRecursiveNameservers(dns01.ParseNameservers(options.Nameservers))) len(options.Nameservers) > 0,
challengeOptions = append(challengeOptions, dns01.DisableAuthoritativeNssPropagationRequirement()) dns01.AddRecursiveNameservers(dns01.ParseNameservers(options.Nameservers)),
} ),
client.Challenge.SetDNS01Provider(challengeProvider, challengeOptions...) dns01.CondOption(
options.DnsPropagationWait > 0,
dns01.PropagationWait(time.Duration(options.DnsPropagationWait)*time.Second, true),
),
dns01.CondOption(
len(options.Nameservers) > 0 || options.DnsPropagationWait > 0,
dns01.DisableAuthoritativeNssPropagationRequirement(),
),
)
// New users need to register first // New users need to register first
if !acmeUser.hasRegistration() { if !user.hasRegistration() {
reg, err := registerAcmeUserWithSingleFlight(client, sslProviderConfig, acmeUser) reg, err := registerAcmeUserWithSingleFlight(client, user, options.CAProviderAccessConfig)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to register: %w", err) return nil, fmt.Errorf("failed to register acme user: %w", err)
} }
acmeUser.Registration = reg user.Registration = reg
} }
// Obtain a certificate // Obtain a certificate
@ -165,64 +220,39 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
Domains: options.Domains, Domains: options.Domains,
Bundle: true, Bundle: true,
} }
if options.ReplacedARICertId != "" && options.ReplacedARIAcctId != acmeUser.Registration.URI { if options.ReplacedARIAcct == user.Registration.URI {
certRequest.ReplacesCertID = options.ReplacedARICertId certRequest.ReplacesCertID = options.ReplacedARICert
} }
certResource, err := client.Certificate.Obtain(certRequest) certResource, err := client.Certificate.Obtain(certRequest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &ApplyCertResult{ return &ApplyResult{
CertificateFullChain: strings.TrimSpace(string(certResource.Certificate)), CertificateFullChain: strings.TrimSpace(string(certResource.Certificate)),
IssuerCertificate: strings.TrimSpace(string(certResource.IssuerCertificate)), IssuerCertificate: strings.TrimSpace(string(certResource.IssuerCertificate)),
PrivateKey: strings.TrimSpace(string(certResource.PrivateKey)), PrivateKey: strings.TrimSpace(string(certResource.PrivateKey)),
ACMEAccountUrl: acmeUser.Registration.URI, ACMEAccountUrl: user.Registration.URI,
ACMECertUrl: certResource.CertURL, ACMECertUrl: certResource.CertURL,
ACMECertStableUrl: certResource.CertStableURL, ACMECertStableUrl: certResource.CertStableURL,
CSR: strings.TrimSpace(string(certResource.CSR)), CSR: strings.TrimSpace(string(certResource.CSR)),
}, nil }, nil
} }
func parseKeyAlgorithm(algo domain.CertificateKeyAlgorithmType) certcrypto.KeyType { func parseLegoKeyAlgorithm(algo domain.CertificateKeyAlgorithmType) certcrypto.KeyType {
switch algo { alogMap := map[domain.CertificateKeyAlgorithmType]certcrypto.KeyType{
case domain.CertificateKeyAlgorithmTypeRSA2048: domain.CertificateKeyAlgorithmTypeRSA2048: certcrypto.RSA2048,
return certcrypto.RSA2048 domain.CertificateKeyAlgorithmTypeRSA3072: certcrypto.RSA3072,
case domain.CertificateKeyAlgorithmTypeRSA3072: domain.CertificateKeyAlgorithmTypeRSA4096: certcrypto.RSA4096,
return certcrypto.RSA3072 domain.CertificateKeyAlgorithmTypeRSA8192: certcrypto.RSA8192,
case domain.CertificateKeyAlgorithmTypeRSA4096: domain.CertificateKeyAlgorithmTypeEC256: certcrypto.EC256,
return certcrypto.RSA4096 domain.CertificateKeyAlgorithmTypeEC384: certcrypto.EC384,
case domain.CertificateKeyAlgorithmTypeRSA8192: domain.CertificateKeyAlgorithmTypeEC512: certcrypto.KeyType("P512"),
return certcrypto.RSA8192 }
case domain.CertificateKeyAlgorithmTypeEC256:
return certcrypto.EC256 if keyType, ok := alogMap[algo]; ok {
case domain.CertificateKeyAlgorithmTypeEC384: return keyType
return certcrypto.EC384
} }
return certcrypto.RSA2048 return certcrypto.RSA2048
} }
// TODO: 暂时使用代理模式以兼容之前版本代码,后续重新实现此处逻辑
type proxyApplicant struct {
applicant challenge.Provider
options *applicantOptions
}
var limiters sync.Map
const (
limitBurst = 300
limitRate float64 = float64(1) / float64(36)
)
func getLimiter(key string) *rate.Limiter {
limiter, _ := limiters.LoadOrStore(key, rate.NewLimiter(rate.Limit(limitRate), 300))
return limiter.(*rate.Limiter)
}
func (d *proxyApplicant) Apply() (*ApplyCertResult, error) {
limiter := getLimiter(fmt.Sprintf("apply_%s", d.options.ContactEmail))
limiter.Wait(context.Background())
return apply(d.applicant, d.options)
}

View File

@ -8,9 +8,11 @@ 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"
pBunny "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/bunny"
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"
@ -34,16 +36,35 @@ import (
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"
"github.com/usual2970/certimate/internal/pkg/utils/maputil" maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
) )
func createApplicant(options *applicantOptions) (challenge.Provider, error) { type applicantProviderOptions struct {
Domains []string
ContactEmail string
Provider domain.ACMEDns01ProviderType
ProviderAccessConfig map[string]any
ProviderExtendedConfig map[string]any
CAProvider domain.CAProviderType
CAProviderAccessConfig map[string]any
CAProviderExtendedConfig map[string]any
KeyAlgorithm string
Nameservers []string
DnsPropagationWait int32
DnsPropagationTimeout int32
DnsTTL int32
DisableFollowCNAME bool
ReplacedARIAcct string
ReplacedARICert string
}
func createApplicantProvider(options *applicantProviderOptions) (challenge.Provider, error) {
/* /*
注意如果追加新的常量值请保持以 ASCII 排序 注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order. NOTICE: If you add new constant, please keep ASCII order.
*/ */
switch options.Provider { switch options.Provider {
case domain.ApplyDNSProviderTypeACMEHttpReq: case domain.ACMEDns01ProviderTypeACMEHttpReq:
{ {
access := domain.AccessConfigForACMEHttpReq{} access := domain.AccessConfigForACMEHttpReq{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -60,23 +81,39 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeAliyun, domain.ApplyDNSProviderTypeAliyunDNS: case domain.ACMEDns01ProviderTypeAliyun, domain.ACMEDns01ProviderTypeAliyunDNS, domain.ACMEDns01ProviderTypeAliyunESA:
{ {
access := domain.AccessConfigForAliyun{} access := domain.AccessConfigForAliyun{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := 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.ProviderExtendedConfig, "region"),
DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL,
})
return applicant, err
default:
break
}
} }
case domain.ApplyDNSProviderTypeAWS, domain.ApplyDNSProviderTypeAWSRoute53: case domain.ACMEDns01ProviderTypeAWS, domain.ACMEDns01ProviderTypeAWSRoute53:
{ {
access := domain.AccessConfigForAWS{} access := domain.AccessConfigForAWS{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -86,15 +123,15 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
applicant, err := pAWSRoute53.NewChallengeProvider(&pAWSRoute53.ChallengeProviderConfig{ applicant, err := pAWSRoute53.NewChallengeProvider(&pAWSRoute53.ChallengeProviderConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey, SecretAccessKey: access.SecretAccessKey,
Region: maputil.GetString(options.ProviderApplyConfig, "region"), Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
HostedZoneId: maputil.GetString(options.ProviderApplyConfig, "hostedZoneId"), HostedZoneId: maputil.GetString(options.ProviderExtendedConfig, "hostedZoneId"),
DnsPropagationTimeout: options.DnsPropagationTimeout, DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL, DnsTTL: options.DnsTTL,
}) })
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeAzure, domain.ApplyDNSProviderTypeAzureDNS: case domain.ACMEDns01ProviderTypeAzure, domain.ACMEDns01ProviderTypeAzureDNS:
{ {
access := domain.AccessConfigForAzure{} access := domain.AccessConfigForAzure{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -112,7 +149,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeBaiduCloud, domain.ApplyDNSProviderTypeBaiduCloudDNS: case domain.ACMEDns01ProviderTypeBaiduCloud, domain.ACMEDns01ProviderTypeBaiduCloudDNS:
{ {
access := domain.AccessConfigForBaiduCloud{} access := domain.AccessConfigForBaiduCloud{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -128,7 +165,22 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeCloudflare: case domain.ACMEDns01ProviderTypeBunny:
{
access := domain.AccessConfigForBunny{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
applicant, err := pBunny.NewChallengeProvider(&pBunny.ChallengeProviderConfig{
ApiKey: access.ApiKey,
DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL,
})
return applicant, err
}
case domain.ACMEDns01ProviderTypeCloudflare:
{ {
access := domain.AccessConfigForCloudflare{} access := domain.AccessConfigForCloudflare{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -137,13 +189,14 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
applicant, err := pCloudflare.NewChallengeProvider(&pCloudflare.ChallengeProviderConfig{ applicant, err := pCloudflare.NewChallengeProvider(&pCloudflare.ChallengeProviderConfig{
DnsApiToken: access.DnsApiToken, DnsApiToken: access.DnsApiToken,
ZoneApiToken: access.ZoneApiToken,
DnsPropagationTimeout: options.DnsPropagationTimeout, DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL, DnsTTL: options.DnsTTL,
}) })
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeClouDNS: case domain.ACMEDns01ProviderTypeClouDNS:
{ {
access := domain.AccessConfigForClouDNS{} access := domain.AccessConfigForClouDNS{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -159,7 +212,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeCMCCCloud: case domain.ACMEDns01ProviderTypeCMCCCloud:
{ {
access := domain.AccessConfigForCMCCCloud{} access := domain.AccessConfigForCMCCCloud{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -175,7 +228,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeDeSEC: case domain.ACMEDns01ProviderTypeDeSEC:
{ {
access := domain.AccessConfigForDeSEC{} access := domain.AccessConfigForDeSEC{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -190,7 +243,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeDNSLA: case domain.ACMEDns01ProviderTypeDNSLA:
{ {
access := domain.AccessConfigForDNSLA{} access := domain.AccessConfigForDNSLA{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -206,7 +259,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeDynv6: case domain.ACMEDns01ProviderTypeDynv6:
{ {
access := domain.AccessConfigForDynv6{} access := domain.AccessConfigForDynv6{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -221,7 +274,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeGcore: case domain.ACMEDns01ProviderTypeGcore:
{ {
access := domain.AccessConfigForGcore{} access := domain.AccessConfigForGcore{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -236,7 +289,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeGname: case domain.ACMEDns01ProviderTypeGname:
{ {
access := domain.AccessConfigForGname{} access := domain.AccessConfigForGname{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -252,7 +305,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeGoDaddy: case domain.ACMEDns01ProviderTypeGoDaddy:
{ {
access := domain.AccessConfigForGoDaddy{} access := domain.AccessConfigForGoDaddy{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -268,7 +321,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeHuaweiCloud, domain.ApplyDNSProviderTypeHuaweiCloudDNS: case domain.ACMEDns01ProviderTypeHuaweiCloud, domain.ACMEDns01ProviderTypeHuaweiCloudDNS:
{ {
access := domain.AccessConfigForHuaweiCloud{} access := domain.AccessConfigForHuaweiCloud{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -278,14 +331,14 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
applicant, err := pHuaweiCloud.NewChallengeProvider(&pHuaweiCloud.ChallengeProviderConfig{ applicant, err := pHuaweiCloud.NewChallengeProvider(&pHuaweiCloud.ChallengeProviderConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey, SecretAccessKey: access.SecretAccessKey,
Region: maputil.GetString(options.ProviderApplyConfig, "region"), Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
DnsPropagationTimeout: options.DnsPropagationTimeout, DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL, DnsTTL: options.DnsTTL,
}) })
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeJDCloud, domain.ApplyDNSProviderTypeJDCloudDNS: case domain.ACMEDns01ProviderTypeJDCloud, domain.ACMEDns01ProviderTypeJDCloudDNS:
{ {
access := domain.AccessConfigForJDCloud{} access := domain.AccessConfigForJDCloud{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -295,14 +348,14 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
applicant, err := pJDCloud.NewChallengeProvider(&pJDCloud.ChallengeProviderConfig{ applicant, err := pJDCloud.NewChallengeProvider(&pJDCloud.ChallengeProviderConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret, AccessKeySecret: access.AccessKeySecret,
RegionId: maputil.GetString(options.ProviderApplyConfig, "regionId"), RegionId: maputil.GetString(options.ProviderExtendedConfig, "regionId"),
DnsPropagationTimeout: options.DnsPropagationTimeout, DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL, DnsTTL: options.DnsTTL,
}) })
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeNamecheap: case domain.ACMEDns01ProviderTypeNamecheap:
{ {
access := domain.AccessConfigForNamecheap{} access := domain.AccessConfigForNamecheap{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -318,7 +371,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeNameDotCom: case domain.ACMEDns01ProviderTypeNameDotCom:
{ {
access := domain.AccessConfigForNameDotCom{} access := domain.AccessConfigForNameDotCom{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -334,7 +387,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeNameSilo: case domain.ACMEDns01ProviderTypeNameSilo:
{ {
access := domain.AccessConfigForNameSilo{} access := domain.AccessConfigForNameSilo{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -349,7 +402,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeNS1: case domain.ACMEDns01ProviderTypeNS1:
{ {
access := domain.AccessConfigForNS1{} access := domain.AccessConfigForNS1{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -364,7 +417,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypePorkbun: case domain.ACMEDns01ProviderTypePorkbun:
{ {
access := domain.AccessConfigForPorkbun{} access := domain.AccessConfigForPorkbun{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -380,7 +433,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypePowerDNS: case domain.ACMEDns01ProviderTypePowerDNS:
{ {
access := domain.AccessConfigForPowerDNS{} access := domain.AccessConfigForPowerDNS{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -388,15 +441,16 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
} }
applicant, err := pPowerDNS.NewChallengeProvider(&pPowerDNS.ChallengeProviderConfig{ applicant, err := pPowerDNS.NewChallengeProvider(&pPowerDNS.ChallengeProviderConfig{
ApiUrl: access.ApiUrl, ApiUrl: access.ApiUrl,
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
} }
case domain.ApplyDNSProviderTypeRainYun: case domain.ACMEDns01ProviderTypeRainYun:
{ {
access := domain.AccessConfigForRainYun{} access := domain.AccessConfigForRainYun{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -411,7 +465,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeTencentCloud, domain.ApplyDNSProviderTypeTencentCloudDNS, domain.ApplyDNSProviderTypeTencentCloudEO: case domain.ACMEDns01ProviderTypeTencentCloud, domain.ACMEDns01ProviderTypeTencentCloudDNS, domain.ACMEDns01ProviderTypeTencentCloudEO:
{ {
access := domain.AccessConfigForTencentCloud{} access := domain.AccessConfigForTencentCloud{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -419,7 +473,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
} }
switch options.Provider { switch options.Provider {
case domain.ApplyDNSProviderTypeTencentCloud, domain.ApplyDNSProviderTypeTencentCloudDNS: case domain.ACMEDns01ProviderTypeTencentCloud, domain.ACMEDns01ProviderTypeTencentCloudDNS:
applicant, err := pTencentCloud.NewChallengeProvider(&pTencentCloud.ChallengeProviderConfig{ applicant, err := pTencentCloud.NewChallengeProvider(&pTencentCloud.ChallengeProviderConfig{
SecretId: access.SecretId, SecretId: access.SecretId,
SecretKey: access.SecretKey, SecretKey: access.SecretKey,
@ -428,11 +482,11 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
}) })
return applicant, err return applicant, err
case domain.ApplyDNSProviderTypeTencentCloudEO: case domain.ACMEDns01ProviderTypeTencentCloudEO:
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.ProviderApplyConfig, "zoneId"), ZoneId: maputil.GetString(options.ProviderExtendedConfig, "zoneId"),
DnsPropagationTimeout: options.DnsPropagationTimeout, DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL, DnsTTL: options.DnsTTL,
}) })
@ -443,7 +497,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
} }
} }
case domain.ApplyDNSProviderTypeVercel: case domain.ACMEDns01ProviderTypeVercel:
{ {
access := domain.AccessConfigForVercel{} access := domain.AccessConfigForVercel{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -459,7 +513,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeVolcEngine, domain.ApplyDNSProviderTypeVolcEngineDNS: case domain.ACMEDns01ProviderTypeVolcEngine, domain.ACMEDns01ProviderTypeVolcEngineDNS:
{ {
access := domain.AccessConfigForVolcEngine{} access := domain.AccessConfigForVolcEngine{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -475,7 +529,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err return applicant, err
} }
case domain.ApplyDNSProviderTypeWestcn: case domain.ACMEDns01ProviderTypeWestcn:
{ {
access := domain.AccessConfigForWestcn{} access := domain.AccessConfigForWestcn{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@ -492,5 +546,5 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
} }
} }
return nil, fmt.Errorf("unsupported applicant provider: %s", string(options.Provider)) return nil, fmt.Errorf("unsupported applicant provider '%s'", string(options.Provider))
} }

View File

@ -17,7 +17,7 @@ import (
"github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/domain"
"github.com/usual2970/certimate/internal/domain/dtos" "github.com/usual2970/certimate/internal/domain/dtos"
"github.com/usual2970/certimate/internal/notify" "github.com/usual2970/certimate/internal/notify"
"github.com/usual2970/certimate/internal/pkg/utils/certutil" certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
"github.com/usual2970/certimate/internal/repository" "github.com/usual2970/certimate/internal/repository"
) )

View File

@ -11,66 +11,62 @@ import (
) )
type Deployer interface { type Deployer interface {
SetLogger(*slog.Logger)
Deploy(ctx context.Context) error Deploy(ctx context.Context) error
} }
type deployerOptions struct { type DeployerWithWorkflowNodeConfig struct {
Provider domain.DeployProviderType Node *domain.WorkflowNode
ProviderAccessConfig map[string]any Logger *slog.Logger
ProviderDeployConfig map[string]any CertificatePEM string
PrivateKeyPEM string
} }
func NewWithDeployNode(node *domain.WorkflowNode, certdata struct { func NewWithWorkflowNode(config DeployerWithWorkflowNodeConfig) (Deployer, error) {
Certificate string if config.Node == nil {
PrivateKey string return nil, fmt.Errorf("node is nil")
}, }
) (Deployer, error) { if config.Node.Type != domain.WorkflowNodeTypeDeploy {
if node.Type != domain.WorkflowNodeTypeDeploy { return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeDeploy))
return nil, fmt.Errorf("node type is not deploy")
} }
nodeConfig := node.GetConfigForDeploy() nodeConfig := config.Node.GetConfigForDeploy()
options := &deployerProviderOptions{
Provider: domain.DeploymentProviderType(nodeConfig.Provider),
ProviderAccessConfig: make(map[string]any),
ProviderExtendedConfig: nodeConfig.ProviderConfig,
}
accessRepo := repository.NewAccessRepository() accessRepo := repository.NewAccessRepository()
access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId) if nodeConfig.ProviderAccessId != "" {
if err != nil { access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId)
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err) if err != nil {
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
} else {
options.ProviderAccessConfig = access.Config
}
} }
deployer, err := createDeployer(&deployerOptions{ deployerProvider, err := createDeployerProvider(options)
Provider: domain.DeployProviderType(nodeConfig.Provider),
ProviderAccessConfig: access.Config,
ProviderDeployConfig: nodeConfig.ProviderConfig,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &proxyDeployer{ return &deployerImpl{
deployer: deployer, provider: deployerProvider.WithLogger(config.Logger),
deployCertificate: certdata.Certificate, certPEM: config.CertificatePEM,
deployPrivateKey: certdata.PrivateKey, privkeyPEM: config.PrivateKeyPEM,
}, nil }, nil
} }
// TODO: 暂时使用代理模式以兼容之前版本代码,后续重新实现此处逻辑 type deployerImpl struct {
type proxyDeployer struct { provider deployer.Deployer
deployer deployer.Deployer certPEM string
deployCertificate string privkeyPEM string
deployPrivateKey string
} }
func (d *proxyDeployer) SetLogger(logger *slog.Logger) { var _ Deployer = (*deployerImpl)(nil)
if logger == nil {
panic("logger is nil")
}
d.deployer.WithLogger(logger) func (d *deployerImpl) Deploy(ctx context.Context) error {
} _, err := d.provider.Deploy(ctx, d.certPEM, d.privkeyPEM)
func (d *proxyDeployer) Deploy(ctx context.Context) error {
_, err := d.deployer.Deploy(ctx, d.deployCertificate, d.deployPrivateKey)
return err return err
} }

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@ type Access struct {
Name string `json:"name" db:"name"` Name string `json:"name" db:"name"`
Provider string `json:"provider" db:"provider"` Provider string `json:"provider" db:"provider"`
Config map[string]any `json:"config" db:"config"` Config map[string]any `json:"config" db:"config"`
Reserve string `json:"reserve,omitempty" db:"reserve"`
DeletedAt *time.Time `json:"deleted" db:"deleted"` DeletedAt *time.Time `json:"deleted" db:"deleted"`
} }
@ -64,18 +65,24 @@ type AccessConfigForBytePlus struct {
SecretKey string `json:"secretKey"` SecretKey string `json:"secretKey"`
} }
type AccessConfigForBunny struct {
ApiKey string `json:"apiKey"`
}
type AccessConfigForCacheFly struct { type AccessConfigForCacheFly struct {
ApiToken string `json:"apiToken"` ApiToken string `json:"apiToken"`
} }
type AccessConfigForCdnfly struct { type AccessConfigForCdnfly struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
ApiSecret string `json:"apiSecret"` ApiSecret string `json:"apiSecret"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
} }
type AccessConfigForCloudflare struct { type AccessConfigForCloudflare struct {
DnsApiToken string `json:"dnsApiToken"` DnsApiToken string `json:"dnsApiToken"`
ZoneApiToken string `json:"zoneApiToken,omitempty"`
} }
type AccessConfigForClouDNS struct { type AccessConfigForClouDNS struct {
@ -92,6 +99,11 @@ type AccessConfigForDeSEC struct {
Token string `json:"token"` Token string `json:"token"`
} }
type AccessConfigForDingTalkBot struct {
WebhookUrl string `json:"webhookUrl"`
Secret string `json:"secret"`
}
type AccessConfigForDNSLA struct { type AccessConfigForDNSLA struct {
ApiId string `json:"apiId"` ApiId string `json:"apiId"`
ApiSecret string `json:"apiSecret"` ApiSecret string `json:"apiSecret"`
@ -111,6 +123,16 @@ type AccessConfigForEdgio struct {
ClientSecret string `json:"clientSecret"` ClientSecret string `json:"clientSecret"`
} }
type AccessConfigForEmail struct {
SmtpHost string `json:"smtpHost"`
SmtpPort int32 `json:"smtpPort"`
SmtpTls bool `json:"smtpTls"`
Username string `json:"username"`
Password string `json:"password"`
DefaultSenderAddress string `json:"defaultSenderAddress,omitempty"`
DefaultReceiverAddress string `json:"defaultReceiverAddress,omitempty"`
}
type AccessConfigForGcore struct { type AccessConfigForGcore struct {
ApiToken string `json:"apiToken"` ApiToken string `json:"apiToken"`
} }
@ -125,6 +147,18 @@ type AccessConfigForGoDaddy struct {
ApiSecret string `json:"apiSecret"` ApiSecret string `json:"apiSecret"`
} }
type AccessConfigForGoEdge struct {
ApiUrl string `json:"apiUrl"`
AccessKeyId string `json:"accessKeyId"`
AccessKey string `json:"accessKey"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
}
type AccessConfigForGoogleTrustServices struct {
EabKid string `json:"eabKid"`
EabHmacKey string `json:"eabHmacKey"`
}
type AccessConfigForHuaweiCloud struct { type AccessConfigForHuaweiCloud struct {
AccessKeyId string `json:"accessKeyId"` AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"` SecretAccessKey string `json:"secretAccessKey"`
@ -139,7 +173,16 @@ type AccessConfigForKubernetes struct {
KubeConfig string `json:"kubeConfig,omitempty"` KubeConfig string `json:"kubeConfig,omitempty"`
} }
type AccessConfigForLocal struct{} type AccessConfigForLarkBot struct {
WebhookUrl string `json:"webhookUrl"`
}
type AccessConfigForMattermost struct {
ServerUrl string `json:"serverUrl"`
Username string `json:"username"`
Password string `json:"password"`
DefaultChannelId string `json:"defaultChannelId,omitempty"`
}
type AccessConfigForNamecheap struct { type AccessConfigForNamecheap struct {
Username string `json:"username"` Username string `json:"username"`
@ -165,8 +208,16 @@ type AccessConfigForPorkbun struct {
} }
type AccessConfigForPowerDNS struct { type AccessConfigForPowerDNS struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
}
type AccessConfigForProxmoxVE struct {
ApiUrl string `json:"apiUrl"`
ApiToken string `json:"apiToken"`
ApiTokenSecret string `json:"apiTokenSecret,omitempty"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
} }
type AccessConfigForQiniu struct { type AccessConfigForQiniu struct {
@ -193,6 +244,16 @@ type AccessConfigForSSH struct {
KeyPassphrase string `json:"keyPassphrase,omitempty"` KeyPassphrase string `json:"keyPassphrase,omitempty"`
} }
type AccessConfigForSSLCom struct {
EabKid string `json:"eabKid"`
EabHmacKey string `json:"eabHmacKey"`
}
type AccessConfigForTelegram struct {
BotToken string `json:"botToken"`
DefaultChatId int64 `json:"defaultChatId,omitempty"`
}
type AccessConfigForTencentCloud struct { type AccessConfigForTencentCloud struct {
SecretId string `json:"secretId"` SecretId string `json:"secretId"`
SecretKey string `json:"secretKey"` SecretKey string `json:"secretKey"`
@ -219,12 +280,31 @@ type AccessConfigForVolcEngine struct {
SecretAccessKey string `json:"secretAccessKey"` SecretAccessKey string `json:"secretAccessKey"`
} }
type AccessConfigForWangsu struct {
AccessKeyId string `json:"accessKeyId"`
AccessKeySecret string `json:"accessKeySecret"`
ApiKey string `json:"apiKey"`
}
type AccessConfigForWebhook struct { type AccessConfigForWebhook struct {
Url string `json:"url"` Url string `json:"url"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` Method string `json:"method,omitempty"`
HeadersString string `json:"headers,omitempty"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
DefaultDataForDeployment string `json:"defaultDataForDeployment,omitempty"`
DefaultDataForNotification string `json:"defaultDataForNotification,omitempty"`
}
type AccessConfigForWeComBot struct {
WebhookUrl string `json:"webhookUrl"`
} }
type AccessConfigForWestcn struct { type AccessConfigForWestcn struct {
Username string `json:"username"` Username string `json:"username"`
ApiPassword string `json:"password"` ApiPassword string `json:"password"`
} }
type AccessConfigForZeroSSL struct {
EabKid string `json:"eabKid"`
EabHmacKey string `json:"eabHmacKey"`
}

View File

@ -8,7 +8,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/usual2970/certimate/internal/pkg/utils/certutil" certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
) )
const CollectionNameCertificate = "certificate" const CollectionNameCertificate = "certificate"

View File

@ -1,4 +1,4 @@
package dtos package dtos
type CertificateArchiveFileReq struct { type CertificateArchiveFileReq struct {
CertificateId string `json:"-"` CertificateId string `json:"-"`

View File

@ -1,4 +1,4 @@
package dtos package dtos
import "github.com/usual2970/certimate/internal/domain" import "github.com/usual2970/certimate/internal/domain"

View File

@ -1,4 +1,4 @@
package dtos package dtos
import "github.com/usual2970/certimate/internal/domain" import "github.com/usual2970/certimate/internal/domain"

View File

@ -8,11 +8,16 @@ type NotifyChannelType string
注意如果追加新的常量值请保持以 ASCII 排序 注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order. NOTICE: If you add new constant, please keep ASCII order.
*/ */
// Deprecated: v0.4.x 将废弃
const ( const (
NotifyChannelTypeBark = NotifyChannelType("bark") NotifyChannelTypeBark = NotifyChannelType("bark")
NotifyChannelTypeDingTalk = NotifyChannelType("dingtalk") NotifyChannelTypeDingTalk = NotifyChannelType("dingtalk")
NotifyChannelTypeEmail = NotifyChannelType("email") NotifyChannelTypeEmail = NotifyChannelType("email")
NotifyChannelTypeGotify = NotifyChannelType("gotify")
NotifyChannelTypeLark = NotifyChannelType("lark") NotifyChannelTypeLark = NotifyChannelType("lark")
NotifyChannelTypeMattermost = NotifyChannelType("mattermost")
NotifyChannelTypePushover = NotifyChannelType("pushover")
NotifyChannelTypePushPlus = NotifyChannelType("pushplus")
NotifyChannelTypeServerChan = NotifyChannelType("serverchan") NotifyChannelTypeServerChan = NotifyChannelType("serverchan")
NotifyChannelTypeTelegram = NotifyChannelType("telegram") NotifyChannelTypeTelegram = NotifyChannelType("telegram")
NotifyChannelTypeWebhook = NotifyChannelType("webhook") NotifyChannelTypeWebhook = NotifyChannelType("webhook")

View File

@ -1,4 +1,4 @@
package domain package domain
type AccessProviderType string type AccessProviderType string
@ -9,183 +9,244 @@ type AccessProviderType string
NOTICE: If you add new constant, please keep ASCII order. NOTICE: If you add new constant, please keep ASCII order.
*/ */
const ( const (
AccessProviderType1Panel = AccessProviderType("1panel") AccessProviderType1Panel = AccessProviderType("1panel")
AccessProviderTypeACMEHttpReq = AccessProviderType("acmehttpreq") AccessProviderTypeACMEHttpReq = AccessProviderType("acmehttpreq")
AccessProviderTypeAkamai = AccessProviderType("akamai") // Akamai预留 AccessProviderTypeAkamai = AccessProviderType("akamai") // Akamai预留
AccessProviderTypeAliyun = AccessProviderType("aliyun") AccessProviderTypeAliyun = AccessProviderType("aliyun")
AccessProviderTypeAWS = AccessProviderType("aws") AccessProviderTypeAWS = AccessProviderType("aws")
AccessProviderTypeAzure = AccessProviderType("azure") AccessProviderTypeAzure = AccessProviderType("azure")
AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud") AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud")
AccessProviderTypeBaishan = AccessProviderType("baishan") AccessProviderTypeBaishan = AccessProviderType("baishan")
AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel") AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel")
AccessProviderTypeBytePlus = AccessProviderType("byteplus") AccessProviderTypeBytePlus = AccessProviderType("byteplus")
AccessProviderTypeCacheFly = AccessProviderType("cachefly") AccessProviderTypeBunny = AccessProviderType("bunny")
AccessProviderTypeCdnfly = AccessProviderType("cdnfly") AccessProviderTypeBuypass = AccessProviderType("buypass")
AccessProviderTypeCloudflare = AccessProviderType("cloudflare") AccessProviderTypeCacheFly = AccessProviderType("cachefly")
AccessProviderTypeClouDNS = AccessProviderType("cloudns") AccessProviderTypeCdnfly = AccessProviderType("cdnfly")
AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud") AccessProviderTypeCloudflare = AccessProviderType("cloudflare")
AccessProviderTypeCTCCCloud = AccessProviderType("ctcccloud") // 联通云(预留) AccessProviderTypeClouDNS = AccessProviderType("cloudns")
AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 天翼云(预留) AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud")
AccessProviderTypeDeSEC = AccessProviderType("desec") AccessProviderTypeCTCCCloud = AccessProviderType("ctcccloud") // 天翼云(预留)
AccessProviderTypeDNSLA = AccessProviderType("dnsla") AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 联通云(预留)
AccessProviderTypeDogeCloud = AccessProviderType("dogecloud") AccessProviderTypeDeSEC = AccessProviderType("desec")
AccessProviderTypeDynv6 = AccessProviderType("dynv6") AccessProviderTypeDingTalkBot = AccessProviderType("dingtalkbot")
AccessProviderTypeEdgio = AccessProviderType("edgio") AccessProviderTypeDNSLA = AccessProviderType("dnsla")
AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly预留 AccessProviderTypeDogeCloud = AccessProviderType("dogecloud")
AccessProviderTypeGname = AccessProviderType("gname") AccessProviderTypeDynv6 = AccessProviderType("dynv6")
AccessProviderTypeGcore = AccessProviderType("gcore") AccessProviderTypeEdgio = AccessProviderType("edgio")
AccessProviderTypeGoDaddy = AccessProviderType("godaddy") AccessProviderTypeEmail = AccessProviderType("email")
AccessProviderTypeGoEdge = AccessProviderType("goedge") // GoEdge预留 AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly预留
AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud") AccessProviderTypeGname = AccessProviderType("gname")
AccessProviderTypeJDCloud = AccessProviderType("jdcloud") AccessProviderTypeGcore = AccessProviderType("gcore")
AccessProviderTypeKubernetes = AccessProviderType("k8s") AccessProviderTypeGoDaddy = AccessProviderType("godaddy")
AccessProviderTypeLocal = AccessProviderType("local") AccessProviderTypeGoEdge = AccessProviderType("goedge")
AccessProviderTypeNamecheap = AccessProviderType("namecheap") AccessProviderTypeGoogleTrustServices = AccessProviderType("googletrustservices")
AccessProviderTypeNameDotCom = AccessProviderType("namedotcom") AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud")
AccessProviderTypeNameSilo = AccessProviderType("namesilo") AccessProviderTypeJDCloud = AccessProviderType("jdcloud")
AccessProviderTypeNS1 = AccessProviderType("ns1") AccessProviderTypeKubernetes = AccessProviderType("k8s")
AccessProviderTypePorkbun = AccessProviderType("porkbun") AccessProviderTypeLarkBot = AccessProviderType("larkbot")
AccessProviderTypePowerDNS = AccessProviderType("powerdns") AccessProviderTypeLetsEncrypt = AccessProviderType("letsencrypt")
AccessProviderTypeQiniu = AccessProviderType("qiniu") AccessProviderTypeLetsEncryptStaging = AccessProviderType("letsencryptstaging")
AccessProviderTypeQingCloud = AccessProviderType("qingcloud") // 青云(预留) AccessProviderTypeLocal = AccessProviderType("local")
AccessProviderTypeRainYun = AccessProviderType("rainyun") AccessProviderTypeMattermost = AccessProviderType("mattermost")
AccessProviderTypeSafeLine = AccessProviderType("safeline") AccessProviderTypeNamecheap = AccessProviderType("namecheap")
AccessProviderTypeSSH = AccessProviderType("ssh") AccessProviderTypeNameDotCom = AccessProviderType("namedotcom")
AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud") AccessProviderTypeNameSilo = AccessProviderType("namesilo")
AccessProviderTypeUCloud = AccessProviderType("ucloud") AccessProviderTypeNS1 = AccessProviderType("ns1")
AccessProviderTypeUpyun = AccessProviderType("upyun") AccessProviderTypePorkbun = AccessProviderType("porkbun")
AccessProviderTypeVercel = AccessProviderType("vercel") AccessProviderTypePowerDNS = AccessProviderType("powerdns")
AccessProviderTypeVolcEngine = AccessProviderType("volcengine") AccessProviderTypeProxmoxVE = AccessProviderType("proxmoxve")
AccessProviderTypeWebhook = AccessProviderType("webhook") AccessProviderTypeQiniu = AccessProviderType("qiniu")
AccessProviderTypeWestcn = AccessProviderType("westcn") AccessProviderTypeQingCloud = AccessProviderType("qingcloud") // 青云(预留)
AccessProviderTypeRainYun = AccessProviderType("rainyun")
AccessProviderTypeSafeLine = AccessProviderType("safeline")
AccessProviderTypeSSH = AccessProviderType("ssh")
AccessProviderTypeSSLCOM = AccessProviderType("sslcom")
AccessProviderTypeTelegram = AccessProviderType("telegram")
AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud")
AccessProviderTypeUCloud = AccessProviderType("ucloud")
AccessProviderTypeUpyun = AccessProviderType("upyun")
AccessProviderTypeVercel = AccessProviderType("vercel")
AccessProviderTypeVolcEngine = AccessProviderType("volcengine")
AccessProviderTypeWangsu = AccessProviderType("wangsu")
AccessProviderTypeWebhook = AccessProviderType("webhook")
AccessProviderTypeWeComBot = AccessProviderType("wecombot")
AccessProviderTypeWestcn = AccessProviderType("westcn")
AccessProviderTypeZeroSSL = AccessProviderType("zerossl")
) )
type ApplyDNSProviderType string type CAProviderType string
/* /*
申请证书 DNS 提供商常量值 证书颁发机构提供商常量值
短横线前的部分始终等于授权提供商类型 短横线前的部分始终等于授权提供商类型
注意如果追加新的常量值请保持以 ASCII 排序 注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order. NOTICE: If you add new constant, please keep ASCII order.
*/ */
const ( const (
ApplyDNSProviderTypeACMEHttpReq = ApplyDNSProviderType("acmehttpreq") CAProviderTypeBuypass = CAProviderType(AccessProviderTypeBuypass)
ApplyDNSProviderTypeAliyun = ApplyDNSProviderType("aliyun") // 兼容旧值,等同于 [ApplyDNSProviderTypeAliyunDNS] CAProviderTypeGoogleTrustServices = CAProviderType(AccessProviderTypeGoogleTrustServices)
ApplyDNSProviderTypeAliyunDNS = ApplyDNSProviderType("aliyun-dns") CAProviderTypeLetsEncrypt = CAProviderType(AccessProviderTypeLetsEncrypt)
ApplyDNSProviderTypeAWS = ApplyDNSProviderType("aws") // 兼容旧值,等同于 [ApplyDNSProviderTypeAWSRoute53] CAProviderTypeLetsEncryptStaging = CAProviderType(AccessProviderTypeLetsEncryptStaging)
ApplyDNSProviderTypeAWSRoute53 = ApplyDNSProviderType("aws-route53") CAProviderTypeSSLCom = CAProviderType(AccessProviderTypeSSLCOM)
ApplyDNSProviderTypeAzure = ApplyDNSProviderType("azure") // 兼容旧值,等同于 [ApplyDNSProviderTypeAzure] CAProviderTypeZeroSSL = CAProviderType(AccessProviderTypeZeroSSL)
ApplyDNSProviderTypeAzureDNS = ApplyDNSProviderType("azure-dns")
ApplyDNSProviderTypeBaiduCloud = ApplyDNSProviderType("baiducloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeBaiduCloudDNS]
ApplyDNSProviderTypeBaiduCloudDNS = ApplyDNSProviderType("baiducloud-dns")
ApplyDNSProviderTypeCloudflare = ApplyDNSProviderType("cloudflare")
ApplyDNSProviderTypeClouDNS = ApplyDNSProviderType("cloudns")
ApplyDNSProviderTypeCMCCCloud = ApplyDNSProviderType("cmcccloud")
ApplyDNSProviderTypeDeSEC = ApplyDNSProviderType("desec")
ApplyDNSProviderTypeDNSLA = ApplyDNSProviderType("dnsla")
ApplyDNSProviderTypeDynv6 = ApplyDNSProviderType("dynv6")
ApplyDNSProviderTypeGcore = ApplyDNSProviderType("gcore")
ApplyDNSProviderTypeGname = ApplyDNSProviderType("gname")
ApplyDNSProviderTypeGoDaddy = ApplyDNSProviderType("godaddy")
ApplyDNSProviderTypeHuaweiCloud = ApplyDNSProviderType("huaweicloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeHuaweiCloudDNS]
ApplyDNSProviderTypeHuaweiCloudDNS = ApplyDNSProviderType("huaweicloud-dns")
ApplyDNSProviderTypeJDCloud = ApplyDNSProviderType("jdcloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeJDCloudDNS]
ApplyDNSProviderTypeJDCloudDNS = ApplyDNSProviderType("jdcloud-dns")
ApplyDNSProviderTypeNamecheap = ApplyDNSProviderType("namecheap")
ApplyDNSProviderTypeNameDotCom = ApplyDNSProviderType("namedotcom")
ApplyDNSProviderTypeNameSilo = ApplyDNSProviderType("namesilo")
ApplyDNSProviderTypeNS1 = ApplyDNSProviderType("ns1")
ApplyDNSProviderTypePorkbun = ApplyDNSProviderType("porkbun")
ApplyDNSProviderTypePowerDNS = ApplyDNSProviderType("powerdns")
ApplyDNSProviderTypeRainYun = ApplyDNSProviderType("rainyun")
ApplyDNSProviderTypeTencentCloud = ApplyDNSProviderType("tencentcloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeTencentCloudDNS]
ApplyDNSProviderTypeTencentCloudDNS = ApplyDNSProviderType("tencentcloud-dns")
ApplyDNSProviderTypeTencentCloudEO = ApplyDNSProviderType("tencentcloud-eo")
ApplyDNSProviderTypeVercel = ApplyDNSProviderType("vercel")
ApplyDNSProviderTypeVolcEngine = ApplyDNSProviderType("volcengine") // 兼容旧值,等同于 [ApplyDNSProviderTypeVolcEngineDNS]
ApplyDNSProviderTypeVolcEngineDNS = ApplyDNSProviderType("volcengine-dns")
ApplyDNSProviderTypeWestcn = ApplyDNSProviderType("westcn")
) )
type DeployProviderType string type ACMEDns01ProviderType string
/* /*
部署目标提供商常量值 ACME DNS-01 提供商常量值
短横线前的部分始终等于授权提供商类型 短横线前的部分始终等于授权提供商类型
注意如果追加新的常量值请保持以 ASCII 排序 注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order. NOTICE: If you add new constant, please keep ASCII order.
*/ */
const ( const (
DeployProviderType1PanelConsole = DeployProviderType("1panel-console") ACMEDns01ProviderTypeACMEHttpReq = ACMEDns01ProviderType(AccessProviderTypeACMEHttpReq)
DeployProviderType1PanelSite = DeployProviderType("1panel-site") ACMEDns01ProviderTypeAliyun = ACMEDns01ProviderType(AccessProviderTypeAliyun) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAliyunDNS]
DeployProviderTypeAliyunALB = DeployProviderType("aliyun-alb") ACMEDns01ProviderTypeAliyunDNS = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-dns")
DeployProviderTypeAliyunCAS = DeployProviderType("aliyun-cas") ACMEDns01ProviderTypeAliyunESA = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-esa")
DeployProviderTypeAliyunCASDeploy = DeployProviderType("aliyun-casdeploy") ACMEDns01ProviderTypeAWS = ACMEDns01ProviderType(AccessProviderTypeAWS) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAWSRoute53]
DeployProviderTypeAliyunCDN = DeployProviderType("aliyun-cdn") ACMEDns01ProviderTypeAWSRoute53 = ACMEDns01ProviderType(AccessProviderTypeAWS + "-route53")
DeployProviderTypeAliyunCLB = DeployProviderType("aliyun-clb") ACMEDns01ProviderTypeAzure = ACMEDns01ProviderType(AccessProviderTypeAzure) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAzure]
DeployProviderTypeAliyunDCDN = DeployProviderType("aliyun-dcdn") ACMEDns01ProviderTypeAzureDNS = ACMEDns01ProviderType(AccessProviderTypeAzure + "-dns")
DeployProviderTypeAliyunESA = DeployProviderType("aliyun-esa") ACMEDns01ProviderTypeBaiduCloud = ACMEDns01ProviderType(AccessProviderTypeBaiduCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeBaiduCloudDNS]
DeployProviderTypeAliyunFC = DeployProviderType("aliyun-fc") ACMEDns01ProviderTypeBaiduCloudDNS = ACMEDns01ProviderType(AccessProviderTypeBaiduCloud + "-dns")
DeployProviderTypeAliyunLive = DeployProviderType("aliyun-live") ACMEDns01ProviderTypeBunny = ACMEDns01ProviderType(AccessProviderTypeBunny)
DeployProviderTypeAliyunNLB = DeployProviderType("aliyun-nlb") ACMEDns01ProviderTypeCloudflare = ACMEDns01ProviderType(AccessProviderTypeCloudflare)
DeployProviderTypeAliyunOSS = DeployProviderType("aliyun-oss") ACMEDns01ProviderTypeClouDNS = ACMEDns01ProviderType(AccessProviderTypeClouDNS)
DeployProviderTypeAliyunVOD = DeployProviderType("aliyun-vod") ACMEDns01ProviderTypeCMCCCloud = ACMEDns01ProviderType(AccessProviderTypeCMCCCloud)
DeployProviderTypeAliyunWAF = DeployProviderType("aliyun-waf") ACMEDns01ProviderTypeDeSEC = ACMEDns01ProviderType(AccessProviderTypeDeSEC)
DeployProviderTypeAWSACM = DeployProviderType("aws-acm") ACMEDns01ProviderTypeDNSLA = ACMEDns01ProviderType(AccessProviderTypeDNSLA)
DeployProviderTypeAWSCloudFront = DeployProviderType("aws-cloudfront") ACMEDns01ProviderTypeDynv6 = ACMEDns01ProviderType(AccessProviderTypeDynv6)
DeployProviderTypeAzureKeyVault = DeployProviderType("azure-keyvault") ACMEDns01ProviderTypeGcore = ACMEDns01ProviderType(AccessProviderTypeGcore)
DeployProviderTypeBaiduCloudAppBLB = DeployProviderType("baiducloud-appblb") ACMEDns01ProviderTypeGname = ACMEDns01ProviderType(AccessProviderTypeGname)
DeployProviderTypeBaiduCloudBLB = DeployProviderType("baiducloud-blb") ACMEDns01ProviderTypeGoDaddy = ACMEDns01ProviderType(AccessProviderTypeGoDaddy)
DeployProviderTypeBaiduCloudCDN = DeployProviderType("baiducloud-cdn") ACMEDns01ProviderTypeHuaweiCloud = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeHuaweiCloudDNS]
DeployProviderTypeBaiduCloudCert = DeployProviderType("baiducloud-cert") ACMEDns01ProviderTypeHuaweiCloudDNS = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud + "-dns")
DeployProviderTypeBaishanCDN = DeployProviderType("baishan-cdn") ACMEDns01ProviderTypeJDCloud = ACMEDns01ProviderType(AccessProviderTypeJDCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeJDCloudDNS]
DeployProviderTypeBaotaPanelConsole = DeployProviderType("baotapanel-console") ACMEDns01ProviderTypeJDCloudDNS = ACMEDns01ProviderType(AccessProviderTypeJDCloud + "-dns")
DeployProviderTypeBaotaPanelSite = DeployProviderType("baotapanel-site") ACMEDns01ProviderTypeNamecheap = ACMEDns01ProviderType(AccessProviderTypeNamecheap)
DeployProviderTypeBytePlusCDN = DeployProviderType("byteplus-cdn") ACMEDns01ProviderTypeNameDotCom = ACMEDns01ProviderType(AccessProviderTypeNameDotCom)
DeployProviderTypeCacheFly = DeployProviderType("cachefly") ACMEDns01ProviderTypeNameSilo = ACMEDns01ProviderType(AccessProviderTypeNameSilo)
DeployProviderTypeCdnfly = DeployProviderType("cdnfly") ACMEDns01ProviderTypeNS1 = ACMEDns01ProviderType(AccessProviderTypeNS1)
DeployProviderTypeDogeCloudCDN = DeployProviderType("dogecloud-cdn") ACMEDns01ProviderTypePorkbun = ACMEDns01ProviderType(AccessProviderTypePorkbun)
DeployProviderTypeEdgioApplications = DeployProviderType("edgio-applications") ACMEDns01ProviderTypePowerDNS = ACMEDns01ProviderType(AccessProviderTypePowerDNS)
DeployProviderTypeGcoreCDN = DeployProviderType("gcore-cdn") ACMEDns01ProviderTypeRainYun = ACMEDns01ProviderType(AccessProviderTypeRainYun)
DeployProviderTypeHuaweiCloudCDN = DeployProviderType("huaweicloud-cdn") ACMEDns01ProviderTypeTencentCloud = ACMEDns01ProviderType(AccessProviderTypeTencentCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeTencentCloudDNS]
DeployProviderTypeHuaweiCloudELB = DeployProviderType("huaweicloud-elb") ACMEDns01ProviderTypeTencentCloudDNS = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-dns")
DeployProviderTypeHuaweiCloudSCM = DeployProviderType("huaweicloud-scm") ACMEDns01ProviderTypeTencentCloudEO = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-eo")
DeployProviderTypeHuaweiCloudWAF = DeployProviderType("huaweicloud-waf") ACMEDns01ProviderTypeVercel = ACMEDns01ProviderType(AccessProviderTypeVercel)
DeployProviderTypeJDCloudALB = DeployProviderType("jdcloud-alb") ACMEDns01ProviderTypeVolcEngine = ACMEDns01ProviderType(AccessProviderTypeVolcEngine) // 兼容旧值,等同于 [ACMEDns01ProviderTypeVolcEngineDNS]
DeployProviderTypeJDCloudCDN = DeployProviderType("jdcloud-cdn") ACMEDns01ProviderTypeVolcEngineDNS = ACMEDns01ProviderType(AccessProviderTypeVolcEngine + "-dns")
DeployProviderTypeJDCloudLive = DeployProviderType("jdcloud-live") ACMEDns01ProviderTypeWestcn = ACMEDns01ProviderType(AccessProviderTypeWestcn)
DeployProviderTypeJDCloudVOD = DeployProviderType("jdcloud-vod") )
DeployProviderTypeKubernetesSecret = DeployProviderType("k8s-secret")
DeployProviderTypeLocal = DeployProviderType("local") type DeploymentProviderType string
DeployProviderTypeQiniuCDN = DeployProviderType("qiniu-cdn")
DeployProviderTypeQiniuKodo = DeployProviderType("qiniu-kodo") /*
DeployProviderTypeQiniuPili = DeployProviderType("qiniu-pili") 部署证书主机提供商常量值
DeployProviderTypeSafeLine = DeployProviderType("safeline") 短横线前的部分始终等于授权提供商类型
DeployProviderTypeSSH = DeployProviderType("ssh")
DeployProviderTypeTencentCloudCDN = DeployProviderType("tencentcloud-cdn") 注意如果追加新的常量值请保持以 ASCII 排序
DeployProviderTypeTencentCloudCLB = DeployProviderType("tencentcloud-clb") NOTICE: If you add new constant, please keep ASCII order.
DeployProviderTypeTencentCloudCOS = DeployProviderType("tencentcloud-cos") */
DeployProviderTypeTencentCloudCSS = DeployProviderType("tencentcloud-css") const (
DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn") DeploymentProviderType1PanelConsole = DeploymentProviderType(AccessProviderType1Panel + "-console")
DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo") DeploymentProviderType1PanelSite = DeploymentProviderType(AccessProviderType1Panel + "-site")
DeployProviderTypeTencentCloudSCF = DeployProviderType("tencentcloud-scf") DeploymentProviderTypeAliyunALB = DeploymentProviderType(AccessProviderTypeAliyun + "-alb")
DeployProviderTypeTencentCloudSSL = DeployProviderType("tencentcloud-ssl") DeploymentProviderTypeAliyunAPIGW = DeploymentProviderType(AccessProviderTypeAliyun + "-apigw")
DeployProviderTypeTencentCloudSSLDeploy = DeployProviderType("tencentcloud-ssldeploy") DeploymentProviderTypeAliyunCAS = DeploymentProviderType(AccessProviderTypeAliyun + "-cas")
DeployProviderTypeTencentCloudVOD = DeployProviderType("tencentcloud-vod") DeploymentProviderTypeAliyunCASDeploy = DeploymentProviderType(AccessProviderTypeAliyun + "-casdeploy")
DeployProviderTypeTencentCloudWAF = DeployProviderType("tencentcloud-waf") DeploymentProviderTypeAliyunCDN = DeploymentProviderType(AccessProviderTypeAliyun + "-cdn")
DeployProviderTypeUCloudUCDN = DeployProviderType("ucloud-ucdn") DeploymentProviderTypeAliyunCLB = DeploymentProviderType(AccessProviderTypeAliyun + "-clb")
DeployProviderTypeUCloudUS3 = DeployProviderType("ucloud-us3") DeploymentProviderTypeAliyunDCDN = DeploymentProviderType(AccessProviderTypeAliyun + "-dcdn")
DeployProviderTypeUpyunCDN = DeployProviderType("upyun-cdn") DeploymentProviderTypeAliyunDDoS = DeploymentProviderType(AccessProviderTypeAliyun + "-ddos")
DeployProviderTypeUpyunFile = DeployProviderType("upyun-file") DeploymentProviderTypeAliyunESA = DeploymentProviderType(AccessProviderTypeAliyun + "-esa")
DeployProviderTypeVolcEngineALB = DeployProviderType("volcengine-alb") DeploymentProviderTypeAliyunFC = DeploymentProviderType(AccessProviderTypeAliyun + "-fc")
DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn") DeploymentProviderTypeAliyunLive = DeploymentProviderType(AccessProviderTypeAliyun + "-live")
DeployProviderTypeVolcEngineCertCenter = DeployProviderType("volcengine-certcenter") DeploymentProviderTypeAliyunNLB = DeploymentProviderType(AccessProviderTypeAliyun + "-nlb")
DeployProviderTypeVolcEngineCLB = DeployProviderType("volcengine-clb") DeploymentProviderTypeAliyunOSS = DeploymentProviderType(AccessProviderTypeAliyun + "-oss")
DeployProviderTypeVolcEngineDCDN = DeployProviderType("volcengine-dcdn") DeploymentProviderTypeAliyunVOD = DeploymentProviderType(AccessProviderTypeAliyun + "-vod")
DeployProviderTypeVolcEngineImageX = DeployProviderType("volcengine-imagex") DeploymentProviderTypeAliyunWAF = DeploymentProviderType(AccessProviderTypeAliyun + "-waf")
DeployProviderTypeVolcEngineLive = DeployProviderType("volcengine-live") DeploymentProviderTypeAWSACM = DeploymentProviderType(AccessProviderTypeAWS + "-acm")
DeployProviderTypeVolcEngineTOS = DeployProviderType("volcengine-tos") DeploymentProviderTypeAWSCloudFront = DeploymentProviderType(AccessProviderTypeAWS + "-cloudfront")
DeployProviderTypeWebhook = DeployProviderType("webhook") DeploymentProviderTypeAzureKeyVault = DeploymentProviderType(AccessProviderTypeAzure + "-keyvault")
DeploymentProviderTypeBaiduCloudAppBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-appblb")
DeploymentProviderTypeBaiduCloudBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-blb")
DeploymentProviderTypeBaiduCloudCDN = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-cdn")
DeploymentProviderTypeBaiduCloudCert = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-cert")
DeploymentProviderTypeBaishanCDN = DeploymentProviderType(AccessProviderTypeBaishan + "-cdn")
DeploymentProviderTypeBaotaPanelConsole = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-console")
DeploymentProviderTypeBaotaPanelSite = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-site")
DeploymentProviderTypeBunnyCDN = DeploymentProviderType(AccessProviderTypeBunny + "-cdn")
DeploymentProviderTypeBytePlusCDN = DeploymentProviderType(AccessProviderTypeBytePlus + "-cdn")
DeploymentProviderTypeCacheFly = DeploymentProviderType(AccessProviderTypeCacheFly)
DeploymentProviderTypeCdnfly = DeploymentProviderType(AccessProviderTypeCdnfly)
DeploymentProviderTypeDogeCloudCDN = DeploymentProviderType(AccessProviderTypeDogeCloud + "-cdn")
DeploymentProviderTypeEdgioApplications = DeploymentProviderType(AccessProviderTypeEdgio + "-applications")
DeploymentProviderTypeGcoreCDN = DeploymentProviderType(AccessProviderTypeGcore + "-cdn")
DeploymentProviderTypeGoEdge = DeploymentProviderType(AccessProviderTypeGoEdge)
DeploymentProviderTypeHuaweiCloudCDN = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-cdn")
DeploymentProviderTypeHuaweiCloudELB = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-elb")
DeploymentProviderTypeHuaweiCloudSCM = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-scm")
DeploymentProviderTypeHuaweiCloudWAF = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-waf")
DeploymentProviderTypeJDCloudALB = DeploymentProviderType(AccessProviderTypeJDCloud + "-alb")
DeploymentProviderTypeJDCloudCDN = DeploymentProviderType(AccessProviderTypeJDCloud + "-cdn")
DeploymentProviderTypeJDCloudLive = DeploymentProviderType(AccessProviderTypeJDCloud + "-live")
DeploymentProviderTypeJDCloudVOD = DeploymentProviderType(AccessProviderTypeJDCloud + "-vod")
DeploymentProviderTypeKubernetesSecret = DeploymentProviderType(AccessProviderTypeKubernetes + "-secret")
DeploymentProviderTypeLocal = DeploymentProviderType(AccessProviderTypeLocal)
DeploymentProviderTypeProxmoxVE = DeploymentProviderType(AccessProviderTypeProxmoxVE)
DeploymentProviderTypeQiniuCDN = DeploymentProviderType(AccessProviderTypeQiniu + "-cdn")
DeploymentProviderTypeQiniuKodo = DeploymentProviderType(AccessProviderTypeQiniu + "-kodo")
DeploymentProviderTypeQiniuPili = DeploymentProviderType(AccessProviderTypeQiniu + "-pili")
DeploymentProviderTypeRainYunRCDN = DeploymentProviderType(AccessProviderTypeRainYun + "-rcdn")
DeploymentProviderTypeSafeLine = DeploymentProviderType(AccessProviderTypeSafeLine)
DeploymentProviderTypeSSH = DeploymentProviderType(AccessProviderTypeSSH)
DeploymentProviderTypeTencentCloudCDN = DeploymentProviderType(AccessProviderTypeTencentCloud + "-cdn")
DeploymentProviderTypeTencentCloudCLB = DeploymentProviderType(AccessProviderTypeTencentCloud + "-clb")
DeploymentProviderTypeTencentCloudCOS = DeploymentProviderType(AccessProviderTypeTencentCloud + "-cos")
DeploymentProviderTypeTencentCloudCSS = DeploymentProviderType(AccessProviderTypeTencentCloud + "-css")
DeploymentProviderTypeTencentCloudECDN = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ecdn")
DeploymentProviderTypeTencentCloudEO = DeploymentProviderType(AccessProviderTypeTencentCloud + "-eo")
DeploymentProviderTypeTencentCloudSCF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-scf")
DeploymentProviderTypeTencentCloudSSL = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssl")
DeploymentProviderTypeTencentCloudSSLDeploy = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssldeploy")
DeploymentProviderTypeTencentCloudVOD = DeploymentProviderType(AccessProviderTypeTencentCloud + "-vod")
DeploymentProviderTypeTencentCloudWAF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-waf")
DeploymentProviderTypeUCloudUCDN = DeploymentProviderType(AccessProviderTypeUCloud + "-ucdn")
DeploymentProviderTypeUCloudUS3 = DeploymentProviderType(AccessProviderTypeUCloud + "-us3")
DeploymentProviderTypeUpyunCDN = DeploymentProviderType(AccessProviderTypeUpyun + "-cdn")
DeploymentProviderTypeUpyunFile = DeploymentProviderType(AccessProviderTypeUpyun + "-file")
DeploymentProviderTypeVolcEngineALB = DeploymentProviderType(AccessProviderTypeVolcEngine + "-alb")
DeploymentProviderTypeVolcEngineCDN = DeploymentProviderType(AccessProviderTypeVolcEngine + "-cdn")
DeploymentProviderTypeVolcEngineCertCenter = DeploymentProviderType(AccessProviderTypeVolcEngine + "-certcenter")
DeploymentProviderTypeVolcEngineCLB = DeploymentProviderType(AccessProviderTypeVolcEngine + "-clb")
DeploymentProviderTypeVolcEngineDCDN = DeploymentProviderType(AccessProviderTypeVolcEngine + "-dcdn")
DeploymentProviderTypeVolcEngineImageX = DeploymentProviderType(AccessProviderTypeVolcEngine + "-imagex")
DeploymentProviderTypeVolcEngineLive = DeploymentProviderType(AccessProviderTypeVolcEngine + "-live")
DeploymentProviderTypeVolcEngineTOS = DeploymentProviderType(AccessProviderTypeVolcEngine + "-tos")
DeploymentProviderTypeWangsuCDNPro = DeploymentProviderType(AccessProviderTypeWangsu + "-cdnpro")
DeploymentProviderTypeWebhook = DeploymentProviderType(AccessProviderTypeWebhook)
)
type NotificationProviderType string
/*
消息通知提供商常量值
短横线前的部分始终等于授权提供商类型
注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order.
*/
const (
NotificationProviderTypeDingTalkBot = NotificationProviderType(AccessProviderTypeDingTalkBot)
NotificationProviderTypeEmail = NotificationProviderType(AccessProviderTypeEmail)
NotificationProviderTypeLarkBot = NotificationProviderType(AccessProviderTypeLarkBot)
NotificationProviderTypeMattermost = NotificationProviderType(AccessProviderTypeMattermost)
NotificationProviderTypeTelegram = NotificationProviderType(AccessProviderTypeTelegram)
NotificationProviderTypeWebhook = NotificationProviderType(AccessProviderTypeWebhook)
NotificationProviderTypeWeComBot = NotificationProviderType(AccessProviderTypeWeComBot)
) )

View File

@ -13,6 +13,7 @@ type Settings struct {
Content string `json:"content" db:"content"` Content string `json:"content" db:"content"`
} }
// Deprecated: v0.4.x 将废弃
type NotifyTemplatesSettingsContent struct { type NotifyTemplatesSettingsContent struct {
NotifyTemplates []struct { NotifyTemplates []struct {
Subject string `json:"subject"` Subject string `json:"subject"`
@ -20,8 +21,10 @@ type NotifyTemplatesSettingsContent struct {
} `json:"notifyTemplates"` } `json:"notifyTemplates"`
} }
// Deprecated: v0.4.x 将废弃
type NotifyChannelsSettingsContent map[string]map[string]any type NotifyChannelsSettingsContent map[string]map[string]any
// Deprecated: v0.4.x 将废弃
func (s *Settings) GetNotifyChannelConfig(channel string) (map[string]any, error) { func (s *Settings) GetNotifyChannelConfig(channel string) (map[string]any, error) {
conf := &NotifyChannelsSettingsContent{} conf := &NotifyChannelsSettingsContent{}
if err := json.Unmarshal([]byte(s.Content), conf); err != nil { if err := json.Unmarshal([]byte(s.Content), conf); err != nil {

View File

@ -3,7 +3,7 @@ package domain
import ( import (
"time" "time"
"github.com/usual2970/certimate/internal/pkg/utils/maputil" maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
) )
const CollectionNameWorkflow = "workflow" const CollectionNameWorkflow = "workflow"
@ -62,19 +62,23 @@ type WorkflowNode struct {
} }
type WorkflowNodeConfigForApply struct { type WorkflowNodeConfigForApply struct {
Domains string `json:"domains"` // 域名列表,以半角分号分隔 Domains string `json:"domains"` // 域名列表,以半角分号分隔
ContactEmail string `json:"contactEmail"` // 联系邮箱 ContactEmail string `json:"contactEmail"` // 联系邮箱
ChallengeType string `json:"challengeType"` // TODO: 验证方式。目前仅支持 dns-01 ChallengeType string `json:"challengeType"` // TODO: 验证方式。目前仅支持 dns-01
Provider string `json:"provider"` // DNS 提供商 Provider string `json:"provider"` // DNS 提供商
ProviderAccessId string `json:"providerAccessId"` // DNS 提供商授权记录 ID ProviderAccessId string `json:"providerAccessId"` // DNS 提供商授权记录 ID
ProviderConfig map[string]any `json:"providerConfig"` // DNS 提供商额外配置 ProviderConfig map[string]any `json:"providerConfig"` // DNS 提供商额外配置
KeyAlgorithm string `json:"keyAlgorithm"` // 密钥算法 CAProvider string `json:"caProvider,omitempty"` // CA 提供商(零值将使用全局配置)
Nameservers string `json:"nameservers"` // DNS 服务器列表,以半角分号分隔 CAProviderAccessId string `json:"caProviderAccessId,omitempty"` // CA 提供商授权记录 ID
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout"` // DNS 传播超时时间(零值取决于提供商的默认值) CAProviderConfig map[string]any `json:"caProviderConfig,omitempty"` // CA 提供商额外配置
DnsTTL int32 `json:"dnsTTL"` // DNS TTL零值取决于提供商的默认值 KeyAlgorithm string `json:"keyAlgorithm"` // 证书算法
DisableFollowCNAME bool `json:"disableFollowCNAME"` // 是否关闭 CNAME 跟随 Nameservers string `json:"nameservers,omitempty"` // DNS 服务器列表,以半角分号分隔
DisableARI bool `json:"disableARI"` // 是否关闭 ARI DnsPropagationWait int32 `json:"dnsPropagationWait,omitempty"` // DNS 传播等待时间,等同于 lego 的 `--dns-propagation-wait` 参数
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays"` // 证书到期前多少天前跳过续期(零值将使用默认值 30 DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` // DNS 传播检查超时时间(零值取决于提供商的默认值)
DnsTTL int32 `json:"dnsTTL,omitempty"` // DNS 解析记录 TTL零值取决于提供商的默认值
DisableFollowCNAME bool `json:"disableFollowCNAME,omitempty"` // 是否关闭 CNAME 跟随
DisableARI bool `json:"disableARI,omitempty"` // 是否关闭 ARI
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays,omitempty"` // 证书到期前多少天前跳过续期(零值将使用默认值 30
} }
type WorkflowNodeConfigForUpload struct { type WorkflowNodeConfigForUpload struct {
@ -84,86 +88,74 @@ type WorkflowNodeConfigForUpload struct {
} }
type WorkflowNodeConfigForDeploy struct { type WorkflowNodeConfigForDeploy struct {
Certificate string `json:"certificate"` // 前序节点输出的证书,形如“${NodeId}#certificate” Certificate string `json:"certificate"` // 前序节点输出的证书,形如“${NodeId}#certificate”
Provider string `json:"provider"` // 主机提供商 Provider string `json:"provider"` // 主机提供商
ProviderAccessId string `json:"providerAccessId"` // 主机提供商授权记录 ID ProviderAccessId string `json:"providerAccessId,omitempty"` // 主机提供商授权记录 ID
ProviderConfig map[string]any `json:"providerConfig"` // 主机提供商额外配置 ProviderConfig map[string]any `json:"providerConfig,omitempty"` // 主机提供商额外配置
SkipOnLastSucceeded bool `json:"skipOnLastSucceeded"` // 上次部署成功时是否跳过 SkipOnLastSucceeded bool `json:"skipOnLastSucceeded"` // 上次部署成功时是否跳过
} }
type WorkflowNodeConfigForNotify struct { type WorkflowNodeConfigForNotify struct {
Channel string `json:"channel"` // 通知渠道 Channel string `json:"channel,omitempty"` // Deprecated: v0.4.x 将废弃
Subject string `json:"subject"` // 通知主题 Provider string `json:"provider"` // 通知提供商
Message string `json:"message"` // 通知内容 ProviderAccessId string `json:"providerAccessId"` // 通知提供商授权记录 ID
} ProviderConfig map[string]any `json:"providerConfig,omitempty"` // 通知提供商额外配置
Subject string `json:"subject"` // 通知主题
func (n *WorkflowNode) getConfigString(key string) string { Message string `json:"message"` // 通知内容
return maputil.GetString(n.Config, key)
}
func (n *WorkflowNode) getConfigBool(key string) bool {
return maputil.GetBool(n.Config, key)
}
func (n *WorkflowNode) getConfigInt32(key string) int32 {
return maputil.GetInt32(n.Config, key)
}
func (n *WorkflowNode) getConfigMap(key string) map[string]any {
if val, ok := n.Config[key]; ok {
if result, ok := val.(map[string]any); ok {
return result
}
}
return make(map[string]any)
} }
func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply { func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply {
skipBeforeExpiryDays := n.getConfigInt32("skipBeforeExpiryDays") skipBeforeExpiryDays := maputil.GetInt32(n.Config, "skipBeforeExpiryDays")
if skipBeforeExpiryDays == 0 { if skipBeforeExpiryDays == 0 {
skipBeforeExpiryDays = 30 skipBeforeExpiryDays = 30
} }
return WorkflowNodeConfigForApply{ return WorkflowNodeConfigForApply{
Domains: n.getConfigString("domains"), Domains: maputil.GetString(n.Config, "domains"),
ContactEmail: n.getConfigString("contactEmail"), ContactEmail: maputil.GetString(n.Config, "contactEmail"),
Provider: n.getConfigString("provider"), Provider: maputil.GetString(n.Config, "provider"),
ProviderAccessId: n.getConfigString("providerAccessId"), ProviderAccessId: maputil.GetString(n.Config, "providerAccessId"),
ProviderConfig: n.getConfigMap("providerConfig"), ProviderConfig: maputil.GetKVMapAny(n.Config, "providerConfig"),
KeyAlgorithm: n.getConfigString("keyAlgorithm"), CAProvider: maputil.GetString(n.Config, "caProvider"),
Nameservers: n.getConfigString("nameservers"), CAProviderAccessId: maputil.GetString(n.Config, "caProviderAccessId"),
DnsPropagationTimeout: n.getConfigInt32("dnsPropagationTimeout"), CAProviderConfig: maputil.GetKVMapAny(n.Config, "caProviderConfig"),
DnsTTL: n.getConfigInt32("dnsTTL"), KeyAlgorithm: maputil.GetString(n.Config, "keyAlgorithm"),
DisableFollowCNAME: n.getConfigBool("disableFollowCNAME"), Nameservers: maputil.GetString(n.Config, "nameservers"),
DisableARI: n.getConfigBool("disableARI"), DnsPropagationWait: maputil.GetInt32(n.Config, "dnsPropagationWait"),
DnsPropagationTimeout: maputil.GetInt32(n.Config, "dnsPropagationTimeout"),
DnsTTL: maputil.GetInt32(n.Config, "dnsTTL"),
DisableFollowCNAME: maputil.GetBool(n.Config, "disableFollowCNAME"),
DisableARI: maputil.GetBool(n.Config, "disableARI"),
SkipBeforeExpiryDays: skipBeforeExpiryDays, SkipBeforeExpiryDays: skipBeforeExpiryDays,
} }
} }
func (n *WorkflowNode) GetConfigForUpload() WorkflowNodeConfigForUpload { func (n *WorkflowNode) GetConfigForUpload() WorkflowNodeConfigForUpload {
return WorkflowNodeConfigForUpload{ return WorkflowNodeConfigForUpload{
Certificate: n.getConfigString("certificate"), Certificate: maputil.GetString(n.Config, "certificate"),
PrivateKey: n.getConfigString("privateKey"), PrivateKey: maputil.GetString(n.Config, "privateKey"),
Domains: n.getConfigString("domains"), Domains: maputil.GetString(n.Config, "domains"),
} }
} }
func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy { func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy {
return WorkflowNodeConfigForDeploy{ return WorkflowNodeConfigForDeploy{
Certificate: n.getConfigString("certificate"), Certificate: maputil.GetString(n.Config, "certificate"),
Provider: n.getConfigString("provider"), Provider: maputil.GetString(n.Config, "provider"),
ProviderAccessId: n.getConfigString("providerAccessId"), ProviderAccessId: maputil.GetString(n.Config, "providerAccessId"),
ProviderConfig: n.getConfigMap("providerConfig"), ProviderConfig: maputil.GetKVMapAny(n.Config, "providerConfig"),
SkipOnLastSucceeded: n.getConfigBool("skipOnLastSucceeded"), SkipOnLastSucceeded: maputil.GetBool(n.Config, "skipOnLastSucceeded"),
} }
} }
func (n *WorkflowNode) GetConfigForNotify() WorkflowNodeConfigForNotify { func (n *WorkflowNode) GetConfigForNotify() WorkflowNodeConfigForNotify {
return WorkflowNodeConfigForNotify{ return WorkflowNodeConfigForNotify{
Channel: n.getConfigString("channel"), Channel: maputil.GetString(n.Config, "channel"),
Subject: n.getConfigString("subject"), Provider: maputil.GetString(n.Config, "provider"),
Message: n.getConfigString("message"), ProviderAccessId: maputil.GetString(n.Config, "providerAccessId"),
ProviderConfig: maputil.GetKVMapAny(n.Config, "providerConfig"),
Subject: maputil.GetString(n.Config, "subject"),
Message: maputil.GetString(n.Config, "message"),
} }
} }

View File

@ -0,0 +1,72 @@
package notify
import (
"context"
"fmt"
"log/slog"
"github.com/usual2970/certimate/internal/domain"
"github.com/usual2970/certimate/internal/pkg/core/notifier"
"github.com/usual2970/certimate/internal/repository"
)
type Notifier interface {
Notify(ctx context.Context) error
}
type NotifierWithWorkflowNodeConfig struct {
Node *domain.WorkflowNode
Logger *slog.Logger
Subject string
Message string
}
func NewWithWorkflowNode(config NotifierWithWorkflowNodeConfig) (Notifier, error) {
if config.Node == nil {
return nil, fmt.Errorf("node is nil")
}
if config.Node.Type != domain.WorkflowNodeTypeNotify {
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeNotify))
}
nodeConfig := config.Node.GetConfigForNotify()
options := &notifierProviderOptions{
Provider: domain.NotificationProviderType(nodeConfig.Provider),
ProviderAccessConfig: make(map[string]any),
ProviderExtendedConfig: nodeConfig.ProviderConfig,
}
accessRepo := repository.NewAccessRepository()
if nodeConfig.ProviderAccessId != "" {
access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId)
if err != nil {
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
} else {
options.ProviderAccessConfig = access.Config
}
}
notifierProvider, err := createNotifierProvider(options)
if err != nil {
return nil, err
}
return &notifierImpl{
provider: notifierProvider.WithLogger(config.Logger),
subject: config.Subject,
message: config.Message,
}, nil
}
type notifierImpl struct {
provider notifier.Notifier
subject string
message string
}
var _ Notifier = (*notifierImpl)(nil)
func (n *notifierImpl) Notify(ctx context.Context) error {
_, err := n.provider.Notify(ctx, n.subject, n.message)
return err
}

View File

@ -9,10 +9,11 @@ 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"
"github.com/usual2970/certimate/internal/pkg/utils/maputil" maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
"github.com/usual2970/certimate/internal/repository" "github.com/usual2970/certimate/internal/repository"
) )
// Deprecated: v0.4.x 将废弃
func SendToAllChannels(subject, message string) error { func SendToAllChannels(subject, message string) error {
notifiers, err := getEnabledNotifiers() notifiers, err := getEnabledNotifiers()
if err != nil { if err != nil {
@ -38,8 +39,9 @@ func SendToAllChannels(subject, message string) error {
return err return err
} }
// Deprecated: v0.4.x 将废弃
func SendToChannel(subject, message string, channel string, channelConfig map[string]any) error { func SendToChannel(subject, message string, channel string, channelConfig map[string]any) error {
notifier, err := createNotifier(domain.NotifyChannelType(channel), channelConfig) notifier, err := createNotifierProviderUseGlobalSettings(domain.NotifyChannelType(channel), channelConfig)
if err != nil { if err != nil {
return err return err
} }
@ -48,6 +50,7 @@ func SendToChannel(subject, message string, channel string, channelConfig map[st
return err return err
} }
// Deprecated: v0.4.x 将废弃
func getEnabledNotifiers() ([]notifier.Notifier, error) { func getEnabledNotifiers() ([]notifier.Notifier, error) {
settingsRepo := repository.NewSettingsRepository() settingsRepo := repository.NewSettingsRepository()
settings, err := settingsRepo.GetByName(context.Background(), "notifyChannels") settings, err := settingsRepo.GetByName(context.Background(), "notifyChannels")
@ -66,7 +69,7 @@ func getEnabledNotifiers() ([]notifier.Notifier, error) {
continue continue
} }
notifier, err := createNotifier(domain.NotifyChannelType(k), v) notifier, err := createNotifierProviderUseGlobalSettings(domain.NotifyChannelType(k), v)
if err != nil { if err != nil {
continue continue
} }

View File

@ -2,76 +2,152 @@ package notify
import ( import (
"fmt" "fmt"
"net/http"
"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"
pDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk" pDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk"
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" pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark"
pServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan" pMattermost "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram" pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram"
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/wecom"
"github.com/usual2970/certimate/internal/pkg/utils/maputil" httputil "github.com/usual2970/certimate/internal/pkg/utils/http"
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
) )
func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]any) (notifier.Notifier, error) { type notifierProviderOptions struct {
Provider domain.NotificationProviderType
ProviderAccessConfig map[string]any
ProviderExtendedConfig map[string]any
}
func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier, error) {
/* /*
注意如果追加新的常量值请保持以 ASCII 排序 注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order. NOTICE: If you add new constant, please keep ASCII order.
*/ */
switch channel { switch options.Provider {
case domain.NotifyChannelTypeBark: case domain.NotificationProviderTypeDingTalkBot:
return pBark.NewNotifier(&pBark.NotifierConfig{ {
DeviceKey: maputil.GetString(channelConfig, "deviceKey"), access := domain.AccessConfigForDingTalkBot{}
ServerUrl: maputil.GetString(channelConfig, "serverUrl"), if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
}) return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
case domain.NotifyChannelTypeDingTalk: return pDingTalk.NewNotifier(&pDingTalk.NotifierConfig{
return pDingTalk.NewNotifier(&pDingTalk.NotifierConfig{ WebhookUrl: access.WebhookUrl,
AccessToken: maputil.GetString(channelConfig, "accessToken"), Secret: access.Secret,
Secret: maputil.GetString(channelConfig, "secret"), })
}) }
case domain.NotifyChannelTypeEmail: case domain.NotificationProviderTypeEmail:
return pEmail.NewNotifier(&pEmail.NotifierConfig{ {
SmtpHost: maputil.GetString(channelConfig, "smtpHost"), access := domain.AccessConfigForEmail{}
SmtpPort: maputil.GetInt32(channelConfig, "smtpPort"), if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
SmtpTLS: maputil.GetOrDefaultBool(channelConfig, "smtpTLS", true), return nil, fmt.Errorf("failed to populate provider access config: %w", err)
Username: maputil.GetOrDefaultString(channelConfig, "username", maputil.GetString(channelConfig, "senderAddress")), }
Password: maputil.GetString(channelConfig, "password"),
SenderAddress: maputil.GetString(channelConfig, "senderAddress"),
ReceiverAddress: maputil.GetString(channelConfig, "receiverAddress"),
})
case domain.NotifyChannelTypeLark: return pEmail.NewNotifier(&pEmail.NotifierConfig{
return pLark.NewNotifier(&pLark.NotifierConfig{ SmtpHost: access.SmtpHost,
WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"), SmtpPort: access.SmtpPort,
}) SmtpTls: access.SmtpTls,
Username: access.Username,
Password: access.Password,
SenderAddress: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "senderAddress", access.DefaultSenderAddress),
ReceiverAddress: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "receiverAddress", access.DefaultReceiverAddress),
})
}
case domain.NotifyChannelTypeServerChan: case domain.NotificationProviderTypeLarkBot:
return pServerChan.NewNotifier(&pServerChan.NotifierConfig{ {
Url: maputil.GetString(channelConfig, "url"), access := domain.AccessConfigForLarkBot{}
}) if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
case domain.NotifyChannelTypeTelegram: return pLark.NewNotifier(&pLark.NotifierConfig{
return pTelegram.NewNotifier(&pTelegram.NotifierConfig{ WebhookUrl: access.WebhookUrl,
ApiToken: maputil.GetString(channelConfig, "apiToken"), })
ChatId: maputil.GetInt64(channelConfig, "chatId"), }
})
case domain.NotifyChannelTypeWebhook: case domain.NotificationProviderTypeMattermost:
return pWebhook.NewNotifier(&pWebhook.NotifierConfig{ {
Url: maputil.GetString(channelConfig, "url"), access := domain.AccessConfigForMattermost{}
AllowInsecureConnections: maputil.GetBool(channelConfig, "allowInsecureConnections"), if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
}) return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
case domain.NotifyChannelTypeWeCom: return pMattermost.NewNotifier(&pMattermost.NotifierConfig{
return pWeCom.NewNotifier(&pWeCom.NotifierConfig{ ServerUrl: access.ServerUrl,
WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"), Username: access.Username,
}) Password: access.Password,
ChannelId: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "channelId", access.DefaultChannelId),
})
}
case domain.NotificationProviderTypeTelegram:
{
access := domain.AccessConfigForTelegram{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
return pTelegram.NewNotifier(&pTelegram.NotifierConfig{
BotToken: access.BotToken,
ChatId: maputil.GetOrDefaultInt64(options.ProviderExtendedConfig, "chatId", access.DefaultChatId),
})
}
case domain.NotificationProviderTypeWebhook:
{
access := domain.AccessConfigForWebhook{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
mergedHeaders := make(map[string]string)
if defaultHeadersString := access.HeadersString; defaultHeadersString != "" {
h, err := httputil.ParseHeaders(defaultHeadersString)
if err != nil {
return nil, fmt.Errorf("failed to parse webhook headers: %w", err)
}
for key := range h {
mergedHeaders[http.CanonicalHeaderKey(key)] = h.Get(key)
}
}
if extendedHeadersString := maputil.GetString(options.ProviderExtendedConfig, "headers"); extendedHeadersString != "" {
h, err := httputil.ParseHeaders(extendedHeadersString)
if err != nil {
return nil, fmt.Errorf("failed to parse webhook headers: %w", err)
}
for key := range h {
mergedHeaders[http.CanonicalHeaderKey(key)] = h.Get(key)
}
}
return pWebhook.NewNotifier(&pWebhook.NotifierConfig{
WebhookUrl: access.Url,
WebhookData: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "webhookData", access.DefaultDataForNotification),
Method: access.Method,
Headers: mergedHeaders,
AllowInsecureConnections: access.AllowInsecureConnections,
})
}
case domain.NotificationProviderTypeWeComBot:
{
access := domain.AccessConfigForWeComBot{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
return pWeCom.NewNotifier(&pWeCom.NotifierConfig{
WebhookUrl: access.WebhookUrl,
})
}
} }
return nil, fmt.Errorf("unsupported notifier channel: %s", channelConfig) return nil, fmt.Errorf("unsupported notifier provider '%s'", options.Provider)
} }

View File

@ -0,0 +1,108 @@
package notify
import (
"fmt"
"github.com/usual2970/certimate/internal/domain"
"github.com/usual2970/certimate/internal/pkg/core/notifier"
pBark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/bark"
pDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk"
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
pGotify "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/gotify"
pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark"
pMattermost "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
pPushover "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushover"
pPushPlus "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushplus"
pServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan"
pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram"
pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook"
pWeCom "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecom"
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
)
// Deprecated: v0.4.x 将废弃
func createNotifierProviderUseGlobalSettings(channel domain.NotifyChannelType, channelConfig map[string]any) (notifier.Notifier, error) {
/*
注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order.
*/
switch channel {
case domain.NotifyChannelTypeBark:
return pBark.NewNotifier(&pBark.NotifierConfig{
DeviceKey: maputil.GetString(channelConfig, "deviceKey"),
ServerUrl: maputil.GetString(channelConfig, "serverUrl"),
})
case domain.NotifyChannelTypeDingTalk:
return pDingTalk.NewNotifier(&pDingTalk.NotifierConfig{
WebhookUrl: "https://oapi.dingtalk.com/robot/send?access_token=" + maputil.GetString(channelConfig, "accessToken"),
Secret: maputil.GetString(channelConfig, "secret"),
})
case domain.NotifyChannelTypeEmail:
return pEmail.NewNotifier(&pEmail.NotifierConfig{
SmtpHost: maputil.GetString(channelConfig, "smtpHost"),
SmtpPort: maputil.GetInt32(channelConfig, "smtpPort"),
SmtpTls: maputil.GetOrDefaultBool(channelConfig, "smtpTLS", true),
Username: maputil.GetOrDefaultString(channelConfig, "username", maputil.GetString(channelConfig, "senderAddress")),
Password: maputil.GetString(channelConfig, "password"),
SenderAddress: maputil.GetString(channelConfig, "senderAddress"),
ReceiverAddress: maputil.GetString(channelConfig, "receiverAddress"),
})
case domain.NotifyChannelTypeGotify:
return pGotify.NewNotifier(&pGotify.NotifierConfig{
Url: maputil.GetString(channelConfig, "url"),
Token: maputil.GetString(channelConfig, "token"),
Priority: maputil.GetOrDefaultInt64(channelConfig, "priority", 1),
})
case domain.NotifyChannelTypeLark:
return pLark.NewNotifier(&pLark.NotifierConfig{
WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"),
})
case domain.NotifyChannelTypeMattermost:
return pMattermost.NewNotifier(&pMattermost.NotifierConfig{
ServerUrl: maputil.GetString(channelConfig, "serverUrl"),
ChannelId: maputil.GetString(channelConfig, "channelId"),
Username: maputil.GetString(channelConfig, "username"),
Password: maputil.GetString(channelConfig, "password"),
})
case domain.NotifyChannelTypePushover:
return pPushover.NewNotifier(&pPushover.NotifierConfig{
Token: maputil.GetString(channelConfig, "token"),
User: maputil.GetString(channelConfig, "user"),
})
case domain.NotifyChannelTypePushPlus:
return pPushPlus.NewNotifier(&pPushPlus.NotifierConfig{
Token: maputil.GetString(channelConfig, "token"),
})
case domain.NotifyChannelTypeServerChan:
return pServerChan.NewNotifier(&pServerChan.NotifierConfig{
Url: maputil.GetString(channelConfig, "url"),
})
case domain.NotifyChannelTypeTelegram:
return pTelegram.NewNotifier(&pTelegram.NotifierConfig{
BotToken: maputil.GetString(channelConfig, "apiToken"),
ChatId: maputil.GetInt64(channelConfig, "chatId"),
})
case domain.NotifyChannelTypeWebhook:
return pWebhook.NewNotifier(&pWebhook.NotifierConfig{
WebhookUrl: maputil.GetString(channelConfig, "url"),
AllowInsecureConnections: maputil.GetBool(channelConfig, "allowInsecureConnections"),
})
case domain.NotifyChannelTypeWeCom:
return pWeCom.NewNotifier(&pWeCom.NotifierConfig{
WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"),
})
}
return nil, fmt.Errorf("unsupported notifier channel '%s'", channelConfig)
}

View File

@ -8,25 +8,30 @@ import (
"github.com/usual2970/certimate/internal/domain/dtos" "github.com/usual2970/certimate/internal/domain/dtos"
) )
// Deprecated: v0.4.x 将废弃
const ( const (
notifyTestTitle = "测试通知" notifyTestTitle = "测试通知"
notifyTestBody = "欢迎使用 Certimate ,这是一条测试通知。" notifyTestBody = "欢迎使用 Certimate ,这是一条测试通知。"
) )
// Deprecated: v0.4.x 将废弃
type settingsRepository interface { type settingsRepository interface {
GetByName(ctx context.Context, name string) (*domain.Settings, error) GetByName(ctx context.Context, name string) (*domain.Settings, error)
} }
// Deprecated: v0.4.x 将废弃
type NotifyService struct { type NotifyService struct {
settingsRepo settingsRepository settingsRepo settingsRepository
} }
// Deprecated: v0.4.x 将废弃
func NewNotifyService(settingsRepo settingsRepository) *NotifyService { func NewNotifyService(settingsRepo settingsRepository) *NotifyService {
return &NotifyService{ return &NotifyService{
settingsRepo: settingsRepo, settingsRepo: settingsRepo,
} }
} }
// Deprecated: v0.4.x 将废弃
func (n *NotifyService) Test(ctx context.Context, req *dtos.NotifyTestPushReq) error { func (n *NotifyService) Test(ctx context.Context, req *dtos.NotifyTestPushReq) error {
settings, err := n.settingsRepo.GetByName(ctx, "notifyChannels") settings, err := n.settingsRepo.GetByName(ctx, "notifyChannels")
if err != nil { if err != nil {

View File

@ -1,4 +1,4 @@
package acmehttpreq package acmehttpreq
import ( import (
"net/url" "net/url"

View File

@ -0,0 +1,40 @@
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
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
}

View File

@ -0,0 +1,266 @@
package lego_aliyunesa
import (
"errors"
"fmt"
"strings"
"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,
}, 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)
}
siteId, err := d.getSiteId(authZone)
if err != nil {
return fmt.Errorf("alicloud-esa: could not find site for zone %q: %w", authZone, err)
}
if err := d.addOrUpdateDNSRecord(siteId, strings.TrimRight(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)
}
siteId, err := d.getSiteId(authZone)
if err != nil {
return fmt.Errorf("alicloud-esa: could not find site for zone %q: %w", authZone, err)
}
if err := d.removeDNSRecord(siteId, strings.TrimRight(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),
PageNumber: tea.Int32(int32(pageNumber)),
PageSize: tea.Int32(int32(pageNumber)),
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("failed to get site id")
}
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),
PageNumber: tea.Int32(int32(pageNumber)),
PageSize: tea.Int32(int32(pageNumber)),
}
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
}
}

View File

@ -6,7 +6,7 @@ import (
"github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/azuredns" "github.com/go-acme/lego/v4/providers/dns/azuredns"
azcommon "github.com/usual2970/certimate/internal/pkg/vendors/azure-sdk/common" azcommon "github.com/usual2970/certimate/internal/pkg/sdk3rd/azure/common"
) )
type ChallengeProviderConfig struct { type ChallengeProviderConfig struct {

View File

@ -1,4 +1,4 @@
package lego_baiducloud package lego_baiducloud
import ( import (
"errors" "errors"
@ -89,7 +89,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("baiducloud: %w", err) return fmt.Errorf("baiducloud: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
@ -109,7 +109,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("baiducloud: %w", err) return fmt.Errorf("baiducloud: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
@ -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
} }

View File

@ -0,0 +1,36 @@
package bunny
import (
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/bunny"
)
type ChallengeProviderConfig struct {
ApiKey string `json:"apiKey"`
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 := bunny.NewDefaultConfig()
providerConfig.APIKey = config.ApiKey
if config.DnsPropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
}
if config.DnsTTL != 0 {
providerConfig.TTL = int(config.DnsTTL)
}
provider, err := bunny.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -9,6 +9,7 @@ import (
type ChallengeProviderConfig struct { type ChallengeProviderConfig struct {
DnsApiToken string `json:"dnsApiToken"` DnsApiToken string `json:"dnsApiToken"`
ZoneApiToken string `json:"zoneApiToken,omitempty"`
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
DnsTTL int32 `json:"dnsTTL,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"`
} }
@ -20,6 +21,7 @@ func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider,
providerConfig := cloudflare.NewDefaultConfig() providerConfig := cloudflare.NewDefaultConfig()
providerConfig.AuthToken = config.DnsApiToken providerConfig.AuthToken = config.DnsApiToken
providerConfig.ZoneToken = config.ZoneApiToken
if config.DnsPropagationTimeout != 0 { if config.DnsPropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
} }

View File

@ -93,7 +93,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
zoneName, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) zoneName, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("cmccecloud: %w", err) return fmt.Errorf("cmccecloud: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zoneName) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zoneName)
@ -108,33 +108,33 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
} }
if record == nil { if record == nil {
// add new record
resp, err := d.client.CreateRecordOpenapi(&model.CreateRecordOpenapiRequest{ resp, err := d.client.CreateRecordOpenapi(&model.CreateRecordOpenapiRequest{
CreateRecordOpenapiBody: &model.CreateRecordOpenapiBody{ CreateRecordOpenapiBody: &model.CreateRecordOpenapiBody{
LineId: "0", // 默认线路 LineId: "0", // 默认线路
Rr: subDomain, Rr: subDomain,
DomainName: readDomain, DomainName: readDomain,
Description: "from certimate", Description: "certimate acme",
Type: model.CreateRecordOpenapiBodyTypeEnumTxt, Type: model.CreateRecordOpenapiBodyTypeEnumTxt,
Value: info.Value, Value: info.Value,
Ttl: &d.config.TTL, Ttl: &d.config.TTL,
}, },
}) })
if err != nil { if err != nil {
return fmt.Errorf("lego: %w", err) return fmt.Errorf("cmccecloud: %w", err)
} }
if resp.State != model.CreateRecordOpenapiResponseStateEnumOk { if resp.State != model.CreateRecordOpenapiResponseStateEnumOk {
return fmt.Errorf("lego: create record failed, response state: %s, message: %s, code: %s", resp.State, resp.ErrorMessage, resp.ErrorCode) return fmt.Errorf("cmccecloud: create record failed, response state: %s, message: %s, code: %s", resp.State, resp.ErrorMessage, resp.ErrorCode)
} }
return nil return nil
} else { } else {
// update record
resp, err := d.client.ModifyRecordOpenapi(&model.ModifyRecordOpenapiRequest{ resp, err := d.client.ModifyRecordOpenapi(&model.ModifyRecordOpenapiRequest{
ModifyRecordOpenapiBody: &model.ModifyRecordOpenapiBody{ ModifyRecordOpenapiBody: &model.ModifyRecordOpenapiBody{
RecordId: record.RecordId, RecordId: record.RecordId,
Rr: subDomain, Rr: subDomain,
DomainName: readDomain, DomainName: readDomain,
Description: "from certmate", Description: "certmate acme",
LineId: "0", LineId: "0",
Type: model.ModifyRecordOpenapiBodyTypeEnumTxt, Type: model.ModifyRecordOpenapiBodyTypeEnumTxt,
Value: info.Value, Value: info.Value,
@ -142,44 +142,52 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
}, },
}) })
if err != nil { if err != nil {
return fmt.Errorf("lego: %w", err) return fmt.Errorf("cmccecloud: %w", err)
} }
if resp.State != model.ModifyRecordOpenapiResponseStateEnumOk { if resp.State != model.ModifyRecordOpenapiResponseStateEnumOk {
return fmt.Errorf("lego: create record failed, response state: %s", resp.State) return fmt.Errorf("cmccecloud: create record failed, response state: %s", resp.State)
} }
return nil return nil
} }
} }
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
challengeInfo := dns01.GetChallengeInfo(domain, keyAuth) challengeInfo := dns01.GetChallengeInfo(domain, keyAuth)
zoneName, err := dns01.FindZoneByFqdn(challengeInfo.FQDN) zoneName, err := dns01.FindZoneByFqdn(challengeInfo.FQDN)
if err != nil { if err != nil {
return fmt.Errorf("cmccecloud: %w", err) return fmt.Errorf("cmccecloud: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(challengeInfo.FQDN, zoneName) subDomain, err := dns01.ExtractSubDomain(challengeInfo.FQDN, zoneName)
if err != nil { if err != nil {
return fmt.Errorf("cmccecloud: %w", err) return fmt.Errorf("cmccecloud: %w", err)
} }
readDomain := strings.Trim(zoneName, ".") readDomain := strings.Trim(zoneName, ".")
record, err := d.getDomainRecord(readDomain, subDomain) record, err := d.getDomainRecord(readDomain, subDomain)
if err != nil { if err != nil {
return err return err
} }
if record == nil { if record == nil {
return nil return nil
} else {
resp, err := d.client.DeleteRecordOpenapi(&model.DeleteRecordOpenapiRequest{
DeleteRecordOpenapiBody: &model.DeleteRecordOpenapiBody{
RecordIdList: []string{record.RecordId},
},
})
if err != nil {
return fmt.Errorf("cmccecloud: %w", err)
}
if resp.State != model.DeleteRecordOpenapiResponseStateEnumOk {
return fmt.Errorf("cmccecloud: delete record failed, unexpected response state: %s", resp.State)
}
} }
resp, err := d.client.DeleteRecordOpenapi(&model.DeleteRecordOpenapiRequest{
DeleteRecordOpenapiBody: &model.DeleteRecordOpenapiBody{
RecordIdList: []string{record.RecordId},
},
})
if err != nil {
return fmt.Errorf("lego: %w", err)
}
if resp.State != model.DeleteRecordOpenapiResponseStateEnumOk {
return fmt.Errorf("lego: delete record failed, response state: %s", resp.State)
}
return nil return nil
} }
@ -205,8 +213,9 @@ func (d *DNSProvider) getDomainRecord(domain string, rr string) (*model.ListReco
} }
if resp.State != model.ListRecordOpenapiResponseStateEnumOk { if resp.State != model.ListRecordOpenapiResponseStateEnumOk {
respStr, _ := json.Marshal(resp) respStr, _ := json.Marshal(resp)
return nil, fmt.Errorf("request error. %s", string(respStr)) return nil, fmt.Errorf("cmccecloud: request error: %s", string(respStr))
} }
if resp.Body.Data != nil { if resp.Body.Data != nil {
for _, item := range *resp.Body.Data { for _, item := range *resp.Body.Data {
if item.Rr == rr { if item.Rr == rr {
@ -214,9 +223,11 @@ func (d *DNSProvider) getDomainRecord(domain string, rr string) (*model.ListReco
} }
} }
} }
if resp.Body.TotalPages == nil || page >= *resp.Body.TotalPages { if resp.Body.TotalPages == nil || page >= *resp.Body.TotalPages {
return nil, nil return nil, nil
} }
page++ page++
} }
} }

View File

@ -1,4 +1,4 @@
package lego_dnsla package lego_dnsla
import ( import (
"errors" "errors"
@ -10,7 +10,7 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01" "github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env" "github.com/go-acme/lego/v4/platform/config/env"
dnslasdk "github.com/usual2970/certimate/internal/pkg/vendors/dnsla-sdk" dnslasdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/dnsla"
) )
const ( const (
@ -83,7 +83,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("dnsla: %w", err) return fmt.Errorf("dnsla: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
@ -103,7 +103,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("dnsla: %w", err) return fmt.Errorf("dnsla: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)

View File

@ -1,4 +1,4 @@
package lego_dynv6 package lego_dynv6
import ( import (
"context" "context"
@ -76,7 +76,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("dynv6: %w", err) return fmt.Errorf("dynv6: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
@ -96,7 +96,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("dynv6: %w", err) return fmt.Errorf("dynv6: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
@ -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
} }

View File

@ -1,4 +1,4 @@
package lego_gname package lego_gname
import ( import (
"errors" "errors"
@ -9,7 +9,7 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01" "github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env" "github.com/go-acme/lego/v4/platform/config/env"
gnamesdk "github.com/usual2970/certimate/internal/pkg/vendors/gname-sdk" gnamesdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/gname"
) )
const ( const (
@ -82,7 +82,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("gname: %w", err) return fmt.Errorf("gname: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
@ -102,7 +102,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("gname: %w", err) return fmt.Errorf("gname: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
@ -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
} }

View File

@ -1,4 +1,4 @@
package lego_jdcloud package lego_jdcloud
import ( import (
"errors" "errors"
@ -91,7 +91,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("jdcloud: %w", err) return fmt.Errorf("jdcloud: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
@ -111,7 +111,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("jdcloud: %w", err) return fmt.Errorf("jdcloud: could not find zone for domain %q: %w", domain, err)
} }
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)

View File

@ -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"` ApiUrl string `json:"apiUrl"`
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) {
@ -24,6 +27,13 @@ func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider,
providerConfig := pdns.NewDefaultConfig() providerConfig := pdns.NewDefaultConfig()
providerConfig.Host = host providerConfig.Host = host
providerConfig.APIKey = config.ApiKey providerConfig.APIKey = config.ApiKey
if config.AllowInsecureConnections {
providerConfig.HTTPClient.Transport = &http.Transport{
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
} }

View File

@ -1,4 +1,4 @@
package lego_tencentcloudeo package lego_tencentcloudeo
import ( import (
"errors" "errors"
@ -20,7 +20,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 +33,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 +56,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 +64,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)
} }
@ -112,12 +112,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 +141,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 +153,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 +169,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 +179,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 +191,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 +200,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

View File

@ -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
} }

View File

@ -1,4 +1,4 @@
package deployer package deployer
import ( import (
"context" "context"
@ -14,13 +14,13 @@ type Deployer interface {
// //
// 入参: // 入参:
// - ctx上下文。 // - ctx上下文。
// - certPem:证书 PEM 内容。 // - certPEM:证书 PEM 内容。
// - privkeyPem:私钥 PEM 内容。 // - privkeyPEM:私钥 PEM 内容。
// //
// 出参: // 出参:
// - 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)
} }
// 表示证书部署结果的数据结构。 // 表示证书部署结果的数据结构。

View File

@ -1,16 +1,15 @@
package onepanelconsole package onepanelconsole
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"net/url" "net/url"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
opsdk "github.com/usual2970/certimate/internal/pkg/vendors/1panel-sdk" opsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
) )
type DeployerConfig struct { type DeployerConfig struct {
@ -39,7 +38,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections) client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -58,11 +57,11 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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 := &opsdk.UpdateSystemSSLRequest{
Cert: certPem, Cert: certPEM,
Key: privkeyPem, Key: privkeyPEM,
SSL: "enable", SSL: "enable",
SSLType: "import-paste", SSLType: "import-paste",
} }
@ -74,13 +73,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
updateSystemSSLResp, err := d.sdkClient.UpdateSystemSSL(updateSystemSSLReq) updateSystemSSLResp, err := d.sdkClient.UpdateSystemSSL(updateSystemSSLReq)
d.logger.Debug("sdk request '1panel.UpdateSystemSSL'", slog.Any("request", updateSystemSSLReq), slog.Any("response", updateSystemSSLResp)) d.logger.Debug("sdk request '1panel.UpdateSystemSSL'", slog.Any("request", updateSystemSSLReq), slog.Any("response", updateSystemSSLResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UpdateSystemSSL'") return nil, fmt.Errorf("failed to execute sdk request '1panel.UpdateSystemSSL': %w", err)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
} }
func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) { func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*opsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil { if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid 1panel api url") return nil, errors.New("invalid 1panel api url")
} }
@ -90,7 +89,7 @@ func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client,
} }
client := opsdk.NewClient(apiUrl, apiKey) client := opsdk.NewClient(apiUrl, apiKey)
if allowInsecure { if skipTlsVerify {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
} }

View File

@ -1,4 +1,4 @@
package onepanelconsole_test package onepanelconsole_test
import ( import (
"context" "context"

View File

@ -1,19 +1,18 @@
package onepanelsite package onepanelsite
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"net/url" "net/url"
"strconv" "strconv"
xerrors "github.com/pkg/errors"
"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/vendors/1panel-sdk" opsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
) )
type DeployerConfig struct { type DeployerConfig struct {
@ -23,8 +22,14 @@ type DeployerConfig struct {
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
// 是否允许不安全的连接。 // 是否允许不安全的连接。
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
// 部署资源类型。
ResourceType ResourceType `json:"resourceType"`
// 网站 ID。 // 网站 ID。
WebsiteId int64 `json:"websiteId"` // 部署资源类型为 [RESOURCE_TYPE_WEBSITE] 时必填。
WebsiteId int64 `json:"websiteId,omitempty"`
// 证书 ID。
// 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。
CertificateId int64 `json:"certificateId,omitempty"`
} }
type DeployerProvider struct { type DeployerProvider struct {
@ -43,7 +48,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections) client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
@ -51,7 +56,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
ApiKey: config.ApiKey, ApiKey: config.ApiKey,
}) })
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -72,7 +77,31 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// 根据部署资源类型决定部署方式
switch d.config.ResourceType {
case RESOURCE_TYPE_WEBSITE:
if err := d.deployToWebsite(ctx, certPEM, privkeyPEM); err != nil {
return nil, err
}
case RESOURCE_TYPE_CERTIFICATE:
if err := d.deployToCertificate(ctx, certPEM, privkeyPEM); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
}
return &deployer.DeployResult{}, nil
}
func (d *DeployerProvider) deployToWebsite(ctx context.Context, certPEM string, privkeyPEM string) error {
if d.config.WebsiteId == 0 {
return errors.New("config `websiteId` is required")
}
// 获取网站 HTTPS 配置 // 获取网站 HTTPS 配置
getHttpsConfReq := &opsdk.GetHttpsConfRequest{ getHttpsConfReq := &opsdk.GetHttpsConfRequest{
WebsiteID: d.config.WebsiteId, WebsiteID: d.config.WebsiteId,
@ -80,13 +109,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
getHttpsConfResp, err := d.sdkClient.GetHttpsConf(getHttpsConfReq) getHttpsConfResp, err := d.sdkClient.GetHttpsConf(getHttpsConfReq)
d.logger.Debug("sdk request '1panel.GetHttpsConf'", slog.Any("request", getHttpsConfReq), slog.Any("response", getHttpsConfResp)) d.logger.Debug("sdk request '1panel.GetHttpsConf'", slog.Any("request", getHttpsConfReq), slog.Any("response", getHttpsConfResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.GetHttpsConf'") return fmt.Errorf("failed to execute sdk request '1panel.GetHttpsConf': %w", err)
} }
// 上传证书到面板 // 上传证书到面板
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -106,13 +135,45 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
updateHttpsConfResp, err := d.sdkClient.UpdateHttpsConf(updateHttpsConfReq) updateHttpsConfResp, err := d.sdkClient.UpdateHttpsConf(updateHttpsConfReq)
d.logger.Debug("sdk request '1panel.UpdateHttpsConf'", slog.Any("request", updateHttpsConfReq), slog.Any("response", updateHttpsConfResp)) d.logger.Debug("sdk request '1panel.UpdateHttpsConf'", slog.Any("request", updateHttpsConfReq), slog.Any("response", updateHttpsConfResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UpdateHttpsConf'") return fmt.Errorf("failed to execute sdk request '1panel.UpdateHttpsConf': %w", err)
} }
return &deployer.DeployResult{}, nil return nil
} }
func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) { func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM string, privkeyPEM string) error {
if d.config.CertificateId == 0 {
return errors.New("config `certificateId` is required")
}
// 获取证书详情
getWebsiteSSLReq := &opsdk.GetWebsiteSSLRequest{
SSLID: d.config.CertificateId,
}
getWebsiteSSLResp, err := d.sdkClient.GetWebsiteSSL(getWebsiteSSLReq)
d.logger.Debug("sdk request '1panel.GetWebsiteSSL'", slog.Any("request", getWebsiteSSLReq), slog.Any("response", getWebsiteSSLResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request '1panel.GetWebsiteSSL': %w", err)
}
// 更新证书
uploadWebsiteSSLReq := &opsdk.UploadWebsiteSSLRequest{
Type: "paste",
SSLID: d.config.CertificateId,
Description: getWebsiteSSLResp.Data.Description,
Certificate: certPEM,
PrivateKey: privkeyPEM,
}
uploadWebsiteSSLResp, err := d.sdkClient.UploadWebsiteSSL(uploadWebsiteSSLReq)
d.logger.Debug("sdk request '1panel.UploadWebsiteSSL'", slog.Any("request", uploadWebsiteSSLReq), slog.Any("response", uploadWebsiteSSLResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request '1panel.UploadWebsiteSSL': %w", err)
}
return nil
}
func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*opsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil { if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid 1panel api url") return nil, errors.New("invalid 1panel api url")
} }
@ -122,7 +183,7 @@ func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client,
} }
client := opsdk.NewClient(apiUrl, apiKey) client := opsdk.NewClient(apiUrl, apiKey)
if allowInsecure { if skipTlsVerify {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
} }

View File

@ -1,4 +1,4 @@
package onepanelsite_test package onepanelsite_test
import ( import (
"context" "context"
@ -20,7 +20,7 @@ var (
) )
func init() { func init() {
argsPrefix := "CERTIMATE_DEPLOYER_1PANELCONSOLE_" argsPrefix := "CERTIMATE_DEPLOYER_1PANELSITE_"
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
@ -32,12 +32,12 @@ func init() {
/* /*
Shell command to run this test: Shell command to run this test:
go test -v ./1panel_console_test.go -args \ go test -v ./1panel_site_test.go -args \
--CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ --CERTIMATE_DEPLOYER_1PANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
--CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \ --CERTIMATE_DEPLOYER_1PANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIURL="http://127.0.0.1:20410" \ --CERTIMATE_DEPLOYER_1PANELSITE_APIURL="http://127.0.0.1:20410" \
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIKEY="your-api-key" \ --CERTIMATE_DEPLOYER_1PANELSITE_APIKEY="your-api-key" \
--CERTIMATE_DEPLOYER_1PANELCONSOLE_WEBSITEID="your-website-id" --CERTIMATE_DEPLOYER_1PANELSITE_WEBSITEID="your-website-id"
*/ */
func TestDeploy(t *testing.T) { func TestDeploy(t *testing.T) {
flag.Parse() flag.Parse()
@ -55,8 +55,9 @@ func TestDeploy(t *testing.T) {
deployer, err := provider.NewDeployer(&provider.DeployerConfig{ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
ApiUrl: fApiUrl, ApiUrl: fApiUrl,
ApiKey: fApiKey, ApiKey: fApiKey,
WebsiteId: fWebsiteId,
AllowInsecureConnections: true, AllowInsecureConnections: true,
ResourceType: provider.RESOURCE_TYPE_WEBSITE,
WebsiteId: fWebsiteId,
}) })
if err != nil { if err != nil {
t.Errorf("err: %+v", err) t.Errorf("err: %+v", err)

View File

@ -0,0 +1,10 @@
package onepanelsite
type ResourceType string
const (
// 资源类型:替换指定网站的证书。
RESOURCE_TYPE_WEBSITE = ResourceType("website")
// 资源类型:替换指定证书。
RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate")
)

View File

@ -1,4 +1,4 @@
package aliyunalb package aliyunalb
import ( import (
"context" "context"
@ -13,7 +13,6 @@ import (
alicas "github.com/alibabacloud-go/cas-20200407/v3/client" alicas "github.com/alibabacloud-go/cas-20200407/v3/client"
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
xerrors "github.com/pkg/errors"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
@ -62,12 +61,12 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
clients, err := createSdkClients(config.AccessKeyId, config.AccessKeySecret, config.Region) clients, err := createSdkClients(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk clients") 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.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -88,11 +87,11 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// 上传证书到 CAS // 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -110,7 +109,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
} }
default: default:
return nil, fmt.Errorf("unsupported resource type: %s", d.config.ResourceType) return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
@ -129,7 +128,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
getLoadBalancerAttributeResp, err := d.sdkClients.ALB.GetLoadBalancerAttribute(getLoadBalancerAttributeReq) getLoadBalancerAttributeResp, err := d.sdkClients.ALB.GetLoadBalancerAttribute(getLoadBalancerAttributeReq)
d.logger.Debug("sdk request 'alb.GetLoadBalancerAttribute'", slog.Any("request", getLoadBalancerAttributeReq), slog.Any("response", getLoadBalancerAttributeResp)) d.logger.Debug("sdk request 'alb.GetLoadBalancerAttribute'", slog.Any("request", getLoadBalancerAttributeReq), slog.Any("response", getLoadBalancerAttributeResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'alb.GetLoadBalancerAttribute'") return fmt.Errorf("failed to execute sdk request 'alb.GetLoadBalancerAttribute': %w", err)
} }
// 查询 HTTPS 监听列表 // 查询 HTTPS 监听列表
@ -138,6 +137,12 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
listListenersLimit := int32(100) listListenersLimit := int32(100)
var listListenersToken *string = nil var listListenersToken *string = nil
for { for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
listListenersReq := &alialb.ListListenersRequest{ listListenersReq := &alialb.ListListenersRequest{
MaxResults: tea.Int32(listListenersLimit), MaxResults: tea.Int32(listListenersLimit),
NextToken: listListenersToken, NextToken: listListenersToken,
@ -147,7 +152,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
listListenersResp, err := d.sdkClients.ALB.ListListeners(listListenersReq) listListenersResp, err := d.sdkClients.ALB.ListListeners(listListenersReq)
d.logger.Debug("sdk request 'alb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp)) d.logger.Debug("sdk request 'alb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'alb.ListListeners'") return fmt.Errorf("failed to execute sdk request 'alb.ListListeners': %w", err)
} }
if listListenersResp.Body.Listeners != nil { if listListenersResp.Body.Listeners != nil {
@ -167,6 +172,12 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
// REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-listlisteners // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-listlisteners
listListenersToken = nil listListenersToken = nil
for { for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
listListenersReq := &alialb.ListListenersRequest{ listListenersReq := &alialb.ListListenersRequest{
MaxResults: tea.Int32(listListenersLimit), MaxResults: tea.Int32(listListenersLimit),
NextToken: listListenersToken, NextToken: listListenersToken,
@ -176,7 +187,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
listListenersResp, err := d.sdkClients.ALB.ListListeners(listListenersReq) listListenersResp, err := d.sdkClients.ALB.ListListeners(listListenersReq)
d.logger.Debug("sdk request 'alb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp)) d.logger.Debug("sdk request 'alb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'alb.ListListeners'") return fmt.Errorf("failed to execute sdk request 'alb.ListListeners': %w", err)
} }
if listListenersResp.Body.Listeners != nil { if listListenersResp.Body.Listeners != nil {
@ -235,7 +246,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
getListenerAttributeResp, err := d.sdkClients.ALB.GetListenerAttribute(getListenerAttributeReq) getListenerAttributeResp, err := d.sdkClients.ALB.GetListenerAttribute(getListenerAttributeReq)
d.logger.Debug("sdk request 'alb.GetListenerAttribute'", slog.Any("request", getListenerAttributeReq), slog.Any("response", getListenerAttributeResp)) d.logger.Debug("sdk request 'alb.GetListenerAttribute'", slog.Any("request", getListenerAttributeReq), slog.Any("response", getListenerAttributeResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'alb.GetListenerAttribute'") return fmt.Errorf("failed to execute sdk request 'alb.GetListenerAttribute': %w", err)
} }
if d.config.Domain == "" { if d.config.Domain == "" {
@ -252,7 +263,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
updateListenerAttributeResp, err := d.sdkClients.ALB.UpdateListenerAttribute(updateListenerAttributeReq) updateListenerAttributeResp, err := d.sdkClients.ALB.UpdateListenerAttribute(updateListenerAttributeReq)
d.logger.Debug("sdk request 'alb.UpdateListenerAttribute'", slog.Any("request", updateListenerAttributeReq), slog.Any("response", updateListenerAttributeResp)) d.logger.Debug("sdk request 'alb.UpdateListenerAttribute'", slog.Any("request", updateListenerAttributeReq), slog.Any("response", updateListenerAttributeResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'alb.UpdateListenerAttribute'") return fmt.Errorf("failed to execute sdk request 'alb.UpdateListenerAttribute': %w", err)
} }
} else { } else {
// 指定 SNI需部署到扩展域名 // 指定 SNI需部署到扩展域名
@ -263,6 +274,12 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
listListenerCertificatesLimit := int32(100) listListenerCertificatesLimit := int32(100)
var listListenerCertificatesToken *string = nil var listListenerCertificatesToken *string = nil
for { for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
listListenerCertificatesReq := &alialb.ListListenerCertificatesRequest{ listListenerCertificatesReq := &alialb.ListListenerCertificatesRequest{
NextToken: listListenerCertificatesToken, NextToken: listListenerCertificatesToken,
MaxResults: tea.Int32(listListenerCertificatesLimit), MaxResults: tea.Int32(listListenerCertificatesLimit),
@ -272,7 +289,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
listListenerCertificatesResp, err := d.sdkClients.ALB.ListListenerCertificates(listListenerCertificatesReq) listListenerCertificatesResp, err := d.sdkClients.ALB.ListListenerCertificates(listListenerCertificatesReq)
d.logger.Debug("sdk request 'alb.ListListenerCertificates'", slog.Any("request", listListenerCertificatesReq), slog.Any("response", listListenerCertificatesResp)) d.logger.Debug("sdk request 'alb.ListListenerCertificates'", slog.Any("request", listListenerCertificatesReq), slog.Any("response", listListenerCertificatesResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'alb.ListListenerCertificates'") return fmt.Errorf("failed to execute sdk request 'alb.ListListenerCertificates': %w", err)
} }
if listListenerCertificatesResp.Body.Certificates != nil { if listListenerCertificatesResp.Body.Certificates != nil {
@ -331,7 +348,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
} }
} }
errs = append(errs, xerrors.Wrap(err, "failed to execute sdk request 'cas.GetUserCertificateDetail'")) errs = append(errs, fmt.Errorf("failed to execute sdk request 'cas.GetUserCertificateDetail': %w", err))
continue continue
} else { } else {
certCNMatched := tea.StringValue(getUserCertificateDetailResp.Body.Common) == d.config.Domain certCNMatched := tea.StringValue(getUserCertificateDetailResp.Body.Common) == d.config.Domain
@ -368,7 +385,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
associateAdditionalCertificatesFromListenerResp, err := d.sdkClients.ALB.AssociateAdditionalCertificatesWithListener(associateAdditionalCertificatesFromListenerReq) associateAdditionalCertificatesFromListenerResp, err := d.sdkClients.ALB.AssociateAdditionalCertificatesWithListener(associateAdditionalCertificatesFromListenerReq)
d.logger.Debug("sdk request 'alb.AssociateAdditionalCertificatesWithListener'", slog.Any("request", associateAdditionalCertificatesFromListenerReq), slog.Any("response", associateAdditionalCertificatesFromListenerResp)) d.logger.Debug("sdk request 'alb.AssociateAdditionalCertificatesWithListener'", slog.Any("request", associateAdditionalCertificatesFromListenerReq), slog.Any("response", associateAdditionalCertificatesFromListenerResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'alb.AssociateAdditionalCertificatesWithListener'") return fmt.Errorf("failed to execute sdk request 'alb.AssociateAdditionalCertificatesWithListener': %w", err)
} }
} }
@ -389,7 +406,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
dissociateAdditionalCertificatesFromListenerResp, err := d.sdkClients.ALB.DissociateAdditionalCertificatesFromListener(dissociateAdditionalCertificatesFromListenerReq) dissociateAdditionalCertificatesFromListenerResp, err := d.sdkClients.ALB.DissociateAdditionalCertificatesFromListener(dissociateAdditionalCertificatesFromListenerReq)
d.logger.Debug("sdk request 'alb.DissociateAdditionalCertificatesFromListener'", slog.Any("request", dissociateAdditionalCertificatesFromListenerReq), slog.Any("response", dissociateAdditionalCertificatesFromListenerResp)) d.logger.Debug("sdk request 'alb.DissociateAdditionalCertificatesFromListener'", slog.Any("request", dissociateAdditionalCertificatesFromListenerReq), slog.Any("response", dissociateAdditionalCertificatesFromListenerResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'alb.DissociateAdditionalCertificatesFromListener'") return fmt.Errorf("failed to execute sdk request 'alb.DissociateAdditionalCertificatesFromListener': %w", err)
} }
} }
} }
@ -447,7 +464,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
// 阿里云 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"

View File

@ -1,4 +1,4 @@
package aliyunalb_test package aliyunalb_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package aliyunalb package aliyunalb
type ResourceType string type ResourceType string

View File

@ -0,0 +1,274 @@
package aliyunapigw
import (
"context"
"errors"
"fmt"
"log/slog"
"strings"
"time"
aliapig "github.com/alibabacloud-go/apig-20240327/v3/client"
alicloudapi "github.com/alibabacloud-go/cloudapi-20160714/v5/client"
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/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"
)
type DeployerConfig struct {
// 阿里云 AccessKeyId。
AccessKeyId string `json:"accessKeyId"`
// 阿里云 AccessKeySecret。
AccessKeySecret string `json:"accessKeySecret"`
// 阿里云地域。
Region string `json:"region"`
// 服务类型。
ServiceType ServiceType `json:"serviceType"`
// API 网关 ID。
// 服务类型为 [SERVICE_TYPE_CLOUDNATIVE] 时必填。
GatewayId string `json:"gatewayId,omitempty"`
// API 分组 ID。
// 服务类型为 [SERVICE_TYPE_TRADITIONAL] 时必填。
GroupId string `json:"groupId,omitempty"`
// 自定义域名(支持泛域名)。
Domain string `json:"domain"`
}
type DeployerProvider struct {
config *DeployerConfig
logger *slog.Logger
sdkClients *wSdkClients
sslUploader uploader.Uploader
}
type wSdkClients struct {
CloudNativeAPIGateway *aliapig.Client
TraditionalAPIGateway *alicloudapi.Client
}
var _ deployer.Deployer = (*DeployerProvider)(nil)
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
if config == nil {
panic("config is nil")
}
clients, err := createSdkClients(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil {
return nil, fmt.Errorf("failed to create sdk clients: %w", err)
}
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil {
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
}
return &DeployerProvider{
config: config,
logger: slog.Default(),
sdkClients: clients,
sslUploader: uploader,
}, nil
}
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
if logger == nil {
d.logger = slog.Default()
} else {
d.logger = logger
}
return d
}
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
switch d.config.ServiceType {
case SERVICE_TYPE_TRADITIONAL:
if err := d.deployToTraditional(ctx, certPEM, privkeyPEM); err != nil {
return nil, err
}
case SERVICE_TYPE_CLOUDNATIVE:
if err := d.deployToCloudNative(ctx, certPEM, privkeyPEM); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported service type '%s'", string(d.config.ServiceType))
}
return &deployer.DeployResult{}, nil
}
func (d *DeployerProvider) deployToTraditional(ctx context.Context, certPEM string, privkeyPEM string) error {
if d.config.GroupId == "" {
return errors.New("config `groupId` is required")
}
if d.config.Domain == "" {
return errors.New("config `domain` is required")
}
// 为自定义域名添加 SSL 证书
// REF: https://help.aliyun.com/zh/api-gateway/traditional-api-gateway/developer-reference/api-cloudapi-2016-07-14-setdomaincertificate
setDomainCertificateReq := &alicloudapi.SetDomainCertificateRequest{
GroupId: tea.String(d.config.GroupId),
DomainName: tea.String(d.config.Domain),
CertificateName: tea.String(fmt.Sprintf("certimate_%d", time.Now().UnixMilli())),
CertificateBody: tea.String(certPEM),
CertificatePrivateKey: tea.String(privkeyPEM),
}
setDomainCertificateResp, err := d.sdkClients.TraditionalAPIGateway.SetDomainCertificate(setDomainCertificateReq)
d.logger.Debug("sdk request 'apigateway.SetDomainCertificate'", slog.Any("request", setDomainCertificateReq), slog.Any("response", setDomainCertificateResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request 'apigateway.SetDomainCertificate': %w", err)
}
return nil
}
func (d *DeployerProvider) deployToCloudNative(ctx context.Context, certPEM string, privkeyPEM string) error {
if d.config.GatewayId == "" {
return errors.New("config `gatewayId` is required")
}
if d.config.Domain == "" {
return errors.New("config `domain` is required")
}
// 遍历查询域名列表,获取域名 ID
// REF: https://help.aliyun.com/zh/api-gateway/cloud-native-api-gateway/developer-reference/api-apig-2024-03-27-listdomains
var domainId string
listDomainsPageNumber := int32(1)
listDomainsPageSize := int32(10)
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
listDomainsReq := &aliapig.ListDomainsRequest{
GatewayId: tea.String(d.config.GatewayId),
NameLike: tea.String(d.config.Domain),
PageNumber: tea.Int32(listDomainsPageNumber),
PageSize: tea.Int32(listDomainsPageSize),
}
listDomainsResp, err := d.sdkClients.CloudNativeAPIGateway.ListDomains(listDomainsReq)
d.logger.Debug("sdk request 'apig.ListDomains'", slog.Any("request", listDomainsReq), slog.Any("response", listDomainsResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request 'apig.ListDomains': %w", err)
}
if listDomainsResp.Body.Data.Items != nil {
for _, domainInfo := range listDomainsResp.Body.Data.Items {
if strings.EqualFold(tea.StringValue(domainInfo.Name), d.config.Domain) {
domainId = tea.StringValue(domainInfo.DomainId)
break
}
}
if domainId != "" {
break
}
}
if listDomainsResp.Body.Data.Items == nil || len(listDomainsResp.Body.Data.Items) < int(listDomainsPageSize) {
break
} else {
listDomainsPageNumber++
}
}
if domainId == "" {
return errors.New("domain not found")
}
// 查询域名
// REF: https://help.aliyun.com/zh/api-gateway/cloud-native-api-gateway/developer-reference/api-apig-2024-03-27-getdomain
getDomainReq := &aliapig.GetDomainRequest{}
getDomainResp, err := d.sdkClients.CloudNativeAPIGateway.GetDomain(tea.String(domainId), getDomainReq)
d.logger.Debug("sdk request 'apig.GetDomain'", slog.Any("domainId", domainId), slog.Any("request", getDomainReq), slog.Any("response", getDomainResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request 'apig.GetDomain': %w", err)
}
// 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil {
return fmt.Errorf("failed to upload certificate file: %w", err)
} else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
}
// 更新域名
// REF: https://help.aliyun.com/zh/api-gateway/cloud-native-api-gateway/developer-reference/api-apig-2024-03-27-updatedomain
updateDomainReq := &aliapig.UpdateDomainRequest{
Protocol: tea.String("HTTPS"),
ForceHttps: getDomainResp.Body.Data.ForceHttps,
MTLSEnabled: getDomainResp.Body.Data.MTLSEnabled,
Http2Option: getDomainResp.Body.Data.Http2Option,
TlsMin: getDomainResp.Body.Data.TlsMin,
TlsMax: getDomainResp.Body.Data.TlsMax,
TlsCipherSuitesConfig: getDomainResp.Body.Data.TlsCipherSuitesConfig,
CertIdentifier: tea.String(upres.ExtendedData["certIdentifier"].(string)),
}
updateDomainResp, err := d.sdkClients.CloudNativeAPIGateway.UpdateDomain(tea.String(domainId), updateDomainReq)
d.logger.Debug("sdk request 'apig.UpdateDomain'", slog.Any("domainId", domainId), slog.Any("request", updateDomainReq), slog.Any("response", updateDomainResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request 'apig.UpdateDomain': %w", err)
}
return nil
}
func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients, error) {
// 接入点一览 https://api.aliyun.com/product/APIG
cloudNativeAPIGEndpoint := fmt.Sprintf("apig.%s.aliyuncs.com", region)
cloudNativeAPIGConfig := &aliopen.Config{
AccessKeyId: tea.String(accessKeyId),
AccessKeySecret: tea.String(accessKeySecret),
Endpoint: tea.String(cloudNativeAPIGEndpoint),
}
cloudNativeAPIGClient, err := aliapig.NewClient(cloudNativeAPIGConfig)
if err != nil {
return nil, err
}
// 接入点一览 https://api.aliyun.com/product/CloudAPI
traditionalAPIGEndpoint := fmt.Sprintf("apigateway.%s.aliyuncs.com", region)
traditionalAPIGConfig := &aliopen.Config{
AccessKeyId: tea.String(accessKeyId),
AccessKeySecret: tea.String(accessKeySecret),
Endpoint: tea.String(traditionalAPIGEndpoint),
}
traditionalAPIGClient, err := alicloudapi.NewClient(traditionalAPIGConfig)
if err != nil {
return nil, err
}
return &wSdkClients{
CloudNativeAPIGateway: cloudNativeAPIGClient,
TraditionalAPIGateway: traditionalAPIGClient,
}, nil
}
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
casRegion := region
if casRegion != "" {
// 阿里云 CAS 服务接入点是独立于 APIGateway 服务的
// 国内版固定接入点:华东一杭州
// 国际版固定接入点:亚太东南一新加坡
if !strings.HasPrefix(casRegion, "cn-") {
casRegion = "ap-southeast-1"
} else {
casRegion = "cn-hangzhou"
}
}
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
Region: casRegion,
})
return uploader, err
}

View File

@ -0,0 +1,95 @@
package aliyunapigw_test
import (
"context"
"flag"
"fmt"
"os"
"strings"
"testing"
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-apigw"
)
var (
fInputCertPath string
fInputKeyPath string
fAccessKeyId string
fAccessKeySecret string
fRegion string
fServiceType string
fGatewayId string
fGroupId string
fDomain string
)
func init() {
argsPrefix := "CERTIMATE_DEPLOYER_ALIYUNAPIGW_"
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(&fGatewayId, argsPrefix+"GATEWARYID", "", "")
flag.StringVar(&fGroupId, argsPrefix+"GROUPID", "", "")
flag.StringVar(&fServiceType, argsPrefix+"SERVICETYPE", "", "")
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
}
/*
Shell command to run this test:
go test -v ./aliyun_apigw_test.go -args \
--CERTIMATE_DEPLOYER_ALIYUNAPIGW_INPUTCERTPATH="/path/to/your-input-cert.pem" \
--CERTIMATE_DEPLOYER_ALIYUNAPIGW_INPUTKEYPATH="/path/to/your-input-key.pem" \
--CERTIMATE_DEPLOYER_ALIYUNAPIGW_ACCESSKEYID="your-access-key-id" \
--CERTIMATE_DEPLOYER_ALIYUNAPIGW_ACCESSKEYSECRET="your-access-key-secret" \
--CERTIMATE_DEPLOYER_ALIYUNAPIGW_REGION="cn-hangzhou" \
--CERTIMATE_DEPLOYER_ALIYUNAPIGW_GATEWAYID="your-api-gateway-id" \
--CERTIMATE_DEPLOYER_ALIYUNAPIGW_GROUPID="your-api-group-id" \
--CERTIMATE_DEPLOYER_ALIYUNAPIGW_SERVICETYPE="cloudnative" \
--CERTIMATE_DEPLOYER_ALIYUNAPIGW_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("GATEWAYID: %v", fGatewayId),
fmt.Sprintf("GROUPID: %v", fGroupId),
fmt.Sprintf("SERVICETYPE: %v", fServiceType),
fmt.Sprintf("DOMAIN: %v", fDomain),
}, "\n"))
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
AccessKeyId: fAccessKeyId,
AccessKeySecret: fAccessKeySecret,
Region: fRegion,
ServiceType: provider.ServiceType(fServiceType),
GatewayId: fGatewayId,
GroupId: fGroupId,
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)
})
}

View File

@ -0,0 +1,10 @@
package aliyunapigw
type ServiceType string
const (
// 服务类型:原 API 网关。
SERVICE_TYPE_TRADITIONAL = ServiceType("traditional")
// 服务类型:云原生 API 网关。
SERVICE_TYPE_CLOUDNATIVE = ServiceType("cloudnative")
)

View File

@ -1,4 +1,4 @@
package aliyuncasdeploy package aliyuncasdeploy
import ( import (
"context" "context"
@ -11,7 +11,6 @@ import (
alicas "github.com/alibabacloud-go/cas-20200407/v3/client" alicas "github.com/alibabacloud-go/cas-20200407/v3/client"
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
"github.com/usual2970/certimate/internal/pkg/core/uploader" "github.com/usual2970/certimate/internal/pkg/core/uploader"
@ -48,7 +47,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
@ -57,7 +56,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
Region: config.Region, Region: config.Region,
}) })
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -78,15 +77,15 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
if len(d.config.ResourceIds) == 0 { if len(d.config.ResourceIds) == 0 {
return nil, errors.New("config `resourceIds` is required") return nil, errors.New("config `resourceIds` is required")
} }
// 上传证书到 CAS // 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -101,7 +100,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
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 {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.ListContact'") return nil, fmt.Errorf("failed to execute sdk request 'cas.ListContact': %w", err)
} }
if len(listContactResp.Body.ContactList) > 0 { if len(listContactResp.Body.ContactList) > 0 {
@ -121,14 +120,16 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
createDeploymentJobResp, err := d.sdkClient.CreateDeploymentJob(createDeploymentJobReq) createDeploymentJobResp, err := d.sdkClient.CreateDeploymentJob(createDeploymentJobReq)
d.logger.Debug("sdk request 'cas.CreateDeploymentJob'", slog.Any("request", createDeploymentJobReq), slog.Any("response", createDeploymentJobResp)) d.logger.Debug("sdk request 'cas.CreateDeploymentJob'", slog.Any("request", createDeploymentJobReq), slog.Any("response", createDeploymentJobResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.CreateDeploymentJob'") return nil, fmt.Errorf("failed to execute sdk request 'cas.CreateDeploymentJob': %w", err)
} }
// 循环获取部署任务详情,等待任务状态变更 // 循环获取部署任务详情,等待任务状态变更
// REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-describedeploymentjob // REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-describedeploymentjob
for { for {
if ctx.Err() != nil { select {
case <-ctx.Done():
return nil, ctx.Err() return nil, ctx.Err()
default:
} }
describeDeploymentJobReq := &alicas.DescribeDeploymentJobRequest{ describeDeploymentJobReq := &alicas.DescribeDeploymentJobRequest{
@ -137,7 +138,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
describeDeploymentJobResp, err := d.sdkClient.DescribeDeploymentJob(describeDeploymentJobReq) describeDeploymentJobResp, err := d.sdkClient.DescribeDeploymentJob(describeDeploymentJobReq)
d.logger.Debug("sdk request 'cas.DescribeDeploymentJob'", slog.Any("request", describeDeploymentJobReq), slog.Any("response", describeDeploymentJobResp)) d.logger.Debug("sdk request 'cas.DescribeDeploymentJob'", slog.Any("request", describeDeploymentJobReq), slog.Any("response", describeDeploymentJobResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.DescribeDeploymentJob'") return nil, fmt.Errorf("failed to execute sdk request 'cas.DescribeDeploymentJob': %w", err)
} }
if describeDeploymentJobResp.Body.Status == nil || *describeDeploymentJobResp.Body.Status == "editing" { if describeDeploymentJobResp.Body.Status == nil || *describeDeploymentJobResp.Body.Status == "editing" {

View File

@ -1,11 +1,10 @@
package aliyuncas package aliyuncas
import ( import (
"context" "context"
"fmt"
"log/slog" "log/slog"
xerrors "github.com/pkg/errors"
"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"
@ -39,7 +38,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
Region: config.Region, Region: config.Region,
}) })
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -59,11 +58,11 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// 上传证书到 CAS // 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }

View File

@ -1,4 +1,4 @@
package aliyuncdn package aliyuncdn
import ( import (
"context" "context"
@ -10,7 +10,6 @@ import (
alicdn "github.com/alibabacloud-go/cdn-20180510/v5/client" alicdn "github.com/alibabacloud-go/cdn-20180510/v5/client"
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
) )
@ -39,7 +38,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret) client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -58,7 +57,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// "*.example.com" → ".example.com",适配阿里云 CDN 要求的泛域名格式 // "*.example.com" → ".example.com",适配阿里云 CDN 要求的泛域名格式
domain := strings.TrimPrefix(d.config.Domain, "*") domain := strings.TrimPrefix(d.config.Domain, "*")
@ -69,13 +68,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())), CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
CertType: tea.String("upload"), CertType: tea.String("upload"),
SSLProtocol: tea.String("on"), SSLProtocol: tea.String("on"),
SSLPub: tea.String(certPem), SSLPub: tea.String(certPEM),
SSLPri: tea.String(privkeyPem), SSLPri: tea.String(privkeyPEM),
} }
setCdnDomainSSLCertificateResp, err := d.sdkClient.SetCdnDomainSSLCertificate(setCdnDomainSSLCertificateReq) setCdnDomainSSLCertificateResp, err := d.sdkClient.SetCdnDomainSSLCertificate(setCdnDomainSSLCertificateReq)
d.logger.Debug("sdk request 'cdn.SetCdnDomainSSLCertificate'", slog.Any("request", setCdnDomainSSLCertificateReq), slog.Any("response", setCdnDomainSSLCertificateResp)) d.logger.Debug("sdk request 'cdn.SetCdnDomainSSLCertificate'", slog.Any("request", setCdnDomainSSLCertificateReq), slog.Any("response", setCdnDomainSSLCertificateResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.SetCdnDomainSSLCertificate'") return nil, fmt.Errorf("failed to execute sdk request 'cdn.SetCdnDomainSSLCertificate': %w", err)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil

View File

@ -1,4 +1,4 @@
package aliyuncdn_test package aliyuncdn_test
import ( import (
"context" "context"

View File

@ -1,15 +1,15 @@
package aliyunclb package aliyunclb
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"log/slog" "log/slog"
"strings"
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
alislb "github.com/alibabacloud-go/slb-20140515/v4/client" alislb "github.com/alibabacloud-go/slb-20140515/v4/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
"github.com/usual2970/certimate/internal/pkg/core/uploader" "github.com/usual2970/certimate/internal/pkg/core/uploader"
@ -52,16 +52,12 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") 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.Region)
AccessKeyId: config.AccessKeyId,
AccessKeySecret: config.AccessKeySecret,
Region: config.Region,
})
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -82,11 +78,11 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// 上传证书到 SLB // 上传证书到 SLB
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -104,7 +100,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
} }
default: default:
return nil, fmt.Errorf("unsupported resource type: %s", d.config.ResourceType) return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
@ -124,7 +120,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
describeLoadBalancerAttributeResp, err := d.sdkClient.DescribeLoadBalancerAttribute(describeLoadBalancerAttributeReq) describeLoadBalancerAttributeResp, err := d.sdkClient.DescribeLoadBalancerAttribute(describeLoadBalancerAttributeReq)
d.logger.Debug("sdk request 'slb.DescribeLoadBalancerAttribute'", slog.Any("request", describeLoadBalancerAttributeReq), slog.Any("response", describeLoadBalancerAttributeResp)) d.logger.Debug("sdk request 'slb.DescribeLoadBalancerAttribute'", slog.Any("request", describeLoadBalancerAttributeReq), slog.Any("response", describeLoadBalancerAttributeResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeLoadBalancerAttribute'") return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerAttribute': %w", err)
} }
// 查询 HTTPS 监听列表 // 查询 HTTPS 监听列表
@ -133,6 +129,12 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
describeLoadBalancerListenersLimit := int32(100) describeLoadBalancerListenersLimit := int32(100)
var describeLoadBalancerListenersToken *string = nil var describeLoadBalancerListenersToken *string = nil
for { for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
describeLoadBalancerListenersReq := &alislb.DescribeLoadBalancerListenersRequest{ describeLoadBalancerListenersReq := &alislb.DescribeLoadBalancerListenersRequest{
RegionId: tea.String(d.config.Region), RegionId: tea.String(d.config.Region),
MaxResults: tea.Int32(describeLoadBalancerListenersLimit), MaxResults: tea.Int32(describeLoadBalancerListenersLimit),
@ -143,7 +145,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
describeLoadBalancerListenersResp, err := d.sdkClient.DescribeLoadBalancerListeners(describeLoadBalancerListenersReq) describeLoadBalancerListenersResp, err := d.sdkClient.DescribeLoadBalancerListeners(describeLoadBalancerListenersReq)
d.logger.Debug("sdk request 'slb.DescribeLoadBalancerListeners'", slog.Any("request", describeLoadBalancerListenersReq), slog.Any("response", describeLoadBalancerListenersResp)) d.logger.Debug("sdk request 'slb.DescribeLoadBalancerListeners'", slog.Any("request", describeLoadBalancerListenersReq), slog.Any("response", describeLoadBalancerListenersResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeLoadBalancerListeners'") return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerListeners': %w", err)
} }
if describeLoadBalancerListenersResp.Body.Listeners != nil { if describeLoadBalancerListenersResp.Body.Listeners != nil {
@ -167,8 +169,14 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
var errs []error var errs []error
for _, listenerPort := range listenerPorts { for _, listenerPort := range listenerPorts {
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listenerPort, cloudCertId); err != nil { select {
errs = append(errs, err) case <-ctx.Done():
return ctx.Err()
default:
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listenerPort, cloudCertId); err != nil {
errs = append(errs, err)
}
} }
} }
@ -206,7 +214,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
describeLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.DescribeLoadBalancerHTTPSListenerAttribute(describeLoadBalancerHTTPSListenerAttributeReq) describeLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.DescribeLoadBalancerHTTPSListenerAttribute(describeLoadBalancerHTTPSListenerAttributeReq)
d.logger.Debug("sdk request 'slb.DescribeLoadBalancerHTTPSListenerAttribute'", slog.Any("request", describeLoadBalancerHTTPSListenerAttributeReq), slog.Any("response", describeLoadBalancerHTTPSListenerAttributeResp)) d.logger.Debug("sdk request 'slb.DescribeLoadBalancerHTTPSListenerAttribute'", slog.Any("request", describeLoadBalancerHTTPSListenerAttributeReq), slog.Any("response", describeLoadBalancerHTTPSListenerAttributeResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeLoadBalancerHTTPSListenerAttribute'") return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerHTTPSListenerAttribute': %w", err)
} }
if d.config.Domain == "" { if d.config.Domain == "" {
@ -223,7 +231,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
setLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.SetLoadBalancerHTTPSListenerAttribute(setLoadBalancerHTTPSListenerAttributeReq) setLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.SetLoadBalancerHTTPSListenerAttribute(setLoadBalancerHTTPSListenerAttributeReq)
d.logger.Debug("sdk request 'slb.SetLoadBalancerHTTPSListenerAttribute'", slog.Any("request", setLoadBalancerHTTPSListenerAttributeReq), slog.Any("response", setLoadBalancerHTTPSListenerAttributeResp)) d.logger.Debug("sdk request 'slb.SetLoadBalancerHTTPSListenerAttribute'", slog.Any("request", setLoadBalancerHTTPSListenerAttributeReq), slog.Any("response", setLoadBalancerHTTPSListenerAttributeResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'slb.SetLoadBalancerHTTPSListenerAttribute'") return fmt.Errorf("failed to execute sdk request 'slb.SetLoadBalancerHTTPSListenerAttribute': %w", err)
} }
} else { } else {
// 指定 SNI需部署到扩展域名 // 指定 SNI需部署到扩展域名
@ -238,7 +246,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
describeDomainExtensionsResp, err := d.sdkClient.DescribeDomainExtensions(describeDomainExtensionsReq) describeDomainExtensionsResp, err := d.sdkClient.DescribeDomainExtensions(describeDomainExtensionsReq)
d.logger.Debug("sdk request 'slb.DescribeDomainExtensions'", slog.Any("request", describeDomainExtensionsReq), slog.Any("response", describeDomainExtensionsResp)) d.logger.Debug("sdk request 'slb.DescribeDomainExtensions'", slog.Any("request", describeDomainExtensionsReq), slog.Any("response", describeDomainExtensionsResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeDomainExtensions'") return fmt.Errorf("failed to execute sdk request 'slb.DescribeDomainExtensions': %w", err)
} }
// 遍历修改扩展域名 // 遍历修改扩展域名
@ -259,7 +267,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
setDomainExtensionAttributeResp, err := d.sdkClient.SetDomainExtensionAttribute(setDomainExtensionAttributeReq) setDomainExtensionAttributeResp, err := d.sdkClient.SetDomainExtensionAttribute(setDomainExtensionAttributeReq)
d.logger.Debug("sdk request 'slb.SetDomainExtensionAttribute'", slog.Any("request", setDomainExtensionAttributeReq), slog.Any("response", setDomainExtensionAttributeResp)) d.logger.Debug("sdk request 'slb.SetDomainExtensionAttribute'", slog.Any("request", setDomainExtensionAttributeReq), slog.Any("response", setDomainExtensionAttributeResp))
if err != nil { if err != nil {
errs = append(errs, xerrors.Wrap(err, "failed to execute sdk request 'slb.SetDomainExtensionAttribute'")) errs = append(errs, fmt.Errorf("failed to execute sdk request 'slb.SetDomainExtensionAttribute': %w", err))
continue continue
} }
} }
@ -300,3 +308,24 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alislb.Clien
return client, nil return client, nil
} }
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
casRegion := region
if casRegion != "" {
// 阿里云 CAS 服务接入点是独立于 CLB 服务的
// 国内版固定接入点:华东一杭州
// 国际版固定接入点:亚太东南一新加坡
if !strings.HasPrefix(casRegion, "cn-") {
casRegion = "ap-southeast-1"
} else {
casRegion = "cn-hangzhou"
}
}
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
Region: casRegion,
})
return uploader, err
}

View File

@ -1,4 +1,4 @@
package aliyunclb_test package aliyunclb_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package aliyunclb package aliyunclb
type ResourceType string type ResourceType string

View File

@ -1,4 +1,4 @@
package aliyundcdn package aliyundcdn
import ( import (
"context" "context"
@ -10,7 +10,6 @@ import (
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
alidcdn "github.com/alibabacloud-go/dcdn-20180115/v3/client" alidcdn "github.com/alibabacloud-go/dcdn-20180115/v3/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
) )
@ -39,7 +38,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret) client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -58,7 +57,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// "*.example.com" → ".example.com",适配阿里云 DCDN 要求的泛域名格式 // "*.example.com" → ".example.com",适配阿里云 DCDN 要求的泛域名格式
domain := strings.TrimPrefix(d.config.Domain, "*") domain := strings.TrimPrefix(d.config.Domain, "*")
@ -69,13 +68,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())), CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
CertType: tea.String("upload"), CertType: tea.String("upload"),
SSLProtocol: tea.String("on"), SSLProtocol: tea.String("on"),
SSLPub: tea.String(certPem), SSLPub: tea.String(certPEM),
SSLPri: tea.String(privkeyPem), SSLPri: tea.String(privkeyPEM),
} }
setDcdnDomainSSLCertificateResp, err := d.sdkClient.SetDcdnDomainSSLCertificate(setDcdnDomainSSLCertificateReq) setDcdnDomainSSLCertificateResp, err := d.sdkClient.SetDcdnDomainSSLCertificate(setDcdnDomainSSLCertificateReq)
d.logger.Debug("sdk request 'dcdn.SetDcdnDomainSSLCertificate'", slog.Any("request", setDcdnDomainSSLCertificateReq), slog.Any("response", setDcdnDomainSSLCertificateResp)) d.logger.Debug("sdk request 'dcdn.SetDcdnDomainSSLCertificate'", slog.Any("request", setDcdnDomainSSLCertificateReq), slog.Any("response", setDcdnDomainSSLCertificateResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'dcdn.SetDcdnDomainSSLCertificate'") return nil, fmt.Errorf("failed to execute sdk request 'dcdn.SetDcdnDomainSSLCertificate': %w", err)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil

View File

@ -1,4 +1,4 @@
package aliyundcdn_test package aliyundcdn_test
import ( import (
"context" "context"

View File

@ -0,0 +1,137 @@
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"`
// 阿里云地域。
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.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.Default()
} else {
d.logger = logger
}
d.sslUploader.WithLogger(logger)
return d
}
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
if d.config.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(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, 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,
Region: casRegion,
})
return uploader, err
}

View File

@ -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)
})
}

View File

@ -1,4 +1,4 @@
package aliyunesa package aliyunesa
import ( import (
"context" "context"
@ -11,7 +11,6 @@ import (
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
aliesa "github.com/alibabacloud-go/esa-20240910/v2/client" aliesa "github.com/alibabacloud-go/esa-20240910/v2/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
"github.com/usual2970/certimate/internal/pkg/core/uploader" "github.com/usual2970/certimate/internal/pkg/core/uploader"
@ -45,12 +44,12 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") 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.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -71,15 +70,15 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
if d.config.SiteId == 0 { if d.config.SiteId == 0 {
return nil, errors.New("config `siteId` is required") return nil, errors.New("config `siteId` is required")
} }
// 上传证书到 CAS // 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -95,7 +94,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
setCertificateResp, err := d.sdkClient.SetCertificate(setCertificateReq) setCertificateResp, err := d.sdkClient.SetCertificate(setCertificateReq)
d.logger.Debug("sdk request 'esa.SetCertificate'", slog.Any("request", setCertificateReq), slog.Any("response", setCertificateResp)) d.logger.Debug("sdk request 'esa.SetCertificate'", slog.Any("request", setCertificateReq), slog.Any("response", setCertificateResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'esa.SetCertificate'") return nil, fmt.Errorf("failed to execute sdk request 'esa.SetCertificate': %w", err)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
@ -123,7 +122,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
// 阿里云 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"

View File

@ -1,4 +1,4 @@
package aliyunesa_test package aliyunesa_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package aliyunfc package aliyunfc
import ( import (
"context" "context"
@ -10,7 +10,6 @@ import (
alifc3 "github.com/alibabacloud-go/fc-20230330/v4/client" alifc3 "github.com/alibabacloud-go/fc-20230330/v4/client"
alifc2 "github.com/alibabacloud-go/fc-open-20210406/v2/client" alifc2 "github.com/alibabacloud-go/fc-open-20210406/v2/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
) )
@ -48,7 +47,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
clients, err := createSdkClients(config.AccessKeyId, config.AccessKeySecret, config.Region) clients, err := createSdkClients(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk clients") return nil, fmt.Errorf("failed to create sdk clients: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -67,32 +66,32 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
switch d.config.ServiceVersion { switch d.config.ServiceVersion {
case "3", "3.0": case "3", "3.0":
if err := d.deployToFC3(ctx, certPem, privkeyPem); err != nil { if err := d.deployToFC3(ctx, certPEM, privkeyPEM); err != nil {
return nil, err return nil, err
} }
case "2", "2.0": case "2", "2.0":
if err := d.deployToFC2(ctx, certPem, privkeyPem); err != nil { if err := d.deployToFC2(ctx, certPEM, privkeyPEM); err != nil {
return nil, err return nil, err
} }
default: default:
return nil, xerrors.Errorf("unsupported service version: %s", d.config.ServiceVersion) return nil, fmt.Errorf("unsupported service version '%s'", d.config.ServiceVersion)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
} }
func (d *DeployerProvider) deployToFC3(ctx context.Context, certPem string, privkeyPem string) error { func (d *DeployerProvider) deployToFC3(ctx context.Context, certPEM string, privkeyPEM string) error {
// 获取自定义域名 // 获取自定义域名
// REF: https://help.aliyun.com/zh/functioncompute/fc-3-0/developer-reference/api-fc-2023-03-30-getcustomdomain // REF: https://help.aliyun.com/zh/functioncompute/fc-3-0/developer-reference/api-fc-2023-03-30-getcustomdomain
getCustomDomainResp, err := d.sdkClients.FC3.GetCustomDomain(tea.String(d.config.Domain)) getCustomDomainResp, err := d.sdkClients.FC3.GetCustomDomain(tea.String(d.config.Domain))
d.logger.Debug("sdk request 'fc.GetCustomDomain'", slog.Any("response", getCustomDomainResp)) d.logger.Debug("sdk request 'fc.GetCustomDomain'", slog.Any("response", getCustomDomainResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'fc.GetCustomDomain'") return fmt.Errorf("failed to execute sdk request 'fc.GetCustomDomain': %w", err)
} }
// 更新自定义域名 // 更新自定义域名
@ -101,8 +100,8 @@ func (d *DeployerProvider) deployToFC3(ctx context.Context, certPem string, priv
Body: &alifc3.UpdateCustomDomainInput{ Body: &alifc3.UpdateCustomDomainInput{
CertConfig: &alifc3.CertConfig{ CertConfig: &alifc3.CertConfig{
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())), CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
Certificate: tea.String(certPem), Certificate: tea.String(certPEM),
PrivateKey: tea.String(privkeyPem), PrivateKey: tea.String(privkeyPEM),
}, },
Protocol: getCustomDomainResp.Body.Protocol, Protocol: getCustomDomainResp.Body.Protocol,
TlsConfig: getCustomDomainResp.Body.TlsConfig, TlsConfig: getCustomDomainResp.Body.TlsConfig,
@ -111,19 +110,19 @@ func (d *DeployerProvider) deployToFC3(ctx context.Context, certPem string, priv
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 {
return xerrors.Wrap(err, "failed to execute sdk request 'fc.UpdateCustomDomain'") return fmt.Errorf("failed to execute sdk request 'fc.UpdateCustomDomain': %w", err)
} }
return nil return nil
} }
func (d *DeployerProvider) deployToFC2(ctx context.Context, certPem string, privkeyPem string) error { func (d *DeployerProvider) deployToFC2(ctx context.Context, certPEM string, privkeyPEM string) error {
// 获取自定义域名 // 获取自定义域名
// REF: https://help.aliyun.com/zh/functioncompute/fc-2-0/developer-reference/api-fc-open-2021-04-06-getcustomdomain // REF: https://help.aliyun.com/zh/functioncompute/fc-2-0/developer-reference/api-fc-open-2021-04-06-getcustomdomain
getCustomDomainResp, err := d.sdkClients.FC2.GetCustomDomain(tea.String(d.config.Domain)) getCustomDomainResp, err := d.sdkClients.FC2.GetCustomDomain(tea.String(d.config.Domain))
d.logger.Debug("sdk request 'fc.GetCustomDomain'", slog.Any("response", getCustomDomainResp)) d.logger.Debug("sdk request 'fc.GetCustomDomain'", slog.Any("response", getCustomDomainResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'fc.GetCustomDomain'") return fmt.Errorf("failed to execute sdk request 'fc.GetCustomDomain': %w", err)
} }
// 更新自定义域名 // 更新自定义域名
@ -131,8 +130,8 @@ func (d *DeployerProvider) deployToFC2(ctx context.Context, certPem string, priv
updateCustomDomainReq := &alifc2.UpdateCustomDomainRequest{ updateCustomDomainReq := &alifc2.UpdateCustomDomainRequest{
CertConfig: &alifc2.CertConfig{ CertConfig: &alifc2.CertConfig{
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())), CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
Certificate: tea.String(certPem), Certificate: tea.String(certPEM),
PrivateKey: tea.String(privkeyPem), PrivateKey: tea.String(privkeyPEM),
}, },
Protocol: getCustomDomainResp.Body.Protocol, Protocol: getCustomDomainResp.Body.Protocol,
TlsConfig: getCustomDomainResp.Body.TlsConfig, TlsConfig: getCustomDomainResp.Body.TlsConfig,
@ -140,7 +139,7 @@ func (d *DeployerProvider) deployToFC2(ctx context.Context, certPem string, priv
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 {
return xerrors.Wrap(err, "failed to execute sdk request 'fc.UpdateCustomDomain'") return fmt.Errorf("failed to execute sdk request 'fc.UpdateCustomDomain': %w", err)
} }
return nil return nil

View File

@ -1,4 +1,4 @@
package aliyunfc_test package aliyunfc_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package aliyunlive package aliyunlive
import ( import (
"context" "context"
@ -10,7 +10,6 @@ import (
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
alilive "github.com/alibabacloud-go/live-20161101/client" alilive "github.com/alibabacloud-go/live-20161101/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
) )
@ -41,7 +40,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -60,7 +59,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// "*.example.com" → ".example.com",适配阿里云 Live 要求的泛域名格式 // "*.example.com" → ".example.com",适配阿里云 Live 要求的泛域名格式
domain := strings.TrimPrefix(d.config.Domain, "*") domain := strings.TrimPrefix(d.config.Domain, "*")
@ -71,13 +70,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())), CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
CertType: tea.String("upload"), CertType: tea.String("upload"),
SSLProtocol: tea.String("on"), SSLProtocol: tea.String("on"),
SSLPub: tea.String(certPem), SSLPub: tea.String(certPEM),
SSLPri: tea.String(privkeyPem), SSLPri: tea.String(privkeyPEM),
} }
setLiveDomainSSLCertificateResp, err := d.sdkClient.SetLiveDomainCertificate(setLiveDomainSSLCertificateReq) setLiveDomainSSLCertificateResp, err := d.sdkClient.SetLiveDomainCertificate(setLiveDomainSSLCertificateReq)
d.logger.Debug("sdk request 'live.SetLiveDomainCertificate'", slog.Any("request", setLiveDomainSSLCertificateReq), slog.Any("response", setLiveDomainSSLCertificateResp)) d.logger.Debug("sdk request 'live.SetLiveDomainCertificate'", slog.Any("request", setLiveDomainSSLCertificateReq), slog.Any("response", setLiveDomainSSLCertificateResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.SetLiveDomainCertificate'") return nil, fmt.Errorf("failed to execute sdk request 'live.SetLiveDomainCertificate': %w", err)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil

View File

@ -1,4 +1,4 @@
package aliyunlive_test package aliyunlive_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package aliyunnlb package aliyunnlb
import ( import (
"context" "context"
@ -10,7 +10,6 @@ import (
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
alinlb "github.com/alibabacloud-go/nlb-20220430/v2/client" alinlb "github.com/alibabacloud-go/nlb-20220430/v2/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
"github.com/usual2970/certimate/internal/pkg/core/uploader" "github.com/usual2970/certimate/internal/pkg/core/uploader"
@ -50,12 +49,12 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") 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.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -76,11 +75,11 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// 上传证书到 CAS // 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -98,7 +97,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
} }
default: default:
return nil, fmt.Errorf("unsupported resource type: %s", d.config.ResourceType) return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
@ -117,7 +116,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
getLoadBalancerAttributeResp, err := d.sdkClient.GetLoadBalancerAttribute(getLoadBalancerAttributeReq) getLoadBalancerAttributeResp, err := d.sdkClient.GetLoadBalancerAttribute(getLoadBalancerAttributeReq)
d.logger.Debug("sdk request 'nlb.GetLoadBalancerAttribute'", slog.Any("request", getLoadBalancerAttributeReq), slog.Any("response", getLoadBalancerAttributeResp)) d.logger.Debug("sdk request 'nlb.GetLoadBalancerAttribute'", slog.Any("request", getLoadBalancerAttributeReq), slog.Any("response", getLoadBalancerAttributeResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'nlb.GetLoadBalancerAttribute'") return fmt.Errorf("failed to execute sdk request 'nlb.GetLoadBalancerAttribute': %w", err)
} }
// 查询 TCPSSL 监听列表 // 查询 TCPSSL 监听列表
@ -126,6 +125,12 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
listListenersLimit := int32(100) listListenersLimit := int32(100)
var listListenersToken *string = nil var listListenersToken *string = nil
for { for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
listListenersReq := &alinlb.ListListenersRequest{ listListenersReq := &alinlb.ListListenersRequest{
MaxResults: tea.Int32(listListenersLimit), MaxResults: tea.Int32(listListenersLimit),
NextToken: listListenersToken, NextToken: listListenersToken,
@ -135,7 +140,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
listListenersResp, err := d.sdkClient.ListListeners(listListenersReq) listListenersResp, err := d.sdkClient.ListListeners(listListenersReq)
d.logger.Debug("sdk request 'nlb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp)) d.logger.Debug("sdk request 'nlb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'nlb.ListListeners'") return fmt.Errorf("failed to execute sdk request 'nlb.ListListeners': %w", err)
} }
if listListenersResp.Body.Listeners != nil { if listListenersResp.Body.Listeners != nil {
@ -159,8 +164,14 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
var errs []error var errs []error
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)
}
} }
} }
@ -194,7 +205,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
getListenerAttributeResp, err := d.sdkClient.GetListenerAttribute(getListenerAttributeReq) getListenerAttributeResp, err := d.sdkClient.GetListenerAttribute(getListenerAttributeReq)
d.logger.Debug("sdk request 'nlb.GetListenerAttribute'", slog.Any("request", getListenerAttributeReq), slog.Any("response", getListenerAttributeResp)) d.logger.Debug("sdk request 'nlb.GetListenerAttribute'", slog.Any("request", getListenerAttributeReq), slog.Any("response", getListenerAttributeResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'nlb.GetListenerAttribute'") return fmt.Errorf("failed to execute sdk request 'nlb.GetListenerAttribute': %w", err)
} }
// 修改监听的属性 // 修改监听的属性
@ -206,7 +217,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
updateListenerAttributeResp, err := d.sdkClient.UpdateListenerAttribute(updateListenerAttributeReq) updateListenerAttributeResp, err := d.sdkClient.UpdateListenerAttribute(updateListenerAttributeReq)
d.logger.Debug("sdk request 'nlb.UpdateListenerAttribute'", slog.Any("request", updateListenerAttributeReq), slog.Any("response", updateListenerAttributeResp)) d.logger.Debug("sdk request 'nlb.UpdateListenerAttribute'", slog.Any("request", updateListenerAttributeReq), slog.Any("response", updateListenerAttributeResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'nlb.UpdateListenerAttribute'") return fmt.Errorf("failed to execute sdk request 'nlb.UpdateListenerAttribute': %w", err)
} }
return nil return nil
@ -240,7 +251,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
// 阿里云 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"

View File

@ -1,4 +1,4 @@
package aliyunnlb_test package aliyunnlb_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package aliyunnlb package aliyunnlb
type ResourceType string type ResourceType string

View File

@ -1,4 +1,4 @@
package aliyunoss package aliyunoss
import ( import (
"context" "context"
@ -7,7 +7,6 @@ import (
"log/slog" "log/slog"
"github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/aliyun/aliyun-oss-go-sdk/oss"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
) )
@ -40,7 +39,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -59,7 +58,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
if d.config.Bucket == "" { if d.config.Bucket == "" {
return nil, errors.New("config `bucket` is required") return nil, errors.New("config `bucket` is required")
} }
@ -72,15 +71,15 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
putBucketCnameWithCertificateReq := oss.PutBucketCname{ putBucketCnameWithCertificateReq := oss.PutBucketCname{
Cname: d.config.Domain, Cname: d.config.Domain,
CertificateConfiguration: &oss.CertificateConfiguration{ CertificateConfiguration: &oss.CertificateConfiguration{
Certificate: certPem, Certificate: certPEM,
PrivateKey: privkeyPem, PrivateKey: privkeyPEM,
Force: true, Force: true,
}, },
} }
err := d.sdkClient.PutBucketCnameWithCertificate(d.config.Bucket, putBucketCnameWithCertificateReq) err := d.sdkClient.PutBucketCnameWithCertificate(d.config.Bucket, putBucketCnameWithCertificateReq)
d.logger.Debug("sdk request 'oss.PutBucketCnameWithCertificate'", slog.Any("bucket", d.config.Bucket), slog.Any("request", putBucketCnameWithCertificateReq)) d.logger.Debug("sdk request 'oss.PutBucketCnameWithCertificate'", slog.Any("bucket", d.config.Bucket), slog.Any("request", putBucketCnameWithCertificateReq))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'oss.PutBucketCnameWithCertificate'") return nil, fmt.Errorf("failed to execute sdk request 'oss.PutBucketCnameWithCertificate': %w", err)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil

View File

@ -1,4 +1,4 @@
package aliyunoss_test package aliyunoss_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package aliyunvod package aliyunvod
import ( import (
"context" "context"
@ -9,7 +9,6 @@ import (
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
alivod "github.com/alibabacloud-go/vod-20170321/v4/client" alivod "github.com/alibabacloud-go/vod-20170321/v4/client"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
) )
@ -40,7 +39,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -59,7 +58,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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://help.aliyun.com/zh/vod/developer-reference/api-vod-2017-03-21-setvoddomainsslcertificate // REF: https://help.aliyun.com/zh/vod/developer-reference/api-vod-2017-03-21-setvoddomainsslcertificate
setVodDomainSSLCertificateReq := &alivod.SetVodDomainSSLCertificateRequest{ setVodDomainSSLCertificateReq := &alivod.SetVodDomainSSLCertificateRequest{
@ -67,13 +66,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())), CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
CertType: tea.String("upload"), CertType: tea.String("upload"),
SSLProtocol: tea.String("on"), SSLProtocol: tea.String("on"),
SSLPub: tea.String(certPem), SSLPub: tea.String(certPEM),
SSLPri: tea.String(privkeyPem), SSLPri: tea.String(privkeyPEM),
} }
setVodDomainSSLCertificateResp, err := d.sdkClient.SetVodDomainSSLCertificate(setVodDomainSSLCertificateReq) setVodDomainSSLCertificateResp, err := d.sdkClient.SetVodDomainSSLCertificate(setVodDomainSSLCertificateReq)
d.logger.Debug("sdk request 'live.SetVodDomainSSLCertificate'", slog.Any("request", setVodDomainSSLCertificateReq), slog.Any("response", setVodDomainSSLCertificateResp)) d.logger.Debug("sdk request 'live.SetVodDomainSSLCertificate'", slog.Any("request", setVodDomainSSLCertificateReq), slog.Any("response", setVodDomainSSLCertificateResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.SetVodDomainSSLCertificate'") return nil, fmt.Errorf("failed to execute sdk request 'live.SetVodDomainSSLCertificate': %w", err)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil

View File

@ -1,4 +1,4 @@
package aliyunvod_test package aliyunvod_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package aliyunwaf package aliyunwaf
import ( import (
"context" "context"
@ -10,12 +10,11 @@ import (
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
"github.com/alibabacloud-go/tea/tea" "github.com/alibabacloud-go/tea/tea"
aliwaf "github.com/alibabacloud-go/waf-openapi-20211001/v5/client" aliwaf "github.com/alibabacloud-go/waf-openapi-20211001/v5/client"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/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"
"github.com/usual2970/certimate/internal/pkg/utils/sliceutil" sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
) )
type DeployerConfig struct { type DeployerConfig struct {
@ -49,12 +48,12 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") 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.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -75,29 +74,29 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
if d.config.InstanceId == "" { if d.config.InstanceId == "" {
return nil, errors.New("config `instanceId` is required") return nil, errors.New("config `instanceId` is required")
} }
switch d.config.ServiceVersion { switch d.config.ServiceVersion {
case "3", "3.0": case "3", "3.0":
if err := d.deployToWAF3(ctx, certPem, privkeyPem); err != nil { if err := d.deployToWAF3(ctx, certPEM, privkeyPEM); err != nil {
return nil, err return nil, err
} }
default: default:
return nil, xerrors.Errorf("unsupported service version: %s", d.config.ServiceVersion) return nil, fmt.Errorf("unsupported service version '%s'", d.config.ServiceVersion)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
} }
func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPem string, privkeyPem string) error { func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPEM string, privkeyPEM string) error {
// 上传证书到 CAS // 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to upload certificate file") return fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -114,7 +113,7 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPem string, pri
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))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDefaultHttps'") return fmt.Errorf("failed to execute sdk request 'waf.DescribeDefaultHttps': %w", err)
} }
// 修改默认 SSL/TLS 设置 // 修改默认 SSL/TLS 设置
@ -133,7 +132,7 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPem string, pri
modifyDefaultHttpsResp, err := d.sdkClient.ModifyDefaultHttps(modifyDefaultHttpsReq) modifyDefaultHttpsResp, err := d.sdkClient.ModifyDefaultHttps(modifyDefaultHttpsReq)
d.logger.Debug("sdk request 'waf.ModifyDefaultHttps'", slog.Any("request", modifyDefaultHttpsReq), slog.Any("response", modifyDefaultHttpsResp)) d.logger.Debug("sdk request 'waf.ModifyDefaultHttps'", slog.Any("request", modifyDefaultHttpsReq), slog.Any("response", modifyDefaultHttpsResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDefaultHttps'") return fmt.Errorf("failed to execute sdk request 'waf.ModifyDefaultHttps': %w", err)
} }
} else { } else {
// 指定接入域名 // 指定接入域名
@ -148,7 +147,7 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPem string, pri
describeDomainDetailResp, err := d.sdkClient.DescribeDomainDetail(describeDomainDetailReq) describeDomainDetailResp, err := d.sdkClient.DescribeDomainDetail(describeDomainDetailReq)
d.logger.Debug("sdk request 'waf.DescribeDomainDetail'", slog.Any("request", describeDomainDetailReq), slog.Any("response", describeDomainDetailResp)) d.logger.Debug("sdk request 'waf.DescribeDomainDetail'", slog.Any("request", describeDomainDetailReq), slog.Any("response", describeDomainDetailResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDomainDetail'") return fmt.Errorf("failed to execute sdk request 'waf.DescribeDomainDetail': %w", err)
} }
// 修改 CNAME 接入资源 // 修改 CNAME 接入资源
@ -157,14 +156,14 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPem string, pri
InstanceId: tea.String(d.config.InstanceId), InstanceId: tea.String(d.config.InstanceId),
RegionId: tea.String(d.config.Region), RegionId: tea.String(d.config.Region),
Domain: tea.String(d.config.Domain), Domain: tea.String(d.config.Domain),
Listen: &aliwaf.ModifyDomainRequestListen{CertId: tea.String(upres.CertId)}, Listen: &aliwaf.ModifyDomainRequestListen{CertId: tea.String(upres.ExtendedData["certIdentifier"].(string))},
Redirect: &aliwaf.ModifyDomainRequestRedirect{Loadbalance: tea.String("iphash")}, Redirect: &aliwaf.ModifyDomainRequestRedirect{Loadbalance: tea.String("iphash")},
} }
modifyDomainReq = assign(modifyDomainReq, describeDomainDetailResp.Body) modifyDomainReq = assign(modifyDomainReq, describeDomainDetailResp.Body)
modifyDomainResp, err := d.sdkClient.ModifyDomain(modifyDomainReq) modifyDomainResp, err := d.sdkClient.ModifyDomain(modifyDomainReq)
d.logger.Debug("sdk request 'waf.ModifyDomain'", slog.Any("request", modifyDomainReq), slog.Any("response", modifyDomainResp)) d.logger.Debug("sdk request 'waf.ModifyDomain'", slog.Any("request", modifyDomainReq), slog.Any("response", modifyDomainResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDomain'") return fmt.Errorf("failed to execute sdk request 'waf.ModifyDomain': %w", err)
} }
} }
@ -193,7 +192,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
// 阿里云 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"

View File

@ -1,4 +1,4 @@
package aliyunwaf_test package aliyunwaf_test
import ( import (
"context" "context"

View File

@ -1,11 +1,10 @@
package awsacm package awsacm
import ( import (
"context" "context"
"fmt"
"log/slog" "log/slog"
xerrors "github.com/pkg/errors"
"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"
@ -39,7 +38,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
Region: config.Region, Region: config.Region,
}) })
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -59,11 +58,11 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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 // 上传证书到 ACM
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }

View File

@ -1,8 +1,9 @@
package awscloudfront package awscloudfront
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"log/slog" "log/slog"
aws "github.com/aws/aws-sdk-go-v2/aws" aws "github.com/aws/aws-sdk-go-v2/aws"
@ -10,7 +11,6 @@ import (
awscred "github.com/aws/aws-sdk-go-v2/credentials" awscred "github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront"
"github.com/aws/aws-sdk-go-v2/service/cloudfront/types" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
"github.com/usual2970/certimate/internal/pkg/core/uploader" "github.com/usual2970/certimate/internal/pkg/core/uploader"
@ -44,7 +44,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region) client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
@ -53,7 +53,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
Region: config.Region, Region: config.Region,
}) })
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -74,15 +74,15 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
if d.config.DistributionId == "" { if d.config.DistributionId == "" {
return nil, errors.New("config `distribuitionId` is required") return nil, errors.New("config `distribuitionId` is required")
} }
// 上传证书到 ACM // 上传证书到 ACM
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -95,7 +95,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
getDistributionConfigResp, err := d.sdkClient.GetDistributionConfig(context.TODO(), getDistributionConfigReq) getDistributionConfigResp, err := d.sdkClient.GetDistributionConfig(context.TODO(), getDistributionConfigReq)
d.logger.Debug("sdk request 'cloudfront.GetDistributionConfig'", slog.Any("request", getDistributionConfigReq), slog.Any("response", getDistributionConfigResp)) d.logger.Debug("sdk request 'cloudfront.GetDistributionConfig'", slog.Any("request", getDistributionConfigReq), slog.Any("response", getDistributionConfigResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cloudfront.GetDistributionConfig'") return nil, fmt.Errorf("failed to execute sdk request 'cloudfront.GetDistributionConfig': %w", err)
} }
// 更新分配配置 // 更新分配配置
@ -113,7 +113,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
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 {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cloudfront.UpdateDistribution'") return nil, fmt.Errorf("failed to execute sdk request 'cloudfront.UpdateDistribution': %w", err)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil

View File

@ -1,4 +1,4 @@
package awscloudfront_test package awscloudfront_test
import ( import (
"context" "context"

View File

@ -1,14 +1,23 @@
package azurekeyvault package azurekeyvault
import ( import (
"context" "context"
"crypto/x509"
"encoding/base64"
"errors"
"fmt"
"log/slog" "log/slog"
xerrors "github.com/pkg/errors" "github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates"
"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/azure-keyvault" uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/azure-keyvault"
azcommon "github.com/usual2970/certimate/internal/pkg/sdk3rd/azure/common"
certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
) )
type DeployerConfig struct { type DeployerConfig struct {
@ -22,11 +31,15 @@ type DeployerConfig struct {
CloudName string `json:"cloudName,omitempty"` CloudName string `json:"cloudName,omitempty"`
// Key Vault 名称。 // Key Vault 名称。
KeyVaultName string `json:"keyvaultName"` KeyVaultName string `json:"keyvaultName"`
// Key Vault 证书名称。
// 选填。
CertificateName string `json:"certificateName,omitempty"`
} }
type DeployerProvider struct { type DeployerProvider struct {
config *DeployerConfig config *DeployerConfig
logger *slog.Logger logger *slog.Logger
sdkClient *azcertificates.Client
sslUploader uploader.Uploader sslUploader uploader.Uploader
} }
@ -37,6 +50,11 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
panic("config is nil") panic("config is nil")
} }
client, err := createSdkClient(config.TenantId, config.ClientId, config.ClientSecret, config.CloudName, config.KeyVaultName)
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{
TenantId: config.TenantId, TenantId: config.TenantId,
ClientId: config.ClientId, ClientId: config.ClientId,
@ -45,12 +63,13 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
KeyVaultName: config.KeyVaultName, KeyVaultName: config.KeyVaultName,
}) })
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
config: config, config: config,
logger: slog.Default(), logger: slog.Default(),
sdkClient: client,
sslUploader: uploader, sslUploader: uploader,
}, nil }, nil
} }
@ -65,14 +84,94 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// 上传证书到 KeyVault // 解析证书内容
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) certX509, err := certutil.ParseCertificateFromPEM(certPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, err
}
// 转换证书格式
certPFX, err := certutil.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, "")
if err != nil {
return nil, fmt.Errorf("failed to transform certificate from PEM to PFX: %w", err)
}
if d.config.CertificateName == "" {
// 上传证书到 KeyVault
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))
}
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) // 获取证书
// REF: https://learn.microsoft.com/en-us/rest/api/keyvault/certificates/get-certificate/get-certificate
getCertificateResp, err := d.sdkClient.GetCertificate(context.TODO(), d.config.CertificateName, "", nil)
d.logger.Debug("sdk request 'keyvault.GetCertificate'", slog.String("request.certificateName", d.config.CertificateName), slog.Any("response", getCertificateResp))
if err != nil {
var respErr *azcore.ResponseError
if !errors.As(err, &respErr) || (respErr.ErrorCode != "ResourceNotFound" && respErr.ErrorCode != "CertificateNotFound") {
return nil, fmt.Errorf("failed to execute sdk request 'keyvault.GetCertificate': %w", err)
}
} else {
oldCertX509, err := x509.ParseCertificate(getCertificateResp.CER)
if err == nil {
if certutil.EqualCertificate(certX509, oldCertX509) {
return &deployer.DeployResult{}, nil
}
}
}
// 导入证书
// REF: https://learn.microsoft.com/en-us/rest/api/keyvault/certificates/import-certificate/import-certificate
importCertificateParams := azcertificates.ImportCertificateParameters{
Base64EncodedCertificate: to.Ptr(base64.StdEncoding.EncodeToString(certPFX)),
CertificatePolicy: &azcertificates.CertificatePolicy{
SecretProperties: &azcertificates.SecretProperties{
ContentType: to.Ptr("application/x-pkcs12"),
},
},
Tags: map[string]*string{
"certimate/cert-cn": to.Ptr(certX509.Subject.CommonName),
"certimate/cert-sn": to.Ptr(certX509.SerialNumber.Text(16)),
},
}
importCertificateResp, err := d.sdkClient.ImportCertificate(context.TODO(), d.config.CertificateName, importCertificateParams, nil)
d.logger.Debug("sdk request 'keyvault.ImportCertificate'", slog.String("request.certificateName", d.config.CertificateName), slog.Any("request.parameters", importCertificateParams), slog.Any("response", importCertificateResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'keyvault.ImportCertificate': %w", err)
}
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
} }
func createSdkClient(tenantId, clientId, clientSecret, cloudName, keyvaultName string) (*azcertificates.Client, error) {
env, err := azcommon.GetCloudEnvironmentConfiguration(cloudName)
if err != nil {
return nil, err
}
clientOptions := azcore.ClientOptions{Cloud: env}
credential, err := azidentity.NewClientSecretCredential(tenantId, clientId, clientSecret,
&azidentity.ClientSecretCredentialOptions{ClientOptions: clientOptions})
if err != nil {
return nil, err
}
endpoint := fmt.Sprintf("https://%s.vault.azure.net", keyvaultName)
if azcommon.IsEnvironmentGovernment(cloudName) {
endpoint = fmt.Sprintf("https://%s.vault.usgovcloudapi.net", keyvaultName)
} else if azcommon.IsEnvironmentChina(cloudName) {
endpoint = fmt.Sprintf("https://%s.vault.azure.cn", keyvaultName)
}
client, err := azcertificates.NewClient(endpoint, credential, nil)
if err != nil {
return nil, err
}
return client, nil
}

View File

@ -1,4 +1,4 @@
package baiducloudappblb package baiducloudappblb
import ( import (
"context" "context"
@ -10,12 +10,11 @@ import (
bceappblb "github.com/baidubce/bce-sdk-go/services/appblb" bceappblb "github.com/baidubce/bce-sdk-go/services/appblb"
"github.com/google/uuid" "github.com/google/uuid"
xerrors "github.com/pkg/errors"
"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/baiducloud-cert" uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/baiducloud-cert"
"github.com/usual2970/certimate/internal/pkg/utils/sliceutil" sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
) )
type DeployerConfig struct { type DeployerConfig struct {
@ -54,7 +53,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region) client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
@ -62,7 +61,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
SecretAccessKey: config.SecretAccessKey, SecretAccessKey: config.SecretAccessKey,
}) })
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -82,11 +81,11 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// 上传证书到 CAS // 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -104,7 +103,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
} }
default: default:
return nil, fmt.Errorf("unsupported resource type: %s", d.config.ResourceType) return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
@ -120,7 +119,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
describeLoadBalancerDetailResp, err := d.sdkClient.DescribeLoadBalancerDetail(d.config.LoadbalancerId) describeLoadBalancerDetailResp, err := d.sdkClient.DescribeLoadBalancerDetail(d.config.LoadbalancerId)
d.logger.Debug("sdk request 'appblb.DescribeLoadBalancerAttribute'", slog.String("blbId", d.config.LoadbalancerId), slog.Any("response", describeLoadBalancerDetailResp)) d.logger.Debug("sdk request 'appblb.DescribeLoadBalancerAttribute'", slog.String("blbId", d.config.LoadbalancerId), slog.Any("response", describeLoadBalancerDetailResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'appblb.DescribeLoadBalancerDetail'") return fmt.Errorf("failed to execute sdk request 'appblb.DescribeLoadBalancerDetail': %w", err)
} }
// 获取全部 HTTPS/SSL 监听端口 // 获取全部 HTTPS/SSL 监听端口
@ -153,8 +152,14 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
var errs []error var errs []error
for _, listener := range listeners { for _, listener := range listeners {
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listener.Type, listener.Port, cloudCertId); err != nil { select {
errs = append(errs, err) case <-ctx.Done():
return ctx.Err()
default:
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listener.Type, listener.Port, cloudCertId); err != nil {
errs = append(errs, err)
}
} }
} }
@ -182,7 +187,7 @@ func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId str
describeAppAllListenersResp, err := d.sdkClient.DescribeAppAllListeners(d.config.LoadbalancerId, describeAppAllListenersRequest) describeAppAllListenersResp, err := d.sdkClient.DescribeAppAllListeners(d.config.LoadbalancerId, describeAppAllListenersRequest)
d.logger.Debug("sdk request 'appblb.DescribeAppAllListeners'", slog.String("blbId", d.config.LoadbalancerId), slog.Any("request", describeAppAllListenersRequest), slog.Any("response", describeAppAllListenersResp)) d.logger.Debug("sdk request 'appblb.DescribeAppAllListeners'", slog.String("blbId", d.config.LoadbalancerId), slog.Any("request", describeAppAllListenersRequest), slog.Any("response", describeAppAllListenersResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'appblb.DescribeAppAllListeners'") return fmt.Errorf("failed to execute sdk request 'appblb.DescribeAppAllListeners': %w", err)
} }
// 获取全部 HTTPS/SSL 监听端口 // 获取全部 HTTPS/SSL 监听端口
@ -210,8 +215,14 @@ func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId str
var errs []error var errs []error
for _, listener := range listeners { for _, listener := range listeners {
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listener.Type, listener.Port, cloudCertId); err != nil { select {
errs = append(errs, err) case <-ctx.Done():
return ctx.Err()
default:
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listener.Type, listener.Port, cloudCertId); err != nil {
errs = append(errs, err)
}
} }
} }
@ -230,7 +241,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
case "SSL": case "SSL":
return d.updateSslListenerCertificate(ctx, cloudLoadbalancerId, cloudListenerPort, cloudCertId) return d.updateSslListenerCertificate(ctx, cloudLoadbalancerId, cloudListenerPort, cloudCertId)
default: default:
return fmt.Errorf("unsupported listener type: %s", cloudListenerType) return fmt.Errorf("unsupported listener type '%s'", cloudListenerType)
} }
} }
@ -244,7 +255,7 @@ func (d *DeployerProvider) updateHttpsListenerCertificate(ctx context.Context, c
describeAppHTTPSListenersResp, err := d.sdkClient.DescribeAppHTTPSListeners(cloudLoadbalancerId, describeAppHTTPSListenersReq) describeAppHTTPSListenersResp, err := d.sdkClient.DescribeAppHTTPSListeners(cloudLoadbalancerId, describeAppHTTPSListenersReq)
d.logger.Debug("sdk request 'appblb.DescribeAppHTTPSListeners'", slog.String("blbId", cloudLoadbalancerId), slog.Any("request", describeAppHTTPSListenersReq), slog.Any("response", describeAppHTTPSListenersResp)) d.logger.Debug("sdk request 'appblb.DescribeAppHTTPSListeners'", slog.String("blbId", cloudLoadbalancerId), slog.Any("request", describeAppHTTPSListenersReq), slog.Any("response", describeAppHTTPSListenersResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'appblb.DescribeAppHTTPSListeners'") return fmt.Errorf("failed to execute sdk request 'appblb.DescribeAppHTTPSListeners': %w", err)
} else if len(describeAppHTTPSListenersResp.ListenerList) == 0 { } else if len(describeAppHTTPSListenersResp.ListenerList) == 0 {
return fmt.Errorf("listener %s:%d not found", cloudLoadbalancerId, cloudHttpsListenerPort) return fmt.Errorf("listener %s:%d not found", cloudLoadbalancerId, cloudHttpsListenerPort)
} }
@ -257,12 +268,13 @@ func (d *DeployerProvider) updateHttpsListenerCertificate(ctx context.Context, c
updateAppHTTPSListenerReq := &bceappblb.UpdateAppHTTPSListenerArgs{ updateAppHTTPSListenerReq := &bceappblb.UpdateAppHTTPSListenerArgs{
ClientToken: generateClientToken(), ClientToken: generateClientToken(),
ListenerPort: uint16(cloudHttpsListenerPort), ListenerPort: uint16(cloudHttpsListenerPort),
Scheduler: describeAppHTTPSListenersResp.ListenerList[0].Scheduler,
CertIds: []string{cloudCertId}, CertIds: []string{cloudCertId},
} }
err := d.sdkClient.UpdateAppHTTPSListener(cloudLoadbalancerId, updateAppHTTPSListenerReq) err := d.sdkClient.UpdateAppHTTPSListener(cloudLoadbalancerId, updateAppHTTPSListenerReq)
d.logger.Debug("sdk request 'appblb.UpdateAppHTTPSListener'", slog.Any("request", updateAppHTTPSListenerReq)) d.logger.Debug("sdk request 'appblb.UpdateAppHTTPSListener'", slog.Any("request", updateAppHTTPSListenerReq))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'appblb.UpdateAppHTTPSListener'") return fmt.Errorf("failed to execute sdk request 'appblb.UpdateAppHTTPSListener': %w", err)
} }
} else { } else {
// 指定 SNI需部署到扩展域名 // 指定 SNI需部署到扩展域名
@ -272,6 +284,7 @@ func (d *DeployerProvider) updateHttpsListenerCertificate(ctx context.Context, c
updateAppHTTPSListenerReq := &bceappblb.UpdateAppHTTPSListenerArgs{ updateAppHTTPSListenerReq := &bceappblb.UpdateAppHTTPSListenerArgs{
ClientToken: generateClientToken(), ClientToken: generateClientToken(),
ListenerPort: uint16(cloudHttpsListenerPort), ListenerPort: uint16(cloudHttpsListenerPort),
Scheduler: describeAppHTTPSListenersResp.ListenerList[0].Scheduler,
AdditionalCertDomains: sliceutil.Map(describeAppHTTPSListenersResp.ListenerList[0].AdditionalCertDomains, func(domain bceappblb.AdditionalCertDomainsModel) bceappblb.AdditionalCertDomainsModel { AdditionalCertDomains: sliceutil.Map(describeAppHTTPSListenersResp.ListenerList[0].AdditionalCertDomains, func(domain bceappblb.AdditionalCertDomainsModel) bceappblb.AdditionalCertDomainsModel {
if domain.Host == d.config.Domain { if domain.Host == d.config.Domain {
return bceappblb.AdditionalCertDomainsModel{ return bceappblb.AdditionalCertDomainsModel{
@ -289,7 +302,7 @@ func (d *DeployerProvider) updateHttpsListenerCertificate(ctx context.Context, c
err := d.sdkClient.UpdateAppHTTPSListener(cloudLoadbalancerId, updateAppHTTPSListenerReq) err := d.sdkClient.UpdateAppHTTPSListener(cloudLoadbalancerId, updateAppHTTPSListenerReq)
d.logger.Debug("sdk request 'appblb.UpdateAppHTTPSListener'", slog.Any("request", updateAppHTTPSListenerReq)) d.logger.Debug("sdk request 'appblb.UpdateAppHTTPSListener'", slog.Any("request", updateAppHTTPSListenerReq))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'appblb.UpdateAppHTTPSListener'") return fmt.Errorf("failed to execute sdk request 'appblb.UpdateAppHTTPSListener': %w", err)
} }
} }
@ -307,7 +320,7 @@ func (d *DeployerProvider) updateSslListenerCertificate(ctx context.Context, clo
err := d.sdkClient.UpdateAppSSLListener(cloudLoadbalancerId, updateAppSSLListenerReq) err := d.sdkClient.UpdateAppSSLListener(cloudLoadbalancerId, updateAppSSLListenerReq)
d.logger.Debug("sdk request 'appblb.UpdateAppSSLListener'", slog.Any("request", updateAppSSLListenerReq)) d.logger.Debug("sdk request 'appblb.UpdateAppSSLListener'", slog.Any("request", updateAppSSLListenerReq))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'appblb.UpdateAppSSLListener'") return fmt.Errorf("failed to execute sdk request 'appblb.UpdateAppSSLListener': %w", err)
} }
return nil return nil

View File

@ -1,4 +1,4 @@
package baiducloudappblb_test package baiducloudappblb_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package baiducloudappblb package baiducloudappblb
type ResourceType string type ResourceType string

View File

@ -1,4 +1,4 @@
package baiducloudblb package baiducloudblb
import ( import (
"context" "context"
@ -10,12 +10,11 @@ import (
bceblb "github.com/baidubce/bce-sdk-go/services/blb" bceblb "github.com/baidubce/bce-sdk-go/services/blb"
"github.com/google/uuid" "github.com/google/uuid"
xerrors "github.com/pkg/errors"
"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/baiducloud-cert" uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/baiducloud-cert"
"github.com/usual2970/certimate/internal/pkg/utils/sliceutil" sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
) )
type DeployerConfig struct { type DeployerConfig struct {
@ -54,7 +53,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region) client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
@ -62,7 +61,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
SecretAccessKey: config.SecretAccessKey, SecretAccessKey: config.SecretAccessKey,
}) })
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -82,11 +81,11 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// 上传证书到 CAS // 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -104,7 +103,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
} }
default: default:
return nil, fmt.Errorf("unsupported resource type: %s", d.config.ResourceType) return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
@ -120,7 +119,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
describeLoadBalancerDetailResp, err := d.sdkClient.DescribeLoadBalancerDetail(d.config.LoadbalancerId) describeLoadBalancerDetailResp, err := d.sdkClient.DescribeLoadBalancerDetail(d.config.LoadbalancerId)
d.logger.Debug("sdk request 'blb.DescribeLoadBalancerAttribute'", slog.String("blbId", d.config.LoadbalancerId), slog.Any("response", describeLoadBalancerDetailResp)) d.logger.Debug("sdk request 'blb.DescribeLoadBalancerAttribute'", slog.String("blbId", d.config.LoadbalancerId), slog.Any("response", describeLoadBalancerDetailResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'blb.DescribeLoadBalancerDetail'") return fmt.Errorf("failed to execute sdk request 'blb.DescribeLoadBalancerDetail': %w", err)
} }
// 获取全部 HTTPS/SSL 监听端口 // 获取全部 HTTPS/SSL 监听端口
@ -153,8 +152,14 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
var errs []error var errs []error
for _, listener := range listeners { for _, listener := range listeners {
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listener.Type, listener.Port, cloudCertId); err != nil { select {
errs = append(errs, err) case <-ctx.Done():
return ctx.Err()
default:
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listener.Type, listener.Port, cloudCertId); err != nil {
errs = append(errs, err)
}
} }
} }
@ -182,7 +187,7 @@ func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId str
describeAllListenersResp, err := d.sdkClient.DescribeAllListeners(d.config.LoadbalancerId, describeAllListenersRequest) describeAllListenersResp, err := d.sdkClient.DescribeAllListeners(d.config.LoadbalancerId, describeAllListenersRequest)
d.logger.Debug("sdk request 'blb.DescribeAllListeners'", slog.String("blbId", d.config.LoadbalancerId), slog.Any("request", describeAllListenersRequest), slog.Any("response", describeAllListenersResp)) d.logger.Debug("sdk request 'blb.DescribeAllListeners'", slog.String("blbId", d.config.LoadbalancerId), slog.Any("request", describeAllListenersRequest), slog.Any("response", describeAllListenersResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'blb.DescribeAllListeners'") return fmt.Errorf("failed to execute sdk request 'blb.DescribeAllListeners': %w", err)
} }
// 获取全部 HTTPS/SSL 监听端口 // 获取全部 HTTPS/SSL 监听端口
@ -210,8 +215,14 @@ func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId str
var errs []error var errs []error
for _, listener := range listeners { for _, listener := range listeners {
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listener.Type, listener.Port, cloudCertId); err != nil { select {
errs = append(errs, err) case <-ctx.Done():
return ctx.Err()
default:
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listener.Type, listener.Port, cloudCertId); err != nil {
errs = append(errs, err)
}
} }
} }
@ -230,7 +241,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
case "SSL": case "SSL":
return d.updateSslListenerCertificate(ctx, cloudLoadbalancerId, cloudListenerPort, cloudCertId) return d.updateSslListenerCertificate(ctx, cloudLoadbalancerId, cloudListenerPort, cloudCertId)
default: default:
return fmt.Errorf("unsupported listener type: %s", cloudListenerType) return fmt.Errorf("unsupported listener type '%s'", cloudListenerType)
} }
} }
@ -244,7 +255,7 @@ func (d *DeployerProvider) updateHttpsListenerCertificate(ctx context.Context, c
describeHTTPSListenersResp, err := d.sdkClient.DescribeHTTPSListeners(cloudLoadbalancerId, describeHTTPSListenersReq) describeHTTPSListenersResp, err := d.sdkClient.DescribeHTTPSListeners(cloudLoadbalancerId, describeHTTPSListenersReq)
d.logger.Debug("sdk request 'blb.DescribeHTTPSListeners'", slog.String("blbId", cloudLoadbalancerId), slog.Any("request", describeHTTPSListenersReq), slog.Any("response", describeHTTPSListenersResp)) d.logger.Debug("sdk request 'blb.DescribeHTTPSListeners'", slog.String("blbId", cloudLoadbalancerId), slog.Any("request", describeHTTPSListenersReq), slog.Any("response", describeHTTPSListenersResp))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'blb.DescribeHTTPSListeners'") return fmt.Errorf("failed to execute sdk request 'blb.DescribeHTTPSListeners': %w", err)
} else if len(describeHTTPSListenersResp.ListenerList) == 0 { } else if len(describeHTTPSListenersResp.ListenerList) == 0 {
return fmt.Errorf("listener %s:%d not found", cloudLoadbalancerId, cloudHttpsListenerPort) return fmt.Errorf("listener %s:%d not found", cloudLoadbalancerId, cloudHttpsListenerPort)
} }
@ -262,7 +273,7 @@ func (d *DeployerProvider) updateHttpsListenerCertificate(ctx context.Context, c
err := d.sdkClient.UpdateHTTPSListener(cloudLoadbalancerId, updateHTTPSListenerReq) err := d.sdkClient.UpdateHTTPSListener(cloudLoadbalancerId, updateHTTPSListenerReq)
d.logger.Debug("sdk request 'blb.UpdateHTTPSListener'", slog.Any("request", updateHTTPSListenerReq)) d.logger.Debug("sdk request 'blb.UpdateHTTPSListener'", slog.Any("request", updateHTTPSListenerReq))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'blb.UpdateHTTPSListener'") return fmt.Errorf("failed to execute sdk request 'blb.UpdateHTTPSListener': %w", err)
} }
} else { } else {
// 指定 SNI需部署到扩展域名 // 指定 SNI需部署到扩展域名
@ -289,7 +300,7 @@ func (d *DeployerProvider) updateHttpsListenerCertificate(ctx context.Context, c
err := d.sdkClient.UpdateHTTPSListener(cloudLoadbalancerId, updateHTTPSListenerReq) err := d.sdkClient.UpdateHTTPSListener(cloudLoadbalancerId, updateHTTPSListenerReq)
d.logger.Debug("sdk request 'blb.UpdateHTTPSListener'", slog.Any("request", updateHTTPSListenerReq)) d.logger.Debug("sdk request 'blb.UpdateHTTPSListener'", slog.Any("request", updateHTTPSListenerReq))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'blb.UpdateHTTPSListener'") return fmt.Errorf("failed to execute sdk request 'blb.UpdateHTTPSListener': %w", err)
} }
} }
@ -307,7 +318,7 @@ func (d *DeployerProvider) updateSslListenerCertificate(ctx context.Context, clo
err := d.sdkClient.UpdateSSLListener(cloudLoadbalancerId, updateSSLListenerReq) err := d.sdkClient.UpdateSSLListener(cloudLoadbalancerId, updateSSLListenerReq)
d.logger.Debug("sdk request 'blb.UpdateSSLListener'", slog.Any("request", updateSSLListenerReq)) d.logger.Debug("sdk request 'blb.UpdateSSLListener'", slog.Any("request", updateSSLListenerReq))
if err != nil { if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'blb.UpdateSSLListener'") return fmt.Errorf("failed to execute sdk request 'blb.UpdateSSLListener': %w", err)
} }
return nil return nil

View File

@ -1,4 +1,4 @@
package baiducloudblb_test package baiducloudblb_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package baiducloudblb package baiducloudblb
type ResourceType string type ResourceType string

View File

@ -1,4 +1,4 @@
package baiducloudcdn package baiducloudcdn
import ( import (
"context" "context"
@ -8,7 +8,6 @@ import (
bcecdn "github.com/baidubce/bce-sdk-go/services/cdn" bcecdn "github.com/baidubce/bce-sdk-go/services/cdn"
bcecdnapi "github.com/baidubce/bce-sdk-go/services/cdn/api" bcecdnapi "github.com/baidubce/bce-sdk-go/services/cdn/api"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
) )
@ -37,7 +36,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey) client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -56,21 +55,21 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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://cloud.baidu.com/doc/CDN/s/qjzuz2hp8 // REF: https://cloud.baidu.com/doc/CDN/s/qjzuz2hp8
putCertResp, err := d.sdkClient.PutCert( putCertResp, err := d.sdkClient.PutCert(
d.config.Domain, d.config.Domain,
&bcecdnapi.UserCertificate{ &bcecdnapi.UserCertificate{
CertName: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()), CertName: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
ServerData: certPem, ServerData: certPEM,
PrivateData: privkeyPem, PrivateData: privkeyPEM,
}, },
"ON", "ON",
) )
d.logger.Debug("sdk request 'cdn.PutCert'", slog.String("request.domain", d.config.Domain), slog.Any("response", putCertResp)) d.logger.Debug("sdk request 'cdn.PutCert'", slog.String("request.domain", d.config.Domain), slog.Any("response", putCertResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.PutCert'") return nil, fmt.Errorf("failed to execute sdk request 'cdn.PutCert': %w", err)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil

View File

@ -1,4 +1,4 @@
package baiducloudcdn_test package baiducloudcdn_test
import ( import (
"context" "context"

View File

@ -1,11 +1,10 @@
package baiducloudcert package baiducloudcert
import ( import (
"context" "context"
"fmt"
"log/slog" "log/slog"
xerrors "github.com/pkg/errors"
"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/baiducloud-cert" uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/baiducloud-cert"
@ -36,7 +35,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
SecretAccessKey: config.SecretAccessKey, SecretAccessKey: config.SecretAccessKey,
}) })
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader") return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -55,11 +54,11 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
// 上传证书到 CAS // 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }

View File

@ -1,4 +1,4 @@
package baishancdn package baishancdn
import ( import (
"context" "context"
@ -10,10 +10,8 @@ import (
"strings" "strings"
"time" "time"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
bssdk "github.com/usual2970/certimate/internal/pkg/vendors/baishan-sdk" bssdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/baishan"
) )
type DeployerConfig struct { type DeployerConfig struct {
@ -21,6 +19,9 @@ type DeployerConfig struct {
ApiToken string `json:"apiToken"` ApiToken string `json:"apiToken"`
// 加速域名(支持泛域名)。 // 加速域名(支持泛域名)。
Domain string `json:"domain"` Domain string `json:"domain"`
// 证书 ID。
// 选填。
CertificateId string `json:"certificateId,omitempty"`
} }
type DeployerProvider struct { type DeployerProvider struct {
@ -38,7 +39,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.ApiToken) client, err := createSdkClient(config.ApiToken)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -57,68 +58,84 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
if d.config.Domain == "" { if d.config.Domain == "" {
return nil, errors.New("config `domain` is required") return nil, errors.New("config `domain` is required")
} }
// 查询域名配置 if d.config.CertificateId == "" {
// REF: https://portal.baishancloud.com/track/document/api/1/1065 // 新增证书
getDomainConfigReq := &bssdk.GetDomainConfigRequest{ // REF: https://portal.baishancloud.com/track/document/downloadPdf/1441
Domains: d.config.Domain, certificateId := ""
Config: []string{"https"}, createCertificateReq := &bssdk.CreateCertificateRequest{
} Certificate: certPEM,
getDomainConfigResp, err := d.sdkClient.GetDomainConfig(getDomainConfigReq) Key: privkeyPEM,
d.logger.Debug("sdk request 'baishan.GetDomainConfig'", slog.Any("request", getDomainConfigReq), slog.Any("response", getDomainConfigResp)) Name: fmt.Sprintf("certimate_%d", time.Now().UnixMilli()),
if err != nil { }
return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.GetDomainConfig'") createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq)
} else if len(getDomainConfigResp.Data) == 0 { d.logger.Debug("sdk request 'baishan.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
return nil, errors.New("domain config not found") if err != nil {
} if createCertificateResp != nil {
if createCertificateResp.GetCode() == 400699 && strings.Contains(createCertificateResp.GetMessage(), "this certificate is exists") {
// 新增证书 // 证书已存在,忽略新增证书接口错误
// REF: https://portal.baishancloud.com/track/document/downloadPdf/1441 re := regexp.MustCompile(`\d+`)
certificateId := "" certificateId = re.FindString(createCertificateResp.GetMessage())
createCertificateReq := &bssdk.CreateCertificateRequest{ }
Certificate: certPem,
Key: privkeyPem,
Name: fmt.Sprintf("certimate_%d", time.Now().UnixMilli()),
}
createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq)
d.logger.Debug("sdk request 'baishan.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
if err != nil {
if createCertificateResp != nil {
if createCertificateResp.GetCode() == 400699 && strings.Contains(createCertificateResp.GetMessage(), "this certificate is exists") {
// 证书已存在,忽略新增证书接口错误
re := regexp.MustCompile(`\d+`)
certificateId = re.FindString(createCertificateResp.GetMessage())
} }
if certificateId == "" {
return nil, fmt.Errorf("failed to execute sdk request 'baishan.CreateCertificate': %w", err)
}
} else {
certificateId = createCertificateResp.Data.CertId.String()
} }
if certificateId == "" { // 查询域名配置
return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.CreateCertificate'") // REF: https://portal.baishancloud.com/track/document/api/1/1065
getDomainConfigReq := &bssdk.GetDomainConfigRequest{
Domains: d.config.Domain,
Config: []string{"https"},
}
getDomainConfigResp, err := d.sdkClient.GetDomainConfig(getDomainConfigReq)
d.logger.Debug("sdk request 'baishan.GetDomainConfig'", slog.Any("request", getDomainConfigReq), slog.Any("response", getDomainConfigResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'baishan.GetDomainConfig': %w", err)
} else if len(getDomainConfigResp.Data) == 0 {
return nil, errors.New("domain config not found")
}
// 设置域名配置
// REF: https://portal.baishancloud.com/track/document/api/1/1045
setDomainConfigReq := &bssdk.SetDomainConfigRequest{
Domains: d.config.Domain,
Config: &bssdk.DomainConfig{
Https: &bssdk.DomainConfigHttps{
CertId: json.Number(certificateId),
ForceHttps: getDomainConfigResp.Data[0].Config.Https.ForceHttps,
EnableHttp2: getDomainConfigResp.Data[0].Config.Https.EnableHttp2,
EnableOcsp: getDomainConfigResp.Data[0].Config.Https.EnableOcsp,
},
},
}
setDomainConfigResp, err := d.sdkClient.SetDomainConfig(setDomainConfigReq)
d.logger.Debug("sdk request 'baishan.SetDomainConfig'", slog.Any("request", setDomainConfigReq), slog.Any("response", setDomainConfigResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'baishan.SetDomainConfig': %w", err)
} }
} else { } else {
certificateId = createCertificateResp.Data.CertId.String() // 替换证书
} // REF: https://portal.baishancloud.com/track/document/downloadPdf/1441
createCertificateReq := &bssdk.CreateCertificateRequest{
// 设置域名配置 CertificateId: &d.config.CertificateId,
// REF: https://portal.baishancloud.com/track/document/api/1/1045 Certificate: certPEM,
setDomainConfigReq := &bssdk.SetDomainConfigRequest{ Key: privkeyPEM,
Domains: d.config.Domain, Name: fmt.Sprintf("certimate_%d", time.Now().UnixMilli()),
Config: &bssdk.DomainConfig{ }
Https: &bssdk.DomainConfigHttps{ createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq)
CertId: json.Number(certificateId), d.logger.Debug("sdk request 'baishan.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
ForceHttps: getDomainConfigResp.Data[0].Config.Https.ForceHttps, if err != nil {
EnableHttp2: getDomainConfigResp.Data[0].Config.Https.EnableHttp2, return nil, fmt.Errorf("failed to execute sdk request 'baishan.CreateCertificate': %w", err)
EnableOcsp: getDomainConfigResp.Data[0].Config.Https.EnableOcsp, }
},
},
}
setDomainConfigResp, err := d.sdkClient.SetDomainConfig(setDomainConfigReq)
d.logger.Debug("sdk request 'baishan.SetDomainConfig'", slog.Any("request", setDomainConfigReq), slog.Any("response", setDomainConfigResp))
if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.SetDomainConfig'")
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil

View File

@ -1,4 +1,4 @@
package baishancdn_test package baishancdn_test
import ( import (
"context" "context"

View File

@ -1,16 +1,15 @@
package baotapanelconsole package baotapanelconsole
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"net/url" "net/url"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
btsdk "github.com/usual2970/certimate/internal/pkg/vendors/btpanel-sdk" btsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/btpanel"
) )
type DeployerConfig struct { type DeployerConfig struct {
@ -39,7 +38,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections) client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -58,16 +57,16 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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 证书
configSavePanelSSLReq := &btsdk.ConfigSavePanelSSLRequest{ configSavePanelSSLReq := &btsdk.ConfigSavePanelSSLRequest{
PrivateKey: privkeyPem, PrivateKey: privkeyPEM,
Certificate: certPem, Certificate: certPEM,
} }
configSavePanelSSLResp, err := d.sdkClient.ConfigSavePanelSSL(configSavePanelSSLReq) configSavePanelSSLResp, err := d.sdkClient.ConfigSavePanelSSL(configSavePanelSSLReq)
d.logger.Debug("sdk request 'bt.ConfigSavePanelSSL'", slog.Any("request", configSavePanelSSLReq), slog.Any("response", configSavePanelSSLResp)) d.logger.Debug("sdk request 'bt.ConfigSavePanelSSL'", slog.Any("request", configSavePanelSSLReq), slog.Any("response", configSavePanelSSLResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.ConfigSavePanelSSL'") return nil, fmt.Errorf("failed to execute sdk request 'bt.ConfigSavePanelSSL': %w", err)
} }
if d.config.AutoRestart { if d.config.AutoRestart {
@ -83,7 +82,7 @@ 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(apiUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil { if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid baota api url") return nil, errors.New("invalid baota api url")
} }
@ -93,7 +92,7 @@ func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client,
} }
client := btsdk.NewClient(apiUrl, apiKey) client := btsdk.NewClient(apiUrl, apiKey)
if allowInsecure { if skipTlsVerify {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
} }

View File

@ -1,4 +1,4 @@
package baotapanelconsole_test package baotapanelconsole_test
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package baotapanelsite package baotapanelsite
import ( import (
"context" "context"
@ -8,11 +8,9 @@ import (
"log/slog" "log/slog"
"net/url" "net/url"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/deployer"
"github.com/usual2970/certimate/internal/pkg/utils/sliceutil" btsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/btpanel"
btsdk "github.com/usual2970/certimate/internal/pkg/vendors/btpanel-sdk" sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
) )
type DeployerConfig struct { type DeployerConfig struct {
@ -45,7 +43,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections) client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, fmt.Errorf("failed to create sdk client: %w", err)
} }
return &DeployerProvider{ return &DeployerProvider{
@ -64,7 +62,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
return d return d
} }
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) {
switch d.config.SiteType { switch d.config.SiteType {
case "php": case "php":
{ {
@ -76,13 +74,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
siteSetSSLReq := &btsdk.SiteSetSSLRequest{ siteSetSSLReq := &btsdk.SiteSetSSLRequest{
SiteName: d.config.SiteName, SiteName: d.config.SiteName,
Type: "0", Type: "0",
Certificate: certPem, Certificate: certPEM,
PrivateKey: privkeyPem, PrivateKey: privkeyPEM,
} }
siteSetSSLResp, err := d.sdkClient.SiteSetSSL(siteSetSSLReq) siteSetSSLResp, err := d.sdkClient.SiteSetSSL(siteSetSSLReq)
d.logger.Debug("sdk request 'bt.SiteSetSSL'", slog.Any("request", siteSetSSLReq), slog.Any("response", siteSetSSLResp)) d.logger.Debug("sdk request 'bt.SiteSetSSL'", slog.Any("request", siteSetSSLReq), slog.Any("response", siteSetSSLResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SiteSetSSL'") return nil, fmt.Errorf("failed to execute sdk request 'bt.SiteSetSSL': %w", err)
} }
} }
@ -94,13 +92,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
// 上传证书 // 上传证书
sslCertSaveCertReq := &btsdk.SSLCertSaveCertRequest{ sslCertSaveCertReq := &btsdk.SSLCertSaveCertRequest{
Certificate: certPem, Certificate: certPEM,
PrivateKey: privkeyPem, PrivateKey: privkeyPEM,
} }
sslCertSaveCertResp, err := d.sdkClient.SSLCertSaveCert(sslCertSaveCertReq) sslCertSaveCertResp, err := d.sdkClient.SSLCertSaveCert(sslCertSaveCertReq)
d.logger.Debug("sdk request 'bt.SSLCertSaveCert'", slog.Any("request", sslCertSaveCertReq), slog.Any("response", sslCertSaveCertResp)) d.logger.Debug("sdk request 'bt.SSLCertSaveCert'", slog.Any("request", sslCertSaveCertReq), slog.Any("response", sslCertSaveCertResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SSLCertSaveCert'") return nil, fmt.Errorf("failed to execute sdk request 'bt.SSLCertSaveCert': %w", err)
} }
// 设置站点证书 // 设置站点证书
@ -115,18 +113,18 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
sslSetBatchCertToSiteResp, err := d.sdkClient.SSLSetBatchCertToSite(sslSetBatchCertToSiteReq) sslSetBatchCertToSiteResp, err := d.sdkClient.SSLSetBatchCertToSite(sslSetBatchCertToSiteReq)
d.logger.Debug("sdk request 'bt.SSLSetBatchCertToSite'", slog.Any("request", sslSetBatchCertToSiteReq), slog.Any("response", sslSetBatchCertToSiteResp)) d.logger.Debug("sdk request 'bt.SSLSetBatchCertToSite'", slog.Any("request", sslSetBatchCertToSiteReq), slog.Any("response", sslSetBatchCertToSiteResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SSLSetBatchCertToSite'") return nil, fmt.Errorf("failed to execute sdk request 'bt.SSLSetBatchCertToSite': %w", err)
} }
} }
default: default:
return nil, fmt.Errorf("unsupported site type: %s", d.config.SiteType) return nil, fmt.Errorf("unsupported site type '%s'", d.config.SiteType)
} }
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
} }
func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, error) { func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil { if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid baota api url") return nil, errors.New("invalid baota api url")
} }
@ -136,7 +134,7 @@ func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client,
} }
client := btsdk.NewClient(apiUrl, apiKey) client := btsdk.NewClient(apiUrl, apiKey)
if allowInsecure { if skipTlsVerify {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
} }

View File

@ -1,4 +1,4 @@
package baotapanelsite_test package baotapanelsite_test
import ( import (
"context" "context"

View File

@ -0,0 +1,66 @@
package bunnycdn
import (
"context"
"encoding/base64"
"fmt"
"log/slog"
"github.com/usual2970/certimate/internal/pkg/core/deployer"
bunnysdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/bunny"
)
type DeployerConfig struct {
// Bunny API Key。
ApiKey string `json:"apiKey"`
// Bunny Pull Zone ID。
PullZoneId string `json:"pullZoneId"`
// Bunny CDN Hostname支持泛域名
Hostname string `json:"hostname"`
}
type DeployerProvider struct {
config *DeployerConfig
logger *slog.Logger
sdkClient *bunnysdk.Client
}
var _ deployer.Deployer = (*DeployerProvider)(nil)
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
if config == nil {
panic("config is nil")
}
return &DeployerProvider{
config: config,
logger: slog.Default(),
sdkClient: bunnysdk.NewClient(config.ApiKey),
}, nil
}
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
if logger == nil {
d.logger = slog.Default()
} else {
d.logger = logger
}
return d
}
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
// 上传证书
createCertificateReq := &bunnysdk.AddCustomCertificateRequest{
Hostname: d.config.Hostname,
PullZoneId: d.config.PullZoneId,
Certificate: base64.StdEncoding.EncodeToString([]byte(certPEM)),
CertificateKey: base64.StdEncoding.EncodeToString([]byte(privkeyPEM)),
}
createCertificateResp, err := d.sdkClient.AddCustomCertificate(createCertificateReq)
d.logger.Debug("sdk request 'bunny.AddCustomCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'bunny.AddCustomCertificate': %w", err)
}
return &deployer.DeployResult{}, nil
}

Some files were not shown because too many files have changed in this diff Show More