mirror of
https://github.com/woodchen-ink/certimate.git
synced 2025-07-19 09:51:55 +08:00
Merge pull request #419 from fudiwei/feat/new-workflow
feat: more providers
This commit is contained in:
commit
2218be5d34
30
README.md
30
README.md
@ -86,20 +86,21 @@ make local.run
|
||||
|
||||
<summary>[展开查看]</summary>
|
||||
|
||||
| 提供商 | 备注 |
|
||||
| :--------------------------------------------- | :-------------------------------------- |
|
||||
| [阿里云](https://www.aliyun.com/) | |
|
||||
| [腾讯云](https://cloud.tencent.com/) | |
|
||||
| [华为云](https://www.huaweicloud.com/) | |
|
||||
| [火山引擎](https://www.volcengine.com/) | |
|
||||
| [AWS Route53](https://aws.amazon.com/route53/) | |
|
||||
| [Azure](https://azure.microsoft.com/) | |
|
||||
| [CloudFlare](https://www.cloudflare.com/) | |
|
||||
| [GoDaddy](https://www.godaddy.com/) | |
|
||||
| [Name.com](https://www.name.com/) | |
|
||||
| [NameSilo](https://www.namesilo.com/) | |
|
||||
| [PowerDNS](https://www.powerdns.com/) | |
|
||||
| ACME 代理 HTTP 请求 | 可申请允许通过 HTTP 请求修改 DNS 的域名 |
|
||||
| 提供商 | 备注 |
|
||||
| :----------------------------------------------------------------- | :-------------------------------------- |
|
||||
| [阿里云](https://www.aliyun.com/) | |
|
||||
| [腾讯云](https://cloud.tencent.com/) | |
|
||||
| [华为云](https://www.huaweicloud.com/) | |
|
||||
| [火山引擎](https://www.volcengine.com/) | |
|
||||
| [AWS Route53](https://aws.amazon.com/route53/) | |
|
||||
| [Azure](https://azure.microsoft.com/) | |
|
||||
| [CloudFlare](https://www.cloudflare.com/) | |
|
||||
| [GoDaddy](https://www.godaddy.com/) | |
|
||||
| [Name.com](https://www.name.com/) | |
|
||||
| [NameSilo](https://www.namesilo.com/) | |
|
||||
| [IBM NS1 Connect](https://www.ibm.com/cn-zh/products/ns1-connect/) | |
|
||||
| [PowerDNS](https://www.powerdns.com/) | |
|
||||
| ACME 代理 HTTP 请求 | 可申请允许通过 HTTP 请求修改 DNS 的域名 |
|
||||
|
||||
</details>
|
||||
|
||||
@ -126,6 +127,7 @@ make local.run
|
||||
| [多吉云](https://www.dogecloud.com/) | 可部署到多吉云 CDN |
|
||||
| [BytePlus](https://www.byteplus.com/) | 可部署到 BytePlus CDN 等服务 |
|
||||
| [优刻得](https://www.ucloud.cn/) | 可部署到优刻得 US3、UCDN 等服务 |
|
||||
| [Edgio](https://edg.io/) | 可部署到 Edgio Applications 等服务 |
|
||||
|
||||
</details>
|
||||
|
||||
|
30
README_EN.md
30
README_EN.md
@ -85,20 +85,21 @@ The following DNS providers are supported:
|
||||
|
||||
<summary>[Fold/Unfold to view ...]</summary>
|
||||
|
||||
| Provider | Remarks |
|
||||
| :--------------------------------------------- | :------------------------------------ |
|
||||
| [Alibaba Cloud](https://www.alibabacloud.com/) | |
|
||||
| [Tencent Cloud](https://www.tencentcloud.com/) | |
|
||||
| [Huawei Cloud](https://www.huaweicloud.com/) | |
|
||||
| [Volcengine](https://www.volcengine.com/) | |
|
||||
| [AWS Route53](https://aws.amazon.com/route53/) | |
|
||||
| [Azure DNS](https://azure.microsoft.com/) | |
|
||||
| [CloudFlare](https://www.cloudflare.com/) | |
|
||||
| [GoDaddy](https://www.godaddy.com/) | |
|
||||
| [Name.com](https://www.name.com/) | |
|
||||
| [NameSilo](https://www.namesilo.com/) | |
|
||||
| [PowerDNS](https://www.powerdns.com/) | |
|
||||
| ACME Proxy HTTP Request | Supports managing DNS by HTTP request |
|
||||
| Provider | Remarks |
|
||||
| :----------------------------------------------------------- | :------------------------------------ |
|
||||
| [Alibaba Cloud](https://www.alibabacloud.com/) | |
|
||||
| [Tencent Cloud](https://www.tencentcloud.com/) | |
|
||||
| [Huawei Cloud](https://www.huaweicloud.com/) | |
|
||||
| [Volcengine](https://www.volcengine.com/) | |
|
||||
| [AWS Route53](https://aws.amazon.com/route53/) | |
|
||||
| [Azure DNS](https://azure.microsoft.com/) | |
|
||||
| [CloudFlare](https://www.cloudflare.com/) | |
|
||||
| [GoDaddy](https://www.godaddy.com/) | |
|
||||
| [Name.com](https://www.name.com/) | |
|
||||
| [NameSilo](https://www.namesilo.com/) | |
|
||||
| [IBM NS1 Connect](https://www.ibm.com/products/ns1-connect/) | |
|
||||
| [PowerDNS](https://www.powerdns.com/) | |
|
||||
| ACME Proxy HTTP Request | Supports managing DNS by HTTP request |
|
||||
|
||||
</details>
|
||||
|
||||
@ -125,6 +126,7 @@ The following hosting providers are supported:
|
||||
| [Doge Cloud](https://www.dogecloud.com/) | Supports deployment to Doge Cloud CDN |
|
||||
| [BytePlus](https://www.byteplus.com/) | Supports deployment to BytePlus CDN |
|
||||
| [UCloud](https://www.ucloud-global.com/) | Supports deployment to UCloud US3, UCDN |
|
||||
| [Edgio](https://edg.io/) | Supports deployment to Edgio Applications |
|
||||
|
||||
</details>
|
||||
|
||||
|
4
go.mod
4
go.mod
@ -18,8 +18,8 @@ require (
|
||||
github.com/baidubce/bce-sdk-go v0.9.209
|
||||
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.35
|
||||
github.com/go-acme/lego/v4 v4.21.0
|
||||
github.com/go-resty/resty/v2 v2.16.3
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1
|
||||
github.com/gojek/heimdall/v7 v7.0.3
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.128
|
||||
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61
|
||||
github.com/nikoksr/notify v1.1.0
|
||||
@ -87,6 +87,7 @@ require (
|
||||
go.mongodb.org/mongo-driver v1.12.0 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ns1/ns1-go.v2 v2.13.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
|
||||
@ -141,7 +142,6 @@ require (
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||
github.com/goccy/go-json v0.10.4 // indirect
|
||||
github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
|
11
go.sum
11
go.sum
@ -81,7 +81,6 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
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.7.1+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.3 h1:cb3br57K508pQEFgBxn9GDhPS9HefpyMPK1RzmtMNzk=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.3/go.mod h1:itPGVDKf9cC/ov4MdvJ2QZ0khw4bfoo9jzwTJlaxy2k=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.3 h1:xir5X8TS8UBVPWg2jHL+cSTf0jZgqYQSA54TscSt1/0=
|
||||
@ -263,7 +262,6 @@ github.com/blinkbean/dingtalk v1.1.3 h1:MbidFZYom7DTFHD/YIs+eaI7kRy52kmWE/sy0xjo
|
||||
github.com/blinkbean/dingtalk v1.1.3/go.mod h1:9BaLuGSBqY3vT5hstValh48DbsKO7vaHaJnG9pXwbto=
|
||||
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.35 h1:bM18V4iw9ylRc2LahQaq3k3gjEVJdyQYvptLVZaCa54=
|
||||
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.35/go.mod h1:7iCaE+dR9EycrJU0GQyMhptbInLbQhsKXiDKDjNi8Vs=
|
||||
github.com/cactus/go-statsd-client/statsd v0.0.0-20200423205355-cb0885a1018c/go.mod h1:l/bIBLeOl9eX+wxJAzxS4TveKRtAqlyDpHjhkfO0MEI=
|
||||
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.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
@ -398,6 +396,8 @@ github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.7.0/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
|
||||
github.com/go-resty/resty/v2 v2.16.3 h1:zacNT7lt4b8M/io2Ahj6yPypL7bqx9n1iprfQuodV+E=
|
||||
github.com/go-resty/resty/v2 v2.16.3/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
@ -418,10 +418,6 @@ github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/gojek/heimdall/v7 v7.0.3 h1:+5sAhl8S0m+qRRL8IVeHCJudFh/XkG3wyO++nvOg+gc=
|
||||
github.com/gojek/heimdall/v7 v7.0.3/go.mod h1:Z43HtMid7ysSjmsedPTXAki6jcdcNVnjn5pmsTyiMic=
|
||||
github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf h1:5xRGbUdOmZKoDXkGx5evVLehuCMpuO1hl701bEQqXOM=
|
||||
github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf/go.mod h1:QzhUKaYKJmcbTnCYCAVQrroCOY7vOOI8cSQ4NbuhYf0=
|
||||
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.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||
@ -807,7 +803,6 @@ github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5J
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
@ -1369,6 +1364,8 @@ gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/ns1/ns1-go.v2 v2.13.0 h1:I5NNqI9Bi1SGK92TVkOvLTwux5LNrix/99H2datVh48=
|
||||
gopkg.in/ns1/ns1-go.v2 v2.13.0/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
"github.com/usual2970/certimate/internal/repository"
|
||||
)
|
||||
|
||||
@ -38,7 +38,7 @@ func newAcmeUser(ca, email string) (*acmeUser, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyPEM, err := x509.ConvertECPrivateKeyToPEM(key)
|
||||
keyPEM, err := certs.ConvertECPrivateKeyToPEM(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -62,7 +62,7 @@ func (u acmeUser) GetRegistration() *registration.Resource {
|
||||
}
|
||||
|
||||
func (u *acmeUser) GetPrivateKey() crypto.PrivateKey {
|
||||
rs, _ := x509.ParseECPrivateKeyFromPEM(u.privkey)
|
||||
rs, _ := certs.ParseECPrivateKeyFromPEM(u.privkey)
|
||||
return rs
|
||||
}
|
||||
|
||||
|
@ -15,16 +15,17 @@ import (
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/slices"
|
||||
"github.com/usual2970/certimate/internal/repository"
|
||||
)
|
||||
|
||||
type ApplyCertResult struct {
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
IssuerCertificate string
|
||||
ACMECertUrl string
|
||||
ACMECertStableUrl string
|
||||
CSR string
|
||||
CertificateFullChain string
|
||||
IssuerCertificate string
|
||||
PrivateKey string
|
||||
ACMECertUrl string
|
||||
ACMECertStableUrl string
|
||||
CSR string
|
||||
}
|
||||
|
||||
type Applicant interface {
|
||||
@ -61,13 +62,13 @@ func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
||||
}
|
||||
|
||||
options := &applicantOptions{
|
||||
Domains: strings.Split(node.GetConfigString("domains"), ";"),
|
||||
Domains: slices.Filter(strings.Split(node.GetConfigString("domains"), ";"), func(s string) bool { return s != "" }),
|
||||
ContactEmail: node.GetConfigString("contactEmail"),
|
||||
Provider: domain.ApplyDNSProviderType(node.GetConfigString("provider")),
|
||||
ProviderAccessConfig: accessConfig,
|
||||
ProviderApplyConfig: node.GetConfigMap("providerConfig"),
|
||||
KeyAlgorithm: node.GetConfigString("keyAlgorithm"),
|
||||
Nameservers: strings.Split(node.GetConfigString("nameservers"), ";"),
|
||||
Nameservers: slices.Filter(strings.Split(node.GetConfigString("nameservers"), ";"), func(s string) bool { return s != "" }),
|
||||
PropagationTimeout: node.GetConfigInt32("propagationTimeout"),
|
||||
DisableFollowCNAME: node.GetConfigBool("disableFollowCNAME"),
|
||||
}
|
||||
@ -149,12 +150,12 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
|
||||
}
|
||||
|
||||
return &ApplyCertResult{
|
||||
PrivateKey: string(certResource.PrivateKey),
|
||||
Certificate: string(certResource.Certificate),
|
||||
IssuerCertificate: string(certResource.IssuerCertificate),
|
||||
ACMECertUrl: certResource.CertURL,
|
||||
ACMECertStableUrl: certResource.CertStableURL,
|
||||
CSR: string(certResource.CSR),
|
||||
CertificateFullChain: strings.TrimSpace(string(certResource.Certificate)),
|
||||
IssuerCertificate: strings.TrimSpace(string(certResource.IssuerCertificate)),
|
||||
PrivateKey: strings.TrimSpace(string(certResource.PrivateKey)),
|
||||
ACMECertUrl: certResource.CertURL,
|
||||
ACMECertStableUrl: certResource.CertStableURL,
|
||||
CSR: string(certResource.CSR),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
providerHuaweiCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud"
|
||||
providerNameDotCom "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom"
|
||||
providerNameSilo "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo"
|
||||
providerNS1 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1"
|
||||
providerPowerDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns"
|
||||
providerTencentCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud"
|
||||
providerVolcEngine "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine"
|
||||
@ -167,6 +168,20 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
return applicant, err
|
||||
}
|
||||
|
||||
case domain.ApplyDNSProviderTypeNS1:
|
||||
{
|
||||
access := domain.AccessConfigForNS1{}
|
||||
if err := maps.Decode(options.ProviderAccessConfig, &access); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode provider access config: %w", err)
|
||||
}
|
||||
|
||||
applicant, err := providerNS1.NewChallengeProvider(&providerNS1.NS1ApplicantConfig{
|
||||
ApiKey: access.ApiKey,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
|
||||
case domain.ApplyDNSProviderTypePowerDNS:
|
||||
{
|
||||
access := domain.AccessConfigForPowerDNS{}
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
providerBaiduCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baiducloud-cdn"
|
||||
providerBytePlusCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/byteplus-cdn"
|
||||
providerDogeCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/dogecloud-cdn"
|
||||
providerEdgioApplications "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/edgio-applications"
|
||||
providerHuaweiCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/huaweicloud-cdn"
|
||||
providerHuaweiCloudELB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/huaweicloud-elb"
|
||||
providerK8sSecret "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/k8s-secret"
|
||||
@ -175,6 +176,21 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger,
|
||||
return deployer, logger, err
|
||||
}
|
||||
|
||||
case domain.DeployProviderTypeEdgioApplications:
|
||||
{
|
||||
access := domain.AccessConfigForEdgio{}
|
||||
if err := maps.Decode(options.ProviderAccessConfig, &access); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to decode provider access config: %w", err)
|
||||
}
|
||||
|
||||
deployer, err := providerEdgioApplications.NewWithLogger(&providerEdgioApplications.EdgioApplicationsDeployerConfig{
|
||||
ClientId: access.ClientId,
|
||||
ClientSecret: access.ClientSecret,
|
||||
EnvironmentId: maps.GetValueAsString(options.ProviderDeployConfig, "environmentId"),
|
||||
}, logger)
|
||||
return deployer, logger, err
|
||||
}
|
||||
|
||||
case domain.DeployProviderTypeHuaweiCloudCDN, domain.DeployProviderTypeHuaweiCloudELB:
|
||||
{
|
||||
access := domain.AccessConfigForHuaweiCloud{}
|
||||
|
@ -66,6 +66,11 @@ type AccessConfigForDogeCloud struct {
|
||||
SecretKey string `json:"secretKey"`
|
||||
}
|
||||
|
||||
type AccessConfigForEdgio struct {
|
||||
ClientId string `json:"clientId"`
|
||||
ClientSecret string `json:"clientSecret"`
|
||||
}
|
||||
|
||||
type AccessConfigForGoDaddy struct {
|
||||
ApiKey string `json:"apiKey"`
|
||||
ApiSecret string `json:"apiSecret"`
|
||||
@ -91,6 +96,10 @@ type AccessConfigForNameSilo struct {
|
||||
ApiKey string `json:"apiKey"`
|
||||
}
|
||||
|
||||
type AccessConfigForNS1 struct {
|
||||
ApiKey string `json:"apiKey"`
|
||||
}
|
||||
|
||||
type AccessConfigForPowerDNS struct {
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
|
@ -17,12 +17,14 @@ const (
|
||||
AccessProviderTypeBytePlus = AccessProviderType("byteplus")
|
||||
AccessProviderTypeCloudflare = AccessProviderType("cloudflare")
|
||||
AccessProviderTypeDogeCloud = AccessProviderType("dogecloud")
|
||||
AccessProviderTypeEdgio = AccessProviderType("edgio")
|
||||
AccessProviderTypeGoDaddy = AccessProviderType("godaddy")
|
||||
AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud")
|
||||
AccessProviderTypeKubernetes = AccessProviderType("k8s")
|
||||
AccessProviderTypeLocal = AccessProviderType("local")
|
||||
AccessProviderTypeNameDotCom = AccessProviderType("namedotcom")
|
||||
AccessProviderTypeNameSilo = AccessProviderType("namesilo")
|
||||
AccessProviderTypeNS1 = AccessProviderType("ns1")
|
||||
AccessProviderTypePowerDNS = AccessProviderType("powerdns")
|
||||
AccessProviderTypeQiniu = AccessProviderType("qiniu")
|
||||
AccessProviderTypeSSH = AccessProviderType("ssh")
|
||||
@ -54,6 +56,7 @@ const (
|
||||
ApplyDNSProviderTypeHuaweiCloudDNS = ApplyDNSProviderType("huaweicloud-dns")
|
||||
ApplyDNSProviderTypeNameDotCom = ApplyDNSProviderType("namedotcom")
|
||||
ApplyDNSProviderTypeNameSilo = ApplyDNSProviderType("namesilo")
|
||||
ApplyDNSProviderTypeNS1 = ApplyDNSProviderType("ns1")
|
||||
ApplyDNSProviderTypePowerDNS = ApplyDNSProviderType("powerdns")
|
||||
ApplyDNSProviderTypeTencentCloud = ApplyDNSProviderType("tencentcloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeTencentCloudDNS]
|
||||
ApplyDNSProviderTypeTencentCloudDNS = ApplyDNSProviderType("tencentcloud-dns")
|
||||
@ -71,34 +74,35 @@ type DeployProviderType string
|
||||
NOTICE: If you add new constant, please keep ASCII order.
|
||||
*/
|
||||
const (
|
||||
DeployProviderTypeAliyunALB = DeployProviderType("aliyun-alb")
|
||||
DeployProviderTypeAliyunCDN = DeployProviderType("aliyun-cdn")
|
||||
DeployProviderTypeAliyunCLB = DeployProviderType("aliyun-clb")
|
||||
DeployProviderTypeAliyunDCDN = DeployProviderType("aliyun-dcdn")
|
||||
DeployProviderTypeAliyunLive = DeployProviderType("aliyun-live")
|
||||
DeployProviderTypeAliyunNLB = DeployProviderType("aliyun-nlb")
|
||||
DeployProviderTypeAliyunOSS = DeployProviderType("aliyun-oss")
|
||||
DeployProviderTypeBaiduCloudCDN = DeployProviderType("baiducloud-cdn")
|
||||
DeployProviderTypeBytePlusCDN = DeployProviderType("byteplus-cdn")
|
||||
DeployProviderTypeDogeCloudCDN = DeployProviderType("dogecloud-cdn")
|
||||
DeployProviderTypeHuaweiCloudCDN = DeployProviderType("huaweicloud-cdn")
|
||||
DeployProviderTypeHuaweiCloudELB = DeployProviderType("huaweicloud-elb")
|
||||
DeployProviderTypeKubernetesSecret = DeployProviderType("k8s-secret")
|
||||
DeployProviderTypeLocal = DeployProviderType("local")
|
||||
DeployProviderTypeQiniuCDN = DeployProviderType("qiniu-cdn")
|
||||
DeployProviderTypeSSH = DeployProviderType("ssh")
|
||||
DeployProviderTypeTencentCloudCDN = DeployProviderType("tencentcloud-cdn")
|
||||
DeployProviderTypeTencentCloudCLB = DeployProviderType("tencentcloud-clb")
|
||||
DeployProviderTypeTencentCloudCOS = DeployProviderType("tencentcloud-cos")
|
||||
DeployProviderTypeTencentCloudCSS = DeployProviderType("tencentcloud-css")
|
||||
DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn")
|
||||
DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo")
|
||||
DeployProviderTypeUCloudUCDN = DeployProviderType("ucloud-ucdn")
|
||||
DeployProviderTypeUCloudUS3 = DeployProviderType("ucloud-us3")
|
||||
DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn")
|
||||
DeployProviderTypeVolcEngineCLB = DeployProviderType("volcengine-clb")
|
||||
DeployProviderTypeVolcEngineDCDN = DeployProviderType("volcengine-dcdn")
|
||||
DeployProviderTypeVolcEngineLive = DeployProviderType("volcengine-live")
|
||||
DeployProviderTypeVolcEngineTOS = DeployProviderType("volcengine-tos")
|
||||
DeployProviderTypeWebhook = DeployProviderType("webhook")
|
||||
DeployProviderTypeAliyunALB = DeployProviderType("aliyun-alb")
|
||||
DeployProviderTypeAliyunCDN = DeployProviderType("aliyun-cdn")
|
||||
DeployProviderTypeAliyunCLB = DeployProviderType("aliyun-clb")
|
||||
DeployProviderTypeAliyunDCDN = DeployProviderType("aliyun-dcdn")
|
||||
DeployProviderTypeAliyunLive = DeployProviderType("aliyun-live")
|
||||
DeployProviderTypeAliyunNLB = DeployProviderType("aliyun-nlb")
|
||||
DeployProviderTypeAliyunOSS = DeployProviderType("aliyun-oss")
|
||||
DeployProviderTypeBaiduCloudCDN = DeployProviderType("baiducloud-cdn")
|
||||
DeployProviderTypeBytePlusCDN = DeployProviderType("byteplus-cdn")
|
||||
DeployProviderTypeDogeCloudCDN = DeployProviderType("dogecloud-cdn")
|
||||
DeployProviderTypeEdgioApplications = DeployProviderType("edgio-applications")
|
||||
DeployProviderTypeHuaweiCloudCDN = DeployProviderType("huaweicloud-cdn")
|
||||
DeployProviderTypeHuaweiCloudELB = DeployProviderType("huaweicloud-elb")
|
||||
DeployProviderTypeKubernetesSecret = DeployProviderType("k8s-secret")
|
||||
DeployProviderTypeLocal = DeployProviderType("local")
|
||||
DeployProviderTypeQiniuCDN = DeployProviderType("qiniu-cdn")
|
||||
DeployProviderTypeSSH = DeployProviderType("ssh")
|
||||
DeployProviderTypeTencentCloudCDN = DeployProviderType("tencentcloud-cdn")
|
||||
DeployProviderTypeTencentCloudCLB = DeployProviderType("tencentcloud-clb")
|
||||
DeployProviderTypeTencentCloudCOS = DeployProviderType("tencentcloud-cos")
|
||||
DeployProviderTypeTencentCloudCSS = DeployProviderType("tencentcloud-css")
|
||||
DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn")
|
||||
DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo")
|
||||
DeployProviderTypeUCloudUCDN = DeployProviderType("ucloud-ucdn")
|
||||
DeployProviderTypeUCloudUS3 = DeployProviderType("ucloud-us3")
|
||||
DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn")
|
||||
DeployProviderTypeVolcEngineCLB = DeployProviderType("volcengine-clb")
|
||||
DeployProviderTypeVolcEngineDCDN = DeployProviderType("volcengine-dcdn")
|
||||
DeployProviderTypeVolcEngineLive = DeployProviderType("volcengine-live")
|
||||
DeployProviderTypeVolcEngineTOS = DeployProviderType("volcengine-tos")
|
||||
DeployProviderTypeWebhook = DeployProviderType("webhook")
|
||||
)
|
||||
|
@ -0,0 +1,33 @@
|
||||
package ns1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/go-acme/lego/v4/providers/dns/ns1"
|
||||
)
|
||||
|
||||
type NS1ApplicantConfig struct {
|
||||
ApiKey string `json:"apiKey"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *NS1ApplicantConfig) (challenge.Provider, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("config is nil")
|
||||
}
|
||||
|
||||
providerConfig := ns1.NewDefaultConfig()
|
||||
providerConfig.APIKey = config.ApiKey
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
}
|
||||
|
||||
provider, err := ns1.NewDNSProviderConfig(providerConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return provider, nil
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package edgioapplications
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
|
||||
xerrors "github.com/pkg/errors"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/logger"
|
||||
edgsdk "github.com/usual2970/certimate/internal/pkg/vendors/edgio-sdk/applications/v7"
|
||||
edgsdkDtos "github.com/usual2970/certimate/internal/pkg/vendors/edgio-sdk/applications/v7/dtos"
|
||||
)
|
||||
|
||||
type EdgioApplicationsDeployerConfig struct {
|
||||
// Edgio ClientId。
|
||||
ClientId string `json:"clientId"`
|
||||
// Edgio ClientSecret。
|
||||
ClientSecret string `json:"clientSecret"`
|
||||
// Edgio 环境 ID。
|
||||
EnvironmentId string `json:"environmentId"`
|
||||
}
|
||||
|
||||
type EdgioApplicationsDeployer struct {
|
||||
config *EdgioApplicationsDeployerConfig
|
||||
logger logger.Logger
|
||||
sdkClient *edgsdk.EdgioClient
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*EdgioApplicationsDeployer)(nil)
|
||||
|
||||
func New(config *EdgioApplicationsDeployerConfig) (*EdgioApplicationsDeployer, error) {
|
||||
return NewWithLogger(config, logger.NewNilLogger())
|
||||
}
|
||||
|
||||
func NewWithLogger(config *EdgioApplicationsDeployerConfig, logger logger.Logger) (*EdgioApplicationsDeployer, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("config is nil")
|
||||
}
|
||||
|
||||
if logger == nil {
|
||||
return nil, errors.New("logger is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.ClientId, config.ClientSecret)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
||||
}
|
||||
|
||||
return &EdgioApplicationsDeployer{
|
||||
logger: logger,
|
||||
config: config,
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *EdgioApplicationsDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
||||
// 提取 Edgio 所需的服务端证书和中间证书内容
|
||||
privateCertPem, intermediateCertPem := extractCertChains(certPem)
|
||||
|
||||
// 上传 TLS 证书
|
||||
// REF: https://docs.edg.io/rest_api/#tag/tls-certs/operation/postConfigV01TlsCerts
|
||||
uploadTlsCertReq := edgsdkDtos.UploadTlsCertRequest{
|
||||
EnvironmentID: d.config.EnvironmentId,
|
||||
PrimaryCert: privateCertPem,
|
||||
IntermediateCert: intermediateCertPem,
|
||||
PrivateKey: privkeyPem,
|
||||
}
|
||||
uploadTlsCertResp, err := d.sdkClient.UploadTlsCert(uploadTlsCertReq)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'edgio.UploadTlsCert'")
|
||||
}
|
||||
|
||||
d.logger.Logt("已上传 TLS 证书", uploadTlsCertResp)
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(clientId, clientSecret string) (*edgsdk.EdgioClient, error) {
|
||||
client := edgsdk.NewEdgioClient(clientId, clientSecret, "", "")
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func extractCertChains(certPem string) (primaryCertPem string, intermediateCertPem string) {
|
||||
pemBlocks := make([]*pem.Block, 0)
|
||||
pemData := []byte(certPem)
|
||||
for {
|
||||
block, rest := pem.Decode(pemData)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
|
||||
pemBlocks = append(pemBlocks, block)
|
||||
pemData = rest
|
||||
}
|
||||
|
||||
primaryCertPem = ""
|
||||
intermediateCertPem = ""
|
||||
|
||||
if len(pemBlocks) > 0 {
|
||||
primaryCertPem = string(pem.EncodeToMemory(pemBlocks[0]))
|
||||
}
|
||||
|
||||
if len(pemBlocks) > 1 {
|
||||
for i := 1; i < len(pemBlocks); i++ {
|
||||
intermediateCertPem += string(pem.EncodeToMemory(pemBlocks[i]))
|
||||
}
|
||||
}
|
||||
|
||||
return primaryCertPem, intermediateCertPem
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package edgioapplications_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/edgio-applications"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fClientId string
|
||||
fClientSecret string
|
||||
fEnvironmentId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_EDGIOAPPLICATIONS_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fClientId, argsPrefix+"CLIENTID", "", "")
|
||||
flag.StringVar(&fClientSecret, argsPrefix+"CLIENTSECRET", "", "")
|
||||
flag.StringVar(&fEnvironmentId, argsPrefix+"ENVIRONMENTID", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./edgio_applications_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_EDGIOAPPLICATIONS_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_EDGIOAPPLICATIONS_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_EDGIOAPPLICATIONS_CLIENTID="your-client-id" \
|
||||
--CERTIMATE_DEPLOYER_EDGIOAPPLICATIONS_CLIENTSECRET="your-client-secret" \
|
||||
--CERTIMATE_DEPLOYER_EDGIOAPPLICATIONS_ENVIRONMENTID="your-enviroment-id"
|
||||
*/
|
||||
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("CLIENTID: %v", fClientId),
|
||||
fmt.Sprintf("CLIENTSECRET: %v", fClientSecret),
|
||||
fmt.Sprintf("ENVIRONMENTID: %v", fEnvironmentId),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.New(&provider.EdgioApplicationsDeployerConfig{
|
||||
ClientId: fClientId,
|
||||
ClientSecret: fClientSecret,
|
||||
EnvironmentId: fEnvironmentId,
|
||||
})
|
||||
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)
|
||||
})
|
||||
}
|
@ -14,7 +14,7 @@ import (
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/logger"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
)
|
||||
|
||||
type K8sSecretDeployerConfig struct {
|
||||
@ -75,7 +75,7 @@ func (d *K8sSecretDeployer) Deploy(ctx context.Context, certPem string, privkeyP
|
||||
return nil, errors.New("config `secretDataKeyForKey` is required")
|
||||
}
|
||||
|
||||
certX509, err := x509.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ import (
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/logger"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/fs"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/files"
|
||||
)
|
||||
|
||||
type LocalDeployerConfig struct {
|
||||
@ -84,41 +84,41 @@ func (d *LocalDeployer) Deploy(ctx context.Context, certPem string, privkeyPem s
|
||||
// 写入证书和私钥文件
|
||||
switch d.config.OutputFormat {
|
||||
case OUTPUT_FORMAT_PEM:
|
||||
if err := fs.WriteFileString(d.config.OutputCertPath, certPem); err != nil {
|
||||
if err := files.WriteString(d.config.OutputCertPath, certPem); err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to save certificate file")
|
||||
}
|
||||
|
||||
d.logger.Logt("certificate file saved")
|
||||
|
||||
if err := fs.WriteFileString(d.config.OutputKeyPath, privkeyPem); err != nil {
|
||||
if err := files.WriteString(d.config.OutputKeyPath, privkeyPem); err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to save private key file")
|
||||
}
|
||||
|
||||
d.logger.Logt("private key file saved")
|
||||
|
||||
case OUTPUT_FORMAT_PFX:
|
||||
pfxData, err := x509.TransformCertificateFromPEMToPFX(certPem, privkeyPem, d.config.PfxPassword)
|
||||
pfxData, err := certs.TransformCertificateFromPEMToPFX(certPem, privkeyPem, d.config.PfxPassword)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to transform certificate to PFX")
|
||||
}
|
||||
|
||||
d.logger.Logt("certificate transformed to PFX")
|
||||
|
||||
if err := fs.WriteFile(d.config.OutputCertPath, pfxData); err != nil {
|
||||
if err := files.Write(d.config.OutputCertPath, pfxData); err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to save certificate file")
|
||||
}
|
||||
|
||||
d.logger.Logt("certificate file saved")
|
||||
|
||||
case OUTPUT_FORMAT_JKS:
|
||||
jksData, err := x509.TransformCertificateFromPEMToJKS(certPem, privkeyPem, d.config.JksAlias, d.config.JksKeypass, d.config.JksStorepass)
|
||||
jksData, err := certs.TransformCertificateFromPEMToJKS(certPem, privkeyPem, d.config.JksAlias, d.config.JksKeypass, d.config.JksStorepass)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to transform certificate to JKS")
|
||||
}
|
||||
|
||||
d.logger.Logt("certificate transformed to JKS")
|
||||
|
||||
if err := fs.WriteFile(d.config.OutputCertPath, jksData); err != nil {
|
||||
if err := files.Write(d.config.OutputCertPath, jksData); err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to save certificate file")
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/logger"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
)
|
||||
|
||||
type SshDeployerConfig struct {
|
||||
@ -125,7 +125,7 @@ func (d *SshDeployer) Deploy(ctx context.Context, certPem string, privkeyPem str
|
||||
d.logger.Logt("private key file uploaded")
|
||||
|
||||
case OUTPUT_FORMAT_PFX:
|
||||
pfxData, err := x509.TransformCertificateFromPEMToPFX(certPem, privkeyPem, d.config.PfxPassword)
|
||||
pfxData, err := certs.TransformCertificateFromPEMToPFX(certPem, privkeyPem, d.config.PfxPassword)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to transform certificate to PFX")
|
||||
}
|
||||
@ -139,7 +139,7 @@ func (d *SshDeployer) Deploy(ctx context.Context, certPem string, privkeyPem str
|
||||
d.logger.Logt("certificate file uploaded")
|
||||
|
||||
case OUTPUT_FORMAT_JKS:
|
||||
jksData, err := x509.TransformCertificateFromPEMToJKS(certPem, privkeyPem, d.config.JksAlias, d.config.JksKeypass, d.config.JksStorepass)
|
||||
jksData, err := certs.TransformCertificateFromPEMToJKS(certPem, privkeyPem, d.config.JksAlias, d.config.JksKeypass, d.config.JksStorepass)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to transform certificate to JKS")
|
||||
}
|
||||
|
@ -1,20 +1,18 @@
|
||||
package webhook
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gojek/heimdall/v7/httpclient"
|
||||
"github.com/go-resty/resty/v2"
|
||||
xerrors "github.com/pkg/errors"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/logger"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
)
|
||||
|
||||
type WebhookDeployerConfig struct {
|
||||
@ -27,7 +25,7 @@ type WebhookDeployerConfig struct {
|
||||
type WebhookDeployer struct {
|
||||
config *WebhookDeployerConfig
|
||||
logger logger.Logger
|
||||
httpClient *httpclient.Client
|
||||
httpClient *resty.Client
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*WebhookDeployer)(nil)
|
||||
@ -45,7 +43,10 @@ func NewWithLogger(config *WebhookDeployerConfig, logger logger.Logger) (*Webhoo
|
||||
return nil, errors.New("logger is nil")
|
||||
}
|
||||
|
||||
client := httpclient.NewClient(httpclient.WithHTTPTimeout(30 * time.Second))
|
||||
client := resty.New().
|
||||
SetTimeout(30 * time.Second).
|
||||
SetRetryCount(3).
|
||||
SetRetryWaitTime(5 * time.Second)
|
||||
|
||||
return &WebhookDeployer{
|
||||
config: config,
|
||||
@ -55,7 +56,7 @@ func NewWithLogger(config *WebhookDeployerConfig, logger logger.Logger) (*Webhoo
|
||||
}
|
||||
|
||||
func (d *WebhookDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
||||
certX509, err := x509.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to parse x509")
|
||||
}
|
||||
@ -72,25 +73,20 @@ func (d *WebhookDeployer) Deploy(ctx context.Context, certPem string, privkeyPem
|
||||
replaceJsonValueRecursively(webhookData, "${CERTIFICATE}", certPem)
|
||||
replaceJsonValueRecursively(webhookData, "${PRIVATE_KEY}", privkeyPem)
|
||||
|
||||
reqBody, _ := json.Marshal(&webhookData)
|
||||
resp, err := d.httpClient.Post(d.config.WebhookUrl, bytes.NewReader(reqBody), map[string][]string{"Content-Type": {"application/json"}})
|
||||
resp, err := d.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(webhookData).
|
||||
Post(d.config.WebhookUrl)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to send webhook request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to read response body")
|
||||
} else if resp.StatusCode() != 200 {
|
||||
return nil, xerrors.Errorf("unexpected webhook response status code: %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
d.logger.Logt("Webhook Response", string(respBody))
|
||||
d.logger.Logt("Webhook request sent", resp.String())
|
||||
|
||||
return &deployer.DeployResult{
|
||||
ExtendedData: map[string]any{
|
||||
"responseText": string(respBody),
|
||||
},
|
||||
}, nil
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func replaceJsonValueRecursively(data interface{}, oldStr, newStr string) interface{} {
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
xerrors "github.com/pkg/errors"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
)
|
||||
|
||||
type AliyunCASUploaderConfig struct {
|
||||
@ -54,7 +54,7 @@ func New(config *AliyunCASUploaderConfig) (*AliyunCASUploader, error) {
|
||||
|
||||
func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 解析证书内容
|
||||
certX509, err := x509.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -90,12 +90,12 @@ func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyP
|
||||
if *getUserCertificateDetailResp.Body.Cert == certPem {
|
||||
isSameCert = true
|
||||
} else {
|
||||
oldCertX509, err := x509.ParseCertificateFromPEM(*getUserCertificateDetailResp.Body.Cert)
|
||||
oldCertX509, err := certs.ParseCertificateFromPEM(*getUserCertificateDetailResp.Body.Cert)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
isSameCert = x509.EqualCertificate(certX509, oldCertX509)
|
||||
isSameCert = certs.EqualCertificate(certX509, oldCertX509)
|
||||
}
|
||||
|
||||
// 如果已存在相同证书,直接返回已有的证书信息
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
xerrors "github.com/pkg/errors"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
)
|
||||
|
||||
type AliyunSLBUploaderConfig struct {
|
||||
@ -57,7 +57,7 @@ func New(config *AliyunSLBUploaderConfig) (*AliyunSLBUploader, error) {
|
||||
|
||||
func (u *AliyunSLBUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 解析证书内容
|
||||
certX509, err := x509.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
xerrors "github.com/pkg/errors"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
)
|
||||
|
||||
type ByteplusCDNUploaderConfig struct {
|
||||
@ -48,7 +48,7 @@ func New(config *ByteplusCDNUploaderConfig) (*ByteplusCDNUploader, error) {
|
||||
|
||||
func (u *ByteplusCDNUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 解析证书内容
|
||||
certX509, err := x509.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
xerrors "github.com/pkg/errors"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk"
|
||||
)
|
||||
|
||||
@ -59,7 +59,7 @@ func New(config *HuaweiCloudELBUploaderConfig) (*HuaweiCloudELBUploader, error)
|
||||
|
||||
func (u *HuaweiCloudELBUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 解析证书内容
|
||||
certX509, err := x509.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -85,12 +85,12 @@ func (u *HuaweiCloudELBUploader) Upload(ctx context.Context, certPem string, pri
|
||||
if certDetail.Certificate == certPem {
|
||||
isSameCert = true
|
||||
} else {
|
||||
oldCertX509, err := x509.ParseCertificateFromPEM(certDetail.Certificate)
|
||||
oldCertX509, err := certs.ParseCertificateFromPEM(certDetail.Certificate)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
isSameCert = x509.EqualCertificate(certX509, oldCertX509)
|
||||
isSameCert = certs.EqualCertificate(certX509, oldCertX509)
|
||||
}
|
||||
|
||||
// 如果已存在相同证书,直接返回已有的证书信息
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
xerrors "github.com/pkg/errors"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk"
|
||||
)
|
||||
|
||||
@ -55,7 +55,7 @@ func New(config *HuaweiCloudSCMUploaderConfig) (*HuaweiCloudSCMUploader, error)
|
||||
|
||||
func (u *HuaweiCloudSCMUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 解析证书内容
|
||||
certX509, err := x509.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -94,12 +94,12 @@ func (u *HuaweiCloudSCMUploader) Upload(ctx context.Context, certPem string, pri
|
||||
if *exportCertificateResp.Certificate == certPem {
|
||||
isSameCert = true
|
||||
} else {
|
||||
oldCertX509, err := x509.ParseCertificateFromPEM(*exportCertificateResp.Certificate)
|
||||
oldCertX509, err := certs.ParseCertificateFromPEM(*exportCertificateResp.Certificate)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
isSameCert = x509.EqualCertificate(certX509, oldCertX509)
|
||||
isSameCert = certs.EqualCertificate(certX509, oldCertX509)
|
||||
}
|
||||
|
||||
// 如果已存在相同证书,直接返回已有的证书信息
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"github.com/qiniu/go-sdk/v7/auth"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
qiniuEx "github.com/usual2970/certimate/internal/pkg/vendors/qiniu-sdk"
|
||||
)
|
||||
|
||||
@ -49,7 +49,7 @@ func New(config *QiniuSSLCertUploaderConfig) (*QiniuSSLCertUploader, error) {
|
||||
|
||||
func (u *QiniuSSLCertUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 解析证书内容
|
||||
certX509, err := x509.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
uAuth "github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
x509util "github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
usdkSsl "github.com/usual2970/certimate/internal/pkg/vendors/ucloud-sdk/ussl"
|
||||
)
|
||||
|
||||
@ -94,7 +94,7 @@ func (u *UCloudUSSLUploader) Upload(ctx context.Context, certPem string, privkey
|
||||
|
||||
func (u *UCloudUSSLUploader) getExistCert(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 解析证书内容
|
||||
certX509, err := x509util.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
ve "github.com/volcengine/volcengine-go-sdk/volcengine"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
)
|
||||
|
||||
type VolcEngineCDNUploaderConfig struct {
|
||||
@ -49,7 +49,7 @@ func New(config *VolcEngineCDNUploaderConfig) (*VolcEngineCDNUploader, error) {
|
||||
|
||||
func (u *VolcEngineCDNUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 解析证书内容
|
||||
certX509, err := x509.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
ve "github.com/volcengine/volcengine-go-sdk/volcengine"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
)
|
||||
|
||||
type VolcEngineLiveUploaderConfig struct {
|
||||
@ -46,7 +46,7 @@ func New(config *VolcEngineLiveUploaderConfig) (*VolcEngineLiveUploader, error)
|
||||
|
||||
func (u *VolcEngineLiveUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 解析证书内容
|
||||
certX509, err := x509.ParseCertificateFromPEM(certPem)
|
||||
certX509, err := certs.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -75,12 +75,12 @@ func (u *VolcEngineLiveUploader) Upload(ctx context.Context, certPem string, pri
|
||||
if certificate == certPem {
|
||||
isSameCert = true
|
||||
} else {
|
||||
oldCertX509, err := x509.ParseCertificateFromPEM(certificate)
|
||||
oldCertX509, err := certs.ParseCertificateFromPEM(certificate)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
isSameCert = x509.EqualCertificate(certX509, oldCertX509)
|
||||
isSameCert = certs.EqualCertificate(certX509, oldCertX509)
|
||||
}
|
||||
|
||||
// 如果已存在相同证书,直接返回已有的证书信息
|
||||
|
@ -1,4 +1,4 @@
|
||||
package x509
|
||||
package certs
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
@ -1,4 +1,4 @@
|
||||
package x509
|
||||
package certs
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
@ -1,4 +1,4 @@
|
||||
package x509
|
||||
package certs
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
@ -1,4 +1,4 @@
|
||||
package x509
|
||||
package certs
|
||||
|
||||
import (
|
||||
"bytes"
|
@ -1,4 +1,4 @@
|
||||
package fs
|
||||
package files
|
||||
|
||||
import (
|
||||
"os"
|
||||
@ -7,7 +7,7 @@ import (
|
||||
xerrors "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// 与 [WriteFile] 类似,但写入的是字符串内容。
|
||||
// 与 [Write] 类似,但写入的是字符串内容。
|
||||
//
|
||||
// 入参:
|
||||
// - path: 文件路径。
|
||||
@ -15,8 +15,8 @@ import (
|
||||
//
|
||||
// 出参:
|
||||
// - 错误。
|
||||
func WriteFileString(path string, content string) error {
|
||||
return WriteFile(path, []byte(content))
|
||||
func WriteString(path string, content string) error {
|
||||
return Write(path, []byte(content))
|
||||
}
|
||||
|
||||
// 将数据写入指定路径的文件。
|
||||
@ -29,7 +29,7 @@ func WriteFileString(path string, content string) error {
|
||||
//
|
||||
// 出参:
|
||||
// - 错误。
|
||||
func WriteFile(path string, data []byte) error {
|
||||
func Write(path string, data []byte) error {
|
||||
dir := filepath.Dir(path)
|
||||
|
||||
err := os.MkdirAll(dir, os.ModePerm)
|
69
internal/pkg/utils/slices/slices.go
Normal file
69
internal/pkg/utils/slices/slices.go
Normal file
@ -0,0 +1,69 @@
|
||||
package slices
|
||||
|
||||
// 创建给定切片一部分的浅拷贝,其包含通过所提供函数实现的测试的所有元素。
|
||||
//
|
||||
// 入参:
|
||||
// - slice: 原切片。
|
||||
// - filter: 为切片中的每个元素执行的函数。它应该返回一个布尔值以指使是否将元素保留在结果切片中。
|
||||
//
|
||||
// 出参:
|
||||
// - 新切片。
|
||||
func Filter[T any](slice []T, filter func(T) bool) []T {
|
||||
var result []T
|
||||
for _, item := range slice {
|
||||
if filter(item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 创建一个新切片,这个新切片由原切片中的每个元素都调用一次提供的函数后的返回值组成。
|
||||
//
|
||||
// 入参:
|
||||
// - slice: 原切片。
|
||||
// - mapper: 为切片中的每个元素执行的函数。它的返回值作为一个元素被添加为新切片中。
|
||||
//
|
||||
// 出参:
|
||||
// - 新切片。
|
||||
func Map[T1 any, T2 any](slice []T1, mapper func(T1) T2) []T2 {
|
||||
result := make([]T2, 0, len(slice))
|
||||
for _, item := range slice {
|
||||
result = append(result, mapper(item))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 测试切片中是否每个元素都通过了由提供的函数实现的测试。
|
||||
//
|
||||
// 入参:
|
||||
// - slice: 切片。
|
||||
// - condition: 为切片中的每个元素执行的函数。它应该返回一个布尔值以指示元素是否通过测试。
|
||||
//
|
||||
// 出参:
|
||||
// - 测试结果。
|
||||
func Every[T any](slice []T, condition func(T) bool) bool {
|
||||
for _, item := range slice {
|
||||
if !condition(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 测试切片中是否至少有一个元素通过了由提供的函数实现的测试。
|
||||
//
|
||||
// 入参:
|
||||
// - slice: 切片。
|
||||
// - condition: 为切片中的每个元素执行的函数。它应该返回一个布尔值以指示元素是否通过测试。
|
||||
//
|
||||
// 出参:
|
||||
// - 测试结果。
|
||||
func Some[T any](slice []T, condition func(T) bool) bool {
|
||||
for _, item := range slice {
|
||||
if condition(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
3
internal/pkg/vendors/edgio-sdk/applications/v7/README.md
vendored
Normal file
3
internal/pkg/vendors/edgio-sdk/applications/v7/README.md
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
```shell
|
||||
git clone https://github.com/Edgio/terraform-provider-edgio.git
|
||||
```
|
93
internal/pkg/vendors/edgio-sdk/applications/v7/dtos/cdn_configuration.go
vendored
Normal file
93
internal/pkg/vendors/edgio-sdk/applications/v7/dtos/cdn_configuration.go
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
package dtos
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type CDNConfiguration struct {
|
||||
ConfigurationID string `json:"id"`
|
||||
EnvironmentID string `json:"environment_id"`
|
||||
Rules json.RawMessage `json:"rules"`
|
||||
Origins []Origin `json:"origins"`
|
||||
Hostnames []Hostname `json:"hostnames"`
|
||||
Experiments *[]string `json:"experiments,omitempty"`
|
||||
EdgeFunctionsSources *map[string]string `json:"edge_functions_sources,omitempty"`
|
||||
EdgeFunctionInitScript *string `json:"edge_function_init_script,omitempty"`
|
||||
}
|
||||
|
||||
type Origin struct {
|
||||
Name string `json:"name"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
Hosts []Host `json:"hosts"`
|
||||
Balancer *string `json:"balancer,omitempty"`
|
||||
OverrideHostHeader *string `json:"override_host_header,omitempty"`
|
||||
Shields *Shields `json:"shields,omitempty"`
|
||||
PciCertifiedShields *bool `json:"pci_certified_shields,omitempty"`
|
||||
TLSVerify *TLSVerify `json:"tls_verify,omitempty"`
|
||||
Retry *Retry `json:"retry,omitempty"`
|
||||
}
|
||||
|
||||
type Host struct {
|
||||
Weight *int64 `json:"weight,omitempty"`
|
||||
DNSMaxTTL *int64 `json:"dns_max_ttl,omitempty"`
|
||||
DNSPreference *string `json:"dns_preference,omitempty"`
|
||||
MaxHardPool *int64 `json:"max_hard_pool,omitempty"`
|
||||
DNSMinTTL *int64 `json:"dns_min_ttl,omitempty"`
|
||||
Location *[]Location `json:"location,omitempty"`
|
||||
MaxPool *int64 `json:"max_pool,omitempty"`
|
||||
Balancer *string `json:"balancer,omitempty"`
|
||||
Scheme *string `json:"scheme,omitempty"`
|
||||
OverrideHostHeader *string `json:"override_host_header,omitempty"`
|
||||
SNIHintAndStrictSanCheck *string `json:"sni_hint_and_strict_san_check,omitempty"`
|
||||
UseSNI *bool `json:"use_sni,omitempty"`
|
||||
}
|
||||
|
||||
type Location struct {
|
||||
Port *int64 `json:"port,omitempty"`
|
||||
Hostname *string `json:"hostname,omitempty"`
|
||||
}
|
||||
|
||||
type Shields struct {
|
||||
Apac *string `json:"apac,omitempty"`
|
||||
Emea *string `json:"emea,omitempty"`
|
||||
USWest *string `json:"us_west,omitempty"`
|
||||
USEast *string `json:"us_east,omitempty"`
|
||||
}
|
||||
|
||||
type TLSVerify struct {
|
||||
UseSNI *bool `json:"use_sni,omitempty"`
|
||||
SNIHintAndStrictSanCheck *string `json:"sni_hint_and_strict_san_check,omitempty"`
|
||||
AllowSelfSignedCerts *bool `json:"allow_self_signed_certs,omitempty"`
|
||||
PinnedCerts *[]string `json:"pinned_certs,omitempty"`
|
||||
}
|
||||
|
||||
type Retry struct {
|
||||
StatusCodes *[]int64 `json:"status_codes,omitempty"`
|
||||
IgnoreRetryAfterHeader *bool `json:"ignore_retry_after_header,omitempty"`
|
||||
AfterSeconds *int64 `json:"after_seconds,omitempty"`
|
||||
MaxRequests *int64 `json:"max_requests,omitempty"`
|
||||
MaxWaitSeconds *int64 `json:"max_wait_seconds,omitempty"`
|
||||
}
|
||||
|
||||
type Hostname struct {
|
||||
Hostname *string `json:"hostname,omitempty"`
|
||||
DefaultOriginName *string `json:"default_origin_name,omitempty"`
|
||||
ReportCode *int64 `json:"report_code,omitempty"`
|
||||
TLS *TLS `json:"tls,omitempty"`
|
||||
Directory *string `json:"directory,omitempty"`
|
||||
}
|
||||
|
||||
type TLS struct {
|
||||
NPN *bool `json:"npn,omitempty"`
|
||||
ALPN *bool `json:"alpn,omitempty"`
|
||||
Protocols *string `json:"protocols,omitempty"`
|
||||
UseSigAlgs *bool `json:"use_sigalgs,omitempty"`
|
||||
SNI *bool `json:"sni,omitempty"`
|
||||
SniStrict *bool `json:"sni_strict,omitempty"`
|
||||
SniHostMatch *bool `json:"sni_host_match,omitempty"`
|
||||
ClientRenegotiation *bool `json:"client_renegotiation,omitempty"`
|
||||
Options *string `json:"options,omitempty"`
|
||||
CipherList *string `json:"cipher_list,omitempty"`
|
||||
NamedCurve *string `json:"named_curve,omitempty"`
|
||||
OCSP *bool `json:"oscp,omitempty"`
|
||||
PEM *string `json:"pem,omitempty"`
|
||||
CA *string `json:"ca,omitempty"`
|
||||
}
|
29
internal/pkg/vendors/edgio-sdk/applications/v7/dtos/environment.go
vendored
Normal file
29
internal/pkg/vendors/edgio-sdk/applications/v7/dtos/environment.go
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
package dtos
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Environment struct {
|
||||
Type string `json:"@type"`
|
||||
IdLink string `json:"@id"`
|
||||
Id string `json:"id"`
|
||||
PropertyID string `json:"property_id"`
|
||||
LegacyAccountNumber string `json:"legacy_account_number"`
|
||||
Name string `json:"name"`
|
||||
CanMembersDeploy bool `json:"can_members_deploy"`
|
||||
OnlyMaintainersCanDeploy bool `json:"only_maintainers_can_deploy"`
|
||||
HttpRequestLogging bool `json:"http_request_logging"`
|
||||
DefaultDomainName string `json:"default_domain_name"`
|
||||
PciCompliance bool `json:"pci_compliance"`
|
||||
DnsDomainName string `json:"dns_domain_name"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type EnvironmentsResponse struct {
|
||||
Type string `json:"@type"`
|
||||
Id string `json:"@id"`
|
||||
TotalItems int `json:"total_items"`
|
||||
Items []Environment `json:"items"`
|
||||
}
|
18
internal/pkg/vendors/edgio-sdk/applications/v7/dtos/property.go
vendored
Normal file
18
internal/pkg/vendors/edgio-sdk/applications/v7/dtos/property.go
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package dtos
|
||||
|
||||
import "time"
|
||||
|
||||
type Property struct {
|
||||
IdLink string `json:"@id"`
|
||||
Id string `json:"id"`
|
||||
OrganizationID string `json:"organization_id"`
|
||||
Slug string `json:"slug"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type Properties struct {
|
||||
ID string `json:"@id"`
|
||||
TotalItems int `json:"total_items"`
|
||||
Items []Property `json:"items"`
|
||||
}
|
18
internal/pkg/vendors/edgio-sdk/applications/v7/dtos/purge.go
vendored
Normal file
18
internal/pkg/vendors/edgio-sdk/applications/v7/dtos/purge.go
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package dtos
|
||||
|
||||
import "time"
|
||||
|
||||
type PurgeResponse struct {
|
||||
ID string `json:"id"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
CompletedAt time.Time `json:"completed_at"`
|
||||
ProgressPercentage float32 `json:"progress_percentage"`
|
||||
}
|
||||
|
||||
type PurgeRequest struct {
|
||||
EnvironmentID string `json:"environment_id"`
|
||||
PurgeType string `json:"purge_type"`
|
||||
Values []string `json:"values"`
|
||||
Hostname *string `json:"hostname"`
|
||||
}
|
30
internal/pkg/vendors/edgio-sdk/applications/v7/dtos/tls_cert.go
vendored
Normal file
30
internal/pkg/vendors/edgio-sdk/applications/v7/dtos/tls_cert.go
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
package dtos
|
||||
|
||||
type TLSCertResponse struct {
|
||||
ID string `json:"id"`
|
||||
EnvironmentID string `json:"environment_id"`
|
||||
PrimaryCert string `json:"primary_cert"`
|
||||
IntermediateCert string `json:"intermediate_cert"`
|
||||
Expiration string `json:"expiration"`
|
||||
Status string `json:"status"`
|
||||
Generated bool `json:"generated"`
|
||||
Serial string `json:"serial"`
|
||||
CommonName string `json:"common_name"`
|
||||
AlternativeNames []string `json:"alternative_names"`
|
||||
ActivationError string `json:"activation_error"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
type UploadTlsCertRequest struct {
|
||||
EnvironmentID string `json:"environment_id"`
|
||||
PrimaryCert string `json:"primary_cert"`
|
||||
IntermediateCert string `json:"intermediate_cert"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
}
|
||||
|
||||
type TLSCertSResponse struct {
|
||||
EnvironmentID string `json:"environment_id"`
|
||||
TotalItems int32 `json:"total_items"`
|
||||
Certificates []TLSCertResponse `json:"items"`
|
||||
}
|
546
internal/pkg/vendors/edgio-sdk/applications/v7/edgio_client.go
vendored
Normal file
546
internal/pkg/vendors/edgio-sdk/applications/v7/edgio_client.go
vendored
Normal file
@ -0,0 +1,546 @@
|
||||
package edgio_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/vendors/edgio-sdk/applications/v7/dtos"
|
||||
)
|
||||
|
||||
// AccessTokenResponse represents the response from the token endpoint.
|
||||
type AccessTokenResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
TokenType string `json:"token_type"`
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
|
||||
// TokenCache represents a cached token. The token is stored along
|
||||
// with its expiry time. Because different endpoints require different
|
||||
// scopes, we store the token with the scope as the key, so that we
|
||||
// can fetch the token from the cache based on the scope.
|
||||
type TokenCache struct {
|
||||
AccessToken string
|
||||
Expiry time.Time
|
||||
}
|
||||
|
||||
type EdgioClient struct {
|
||||
client *resty.Client
|
||||
clientID string
|
||||
clientSecret string
|
||||
tokenURL string
|
||||
apiURL string
|
||||
tokenCache map[string]TokenCache
|
||||
}
|
||||
|
||||
func NewEdgioClient(clientID, clientSecret, tokenURL, apiURL string) *EdgioClient {
|
||||
client := resty.New().
|
||||
SetTimeout(30 * time.Second).
|
||||
SetRetryCount(3).
|
||||
SetRetryWaitTime(5 * time.Second).
|
||||
SetRetryMaxWaitTime(20 * time.Second)
|
||||
|
||||
if tokenURL == "" {
|
||||
tokenURL = "https://id.edgio.app/connect/token"
|
||||
}
|
||||
|
||||
if apiURL == "" {
|
||||
apiURL = "https://edgioapis.com"
|
||||
}
|
||||
|
||||
return &EdgioClient{
|
||||
client: client,
|
||||
clientID: clientID,
|
||||
clientSecret: clientSecret,
|
||||
tokenURL: tokenURL,
|
||||
apiURL: apiURL,
|
||||
tokenCache: make(map[string]TokenCache),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *EdgioClient) getToken(scope string) (string, error) {
|
||||
if cachedToken, exists := c.tokenCache[scope]; exists && time.Now().Before(cachedToken.Expiry) {
|
||||
return cachedToken.AccessToken, nil
|
||||
}
|
||||
|
||||
var tokenResp AccessTokenResponse
|
||||
resp, err := c.client.R().
|
||||
SetFormData(map[string]string{
|
||||
"client_id": c.clientID,
|
||||
"client_secret": c.clientSecret,
|
||||
"grant_type": "client_credentials",
|
||||
"scope": scope,
|
||||
}).
|
||||
SetResult(&tokenResp).
|
||||
Post(c.tokenURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to request token: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return "", fmt.Errorf("unexpected status code for getToken: %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
c.tokenCache[scope] = TokenCache{
|
||||
AccessToken: tokenResp.AccessToken,
|
||||
Expiry: time.Now().Add(time.Duration(tokenResp.ExpiresIn) * time.Second),
|
||||
}
|
||||
|
||||
return tokenResp.AccessToken, nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) GetProperty(ctx context.Context, propertyID string) (*dtos.Property, error) {
|
||||
token, err := c.getToken("app.accounts")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/accounts/v0.1/properties/%s", c.apiURL, propertyID)
|
||||
|
||||
var property dtos.Property
|
||||
resp, err := c.client.R().
|
||||
SetContext(ctx).
|
||||
SetAuthToken(token).
|
||||
SetResult(&property).
|
||||
Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("unexpected status code for getSpecificProperty: %d, %s", resp.StatusCode(), resp.Request.URL)
|
||||
}
|
||||
|
||||
return &property, nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) GetProperties(page int, pageSize int, organizationID string) (*dtos.Properties, error) {
|
||||
token, err := c.getToken("app.accounts")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/accounts/v0.1/properties", c.apiURL)
|
||||
|
||||
var propertiesResp dtos.Properties
|
||||
resp, err := c.client.R().
|
||||
SetAuthToken(token).
|
||||
SetQueryParams(map[string]string{
|
||||
"page": fmt.Sprintf("%d", page),
|
||||
"page_size": fmt.Sprintf("%d", pageSize),
|
||||
"organization_id": organizationID,
|
||||
}).
|
||||
SetResult(&propertiesResp).
|
||||
Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("unexpected status code for getProperties: %d, %s", resp.StatusCode(), resp.Body())
|
||||
}
|
||||
|
||||
return &propertiesResp, nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) CreateProperty(ctx context.Context, organizationID, slug string) (*dtos.Property, error) {
|
||||
token, err := c.getToken("app.accounts")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/accounts/v0.1/properties", c.apiURL)
|
||||
|
||||
var createdProperty dtos.Property
|
||||
resp, err := c.client.R().
|
||||
SetContext(ctx).
|
||||
SetAuthToken(token).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(map[string]string{
|
||||
"organization_id": organizationID,
|
||||
"slug": slug,
|
||||
}).
|
||||
SetResult(&createdProperty).
|
||||
Post(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("unexpected status code for createProperty: %d, response: %s", resp.StatusCode(), resp.String())
|
||||
}
|
||||
|
||||
return &createdProperty, nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) DeleteProperty(propertyID string) error {
|
||||
token, err := c.getToken("app.accounts")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/accounts/v0.1/properties/%s", c.apiURL, propertyID)
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetAuthToken(token).
|
||||
Delete(url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error sending DELETE request: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return fmt.Errorf("error deleting property: status code %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) UpdateProperty(ctx context.Context, propertyID string, slug string) (*dtos.Property, error) {
|
||||
token, err := c.getToken("app.accounts")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/accounts/v0.1/properties/%s", c.apiURL, propertyID)
|
||||
|
||||
requestBody := map[string]interface{}{
|
||||
"slug": slug,
|
||||
}
|
||||
|
||||
var updatedProperty dtos.Property
|
||||
resp, err := c.client.R().
|
||||
SetContext(ctx).
|
||||
SetAuthToken(token).
|
||||
SetBody(requestBody).
|
||||
SetResult(&updatedProperty).
|
||||
Patch(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("unexpected status code for updateProperty: %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
return &updatedProperty, nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) GetEnvironments(page, pageSize int, propertyID string) (*dtos.EnvironmentsResponse, error) {
|
||||
token, err := c.getToken("app.accounts")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/accounts/v0.1/environments", c.apiURL)
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetAuthToken(token).
|
||||
SetQueryParams(map[string]string{
|
||||
"page": fmt.Sprintf("%d", page),
|
||||
"page_size": fmt.Sprintf("%d", pageSize),
|
||||
"property_id": propertyID,
|
||||
}).
|
||||
SetResult(&dtos.EnvironmentsResponse{}).
|
||||
Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("error response: %s", resp.String())
|
||||
}
|
||||
|
||||
return resp.Result().(*dtos.EnvironmentsResponse), nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) GetEnvironment(environmentID string) (*dtos.Environment, error) {
|
||||
token, err := c.getToken("app.accounts")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/accounts/v0.1/environments/%s", c.apiURL, environmentID)
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetPathParams(map[string]string{
|
||||
"environment_id": environmentID,
|
||||
}).
|
||||
SetAuthToken(token).
|
||||
SetResult(&dtos.Environment{}).
|
||||
Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("error response: %s", resp.String())
|
||||
}
|
||||
|
||||
return resp.Result().(*dtos.Environment), nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) CreateEnvironment(propertyID, name string, onlyMaintainersCanDeploy, httpRequestLogging bool) (*dtos.Environment, error) {
|
||||
token, err := c.getToken("app.accounts")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/accounts/v0.1/environments", c.apiURL)
|
||||
|
||||
body := map[string]interface{}{
|
||||
"property_id": propertyID,
|
||||
"name": name,
|
||||
"only_maintainers_can_deploy": onlyMaintainersCanDeploy,
|
||||
"http_request_logging": httpRequestLogging,
|
||||
}
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetAuthToken(token).
|
||||
SetResult(&dtos.Environment{}).
|
||||
Post(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("error response: %s", resp.String())
|
||||
}
|
||||
|
||||
return resp.Result().(*dtos.Environment), nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) UpdateEnvironment(environmentID, name string, onlyMaintainersCanDeploy, httpRequestLogging, preserveCache bool) (*dtos.Environment, error) {
|
||||
token, err := c.getToken("app.accounts")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/accounts/v0.1/environments/%s", c.apiURL, environmentID)
|
||||
|
||||
body := map[string]interface{}{
|
||||
"name": name,
|
||||
// as can_members_deploy is depricated, but update api is not
|
||||
// we need to use it to map onlyMaintainersCanDeploy
|
||||
"only_maintainers_can_deploy": onlyMaintainersCanDeploy,
|
||||
"http_request_logging": httpRequestLogging,
|
||||
"preserve_cache": preserveCache,
|
||||
}
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetPathParams(map[string]string{
|
||||
"environment_id": environmentID,
|
||||
}).
|
||||
SetBody(body).
|
||||
SetAuthToken(token).
|
||||
SetResult(&dtos.Environment{}).
|
||||
Patch(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("error response: %s", resp.String())
|
||||
}
|
||||
|
||||
return resp.Result().(*dtos.Environment), nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) DeleteEnvironment(environmentID string) error {
|
||||
token, err := c.getToken("app.accounts")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/accounts/v0.1/environments/%s", c.apiURL, environmentID)
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetPathParams(map[string]string{
|
||||
"environment_id": environmentID,
|
||||
}).
|
||||
SetAuthToken(token).
|
||||
SetResult(&dtos.Environment{}).
|
||||
Delete(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return fmt.Errorf("error response: %s", resp.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) GetTlsCert(tlsCertId string) (*dtos.TLSCertResponse, error) {
|
||||
token, err := c.getToken("app.config")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/config/v0.1/tls-certs/%s", c.apiURL, tlsCertId)
|
||||
|
||||
var tlsCertResponse dtos.TLSCertResponse
|
||||
resp, err := c.client.R().
|
||||
SetAuthToken(token).
|
||||
SetResult(&tlsCertResponse).
|
||||
Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error response: %s", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("error response: %s", resp.String())
|
||||
}
|
||||
|
||||
return &tlsCertResponse, nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) UploadTlsCert(req dtos.UploadTlsCertRequest) (*dtos.TLSCertResponse, error) {
|
||||
token, err := c.getToken("app.config")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/config/v0.1/tls-certs", c.apiURL)
|
||||
response := &dtos.TLSCertResponse{}
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetAuthToken(token).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(req).
|
||||
SetResult(response).
|
||||
Post(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload TLS certificate: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("API responded with error: %s", resp.String())
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) GenerateTlsCert(environmentId string) (*dtos.TLSCertResponse, error) {
|
||||
token, err := c.getToken("app.config")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/config/v0.1/tls-certs/generate", c.apiURL)
|
||||
request := map[string]interface{}{
|
||||
"environment_id": environmentId,
|
||||
}
|
||||
response := &dtos.TLSCertResponse{}
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetAuthToken(token).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(request).
|
||||
SetResult(response).
|
||||
Post(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload TLS certificate: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("API responded with error: %s", resp.String())
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) GetTlsCerts(page int, pageSize int, environmentID string) (*dtos.TLSCertSResponse, error) {
|
||||
token, err := c.getToken("app.config")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/config/v0.1/tls-certs", c.apiURL)
|
||||
|
||||
var tlsCertsResponse dtos.TLSCertSResponse
|
||||
resp, err := c.client.R().
|
||||
SetAuthToken(token).
|
||||
SetQueryParams(map[string]string{
|
||||
"page": fmt.Sprintf("%d", page),
|
||||
"page_size": fmt.Sprintf("%d", pageSize),
|
||||
"environment_id": environmentID,
|
||||
}).
|
||||
SetResult(&tlsCertsResponse).
|
||||
Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("unexpected status code for getTlsCerts: %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
return &tlsCertsResponse, nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) UploadCdnConfiguration(config *dtos.CDNConfiguration) (*dtos.CDNConfiguration, error) {
|
||||
fmt.Println("------------------------------------------------------------------------- uploading")
|
||||
|
||||
token, err := c.getToken("app.config")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/config/v0.1/configs", c.apiURL)
|
||||
var response dtos.CDNConfiguration
|
||||
|
||||
// Convert config to json
|
||||
jsonBody, _ := json.MarshalIndent(config, "", " ")
|
||||
jsonString := string(jsonBody)
|
||||
fmt.Println("------------------------- config report code: ", config.Hostnames[0].ReportCode == nil)
|
||||
fmt.Println("------------------------- config report code value: ", config.Hostnames[0].ReportCode)
|
||||
fmt.Println("----------------------------------- jsonBody: ", jsonString)
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetAuthToken(token).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(config).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload CDN configuration: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("unexpected status code for uploadCdnConfiguration: %d, %s", resp.StatusCode(), resp.Body())
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (c *EdgioClient) GetCDNConfiguration(configID string) (*dtos.CDNConfiguration, error) {
|
||||
fmt.Println("------------------------------------------------------------------------- reading config")
|
||||
|
||||
token, err := c.getToken("app.config")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://edgioapis.com/config/v0.1/configs/%s", configID)
|
||||
var response dtos.CDNConfiguration
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetAuthToken(token).
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get CDN configuration: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("unexpected status code for GetCDNConfiguration: %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
26
internal/pkg/vendors/edgio-sdk/applications/v7/edgio_client_interface.go
vendored
Normal file
26
internal/pkg/vendors/edgio-sdk/applications/v7/edgio_client_interface.go
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
package edgio_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/vendors/edgio-sdk/applications/v7/dtos"
|
||||
)
|
||||
|
||||
type EdgioClientInterface interface {
|
||||
GetProperty(ctx context.Context, propertyID string) (*dtos.Property, error)
|
||||
GetProperties(page int, pageSize int, organizationID string) (*dtos.Properties, error)
|
||||
CreateProperty(ctx context.Context, organizationID, slug string) (*dtos.Property, error)
|
||||
DeleteProperty(propertyID string) error
|
||||
UpdateProperty(ctx context.Context, propertyID string, slug string) (*dtos.Property, error)
|
||||
GetEnvironments(page, pageSize int, propertyID string) (*dtos.EnvironmentsResponse, error)
|
||||
GetEnvironment(environmentID string) (*dtos.Environment, error)
|
||||
CreateEnvironment(propertyID, name string, onlyMaintainersCanDeploy, httpRequestLogging bool) (*dtos.Environment, error)
|
||||
UpdateEnvironment(environmentID, name string, onlyMaintainersCanDeploy, httpRequestLogging, preserveCache bool) (*dtos.Environment, error)
|
||||
DeleteEnvironment(environmentID string) error
|
||||
GetTlsCert(tlsCertId string) (*dtos.TLSCertResponse, error)
|
||||
UploadTlsCert(req dtos.UploadTlsCertRequest) (*dtos.TLSCertResponse, error)
|
||||
GenerateTlsCert(environmentId string) (*dtos.TLSCertResponse, error)
|
||||
GetTlsCerts(page int, pageSize int, environmentID string) (*dtos.TLSCertSResponse, error)
|
||||
UploadCdnConfiguration(config *dtos.CDNConfiguration) (*dtos.CDNConfiguration, error)
|
||||
GetCDNConfiguration(configID string) (*dtos.CDNConfiguration, error)
|
||||
}
|
@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/usual2970/certimate/internal/applicant"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
"github.com/usual2970/certimate/internal/repository"
|
||||
)
|
||||
|
||||
@ -89,7 +89,7 @@ func (a *applyNode) Run(ctx context.Context) error {
|
||||
Outputs: a.node.Outputs,
|
||||
}
|
||||
|
||||
certX509, err := x509.ParseCertificateFromPEM(applyResult.Certificate)
|
||||
certX509, err := certs.ParseCertificateFromPEM(applyResult.CertificateFullChain)
|
||||
if err != nil {
|
||||
a.AddOutput(ctx, a.node.Name, "解析证书失败", err.Error())
|
||||
return err
|
||||
@ -98,7 +98,7 @@ func (a *applyNode) Run(ctx context.Context) error {
|
||||
certificate := &domain.Certificate{
|
||||
Source: domain.CertificateSourceTypeWorkflow,
|
||||
SubjectAltNames: strings.Join(certX509.DNSNames, ";"),
|
||||
Certificate: applyResult.Certificate,
|
||||
Certificate: applyResult.CertificateFullChain,
|
||||
PrivateKey: applyResult.PrivateKey,
|
||||
IssuerCertificate: applyResult.IssuerCertificate,
|
||||
ACMECertUrl: applyResult.ACMECertUrl,
|
||||
|
1
ui/public/imgs/providers/edgio.svg
Normal file
1
ui/public/imgs/providers/edgio.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 256 256"><defs><radialGradient id="logosEdgioIcon0" cx="104.362%" cy="13.088%" r="94.575%" fx="104.362%" fy="13.088%"><stop offset="0%" stop-color="#01B07D"></stop><stop offset="100%" stop-color="#01B07D" stop-opacity="0"></stop></radialGradient><radialGradient id="logosEdgioIcon1" cx="68.749%" cy="120.916%" r="68.487%" fx="68.749%" fy="120.916%"><stop offset="0%" stop-color="#00AAE5"></stop><stop offset="100%" stop-color="#00AAE5" stop-opacity="0"></stop></radialGradient><linearGradient id="logosEdgioIcon2" x1="3.185%" x2="57.325%" y1="2.866%" y2="58.917%"><stop offset="0%" stop-color="#793092"></stop><stop offset="100%" stop-color="#6144A1"></stop></linearGradient></defs><path fill="url(#logosEdgioIcon2)" d="M0 0h256v256H0z"></path><path fill="url(#logosEdgioIcon0)" d="M0 0h256v256H0z"></path><path fill="url(#logosEdgioIcon1)" d="M0 0h256v256H0z"></path><path fill="#FFF" d="m170.908 77.201l16.225-29.253H68.867v160.103h118.266l-16.144-29.293h-70.24v-36.819h55.755l8.983-29.294h-64.738V77.201z"></path></svg>
|
1
ui/public/imgs/providers/ns1.svg
Normal file
1
ui/public/imgs/providers/ns1.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 390 390"><g fill="#231F20FD" stroke="#231F20FD"><path d="M 51.963 131.224 C 51.886 131.803 51.845 243.686 51.921 247.250 L 52.000 251.000 63.566 251.000 L 75.132 251.000 74.816 206.999 C 74.642 182.799 74.742 162.999 75.039 162.999 C 75.335 163.000 77.312 167.388 79.432 172.750 C 83.399 182.788 90.389 197.123 107.833 231.000 L 117.874 250.500 132.937 250.776 L 148.000 251.052 148.000 190.994 L 148.000 130.937 136.250 131.218 L 124.500 131.500 124.500 173.500 L 124.500 215.500 120.750 207.625 C 118.688 203.294 117.000 199.596 117.000 199.407 C 117.000 198.519 89.835 145.115 83.984 134.500 L 82.331 131.500 67.165 131.224 C 58.824 131.072 51.983 131.072 51.963 131.224 "/></g><g fill="#231F20FD" stroke="#231F20FD"><path d="M 198.000 132.031 C 186.222 134.506 175.076 142.919 170.355 152.899 C 166.812 160.387 166.653 172.157 169.999 179.275 C 173.108 185.888 182.377 194.106 191.729 198.540 C 214.885 209.518 217.990 211.199 220.403 214.067 C 225.383 219.986 222.954 228.450 215.364 231.621 C 205.909 235.572 189.337 230.763 178.483 220.919 C 176.495 219.115 176.374 219.224 169.983 228.525 C 166.417 233.714 163.500 238.750 163.500 239.716 C 163.500 243.321 178.319 250.974 189.353 253.067 C 195.907 254.310 210.272 254.251 217.295 252.953 C 233.791 249.904 246.375 238.021 248.563 223.425 C 250.000 213.849 245.659 202.627 237.670 195.264 C 232.765 190.743 229.887 189.103 213.403 181.443 C 200.793 175.583 196.411 172.667 194.403 168.800 C 192.158 164.479 192.698 161.300 196.355 157.310 C 199.384 154.005 200.311 153.605 205.890 153.202 C 213.355 152.662 219.518 154.710 225.794 159.818 C 228.193 161.771 230.428 162.913 230.859 162.406 C 231.283 161.908 234.301 158.350 237.565 154.500 C 240.829 150.650 243.838 147.350 244.250 147.167 C 248.483 145.285 237.577 136.985 226.119 133.367 C 220.358 131.549 203.998 130.771 198.000 132.031 "/></g><g fill="#231F20FD" stroke="#231F20FD"><path d="M 272.000 138.618 C 258.179 148.122 258.897 146.529 263.910 156.550 C 266.273 161.276 268.771 165.359 269.460 165.623 C 270.149 165.887 273.365 164.338 276.606 162.179 L 282.500 158.254 282.760 204.627 L 283.020 251.000 295.010 251.000 L 307.000 251.000 307.000 191.500 L 307.000 132.000 294.250 132.043 L 281.500 132.086 272.000 138.618 "/></g><g fill="#F30270FE" stroke="#F30270FE"><path d="M 325.071 225.703 C 315.164 230.894 314.604 243.488 324.000 249.818 C 334.022 256.571 347.264 246.120 344.007 234.027 C 341.944 226.364 332.083 222.030 325.071 225.703 "/></g></svg>
|
@ -17,10 +17,12 @@ import AccessFormBaiduCloudConfig from "./AccessFormBaiduCloudConfig";
|
||||
import AccessFormBytePlusConfig from "./AccessFormBytePlusConfig";
|
||||
import AccessFormCloudflareConfig from "./AccessFormCloudflareConfig";
|
||||
import AccessFormDogeCloudConfig from "./AccessFormDogeCloudConfig";
|
||||
import AccessFormEdgioConfig from "./AccessFormEdgioConfig";
|
||||
import AccessFormGoDaddyConfig from "./AccessFormGoDaddyConfig";
|
||||
import AccessFormHuaweiCloudConfig from "./AccessFormHuaweiCloudConfig";
|
||||
import AccessFormKubernetesConfig from "./AccessFormKubernetesConfig";
|
||||
import AccessFormLocalConfig from "./AccessFormLocalConfig";
|
||||
import AccessFormNS1Config from "./AccessFormNS1Config";
|
||||
import AccessFormNameDotComConfig from "./AccessFormNameDotComConfig";
|
||||
import AccessFormNameSiloConfig from "./AccessFormNameSiloConfig";
|
||||
import AccessFormPowerDNSConfig from "./AccessFormPowerDNSConfig";
|
||||
@ -101,6 +103,8 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
||||
return <AccessFormDogeCloudConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.GODADDY:
|
||||
return <AccessFormGoDaddyConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.EDGIO:
|
||||
return <AccessFormEdgioConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.HUAWEICLOUD:
|
||||
return <AccessFormHuaweiCloudConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.KUBERNETES:
|
||||
@ -111,6 +115,8 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
||||
return <AccessFormNameDotComConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.NAMESILO:
|
||||
return <AccessFormNameSiloConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.NS1:
|
||||
return <AccessFormNS1Config {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.POWERDNS:
|
||||
return <AccessFormPowerDNSConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.QINIU:
|
||||
|
76
ui/src/components/access/AccessFormEdgioConfig.tsx
Normal file
76
ui/src/components/access/AccessFormEdgioConfig.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, type FormInstance, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type AccessConfigForEdgio } from "@/domain/access";
|
||||
|
||||
type AccessFormEdgioConfigFieldValues = Nullish<AccessConfigForEdgio>;
|
||||
|
||||
export type AccessFormEdgioConfigProps = {
|
||||
form: FormInstance;
|
||||
formName: string;
|
||||
disabled?: boolean;
|
||||
initialValues?: AccessFormEdgioConfigFieldValues;
|
||||
onValuesChange?: (values: AccessFormEdgioConfigFieldValues) => void;
|
||||
};
|
||||
|
||||
const initFormModel = (): AccessFormEdgioConfigFieldValues => {
|
||||
return {
|
||||
clientId: "",
|
||||
clientSecret: "",
|
||||
};
|
||||
};
|
||||
|
||||
const AccessFormEdgioConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormEdgioConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
clientId: z
|
||||
.string()
|
||||
.min(1, t("access.form.edgio_client_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
clientSecret: z
|
||||
.string()
|
||||
.min(1, t("access.form.edgio_client_secret.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
|
||||
onValuesChange?.(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={formInst}
|
||||
disabled={disabled}
|
||||
initialValues={initialValues ?? initFormModel()}
|
||||
layout="vertical"
|
||||
name={formName}
|
||||
onValuesChange={handleFormChange}
|
||||
>
|
||||
<Form.Item
|
||||
name="clientId"
|
||||
label={t("access.form.edgio_client_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.edgio_client_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input autoComplete="new-password" placeholder={t("access.form.edgio_client_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="clientSecret"
|
||||
label={t("access.form.edgio_client_secret.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.edgio_client_secret.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password autoComplete="new-password" placeholder={t("access.form.edgio_client_secret.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessFormEdgioConfig;
|
61
ui/src/components/access/AccessFormNS1Config.tsx
Normal file
61
ui/src/components/access/AccessFormNS1Config.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, type FormInstance, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type AccessConfigForNS1 } from "@/domain/access";
|
||||
|
||||
type AccessFormNS1ConfigFieldValues = Nullish<AccessConfigForNS1>;
|
||||
|
||||
export type AccessFormNS1ConfigProps = {
|
||||
form: FormInstance;
|
||||
formName: string;
|
||||
disabled?: boolean;
|
||||
initialValues?: AccessFormNS1ConfigFieldValues;
|
||||
onValuesChange?: (values: AccessFormNS1ConfigFieldValues) => void;
|
||||
};
|
||||
|
||||
const initFormModel = (): AccessFormNS1ConfigFieldValues => {
|
||||
return {
|
||||
apiKey: "",
|
||||
};
|
||||
};
|
||||
|
||||
const AccessFormNS1Config = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormNS1ConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
apiKey: z
|
||||
.string()
|
||||
.min(1, t("access.form.ns1_api_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
|
||||
onValuesChange?.(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={formInst}
|
||||
disabled={disabled}
|
||||
initialValues={initialValues ?? initFormModel()}
|
||||
layout="vertical"
|
||||
name={formName}
|
||||
onValuesChange={handleFormChange}
|
||||
>
|
||||
<Form.Item
|
||||
name="apiKey"
|
||||
label={t("access.form.ns1_api_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ns1_api_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password autoComplete="new-password" placeholder={t("access.form.ns1_api_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessFormNS1Config;
|
@ -25,6 +25,7 @@ import DeployNodeConfigFormAliyunOSSConfig from "./DeployNodeConfigFormAliyunOSS
|
||||
import DeployNodeConfigFormBaiduCloudCDNConfig from "./DeployNodeConfigFormBaiduCloudCDNConfig";
|
||||
import DeployNodeConfigFormBytePlusCDNConfig from "./DeployNodeConfigFormBytePlusCDNConfig";
|
||||
import DeployNodeConfigFormDogeCloudCDNConfig from "./DeployNodeConfigFormDogeCloudCDNConfig";
|
||||
import DeployNodeConfigFormEdgioApplicationsConfig from "./DeployNodeConfigFormEdgioApplicationsConfig";
|
||||
import DeployNodeConfigFormHuaweiCloudCDNConfig from "./DeployNodeConfigFormHuaweiCloudCDNConfig";
|
||||
import DeployNodeConfigFormHuaweiCloudELBConfig from "./DeployNodeConfigFormHuaweiCloudELBConfig";
|
||||
import DeployNodeConfigFormKubernetesSecretConfig from "./DeployNodeConfigFormKubernetesSecretConfig";
|
||||
@ -134,6 +135,8 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
||||
return <DeployNodeConfigFormBytePlusCDNConfig {...nestedFormProps} />;
|
||||
case DEPLOY_PROVIDERS.DOGECLOUD_CDN:
|
||||
return <DeployNodeConfigFormDogeCloudCDNConfig {...nestedFormProps} />;
|
||||
case DEPLOY_PROVIDERS.EDGIO_APPLICATIONS:
|
||||
return <DeployNodeConfigFormEdgioApplicationsConfig {...nestedFormProps} />;
|
||||
case DEPLOY_PROVIDERS.HUAWEICLOUD_CDN:
|
||||
return <DeployNodeConfigFormHuaweiCloudCDNConfig {...nestedFormProps} />;
|
||||
case DEPLOY_PROVIDERS.HUAWEICLOUD_ELB:
|
||||
|
@ -0,0 +1,65 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, type FormInstance, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
type DeployNodeConfigFormEdgioApplicationsConfigFieldValues = Nullish<{
|
||||
environmentId: string;
|
||||
}>;
|
||||
|
||||
export type DeployNodeConfigFormEdgioApplicationsConfigProps = {
|
||||
form: FormInstance;
|
||||
formName: string;
|
||||
disabled?: boolean;
|
||||
initialValues?: DeployNodeConfigFormEdgioApplicationsConfigFieldValues;
|
||||
onValuesChange?: (values: DeployNodeConfigFormEdgioApplicationsConfigFieldValues) => void;
|
||||
};
|
||||
|
||||
const initFormModel = (): DeployNodeConfigFormEdgioApplicationsConfigFieldValues => {
|
||||
return {};
|
||||
};
|
||||
|
||||
const DeployNodeConfigFormEdgioApplicationsConfig = ({
|
||||
form: formInst,
|
||||
formName,
|
||||
disabled,
|
||||
initialValues,
|
||||
onValuesChange,
|
||||
}: DeployNodeConfigFormEdgioApplicationsConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
environmentId: z
|
||||
.string({ message: t("workflow_node.deploy.form.edgio_applications_environment_id.placeholder") })
|
||||
.min(1, t("workflow_node.deploy.form.edgio_applications_environment_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
|
||||
onValuesChange?.(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={formInst}
|
||||
disabled={disabled}
|
||||
initialValues={initialValues ?? initFormModel()}
|
||||
layout="vertical"
|
||||
name={formName}
|
||||
onValuesChange={handleFormChange}
|
||||
>
|
||||
<Form.Item
|
||||
name="environmentId"
|
||||
label={t("workflow_node.deploy.form.edgio_applications_environment_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.edgio_applications_environment_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.edgio_applications_environment_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployNodeConfigFormEdgioApplicationsConfig;
|
@ -16,6 +16,7 @@ export interface AccessModel extends BaseModel {
|
||||
| AccessConfigForBytePlus
|
||||
| AccessConfigForCloudflare
|
||||
| AccessConfigForDogeCloud
|
||||
| AccessConfigForEdgio
|
||||
| AccessConfigForGoDaddy
|
||||
| AccessConfigForHuaweiCloud
|
||||
| AccessConfigForKubernetes
|
||||
@ -77,6 +78,11 @@ export type AccessConfigForDogeCloud = {
|
||||
secretKey: string;
|
||||
};
|
||||
|
||||
export type AccessConfigForEdgio = {
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
};
|
||||
|
||||
export type AccessConfigForGoDaddy = {
|
||||
apiKey: string;
|
||||
apiSecret: string;
|
||||
@ -102,6 +108,10 @@ export type AccessConfigForNameSilo = {
|
||||
apiKey: string;
|
||||
};
|
||||
|
||||
export type AccessConfigForNS1 = {
|
||||
apiKey: string;
|
||||
};
|
||||
|
||||
export type AccessConfigForPowerDNS = {
|
||||
apiUrl: string;
|
||||
apiKey: string;
|
||||
|
@ -13,11 +13,13 @@ export const ACCESS_PROVIDERS = Object.freeze({
|
||||
CLOUDFLARE: "cloudflare",
|
||||
DOGECLOUD: "dogecloud",
|
||||
GODADDY: "godaddy",
|
||||
EDGIO: "edgio",
|
||||
HUAWEICLOUD: "huaweicloud",
|
||||
KUBERNETES: "k8s",
|
||||
LOCAL: "local",
|
||||
NAMEDOTCOM: "namedotcom",
|
||||
NAMESILO: "namesilo",
|
||||
NS1: "ns1",
|
||||
POWERDNS: "powerdns",
|
||||
QINIU: "qiniu",
|
||||
SSH: "ssh",
|
||||
@ -63,11 +65,13 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
|
||||
[ACCESS_PROVIDERS.VOLCENGINE, "common.provider.volcengine", "/imgs/providers/volcengine.svg", ACCESS_USAGES.ALL],
|
||||
[ACCESS_PROVIDERS.BYTEPLUS, "common.provider.byteplus", "/imgs/providers/byteplus.svg", ACCESS_USAGES.DEPLOY],
|
||||
[ACCESS_PROVIDERS.UCLOUD, "common.provider.ucloud", "/imgs/providers/ucloud.svg", ACCESS_USAGES.DEPLOY],
|
||||
[ACCESS_PROVIDERS.EDGIO, "common.provider.edgio", "/imgs/providers/edgio.svg", ACCESS_USAGES.DEPLOY],
|
||||
[ACCESS_PROVIDERS.AWS, "common.provider.aws", "/imgs/providers/aws.svg", ACCESS_USAGES.APPLY],
|
||||
[ACCESS_PROVIDERS.AZURE, "common.provider.azure", "/imgs/providers/azure.svg", ACCESS_USAGES.APPLY],
|
||||
[ACCESS_PROVIDERS.CLOUDFLARE, "common.provider.cloudflare", "/imgs/providers/cloudflare.svg", ACCESS_USAGES.APPLY],
|
||||
[ACCESS_PROVIDERS.NAMEDOTCOM, "common.provider.namedotcom", "/imgs/providers/namedotcom.svg", ACCESS_USAGES.APPLY],
|
||||
[ACCESS_PROVIDERS.NAMESILO, "common.provider.namesilo", "/imgs/providers/namesilo.svg", ACCESS_USAGES.APPLY],
|
||||
[ACCESS_PROVIDERS.NS1, "common.provider.ns1", "/imgs/providers/ns1.svg", ACCESS_USAGES.APPLY],
|
||||
[ACCESS_PROVIDERS.GODADDY, "common.provider.godaddy", "/imgs/providers/godaddy.svg", ACCESS_USAGES.APPLY],
|
||||
[ACCESS_PROVIDERS.POWERDNS, "common.provider.powerdns", "/imgs/providers/powerdns.svg", ACCESS_USAGES.APPLY],
|
||||
[ACCESS_PROVIDERS.ACMEHTTPREQ, "common.provider.acmehttpreq", "/imgs/providers/acmehttpreq.svg", ACCESS_USAGES.APPLY],
|
||||
@ -101,6 +105,7 @@ export const APPLY_DNS_PROVIDERS = Object.freeze({
|
||||
HUAWEICLOUD_DNS: `${ACCESS_PROVIDERS.HUAWEICLOUD}-dns`,
|
||||
NAMEDOTCOM: `${ACCESS_PROVIDERS.NAMEDOTCOM}`,
|
||||
NAMESILO: `${ACCESS_PROVIDERS.NAMESILO}`,
|
||||
NS1: `${ACCESS_PROVIDERS.NS1}`,
|
||||
POWERDNS: `${ACCESS_PROVIDERS.POWERDNS}`,
|
||||
TENCENTCLOUD: `${ACCESS_PROVIDERS.TENCENTCLOUD}`, // 兼容旧值,等同于 `TENCENTCLOUD_DNS`
|
||||
TENCENTCLOUD_DNS: `${ACCESS_PROVIDERS.TENCENTCLOUD}-dns`,
|
||||
@ -133,6 +138,7 @@ export const applyDNSProvidersMap: Map<ApplyDNSProvider["type"] | string, ApplyD
|
||||
[APPLY_DNS_PROVIDERS.GODADDY, "common.provider.godaddy"],
|
||||
[APPLY_DNS_PROVIDERS.NAMEDOTCOM, "common.provider.namedotcom"],
|
||||
[APPLY_DNS_PROVIDERS.NAMESILO, "common.provider.namesilo"],
|
||||
[APPLY_DNS_PROVIDERS.NS1, "common.provider.ns1"],
|
||||
[APPLY_DNS_PROVIDERS.POWERDNS, "common.provider.powerdns"],
|
||||
[APPLY_DNS_PROVIDERS.ACMEHTTPREQ, "common.provider.acmehttpreq"],
|
||||
].map(([type, name]) => [
|
||||
@ -163,6 +169,7 @@ export const DEPLOY_PROVIDERS = Object.freeze({
|
||||
BAIDUCLOUD_CDN: `${ACCESS_PROVIDERS.BAIDUCLOUD}-cdn`,
|
||||
BYTEPLUS_CDN: `${ACCESS_PROVIDERS.BYTEPLUS}-cdn`,
|
||||
DOGECLOUD_CDN: `${ACCESS_PROVIDERS.DOGECLOUD}-cdn`,
|
||||
EDGIO_APPLICATIONS: `${ACCESS_PROVIDERS.EDGIO}-applications`,
|
||||
HUAWEICLOUD_CDN: `${ACCESS_PROVIDERS.HUAWEICLOUD}-cdn`,
|
||||
HUAWEICLOUD_ELB: `${ACCESS_PROVIDERS.HUAWEICLOUD}-elb`,
|
||||
KUBERNETES_SECRET: `${ACCESS_PROVIDERS.KUBERNETES}-secret`,
|
||||
@ -230,6 +237,7 @@ export const deployProvidersMap: Map<DeployProvider["type"] | string, DeployProv
|
||||
[DEPLOY_PROVIDERS.BYTEPLUS_CDN, "common.provider.byteplus.cdn"],
|
||||
[DEPLOY_PROVIDERS.UCLOUD_US3, "common.provider.ucloud.us3"],
|
||||
[DEPLOY_PROVIDERS.UCLOUD_UCDN, "common.provider.ucloud.ucdn"],
|
||||
[DEPLOY_PROVIDERS.EDGIO_APPLICATIONS, "common.provider.edgio.applications"],
|
||||
].map(([type, name]) => [
|
||||
type,
|
||||
{
|
||||
|
@ -78,6 +78,12 @@
|
||||
"access.form.dogecloud_secret_key.label": "Doge Cloud SecretKey",
|
||||
"access.form.dogecloud_secret_key.placeholder": "Please enter Doge Cloud SecretKey",
|
||||
"access.form.dogecloud_secret_key.tooltip": "For more information, see <a href=\"https://console.dogecloud.com/\" target=\"_blank\">https://console.dogecloud.com/</a>",
|
||||
"access.form.edgio_client_id.label": "Edgio ClientId",
|
||||
"access.form.edgio_client_id.placeholder": "Please enter Edgio ClientId",
|
||||
"access.form.edgio_client_id.tooltip": "For more information, see <a href=\"https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients\" target=\"_blank\">https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients</a>",
|
||||
"access.form.edgio_client_secret.label": "Edgio ClientSecret",
|
||||
"access.form.edgio_client_secret.placeholder": "Please enter Edgio ClientSecret",
|
||||
"access.form.edgio_client_secret.tooltip": "For more information, see <a href=\"https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients\" target=\"_blank\">https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients</a>",
|
||||
"access.form.godaddy_api_key.label": "GoDaddy API key",
|
||||
"access.form.godaddy_api_key.placeholder": "Please enter GoDaddy API key",
|
||||
"access.form.godaddy_api_key.tooltip": "For more information, see <a href=\"https://developer.godaddy.com/\" target=\"_blank\">https://developer.godaddy.com/</a>",
|
||||
@ -103,6 +109,9 @@
|
||||
"access.form.namesilo_api_key.label": "NameSilo API key",
|
||||
"access.form.namesilo_api_key.placeholder": "Please enter NameSilo API key",
|
||||
"access.form.namesilo_api_key.tooltip": "For more information, see <a href=\"https://www.namesilo.com/support/v2/articles/account-options/api-manager\" target=\"_blank\">https://www.namesilo.com/support/v2/articles/account-options/api-manager</a>",
|
||||
"access.form.ns1_api_key.label": "NS1 API key",
|
||||
"access.form.ns1_api_key.placeholder": "Please enter NS1 API key",
|
||||
"access.form.ns1_api_key.tooltip": "For more information, see <a href=\"https://www.ibm.com/docs/en/ns1-connect?topic=introduction-using-api\" target=\"_blank\">https://www.ibm.com/docs/en/ns1-connect?topic=introduction-using-api</a>",
|
||||
"access.form.powerdns_api_url.label": "PowerDNS API URL",
|
||||
"access.form.powerdns_api_url.placeholder": "Please enter PowerDNS API URL",
|
||||
"access.form.powerdns_api_url.tooltip": "For more information, see <a href=\"https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api\" target=\"_blank\">https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api</a>",
|
||||
|
@ -56,6 +56,8 @@
|
||||
"common.provider.cloudflare": "Cloudflare",
|
||||
"common.provider.dogecloud": "Doge Cloud",
|
||||
"common.provider.dogecloud.cdn": "Doge Cloud - Content Delivery Network (CDN)",
|
||||
"common.provider.edgio": "Edgio",
|
||||
"common.provider.edgio.applications": "Edgio - Applications",
|
||||
"common.provider.godaddy": "GoDaddy",
|
||||
"common.provider.huaweicloud": "Huawei Cloud",
|
||||
"common.provider.huaweicloud.cdn": "Huawei Cloud - Content Delivery Network (CDN)",
|
||||
@ -66,6 +68,7 @@
|
||||
"common.provider.local": "Local deployment",
|
||||
"common.provider.namedotcom": "Name.com",
|
||||
"common.provider.namesilo": "NameSilo",
|
||||
"common.provider.ns1": "NS1 (IBM NS1 Connect)",
|
||||
"common.provider.powerdns": "PowerDNS",
|
||||
"common.provider.qiniu": "Qiniu",
|
||||
"common.provider.qiniu.cdn": "Qiniu - Content Delivery Network (CDN)",
|
||||
|
@ -148,6 +148,9 @@
|
||||
"workflow_node.deploy.form.dogecloud_cdn_domain.label": "Doge Cloud CDN domain",
|
||||
"workflow_node.deploy.form.dogecloud_cdn_domain.placeholder": "Please enter Doge Cloud CDN domain name",
|
||||
"workflow_node.deploy.form.dogecloud_cdn_domain.tooltip": "For more information, see <a href=\"https://console.dogecloud.com/\" target=\"_blank\">https://console.dogecloud.com/</a>",
|
||||
"workflow_node.deploy.form.edgio_applications_environment_id.label": "Edgio Applications environment ID",
|
||||
"workflow_node.deploy.form.edgio_applications_environment_id.placeholder": "Please enter Edgio Applications environment ID",
|
||||
"workflow_node.deploy.form.edgio_applications_environment_id.tooltip": "For more information, see <a href=\"https://edgio.app/\" target=\"_blank\">https://edgio.app/</a>",
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_region.label": "Huawei Cloud region",
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_region.placeholder": "Please enter Huawei Cloud region (e.g. cn-north-1)",
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_region.tooltip": "For more information, see <a href=\"https://console-intl.huaweicloud.com/apiexplorer/#/endpoint?locale=en-us\" target=\"_blank\">https://console-intl.huaweicloud.com/apiexplorer/#/endpoint</a>",
|
||||
|
@ -45,14 +45,14 @@
|
||||
"access.form.aws_secret_access_key.label": "AWS SecretAccessKey",
|
||||
"access.form.aws_secret_access_key.placeholder": "请输入 AWS SecretAccessKey",
|
||||
"access.form.aws_secret_access_key.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html</a>",
|
||||
"access.form.azure_tenant_id.label": "Azure TenantId",
|
||||
"access.form.azure_tenant_id.placeholder": "请输入 Azure TenantId",
|
||||
"access.form.azure_tenant_id.label": "Azure 租户 ID",
|
||||
"access.form.azure_tenant_id.placeholder": "请输入 Azure 租户 ID",
|
||||
"access.form.azure_tenant_id.tooltip": "这是什么?请参阅 <a href=\"https://learn.microsoft.com/zh-cn/azure/azure-portal/get-subscription-tenant-id\" target=\"_blank\">https://learn.microsoft.com/zh-cn/azure/azure-portal/get-subscription-tenant-id</a>",
|
||||
"access.form.azure_client_id.label": "Azure ClientId",
|
||||
"access.form.azure_client_id.placeholder": "请输入 Azure ClientId",
|
||||
"access.form.azure_client_id.label": "Azure 客户端 ID",
|
||||
"access.form.azure_client_id.placeholder": "请输入 Azure 客户端 ID",
|
||||
"access.form.azure_client_id.tooltip": "这是什么?请参阅 <a href=\"https://learn.microsoft.com/zh-cn/azure/azure-monitor/logs/api/register-app-for-token\" target=\"_blank\">https://learn.microsoft.com/zh-cn/azure/azure-monitor/logs/api/register-app-for-token</a>",
|
||||
"access.form.azure_client_secret.label": "Azure ClientSecret",
|
||||
"access.form.azure_client_secret.placeholder": "请输入 Azure ClientSecret",
|
||||
"access.form.azure_client_secret.label": "Azure 客户端密码",
|
||||
"access.form.azure_client_secret.placeholder": "请输入 Azure 客户端密码",
|
||||
"access.form.azure_client_secret.tooltip": "这是什么?请参阅 <a href=\"https://learn.microsoft.com/zh-cn/azure/azure-monitor/logs/api/register-app-for-token\" target=\"_blank\">https://learn.microsoft.com/zh-cn/azure/azure-monitor/logs/api/register-app-for-token</a>",
|
||||
"access.form.azure_cloud_name.label": "Azure 主权云环境(可选)",
|
||||
"access.form.azure_cloud_name.placeholder": "请输入 Azure 主权云环境(例如:public)",
|
||||
@ -78,6 +78,12 @@
|
||||
"access.form.dogecloud_secret_key.label": "多吉云 SecretKey",
|
||||
"access.form.dogecloud_secret_key.placeholder": "请输入多吉云 SecretKey",
|
||||
"access.form.dogecloud_secret_key.tooltip": "这是什么?请参阅 <a href=\"https://console.dogecloud.com/\" target=\"_blank\">https://console.dogecloud.com/</a>",
|
||||
"access.form.edgio_client_id.label": "Edgio 客户端 ID",
|
||||
"access.form.edgio_client_id.placeholder": "请输入 Edgio 客户端 ID",
|
||||
"access.form.edgio_client_id.tooltip": "这是什么?请参阅 <a href=\"https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients\" target=\"_blank\">https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients</a>",
|
||||
"access.form.edgio_client_secret.label": "Edgio 客户端密码",
|
||||
"access.form.edgio_client_secret.placeholder": "请输入 Edgio 客户端密码",
|
||||
"access.form.edgio_client_secret.tooltip": "这是什么?请参阅 <a href=\"https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients\" target=\"_blank\">https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients</a>",
|
||||
"access.form.godaddy_api_key.label": "GoDaddy API Key",
|
||||
"access.form.godaddy_api_key.placeholder": "请输入 GoDaddy API Key",
|
||||
"access.form.godaddy_api_key.tooltip": "这是什么?请参阅 <a href=\"https://developer.godaddy.com/\" target=\"_blank\">https://developer.godaddy.com/</a>",
|
||||
@ -103,6 +109,9 @@
|
||||
"access.form.namesilo_api_key.label": "NameSilo API Key",
|
||||
"access.form.namesilo_api_key.placeholder": "请输入 NameSilo API Key",
|
||||
"access.form.namesilo_api_key.tooltip": "这是什么?请参阅 <a href=\"https://www.namesilo.com/support/v2/articles/account-options/api-manager\" target=\"_blank\">https://www.namesilo.com/support/v2/articles/account-options/api-manager</a>",
|
||||
"access.form.ns1_api_key.label": "NS1 API Key",
|
||||
"access.form.ns1_api_key.placeholder": "请输入 NS1 API Key",
|
||||
"access.form.ns1_api_key.tooltip": "这是什么?请参阅 <a href=\"https://www.ibm.com/docs/zh/ns1-connect?topic=introduction-using-api\" target=\"_blank\">https://www.ibm.com/docs/zh/ns1-connect?topic=introduction-using-api</a>",
|
||||
"access.form.powerdns_api_url.label": "PowerDNS API URL",
|
||||
"access.form.powerdns_api_url.placeholder": "请输入 PowerDNS API URL",
|
||||
"access.form.powerdns_api_url.tooltip": "这是什么?请参阅 <a href=\"https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api\" target=\"_blank\">https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api</a>",
|
||||
|
@ -56,6 +56,8 @@
|
||||
"common.provider.cloudflare": "Cloudflare",
|
||||
"common.provider.dogecloud": "多吉云",
|
||||
"common.provider.dogecloud.cdn": "多吉云 - 内容分发网络 CDN",
|
||||
"common.provider.edgio": "Edgio",
|
||||
"common.provider.edgio.applications": "Edgio - Applications",
|
||||
"common.provider.godaddy": "GoDaddy",
|
||||
"common.provider.huaweicloud": "华为云",
|
||||
"common.provider.huaweicloud.cdn": "华为云 - 内容分发网络 CDN",
|
||||
@ -66,6 +68,7 @@
|
||||
"common.provider.local": "本地部署",
|
||||
"common.provider.namedotcom": "Name.com",
|
||||
"common.provider.namesilo": "NameSilo",
|
||||
"common.provider.ns1": "NS1(IBM NS1 Connect)",
|
||||
"common.provider.powerdns": "PowerDNS",
|
||||
"common.provider.qiniu": "七牛云",
|
||||
"common.provider.qiniu.cdn": "七牛云 - 内容分发网络 CDN",
|
||||
|
@ -148,6 +148,9 @@
|
||||
"workflow_node.deploy.form.dogecloud_cdn_domain.label": "多吉云 CDN 加速域名",
|
||||
"workflow_node.deploy.form.dogecloud_cdn_domain.placeholder": "请输入多吉云 CDN 加速域名",
|
||||
"workflow_node.deploy.form.dogecloud_cdn_domain.tooltip": "这是什么?请参阅 <a href=\"https://console.dogecloud.com\" target=\"_blank\">https://console.dogecloud.com</a>",
|
||||
"workflow_node.deploy.form.edgio_applications_environment_id.label": "Edgio Applications 环境 ID",
|
||||
"workflow_node.deploy.form.edgio_applications_environment_id.placeholder": "请输入 Edgio Applications 环境 ID",
|
||||
"workflow_node.deploy.form.edgio_applications_environment_id.tooltip": "这是什么?请参阅 <a href=\"https://edgio.app/\" target=\"_blank\">https://edgio.app/</a>",
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_region.label": "华为云区域",
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_region.placeholder": "请输入华为云区域(例如:cn-north-1)",
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_region.tooltip": "这是什么?请参阅 <a href=\"https://console.huaweicloud.com/apiexplorer/#/endpoint\" target=\"_blank\">https://console.huaweicloud.com/apiexplorer/#/endpoint</a>",
|
||||
|
Loading…
x
Reference in New Issue
Block a user