Merge pull request #465 from fudiwei/hotfix

bugfix
This commit is contained in:
Yoan.liu 2025-02-28 09:12:35 +08:00 committed by GitHub
commit 28647d6902
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 391 additions and 53 deletions

View File

@ -138,7 +138,7 @@ The following hosting providers are supported:
| [Doge Cloud](https://www.dogecloud.com/) | Supports deployment to Doge Cloud CDN |
| [UCloud](https://www.ucloud-global.com/) | Supports deployment to UCloud US3, UCDN |
| [SafeLine](https://waf.chaitin.com/) | Supports deployment to SafeLine WAF |
| [BaoTa Panel](https://www.bt.cn/) | Supports deployment to BaoTa Panel sites |
| [aaPanel](https://www.aapanel.com/) | Supports deployment to aaPanel (aka BaoTaPanel) sites |
| [AWS](https://aws.amazon.com/) | Supports deployment to AWS CloudFront |
| [BytePlus](https://www.byteplus.com/) | Supports deployment to BytePlus CDN |
| [CacheFly](https://www.cachefly.com/) | Supports deployment to CacheFly CDN |

8
go.mod
View File

@ -51,12 +51,16 @@ require (
)
require (
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 // 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/privatedns/armprivatedns v1.3.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.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1 // 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.3.3 // indirect
github.com/G-Core/gcorelabscdn-go v1.0.26 // indirect
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 // indirect
github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect

13
go.sum
View File

@ -54,10 +54,17 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WW
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1 h1:1mvYtZfWQAnwNah/C+Z+Jb9rQH95LPE2vlmMuWAHJk8=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1/go.mod h1:75I/mXtme1JyWFtz8GocPHVFyH421IBoZErnO16dd0k=
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.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.1 h1:Bk5uOhSAenHyR5P61D/NzeQCv+4fEVV8mOkJ82NqpWw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.1/go.mod h1:QZ4pw3or1WPmRBxf0cHd1tknzrT54WPBOQoGutCPvSU=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
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.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
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/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0 h1:2qsIIvxVT+uE6yrNldntJKlLRgxGbZ85kgtz5SNBhMw=
@ -68,10 +75,16 @@ 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/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/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/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
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.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
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.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=

View File

@ -1,13 +1,12 @@
package azuredns
import (
"fmt"
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/azuredns"
azcommon "github.com/usual2970/certimate/internal/pkg/vendors/azure-sdk/common"
)
type ChallengeProviderConfig struct {
@ -29,16 +28,11 @@ func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider,
providerConfig.ClientID = config.ClientId
providerConfig.ClientSecret = config.ClientSecret
if config.CloudName != "" {
switch strings.ToLower(config.CloudName) {
case "default", "public", "cloud", "azurecloud":
providerConfig.Environment = cloud.AzurePublic
case "usgovernment", "azureusgovernment":
providerConfig.Environment = cloud.AzureGovernment
case "china", "chinacloud", "azurechina", "azurechinacloud":
providerConfig.Environment = cloud.AzureChina
default:
return nil, fmt.Errorf("azuredns: unknown environment %s", config.CloudName)
env, err := azcommon.GetCloudEnvironmentConfiguration(config.CloudName)
if err != nil {
return nil, err
}
providerConfig.Environment = env
}
if config.DnsPropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second

View File

@ -47,6 +47,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
}
return &DeployerProvider{
config: config,
logger: logger.NewNilLogger(),
sdkClient: client,
sslUploader: uploader,

View File

@ -60,6 +60,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
return &DeployerProvider{
config: config,
logger: logger.NewNilLogger(),
sdkClient: client,
sslUploader: uploader,
}, nil

View File

@ -2,14 +2,13 @@
import (
"context"
"fmt"
"time"
aws "github.com/aws/aws-sdk-go-v2/aws"
awsCfg "github.com/aws/aws-sdk-go-v2/config"
awsCred "github.com/aws/aws-sdk-go-v2/credentials"
awsAcm "github.com/aws/aws-sdk-go-v2/service/acm"
xerrors "github.com/pkg/errors"
"golang.org/x/exp/slices"
"github.com/usual2970/certimate/internal/pkg/core/uploader"
"github.com/usual2970/certimate/internal/pkg/utils/certs"
@ -54,13 +53,74 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe
return nil, err
}
// 生成 AWS 所需的服务端证书和证书链参数
// 生成 AWS 业务参数
scertPem, _ := certs.ConvertCertificateToPEM(certX509)
bcertPem := certPem
// 生成新证书名(需符合 AWS 命名规则)
var certId, certName string
certName = fmt.Sprintf("certimate_%d", time.Now().UnixMilli())
// 获取证书列表,避免重复上传
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ListCertificates.html
listCertificatesNextToken := new(string)
listCertificatesMaxItems := int32(1000)
for {
listCertificatesReq := &awsAcm.ListCertificatesInput{
NextToken: listCertificatesNextToken,
MaxItems: aws.Int32(listCertificatesMaxItems),
}
listCertificatesResp, err := u.sdkClient.ListCertificates(context.TODO(), listCertificatesReq)
if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'acm.ListCertificates'")
}
for _, certSummary := range listCertificatesResp.CertificateSummaryList {
// 先对比证书有效期
if certSummary.NotBefore == nil || !certSummary.NotBefore.Equal(certX509.NotBefore) {
continue
}
if certSummary.NotAfter == nil || !certSummary.NotAfter.Equal(certX509.NotAfter) {
continue
}
// 再对比证书多域名
if !slices.Equal(certX509.DNSNames, certSummary.SubjectAlternativeNameSummaries) {
continue
}
// 最后对比证书内容
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ListTagsForCertificate.html
getCertificateReq := &awsAcm.GetCertificateInput{
CertificateArn: certSummary.CertificateArn,
}
getCertificateResp, err := u.sdkClient.GetCertificate(context.TODO(), getCertificateReq)
if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'acm.GetCertificate'")
} else {
oldCertPem := aws.ToString(getCertificateResp.CertificateChain)
if oldCertPem == "" {
oldCertPem = aws.ToString(getCertificateResp.Certificate)
}
oldCertX509, err := certs.ParseCertificateFromPEM(oldCertPem)
if err != nil {
continue
}
if !certs.EqualCertificate(certX509, oldCertX509) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
return &uploader.UploadResult{
CertId: *certSummary.CertificateArn,
}, nil
}
if listCertificatesResp.NextToken == nil || len(listCertificatesResp.CertificateSummaryList) < int(listCertificatesMaxItems) {
break
} else {
listCertificatesNextToken = listCertificatesResp.NextToken
}
}
// 导入证书
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ImportCertificate.html
@ -74,10 +134,8 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe
return nil, xerrors.Wrap(err, "failed to execute sdk request 'acm.ImportCertificate'")
}
certId = *importCertificateResp.CertificateArn
return &uploader.UploadResult{
CertId: certId,
CertName: certName,
CertId: *importCertificateResp.CertificateArn,
}, nil
}

View File

@ -0,0 +1,181 @@
package azurekeyvault
import (
"context"
"crypto/x509"
"fmt"
"time"
"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/keyvault/azcertificates"
xerrors "github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/uploader"
"github.com/usual2970/certimate/internal/pkg/utils/certs"
azcommon "github.com/usual2970/certimate/internal/pkg/vendors/azure-sdk/common"
)
type UploaderConfig struct {
// Azure TenantId。
TenantId string `json:"tenantId"`
// Azure ClientId。
ClientId string `json:"clientId"`
// Azure ClientSecret。
ClientSecret string `json:"clientSecret"`
// Azure 主权云环境。
CloudName string `json:"cloudName,omitempty"`
// Key Vault 名称。
KeyVaultName string `json:"keyvaultName"`
}
type UploaderProvider struct {
config *UploaderConfig
sdkClient *azcertificates.Client
}
var _ uploader.Uploader = (*UploaderProvider)(nil)
func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
if config == nil {
panic("config is nil")
}
client, err := createSdkClient(config.TenantId, config.ClientId, config.ClientSecret, config.CloudName, config.KeyVaultName)
if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client")
}
return &UploaderProvider{
config: config,
sdkClient: client,
}, nil
}
func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
// 解析证书内容
certX509, err := certs.ParseCertificateFromPEM(certPem)
if err != nil {
return nil, err
}
// 生成 Azure 业务参数
const TAG_CERTCN = "certimate/cert-cn"
const TAG_CERTSN = "certimate/cert-sn"
certCN := certX509.Subject.CommonName
certSN := certX509.SerialNumber.Text(16)
// 获取证书列表,避免重复上传
// REF: https://learn.microsoft.com/en-us/rest/api/keyvault/certificates/get-certificates/get-certificates
listCertificatesPager := u.sdkClient.NewListCertificatesPager(nil)
for listCertificatesPager.More() {
page, err := listCertificatesPager.NextPage(context.TODO())
if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'keyvault.GetCertificates'")
}
for _, certItem := range page.Value {
// 先对比证书有效期
if certItem.Attributes == nil {
continue
}
if certItem.Attributes.NotBefore == nil || !certItem.Attributes.NotBefore.Equal(certX509.NotBefore) {
continue
}
if certItem.Attributes.Expires == nil || !certItem.Attributes.Expires.Equal(certX509.NotAfter) {
continue
}
// 再对比 Tag 中的通用名称
if v, ok := certItem.Tags[TAG_CERTCN]; !ok || v == nil {
continue
} else if *v != certCN {
continue
}
// 再对比 Tag 中的序列号
if v, ok := certItem.Tags[TAG_CERTSN]; !ok || v == nil {
continue
} else if *v != certSN {
continue
}
// 最后对比证书内容
getCertificateResp, err := u.sdkClient.GetCertificate(context.TODO(), certItem.ID.Name(), certItem.ID.Version(), nil)
if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'keyvault.GetCertificate'")
} else {
oldCertX509, err := x509.ParseCertificate(getCertificateResp.CER)
if err != nil {
continue
}
if !certs.EqualCertificate(certX509, oldCertX509) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
return &uploader.UploadResult{
CertId: string(*certItem.ID),
CertName: certItem.ID.Name(),
}, nil
}
}
// 生成新证书名(需符合 Azure 命名规则)
certName := fmt.Sprintf("certimate-%d", time.Now().UnixMilli())
// 导入证书
// REF: https://learn.microsoft.com/en-us/rest/api/keyvault/certificates/import-certificate/import-certificate
importCertificateParams := azcertificates.ImportCertificateParameters{
Base64EncodedCertificate: to.Ptr(certPem),
CertificatePolicy: &azcertificates.CertificatePolicy{
SecretProperties: &azcertificates.SecretProperties{
ContentType: to.Ptr("application/x-pem-file"),
},
},
Tags: map[string]*string{
TAG_CERTCN: to.Ptr(certCN),
TAG_CERTSN: to.Ptr(certSN),
},
}
importCertificateResp, err := u.sdkClient.ImportCertificate(context.TODO(), certName, importCertificateParams, nil)
if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'keyvault.ImportCertificate'")
}
return &uploader.UploadResult{
CertId: string(*importCertificateResp.ID),
CertName: certName,
}, 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

@ -76,31 +76,31 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe
}
for _, certDetail := range describeCertsResp.Result.CertListDetails {
// 先尝试匹配 CN
// 先对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certDetail.CommonName) {
continue
}
// 再尝试匹配 SAN
// 再对比证书多域名
if !slices.Equal(certX509.DNSNames, certDetail.DnsNames) {
continue
}
// 再尝试匹配证书有效期
// 再对比证书有效期
oldCertNotBefore, _ := time.Parse(time.RFC3339, certDetail.StartTime)
oldCertNotAfter, _ := time.Parse(time.RFC3339, certDetail.EndTime)
if !certX509.NotBefore.Equal(oldCertNotBefore) || !certX509.NotAfter.Equal(oldCertNotAfter) {
continue
}
// 最后尝试匹配私钥摘要
// 最后对比私钥摘要
newKeyDigest := sha256.Sum256([]byte(privkeyPem))
newKeyDigestHex := hex.EncodeToString(newKeyDigest[:])
if !strings.EqualFold(newKeyDigestHex, certDetail.Digest) {
continue
}
// 如果以上都匹配,则视为已存在相同证书,直接返回已有的证书信息
// 如果以上信息都一致,则视为已存在相同证书,直接返回
return &uploader.UploadResult{
CertId: certDetail.CertId,
CertName: certDetail.CertName,

View File

@ -121,8 +121,8 @@ func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string) (re
if getCertificateListResp.CertificateList != nil {
for _, certInfo := range getCertificateListResp.CertificateList {
// 优刻得未提供可唯一标识证书的字段,只能通过多个字段尝试匹配来判断是否为同一证书
// 先分别匹配证书的域名、品牌、有效期,再匹配签名算法
// 优刻得未提供可唯一标识证书的字段,只能通过多个字段尝试对比来判断是否为同一证书
// 先分别对比证书的多域名、品牌、有效期,再对比签名算法
if len(certX509.DNSNames) == 0 || certInfo.Domains != strings.Join(certX509.DNSNames, ",") {
continue

View File

@ -24,3 +24,29 @@ func IsNil(obj any) bool {
return false
}
// 将对象转换为指针。
//
// 入参:
// - 待转换的对象。
//
// 出参:
// - 返回对象的指针。
func ToPtr[T any](v T) (p *T) {
return &v
}
// 将指针转换为对象。
//
// 入参:
// - 待转换的指针。
//
// 出参:
// - 返回指针指向的对象。如果指针为空,则返回对象的零值。
func ToObj[T any](p *T) (v T) {
if p == nil {
return v
}
return *p
}

View File

@ -0,0 +1,47 @@
package common
import (
"fmt"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
)
func IsEnvironmentPublic(env string) bool {
switch strings.ToLower(env) {
case "", "default", "public", "azurecloud":
return true
default:
return false
}
}
func IsEnvironmentGovernment(env string) bool {
switch strings.ToLower(env) {
case "usgovernment", "government", "azureusgovernment", "azuregovernment":
return true
default:
return false
}
}
func IsEnvironmentChina(env string) bool {
switch strings.ToLower(env) {
case "china", "chinacloud", "azurechina", "azurechinacloud":
return true
default:
return false
}
}
func GetCloudEnvironmentConfiguration(env string) (cloud.Configuration, error) {
if IsEnvironmentPublic(env) {
return cloud.AzurePublic, nil
} else if IsEnvironmentGovernment(env) {
return cloud.AzureGovernment, nil
} else if IsEnvironmentChina(env) {
return cloud.AzureChina, nil
}
return cloud.Configuration{}, fmt.Errorf("unknown azure cloud environment %s", env)
}

View File

@ -5,6 +5,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"reflect"
"strings"
"time"
@ -45,24 +46,36 @@ func (c *Client) generateSignature(timestamp string) string {
func (c *Client) sendRequest(path string, params interface{}) (*resty.Response, error) {
timestamp := time.Now().Unix()
data := make(map[string]any)
data := make(map[string]string)
if params != nil {
temp := make(map[string]any)
jsonb, _ := json.Marshal(params)
json.Unmarshal(jsonb, &temp)
for k, v := range temp {
if v != nil {
data[k] = v
switch reflect.Indirect(reflect.ValueOf(v)).Kind() {
case reflect.String:
data[k] = v.(string)
case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
data[k] = fmt.Sprintf("%v", v)
default:
if t, ok := v.(time.Time); ok {
data[k] = t.Format(time.RFC3339)
} else {
jbytes, _ := json.Marshal(v)
data[k] = string(jbytes)
}
}
}
}
}
data["request_time"] = timestamp
data["request_time"] = fmt.Sprintf("%d", timestamp)
data["request_token"] = c.generateSignature(fmt.Sprintf("%d", timestamp))
url := c.apiHost + path
req := c.client.R().
SetHeader("Content-Type", "application/json").
SetBody(data)
SetHeader("Content-Type", "application/x-www-form-urlencoded").
SetFormData(data)
resp, err := req.Post(url)
if err != nil {
return nil, fmt.Errorf("baota api error: failed to send request: %w", err)

View File

@ -67,12 +67,12 @@
"access.form.baiducloud_secret_access_key.tooltip": "For more information, see <a href=\"https://intl.cloud.baidu.com/doc/Reference/s/jjwvz2e3p-en\" target=\"_blank\">https://intl.cloud.baidu.com/doc/Reference/s/jjwvz2e3p-en</a>",
"access.form.baishan_api_token.label": "Baishan Cloud API token",
"access.form.baishan_api_token.placeholder": "Please enter Baishan Cloud API token",
"access.form.baotapanel_api_url.label": "BaoTa Panel URL",
"access.form.baotapanel_api_url.placeholder": "Please enter BaoTa Panel URL",
"access.form.baotapanel_api_url.label": "aaPanel URL",
"access.form.baotapanel_api_url.placeholder": "Please enter aaPanel URL",
"access.form.baotapanel_api_url.tooltip": "For more information, see <a href=\"https://www.bt.cn/bbs/thread-20376-1-1.html\" target=\"_blank\">https://www.bt.cn/bbs/thread-20376-1-1.html</a>",
"access.form.baotapanel_api_key.label": "BaoTa Panel API key",
"access.form.baotapanel_api_key.placeholder": "Please enter BaoTa Panel API key",
"access.form.baotapanel_api_key.tooltip": "For more information, see <a href=\"https://www.bt.cn/bbs/thread-113890-1-1.html\" target=\"_blank\">https://www.bt.cn/bbs/thread-113890-1-1.html</a>",
"access.form.baotapanel_api_key.label": "aaPanel API key",
"access.form.baotapanel_api_key.placeholder": "Please enter aaPanel API key",
"access.form.baotapanel_api_key.tooltip": "For more information, see <a href=\"https://www.bt.cn/bbs/thread-20376-1-1.html\" target=\"_blank\">https://www.bt.cn/bbs/thread-20376-1-1.html</a>",
"access.form.byteplus_access_key.label": "BytePlus AccessKey",
"access.form.byteplus_access_key.placeholder": "Please enter BytePlus AccessKey",
"access.form.byteplus_access_key.tooltip": "For more information, see <a href=\"https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys\" target=\"_blank\">https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys</a>",

View File

@ -26,9 +26,9 @@
"provider.baiducloud.dns": "Baidu Cloud - DNS (Domain Name Service)",
"provider.baishan": "Baishan",
"provider.baishan.cdn": "Baishan - CDN (Content Delivery Network)",
"provider.baotapanel": "BaoTa Panel",
"provider.baotapanel.console": "BaoTa Panel - Console",
"provider.baotapanel.site": "BaoTa Panel - Site",
"provider.baotapanel": "aaPanel (aka BaoTaPanel)",
"provider.baotapanel.console": "aaPanel (aka BaoTaPanel) - Console",
"provider.baotapanel.site": "aaPanel (aka BaoTaPanel) - Site",
"provider.byteplus": "BytePlus",
"provider.byteplus.cdn": "BytePlus - CDN (Content Delivery Network)",
"provider.cachefly": "CacheFly",

View File

@ -203,19 +203,19 @@
"workflow_node.deploy.form.baishan_cdn_domain.placeholder": "Please enter Baishan CDN domain name",
"workflow_node.deploy.form.baishan_cdn_domain.tooltip": "For more information, see <a href=\"https://cdnx.console.baishan.com\" target=\"_blank\">https://cdnx.console.baishan.com</a>",
"workflow_node.deploy.form.baotapanel_console_auto_restart.label": "Auto restart after deployment",
"workflow_node.deploy.form.baotapanel_site_type.label": "BaoTa Panel site type",
"workflow_node.deploy.form.baotapanel_site_type.placeholder": "Please select BaoTa Panel site type",
"workflow_node.deploy.form.baotapanel_site_type.label": "aaPanel site type",
"workflow_node.deploy.form.baotapanel_site_type.placeholder": "Please select aaPanel site type",
"workflow_node.deploy.form.baotapanel_site_type.option.php.label": "PHP sites",
"workflow_node.deploy.form.baotapanel_site_type.option.other.label": "Other sites",
"workflow_node.deploy.form.baotapanel_site_name.label": "BaoTa Panel site name",
"workflow_node.deploy.form.baotapanel_site_name.placeholder": "Please enter BaoTa Panel site name",
"workflow_node.deploy.form.baotapanel_site_name.label": "aaPanel site name",
"workflow_node.deploy.form.baotapanel_site_name.placeholder": "Please enter aaPanel site name",
"workflow_node.deploy.form.baotapanel_site_name.tooltip": "Usually equal to the website domain name.",
"workflow_node.deploy.form.baotapanel_site_names.label": "BaoTa Panel site names",
"workflow_node.deploy.form.baotapanel_site_names.placeholder": "Please enter BaoTa Panel site names (separated by semicolons)",
"workflow_node.deploy.form.baotapanel_site_names.errmsg.invalid": "Please enter a valid BaoTa Panel site name",
"workflow_node.deploy.form.baotapanel_site_names.label": "aaPanel site names",
"workflow_node.deploy.form.baotapanel_site_names.placeholder": "Please enter aaPanel site names (separated by semicolons)",
"workflow_node.deploy.form.baotapanel_site_names.errmsg.invalid": "Please enter a valid aaPanel site name",
"workflow_node.deploy.form.baotapanel_site_names.tooltip": "Usually equal to the websites domain name.",
"workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.title": "Change BaoTa Panel site names",
"workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.placeholder": "Please enter BaoTa Panel site name",
"workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.title": "Change aaPanel site names",
"workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.placeholder": "Please enter aaPanel site name",
"workflow_node.deploy.form.byteplus_cdn_domain.label": "BytePlus CDN domain",
"workflow_node.deploy.form.byteplus_cdn_domain.placeholder": "Please enter BytePlus CDN domain name",
"workflow_node.deploy.form.byteplus_cdn_domain.tooltip": "For more information, see <a href=\"https://console.byteplus.com/cdn\" target=\"_blank\">https://console.byteplus.com/cdn</a>",