diff --git a/go.mod b/go.mod index 06ea5977..fd7c0355 100644 --- a/go.mod +++ b/go.mod @@ -84,6 +84,9 @@ require ( github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 // indirect github.com/blinkbean/dingtalk v1.1.3 // indirect + github.com/buger/goterm v1.0.4 // indirect + github.com/diskfs/go-diskfs v1.5.0 // indirect + github.com/djherbis/times v1.6.0 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-lark/lark v1.15.1 // indirect @@ -103,11 +106,15 @@ require ( github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/jinzhu/copier v0.3.4 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/luthermonson/go-proxmox v0.2.2 // indirect + github.com/magefile/mage v1.14.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect @@ -120,7 +127,7 @@ require ( github.com/qiniu/dyn v1.3.0 // indirect github.com/qiniu/x v1.10.5 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/x448/float16 v0.8.4 // indirect go.mongodb.org/mongo-driver v1.17.2 // indirect diff --git a/go.sum b/go.sum index b1370567..7b7fcb73 100644 --- a/go.sum +++ b/go.sum @@ -254,6 +254,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blinkbean/dingtalk v1.1.3 h1:MbidFZYom7DTFHD/YIs+eaI7kRy52kmWE/sy0xjo6E4= github.com/blinkbean/dingtalk v1.1.3/go.mod h1:9BaLuGSBqY3vT5hstValh48DbsKO7vaHaJnG9pXwbto= +github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY= +github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE= github.com/byteplus-sdk/byteplus-sdk-golang v1.0.44 h1:men5pKZNho+cw9/YU7TFerTspS3lKayS64zctl/D7Fk= github.com/byteplus-sdk/byteplus-sdk-golang v1.0.44/go.mod h1:CIL/T2dxgbIA79os+wl0Fq0vCbADTZNIddV6PNYB6DY= github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= @@ -297,6 +299,10 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= +github.com/diskfs/go-diskfs v1.5.0 h1:0SANkrab4ifiZBytk380gIesYh5Gc+3i40l7qsrYP4s= +github.com/diskfs/go-diskfs v1.5.0/go.mod h1:bRFumZeGFCO8C2KNswrQeuj2m1WCVr4Ms5IjWMczMDk= +github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= +github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8= github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -494,6 +500,8 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= @@ -546,6 +554,8 @@ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJk github.com/jdcloud-api/jdcloud-sdk-go v1.64.0 h1:xZc/ZRcrOhDx9Ra9htu6ui2gUUttmLsXIqH61LcvY4U= github.com/jdcloud-api/jdcloud-sdk-go v1.64.0/go.mod h1:UrKjuULIWLjHFlG6aSPunArE5QX57LftMmStAZJBEX8= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/copier v0.3.4 h1:mfU6jI9PtCeUjkjQ322dlff9ELjGDu975C2p/nrubVI= +github.com/jinzhu/copier v0.3.4/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -602,6 +612,10 @@ github.com/libdns/dynv6 v1.0.0/go.mod h1:65PL/bAlyH0J+0WGlOJYnMpoIuXcg/FmW4dTBYW github.com/libdns/libdns v0.1.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/libdns/libdns v0.2.3 h1:ba30K4ObwMGB/QTmqUxf3H4/GmUrCAIkMWejeGl12v8= github.com/libdns/libdns v0.2.3/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= +github.com/luthermonson/go-proxmox v0.2.2 h1:BZ7VEj302wxw2i/EwTcyEiBzQib8teocB2SSkLHyySY= +github.com/luthermonson/go-proxmox v0.2.2/go.mod h1:oyFgg2WwTEIF0rP6ppjiixOHa5ebK1p8OaRiFhvICBQ= +github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo= +github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -769,6 +783,8 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= +github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -1101,6 +1117,7 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1109,6 +1126,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/internal/applicant/providers.go b/internal/applicant/providers.go index 3b4c6894..454f9376 100644 --- a/internal/applicant/providers.go +++ b/internal/applicant/providers.go @@ -441,10 +441,11 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi } applicant, err := pPowerDNS.NewChallengeProvider(&pPowerDNS.ChallengeProviderConfig{ - ApiUrl: access.ApiUrl, - ApiKey: access.ApiKey, - DnsPropagationTimeout: options.DnsPropagationTimeout, - DnsTTL: options.DnsTTL, + ApiUrl: access.ApiUrl, + ApiKey: access.ApiKey, + AllowInsecureConnections: access.AllowInsecureConnections, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, }) return applicant, err } diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index ab92fa6f..77ed8acb 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -52,6 +52,7 @@ import ( pJDCloudVOD "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-vod" pK8sSecret "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/k8s-secret" pLocal "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/local" + pProxmoxVE "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/proxmoxve" pQiniuCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/qiniu-cdn" pQiniuPili "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/qiniu-pili" pRainYunRCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/rainyun-rcdn" @@ -509,12 +510,13 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer } deployer, err := pCdnfly.NewDeployer(&pCdnfly.DeployerConfig{ - ApiUrl: access.ApiUrl, - ApiKey: access.ApiKey, - ApiSecret: access.ApiSecret, - ResourceType: pCdnfly.ResourceType(maputil.GetOrDefaultString(options.ProviderExtendedConfig, "resourceType", string(pCdnfly.RESOURCE_TYPE_SITE))), - SiteId: maputil.GetString(options.ProviderExtendedConfig, "siteId"), - CertificateId: maputil.GetString(options.ProviderExtendedConfig, "certificateId"), + ApiUrl: access.ApiUrl, + ApiKey: access.ApiKey, + ApiSecret: access.ApiSecret, + AllowInsecureConnections: access.AllowInsecureConnections, + ResourceType: pCdnfly.ResourceType(maputil.GetOrDefaultString(options.ProviderExtendedConfig, "resourceType", string(pCdnfly.RESOURCE_TYPE_SITE))), + SiteId: maputil.GetString(options.ProviderExtendedConfig, "siteId"), + CertificateId: maputil.GetString(options.ProviderExtendedConfig, "certificateId"), }) return deployer, err } @@ -577,11 +579,12 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer } deployer, err := pGoEdge.NewDeployer(&pGoEdge.DeployerConfig{ - ApiUrl: access.ApiUrl, - AccessKeyId: access.AccessKeyId, - AccessKey: access.AccessKey, - ResourceType: pGoEdge.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")), - CertificateId: maputil.GetInt64(options.ProviderExtendedConfig, "certificateId"), + ApiUrl: access.ApiUrl, + AccessKeyId: access.AccessKeyId, + AccessKey: access.AccessKey, + AllowInsecureConnections: access.AllowInsecureConnections, + ResourceType: pGoEdge.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")), + CertificateId: maputil.GetInt64(options.ProviderExtendedConfig, "certificateId"), }) return deployer, err } @@ -721,6 +724,24 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer return deployer, err } + case domain.DeploymentProviderTypeProxmoxVE: + { + access := domain.AccessConfigForProxmoxVE{} + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + deployer, err := pProxmoxVE.NewDeployer(&pProxmoxVE.DeployerConfig{ + ApiUrl: access.ApiUrl, + ApiToken: access.ApiToken, + ApiTokenSecret: access.ApiTokenSecret, + AllowInsecureConnections: access.AllowInsecureConnections, + NodeName: maputil.GetString(options.ProviderExtendedConfig, "nodeName"), + AutoRestart: maputil.GetBool(options.ProviderExtendedConfig, "autoRestart"), + }) + return deployer, err + } + case domain.DeploymentProviderTypeQiniuCDN, domain.DeploymentProviderTypeQiniuKodo, domain.DeploymentProviderTypeQiniuPili: { access := domain.AccessConfigForQiniu{} diff --git a/internal/domain/access.go b/internal/domain/access.go index 39d945a1..84afd292 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -74,9 +74,10 @@ type AccessConfigForCacheFly struct { } type AccessConfigForCdnfly struct { - ApiUrl string `json:"apiUrl"` - ApiKey string `json:"apiKey"` - ApiSecret string `json:"apiSecret"` + ApiUrl string `json:"apiUrl"` + ApiKey string `json:"apiKey"` + ApiSecret string `json:"apiSecret"` + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` } type AccessConfigForCloudflare struct { @@ -147,9 +148,10 @@ type AccessConfigForGoDaddy struct { } type AccessConfigForGoEdge struct { - ApiUrl string `json:"apiUrl"` - AccessKeyId string `json:"accessKeyId"` - AccessKey string `json:"accessKey"` + ApiUrl string `json:"apiUrl"` + AccessKeyId string `json:"accessKeyId"` + AccessKey string `json:"accessKey"` + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` } type AccessConfigForGoogleTrustServices struct { @@ -206,8 +208,16 @@ type AccessConfigForPorkbun struct { } type AccessConfigForPowerDNS struct { - ApiUrl string `json:"apiUrl"` - ApiKey string `json:"apiKey"` + ApiUrl string `json:"apiUrl"` + ApiKey string `json:"apiKey"` + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` +} + +type AccessConfigForProxmoxVE struct { + ApiUrl string `json:"apiUrl"` + ApiToken string `json:"apiToken"` + ApiTokenSecret string `json:"apiTokenSecret,omitempty"` + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` } type AccessConfigForQiniu struct { diff --git a/internal/domain/provider.go b/internal/domain/provider.go index ffc33b5f..728f89b6 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -55,6 +55,7 @@ const ( AccessProviderTypeNS1 = AccessProviderType("ns1") AccessProviderTypePorkbun = AccessProviderType("porkbun") AccessProviderTypePowerDNS = AccessProviderType("powerdns") + AccessProviderTypeProxmoxVE = AccessProviderType("proxmoxve") AccessProviderTypeQiniu = AccessProviderType("qiniu") AccessProviderTypeQingCloud = AccessProviderType("qingcloud") // 青云(预留) AccessProviderTypeRainYun = AccessProviderType("rainyun") @@ -197,6 +198,7 @@ const ( DeploymentProviderTypeJDCloudVOD = DeploymentProviderType(AccessProviderTypeJDCloud + "-vod") DeploymentProviderTypeKubernetesSecret = DeploymentProviderType(AccessProviderTypeKubernetes + "-secret") DeploymentProviderTypeLocal = DeploymentProviderType(AccessProviderTypeLocal) + DeploymentProviderTypeProxmoxVE = DeploymentProviderType(AccessProviderTypeProxmoxVE) DeploymentProviderTypeQiniuCDN = DeploymentProviderType(AccessProviderTypeQiniu + "-cdn") DeploymentProviderTypeQiniuKodo = DeploymentProviderType(AccessProviderTypeQiniu + "-kodo") DeploymentProviderTypeQiniuPili = DeploymentProviderType(AccessProviderTypeQiniu + "-pili") diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns/powerdns.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns/powerdns.go index e5275efe..7630633c 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns/powerdns.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns/powerdns.go @@ -1,6 +1,8 @@ package powerdns import ( + "crypto/tls" + "net/http" "net/url" "time" @@ -9,10 +11,11 @@ import ( ) type ChallengeProviderConfig struct { - ApiUrl string `json:"apiUrl"` - ApiKey string `json:"apiKey"` - DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` - DnsTTL int32 `json:"dnsTTL,omitempty"` + ApiUrl string `json:"apiUrl"` + ApiKey string `json:"apiKey"` + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` + DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` + DnsTTL int32 `json:"dnsTTL,omitempty"` } func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { @@ -24,6 +27,13 @@ func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, providerConfig := pdns.NewDefaultConfig() providerConfig.Host = host providerConfig.APIKey = config.ApiKey + if config.AllowInsecureConnections { + providerConfig.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + } if config.DnsPropagationTimeout != 0 { providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second } diff --git a/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go b/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go index 55a48035..069e01f9 100644 --- a/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go +++ b/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go @@ -79,7 +79,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE return &deployer.DeployResult{}, nil } -func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) { +func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*opsdk.Client, error) { if _, err := url.Parse(apiUrl); err != nil { return nil, errors.New("invalid 1panel api url") } @@ -89,7 +89,7 @@ func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, } client := opsdk.NewClient(apiUrl, apiKey) - if allowInsecure { + if skipTlsVerify { client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) } diff --git a/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go b/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go index aa5fa507..7d360c77 100644 --- a/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go +++ b/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go @@ -173,7 +173,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri return nil } -func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) { +func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*opsdk.Client, error) { if _, err := url.Parse(apiUrl); err != nil { return nil, errors.New("invalid 1panel api url") } @@ -183,7 +183,7 @@ func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, } client := opsdk.NewClient(apiUrl, apiKey) - if allowInsecure { + if skipTlsVerify { client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) } diff --git a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go index 34df198f..b1a57a81 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go +++ b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go @@ -82,7 +82,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE return &deployer.DeployResult{}, nil } -func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, error) { +func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) { if _, err := url.Parse(apiUrl); err != nil { return nil, errors.New("invalid baota api url") } @@ -92,7 +92,7 @@ func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, } client := btsdk.NewClient(apiUrl, apiKey) - if allowInsecure { + if skipTlsVerify { client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) } diff --git a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go index a06d32fe..f8266791 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go +++ b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go @@ -124,7 +124,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE return &deployer.DeployResult{}, nil } -func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, error) { +func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) { if _, err := url.Parse(apiUrl); err != nil { return nil, errors.New("invalid baota api url") } @@ -134,7 +134,7 @@ func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, } client := btsdk.NewClient(apiUrl, apiKey) - if allowInsecure { + if skipTlsVerify { client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) } diff --git a/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go b/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go index 788d18d5..909caf3e 100644 --- a/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go +++ b/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go @@ -2,6 +2,7 @@ package cdnfly import ( "context" + "crypto/tls" "encoding/json" "errors" "fmt" @@ -20,6 +21,8 @@ type DeployerConfig struct { ApiKey string `json:"apiKey"` // Cdnfly 用户端 API Secret。 ApiSecret string `json:"apiSecret"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` // 部署资源类型。 ResourceType ResourceType `json:"resourceType"` // 网站 ID。 @@ -43,7 +46,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { panic("config is nil") } - client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.ApiSecret) + client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.ApiSecret, config.AllowInsecureConnections) if err != nil { return nil, fmt.Errorf("failed to create sdk client: %w", err) } @@ -157,7 +160,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri return nil } -func createSdkClient(apiUrl, apiKey, apiSecret string) (*cfsdk.Client, error) { +func createSdkClient(apiUrl, apiKey, apiSecret string, skipTlsVerify bool) (*cfsdk.Client, error) { if _, err := url.Parse(apiUrl); err != nil { return nil, errors.New("invalid cachefly api url") } @@ -171,5 +174,9 @@ func createSdkClient(apiUrl, apiKey, apiSecret string) (*cfsdk.Client, error) { } client := cfsdk.NewClient(apiUrl, apiKey, apiSecret) + if skipTlsVerify { + client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) + } + return client, nil } diff --git a/internal/pkg/core/deployer/providers/cdnfly/cdnfly_test.go b/internal/pkg/core/deployer/providers/cdnfly/cdnfly_test.go index 5356e023..26486721 100644 --- a/internal/pkg/core/deployer/providers/cdnfly/cdnfly_test.go +++ b/internal/pkg/core/deployer/providers/cdnfly/cdnfly_test.go @@ -57,11 +57,12 @@ func TestDeploy(t *testing.T) { }, "\n")) deployer, err := provider.NewDeployer(&provider.DeployerConfig{ - ApiUrl: fApiUrl, - ApiKey: fApiKey, - ApiSecret: fApiSecret, - ResourceType: provider.RESOURCE_TYPE_CERTIFICATE, - CertificateId: fCertificateId, + ApiUrl: fApiUrl, + ApiKey: fApiKey, + ApiSecret: fApiSecret, + AllowInsecureConnections: true, + ResourceType: provider.RESOURCE_TYPE_CERTIFICATE, + CertificateId: fCertificateId, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/deployer/providers/goedge/goedge.go b/internal/pkg/core/deployer/providers/goedge/goedge.go index 6aed4d56..61153b1b 100644 --- a/internal/pkg/core/deployer/providers/goedge/goedge.go +++ b/internal/pkg/core/deployer/providers/goedge/goedge.go @@ -2,6 +2,7 @@ package goedge import ( "context" + "crypto/tls" "encoding/base64" "errors" "fmt" @@ -21,6 +22,8 @@ type DeployerConfig struct { AccessKeyId string `json:"accessKeyId"` // GoEdge 用户 AccessKey。 AccessKey string `json:"accessKey"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` // 部署资源类型。 ResourceType ResourceType `json:"resourceType"` // 证书 ID。 @@ -41,7 +44,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { panic("config is nil") } - client, err := createSdkClient(config.ApiUrl, config.AccessKeyId, config.AccessKey) + client, err := createSdkClient(config.ApiUrl, config.AccessKeyId, config.AccessKey, config.AllowInsecureConnections) if err != nil { return nil, fmt.Errorf("failed to create sdk client: %w", err) } @@ -113,7 +116,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri return nil } -func createSdkClient(apiUrl, accessKeyId, accessKey string) (*goedgesdk.Client, error) { +func createSdkClient(apiUrl, accessKeyId, accessKey string, skipTlsVerify bool) (*goedgesdk.Client, error) { if _, err := url.Parse(apiUrl); err != nil { return nil, errors.New("invalid goedge api url") } @@ -127,5 +130,9 @@ func createSdkClient(apiUrl, accessKeyId, accessKey string) (*goedgesdk.Client, } client := goedgesdk.NewClient(apiUrl, "user", accessKeyId, accessKey) + if skipTlsVerify { + client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) + } + return client, nil } diff --git a/internal/pkg/core/deployer/providers/goedge/goedge_test.go b/internal/pkg/core/deployer/providers/goedge/goedge_test.go index 1f326b9e..c8c32b37 100644 --- a/internal/pkg/core/deployer/providers/goedge/goedge_test.go +++ b/internal/pkg/core/deployer/providers/goedge/goedge_test.go @@ -57,11 +57,12 @@ func TestDeploy(t *testing.T) { }, "\n")) deployer, err := provider.NewDeployer(&provider.DeployerConfig{ - ApiUrl: fApiUrl, - AccessKeyId: fAccessKeyId, - AccessKey: fAccessKey, - ResourceType: provider.RESOURCE_TYPE_CERTIFICATE, - CertificateId: int64(fCertificateId), + ApiUrl: fApiUrl, + AccessKeyId: fAccessKeyId, + AccessKey: fAccessKey, + AllowInsecureConnections: true, + ResourceType: provider.RESOURCE_TYPE_CERTIFICATE, + CertificateId: int64(fCertificateId), }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/deployer/providers/proxmoxve/proxmoxve.go b/internal/pkg/core/deployer/providers/proxmoxve/proxmoxve.go new file mode 100644 index 00000000..d2e92460 --- /dev/null +++ b/internal/pkg/core/deployer/providers/proxmoxve/proxmoxve.go @@ -0,0 +1,121 @@ +package proxmoxve + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "log/slog" + "net/http" + "net/url" + "strings" + + "github.com/luthermonson/go-proxmox" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" +) + +type DeployerConfig struct { + // Proxmox VE 地址。 + ApiUrl string `json:"apiUrl"` + // Proxmox VE API Token。 + ApiToken string `json:"apiToken"` + // Proxmox VE API Token Secret。 + ApiTokenSecret string `json:"apiTokenSecret,omitempty"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` + // 集群节点名称。 + NodeName string `json:"nodeName"` + // 是否自动重启。 + AutoRestart bool `json:"autoRestart"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sdkClient *proxmox.Client +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiUrl, config.ApiToken, config.ApiTokenSecret, config.AllowInsecureConnections) + if err != nil { + return nil, fmt.Errorf("failed to create sdk client: %w", err) + } + + return &DeployerProvider{ + config: config, + logger: slog.Default(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) { + if d.config.NodeName == "" { + return nil, errors.New("config `nodeName` is required") + } + + // 获取节点信息 + // REF: https://pve.proxmox.com/pve-docs/api-viewer/index.html#/nodes/{node} + node, err := d.sdkClient.Node(context.TODO(), d.config.NodeName) + if err != nil { + return nil, fmt.Errorf("failed to get node '%s': %w", d.config.NodeName, err) + } + + // 上传自定义证书 + // REF: https://pve.proxmox.com/pve-docs/api-viewer/index.html#/nodes/{node}/certificates/custom + err = node.UploadCustomCertificate(context.TODO(), &proxmox.CustomCertificate{ + Certificates: certPEM, + Key: privkeyPEM, + Force: true, + Restart: d.config.AutoRestart, + }) + if err != nil { + return nil, fmt.Errorf("failed to upload custom certificate to node '%s': %w", node.Name, err) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiUrl, apiToken, apiTokenSecret string, skipTlsVerify bool) (*proxmox.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid pve api url") + } + + if apiToken == "" { + return nil, errors.New("invalid pve api token") + } + + httpClient := &http.Client{ + Transport: http.DefaultTransport, + Timeout: http.DefaultClient.Timeout, + } + if skipTlsVerify { + httpClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + } + client := proxmox.NewClient( + strings.TrimRight(apiUrl, "/")+"/api2/json", + proxmox.WithHTTPClient(httpClient), + proxmox.WithAPIToken(apiToken, apiTokenSecret), + ) + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/proxmoxve/proxmoxve_test.go b/internal/pkg/core/deployer/providers/proxmoxve/proxmoxve_test.go new file mode 100644 index 00000000..6251bd75 --- /dev/null +++ b/internal/pkg/core/deployer/providers/proxmoxve/proxmoxve_test.go @@ -0,0 +1,82 @@ +package proxmoxve_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/proxmoxve" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiUrl string + fApiToken string + fApiTokenSecret string + fNodeName string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_PROXMOXVE_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") + flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "") + flag.StringVar(&fApiTokenSecret, argsPrefix+"APITOKENSECRET", "", "") + flag.StringVar(&fNodeName, argsPrefix+"NODENAME", "", "") +} + +/* +Shell command to run this test: + + go test -v ./proxmoxve_test.go -args \ + --CERTIMATE_DEPLOYER_PROXMOXVE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_PROXMOXVE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_PROXMOXVE_APIURL="http://127.0.0.1:8006" \ + --CERTIMATE_DEPLOYER_PROXMOXVE_APITOKEN="your-api-token" \ + --CERTIMATE_DEPLOYER_PROXMOXVE_APITOKENSECRET="your-api-token-secret" \ + --CERTIMATE_DEPLOYER_PROXMOXVE_NODENAME="your-cluster-node-name" +*/ +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("APIURL: %v", fApiUrl), + fmt.Sprintf("APITOKEN: %v", fApiToken), + fmt.Sprintf("APITOKENSECRET: %v", fApiTokenSecret), + fmt.Sprintf("NODENAME: %v", fNodeName), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiUrl: fApiUrl, + ApiToken: fApiToken, + ApiTokenSecret: fApiTokenSecret, + AllowInsecureConnections: true, + NodeName: fNodeName, + AutoRestart: true, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + t.Logf("ok: %v", res) + }) +} diff --git a/internal/pkg/core/deployer/providers/safeline/safeline.go b/internal/pkg/core/deployer/providers/safeline/safeline.go index a4621109..f737fda9 100644 --- a/internal/pkg/core/deployer/providers/safeline/safeline.go +++ b/internal/pkg/core/deployer/providers/safeline/safeline.go @@ -98,7 +98,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri return nil } -func createSdkClient(apiUrl, apiToken string, allowInsecure bool) (*safelinesdk.Client, error) { +func createSdkClient(apiUrl, apiToken string, skipTlsVerify bool) (*safelinesdk.Client, error) { if _, err := url.Parse(apiUrl); err != nil { return nil, errors.New("invalid safeline api url") } @@ -108,7 +108,7 @@ func createSdkClient(apiUrl, apiToken string, allowInsecure bool) (*safelinesdk. } client := safelinesdk.NewClient(apiUrl, apiToken) - if allowInsecure { + if skipTlsVerify { client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) } diff --git a/internal/pkg/sdk3rd/cdnfly/client.go b/internal/pkg/sdk3rd/cdnfly/client.go index 47738f29..c1a810d9 100644 --- a/internal/pkg/sdk3rd/cdnfly/client.go +++ b/internal/pkg/sdk3rd/cdnfly/client.go @@ -1,6 +1,7 @@ package cdnflysdk import ( + "crypto/tls" "encoding/json" "fmt" "net/http" @@ -34,6 +35,11 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client { return c } +func (c *Client) WithTLSConfig(config *tls.Config) *Client { + c.client.SetTLSClientConfig(config) + return c +} + func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) { req := c.client.R() req.Method = method diff --git a/internal/pkg/sdk3rd/goedge/client.go b/internal/pkg/sdk3rd/goedge/client.go index c2e3b4f8..96291fb3 100644 --- a/internal/pkg/sdk3rd/goedge/client.go +++ b/internal/pkg/sdk3rd/goedge/client.go @@ -1,6 +1,7 @@ package goedge import ( + "crypto/tls" "encoding/json" "fmt" "net/http" @@ -41,6 +42,11 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client { return c } +func (c *Client) WithTLSConfig(config *tls.Config) *Client { + c.client.SetTLSClientConfig(config) + return c +} + func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) { req := c.client.R().SetBasicAuth(c.accessKeyId, c.accessKey) req.Method = method diff --git a/ui/public/imgs/providers/proxmoxve.svg b/ui/public/imgs/providers/proxmoxve.svg new file mode 100644 index 00000000..76e497f1 --- /dev/null +++ b/ui/public/imgs/providers/proxmoxve.svg @@ -0,0 +1 @@ + diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index 3727f09c..5f82ad67 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -47,6 +47,7 @@ import AccessFormNameSiloConfig from "./AccessFormNameSiloConfig"; import AccessFormNS1Config from "./AccessFormNS1Config"; import AccessFormPorkbunConfig from "./AccessFormPorkbunConfig"; import AccessFormPowerDNSConfig from "./AccessFormPowerDNSConfig"; +import AccessFormProxmoxVEConfig from "./AccessFormProxmoxVEConfig"; import AccessFormQiniuConfig from "./AccessFormQiniuConfig"; import AccessFormRainYunConfig from "./AccessFormRainYunConfig"; import AccessFormSafeLineConfig from "./AccessFormSafeLineConfig"; @@ -231,6 +232,8 @@ const AccessForm = forwardRef(({ className, return ; case ACCESS_PROVIDERS.POWERDNS: return ; + case ACCESS_PROVIDERS.PROXMOXVE: + return ; case ACCESS_PROVIDERS.QINIU: return ; case ACCESS_PROVIDERS.RAINYUN: diff --git a/ui/src/components/access/AccessForm1PanelConfig.tsx b/ui/src/components/access/AccessForm1PanelConfig.tsx index 1dde96b5..c0762bbd 100644 --- a/ui/src/components/access/AccessForm1PanelConfig.tsx +++ b/ui/src/components/access/AccessForm1PanelConfig.tsx @@ -49,12 +49,7 @@ const AccessForm1PanelConfig = ({ form: formInst, formName, disabled, initialVal name={formName} onValuesChange={handleFormChange} > - } - > + @@ -67,12 +62,7 @@ const AccessForm1PanelConfig = ({ form: formInst, formName, disabled, initialVal - } - > + - } - > + @@ -67,12 +62,7 @@ const AccessFormBaotaPanelConfig = ({ form: formInst, formName, disabled, initia - } - > + - } - > + @@ -80,6 +76,13 @@ const AccessFormCdnflyConfig = ({ form: formInst, formName, disabled, initialVal > + + + + ); }; diff --git a/ui/src/components/access/AccessFormGoEdgeConfig.tsx b/ui/src/components/access/AccessFormGoEdgeConfig.tsx index a673aa56..eb4140f4 100644 --- a/ui/src/components/access/AccessFormGoEdgeConfig.tsx +++ b/ui/src/components/access/AccessFormGoEdgeConfig.tsx @@ -1,5 +1,5 @@ import { useTranslation } from "react-i18next"; -import { Form, type FormInstance, Input } from "antd"; +import { Form, type FormInstance, Input, Switch } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; @@ -38,6 +38,7 @@ const AccessFormGoEdgeConfig = ({ form: formInst, formName, disabled, initialVal .min(1, t("access.form.goedge_access_key.placeholder")) .max(64, t("common.errmsg.string_max", { max: 64 })) .trim(), + allowInsecureConnections: z.boolean().nullish(), }); const formRule = createSchemaFieldRule(formSchema); @@ -54,12 +55,7 @@ const AccessFormGoEdgeConfig = ({ form: formInst, formName, disabled, initialVal name={formName} onValuesChange={handleFormChange} > - } - > + @@ -80,6 +76,13 @@ const AccessFormGoEdgeConfig = ({ form: formInst, formName, disabled, initialVal > + + + + ); }; diff --git a/ui/src/components/access/AccessFormPowerDNSConfig.tsx b/ui/src/components/access/AccessFormPowerDNSConfig.tsx index cada5b61..b2bfb081 100644 --- a/ui/src/components/access/AccessFormPowerDNSConfig.tsx +++ b/ui/src/components/access/AccessFormPowerDNSConfig.tsx @@ -1,5 +1,5 @@ import { useTranslation } from "react-i18next"; -import { Form, type FormInstance, Input } from "antd"; +import { Form, type FormInstance, Input, Switch } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; @@ -32,6 +32,7 @@ const AccessFormPowerDNSConfig = ({ form: formInst, formName, disabled, initialV .min(1, t("access.form.powerdns_api_key.placeholder")) .max(64, t("common.errmsg.string_max", { max: 64 })) .trim(), + allowInsecureConnections: z.boolean().nullish(), }); const formRule = createSchemaFieldRule(formSchema); @@ -48,12 +49,7 @@ const AccessFormPowerDNSConfig = ({ form: formInst, formName, disabled, initialV name={formName} onValuesChange={handleFormChange} > - } - > + @@ -65,6 +61,13 @@ const AccessFormPowerDNSConfig = ({ form: formInst, formName, disabled, initialV > + + + + ); }; diff --git a/ui/src/components/access/AccessFormProxmoxVEConfig.tsx b/ui/src/components/access/AccessFormProxmoxVEConfig.tsx new file mode 100644 index 00000000..afdc02de --- /dev/null +++ b/ui/src/components/access/AccessFormProxmoxVEConfig.tsx @@ -0,0 +1,81 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input, Switch } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForProxmoxVE } from "@/domain/access"; + +type AccessFormProxmoxVEConfigFieldValues = Nullish; + +export type AccessFormProxmoxVEConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormProxmoxVEConfigFieldValues; + onValuesChange?: (values: AccessFormProxmoxVEConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormProxmoxVEConfigFieldValues => { + return { + apiUrl: "http://:8006/", + apiToken: "", + }; +}; + +const AccessFormProxmoxVEConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormProxmoxVEConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiUrl: z.string().url(t("common.errmsg.url_invalid")), + apiToken: z.string().nonempty(t("access.form.proxmoxve_api_token.placeholder")).trim(), + apiTokenSecret: z.string().nullish(), + allowInsecureConnections: z.boolean().nullish(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + + + } + > + + + + } + > + + + + + + +
+ ); +}; + +export default AccessFormProxmoxVEConfig; diff --git a/ui/src/components/access/AccessFormSafeLineConfig.tsx b/ui/src/components/access/AccessFormSafeLineConfig.tsx index 5b16c508..2fde089d 100644 --- a/ui/src/components/access/AccessFormSafeLineConfig.tsx +++ b/ui/src/components/access/AccessFormSafeLineConfig.tsx @@ -49,12 +49,7 @@ const AccessFormSafeLineConfig = ({ form: formInst, formName, disabled, initialV name={formName} onValuesChange={handleFormChange} > - } - > + @@ -67,12 +62,7 @@ const AccessFormSafeLineConfig = ({ form: formInst, formName, disabled, initialV - } - > + - } - > + ({ key: key, diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx index e2e4f811..fc096e80 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx @@ -57,6 +57,7 @@ import DeployNodeConfigFormJDCloudLiveConfig from "./DeployNodeConfigFormJDCloud import DeployNodeConfigFormJDCloudVODConfig from "./DeployNodeConfigFormJDCloudVODConfig"; import DeployNodeConfigFormKubernetesSecretConfig from "./DeployNodeConfigFormKubernetesSecretConfig"; import DeployNodeConfigFormLocalConfig from "./DeployNodeConfigFormLocalConfig"; +import DeployNodeConfigFormProxmoxVEConfig from "./DeployNodeConfigFormProxmoxVEConfig"; import DeployNodeConfigFormQiniuCDNConfig from "./DeployNodeConfigFormQiniuCDNConfig"; import DeployNodeConfigFormQiniuKodoConfig from "./DeployNodeConfigFormQiniuKodoConfig"; import DeployNodeConfigFormQiniuPiliConfig from "./DeployNodeConfigFormQiniuPiliConfig"; @@ -259,6 +260,8 @@ const DeployNodeConfigForm = forwardRef; case DEPLOYMENT_PROVIDERS.LOCAL: return ; + case DEPLOYMENT_PROVIDERS.PROXMOXVE: + return ; case DEPLOYMENT_PROVIDERS.QINIU_CDN: return ; case DEPLOYMENT_PROVIDERS.QINIU_KODO: diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormProxmoxVEConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormProxmoxVEConfig.tsx new file mode 100644 index 00000000..444b1082 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormProxmoxVEConfig.tsx @@ -0,0 +1,66 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input, Switch } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +type DeployNodeConfigFormProxmoxVEConfigFieldValues = Nullish<{ + nodeName: string; + autoRestart?: boolean; +}>; + +export type DeployNodeConfigFormProxmoxVEConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormProxmoxVEConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormProxmoxVEConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormProxmoxVEConfigFieldValues => { + return { + autoRestart: true, + }; +}; + +const DeployNodeConfigFormProxmoxVEConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormProxmoxVEConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + nodeName: z + .string({ message: t("workflow_node.deploy.form.proxmoxve_node_name.placeholder") }) + .nonempty(t("workflow_node.deploy.form.proxmoxve_node_name.placeholder")), + autoRestart: z.boolean().nullish(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + + + + + +
+ ); +}; + +export default DeployNodeConfigFormProxmoxVEConfig; diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index f28de47b..1cac27ba 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -43,6 +43,7 @@ export interface AccessModel extends BaseModel { | AccessConfigForNameSilo | AccessConfigForPorkbun | AccessConfigForPowerDNS + | AccessConfigForProxmoxVE | AccessConfigForQiniu | AccessConfigForRainYun | AccessConfigForSafeLine @@ -126,6 +127,7 @@ export type AccessConfigForCdnfly = { apiUrl: string; apiKey: string; apiSecret: string; + allowInsecureConnections?: boolean; }; export type AccessConfigForCloudflare = { @@ -199,6 +201,7 @@ export type AccessConfigForGoEdge = { apiUrl: string; accessKeyId: string; accessKey: string; + allowInsecureConnections?: boolean; }; export type AccessConfigForGoogleTrustServices = { @@ -257,6 +260,14 @@ export type AccessConfigForPorkbun = { export type AccessConfigForPowerDNS = { apiUrl: string; apiKey: string; + allowInsecureConnections?: boolean; +}; + +export type AccessConfigForProxmoxVE = { + apiUrl: string; + apiToken: string; + apiTokenSecret?: string; + allowInsecureConnections?: boolean; }; export type AccessConfigForQiniu = { diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index ea8744f4..6fc29ad4 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -46,6 +46,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ NS1: "ns1", PORKBUN: "porkbun", POWERDNS: "powerdns", + PROXMOXVE: "proxmoxve", QINIU: "qiniu", RAINYUN: "rainyun", SAFELINE: "safeline", @@ -120,6 +121,7 @@ export const accessProvidersMap: Map [ type, { diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json index ea2fe7fc..be9a3508 100644 --- a/ui/src/i18n/locales/en/nls.access.json +++ b/ui/src/i18n/locales/en/nls.access.json @@ -35,12 +35,10 @@ "access.form.notification_channel.placeholder": "Please select a notification channel", "access.form.1panel_api_url.label": "1Panel URL", "access.form.1panel_api_url.placeholder": "Please enter 1Panel URL", - "access.form.1panel_api_url.tooltip": "For more information, see https://docs.1panel.pro/dev_manual/api_manual/", "access.form.1panel_api_key.label": "1Panel API key", "access.form.1panel_api_key.placeholder": "Please enter 1Panel API key", "access.form.1panel_api_key.tooltip": "For more information, see https://docs.1panel.pro/dev_manual/api_manual/", "access.form.1panel_allow_insecure_conns.label": "Insecure SSL/TLS connections", - "access.form.1panel_allow_insecure_conns.tooltip": "Allowing insecure connections may lead to data leak or tampering. Use this option only when under trusted networks.", "access.form.1panel_allow_insecure_conns.switch.on": "Allow", "access.form.1panel_allow_insecure_conns.switch.off": "Disallow", "access.form.acmehttpreq_endpoint.label": "Endpoint", @@ -98,12 +96,10 @@ "access.form.baishan_api_token.placeholder": "Please enter Baishan Cloud API token", "access.form.baotapanel_api_url.label": "aaPanel URL", "access.form.baotapanel_api_url.placeholder": "Please enter aaPanel URL", - "access.form.baotapanel_api_url.tooltip": "For more information, see https://www.bt.cn/bbs/thread-20376-1-1.html", "access.form.baotapanel_api_key.label": "aaPanel API key", "access.form.baotapanel_api_key.placeholder": "Please enter aaPanel API key", "access.form.baotapanel_api_key.tooltip": "For more information, see https://www.bt.cn/bbs/thread-20376-1-1.html", "access.form.baotapanel_allow_insecure_conns.label": "Insecure SSL/TLS connections", - "access.form.baotapanel_allow_insecure_conns.tooltip": "Allowing insecure connections may lead to data leak or tampering. Use this option only when under trusted networks.", "access.form.baotapanel_allow_insecure_conns.switch.on": "Allow", "access.form.baotapanel_allow_insecure_conns.switch.off": "Disallow", "access.form.byteplus_access_key.label": "BytePlus AccessKey", @@ -117,13 +113,15 @@ "access.form.cachefly_api_token.tooltip": "For more information, see https://kb.cachefly.com/kb/guide/en/generating-tokens-and-keys-Oll9Irt5TI/Steps/2460228", "access.form.cdnfly_api_url.label": "Cdnfly API URL", "access.form.cdnfly_api_url.placeholder": "Please enter Cdnfly API URL", - "access.form.cdnfly_api_url.tooltip": "For more information, see https://doc.cdnfly.cn/anzhuangshuoming.html", "access.form.cdnfly_api_key.label": "Cdnfly user API key", "access.form.cdnfly_api_key.placeholder": "Please enter Cdnfly user API key", "access.form.cdnfly_api_key.tooltip": "For more information, see https://doc.cdnfly.cn/shiyongjieshao.html", "access.form.cdnfly_api_secret.label": "Cdnfly user API secret", "access.form.cdnfly_api_secret.placeholder": "Please enter Cdnfly user API secret", "access.form.cdnfly_api_secret.tooltip": "For more information, see https://doc.cdnfly.cn/shiyongjieshao.html", + "access.form.cdnfly_allow_insecure_conns.label": "Insecure SSL/TLS connections", + "access.form.cdnfly_allow_insecure_conns.switch.on": "Allow", + "access.form.cdnfly_allow_insecure_conns.switch.off": "Disallow", "access.form.cloudflare_dns_api_token.label": "Cloudflare DNS API token", "access.form.cloudflare_dns_api_token.placeholder": "Please enter Cloudflare DNS API token", "access.form.cloudflare_dns_api_token.tooltip": "For more information, see https://developers.cloudflare.com/fundamentals/api/get-started/create-token/", @@ -202,13 +200,15 @@ "access.form.godaddy_api_secret.tooltip": "For more information, see https://developer.godaddy.com/", "access.form.goedge_api_url.label": "GoEdge API URL", "access.form.goedge_api_url.placeholder": "Please enter GoEdge API URL", - "access.form.goedge_api_url.tooltip": "For more information, see https://goedge.cloud/docs/API/Summary.md", "access.form.goedge_access_key_id.label": "GoEdge user AccessKeyId", "access.form.goedge_access_key_id.placeholder": "Please enter GoEdge user AccessKeyId", "access.form.goedge_access_key_id.tooltip": "For more information, see https://goedge.cloud/docs/API/Auth.md", "access.form.goedge_access_key.label": "GoEdge user AccessKey", "access.form.goedge_access_key.placeholder": "Please enter GoEdge user AccessKey", "access.form.goedge_access_key.tooltip": "For more information, see https://goedge.cloud/docs/API/Auth.md", + "access.form.goedge_allow_insecure_conns.label": "Insecure SSL/TLS connections", + "access.form.goedge_allow_insecure_conns.switch.on": "Allow", + "access.form.goedge_allow_insecure_conns.switch.off": "Disallow", "access.form.googletrustservices_eab_kid.label": "ACME EAB KID", "access.form.googletrustservices_eab_kid.placeholder": "Please enter ACME EAB KID", "access.form.googletrustservices_eab_kid.tooltip": "For more information, see https://cloud.google.com/certificate-manager/docs/public-ca-tutorial", @@ -269,10 +269,23 @@ "access.form.porkbun_secret_api_key.tooltip": "For more information, see https://porkbun.com/api/json/v3/documentation", "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 https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api", "access.form.powerdns_api_key.label": "PowerDNS API key", "access.form.powerdns_api_key.placeholder": "Please enter PowerDNS API key", "access.form.powerdns_api_key.tooltip": "For more information, see https://doc.powerdns.com/authoritative/http-api/index.html#enabling-the-api", + "access.form.powerdns_allow_insecure_conns.label": "Insecure SSL/TLS connections", + "access.form.powerdns_allow_insecure_conns.switch.on": "Allow", + "access.form.powerdns_allow_insecure_conns.switch.off": "Disallow", + "access.form.proxmoxve_api_url.label": "Proxmox VE URL", + "access.form.proxmoxve_api_url.placeholder": "Please enter Proxmox VE URL", + "access.form.proxmoxve_api_token.label": "Proxmox VE API token", + "access.form.proxmoxve_api_token.placeholder": "Please enter Proxmox VE API token", + "access.form.proxmoxve_api_token.tooltip": "For more information, see https://pve.proxmox.com/pve-docs/pve-admin-guide.html#pveum_tokens", + "access.form.proxmoxve_api_token_secret.label": "Proxmox VE API token secret (Optional)", + "access.form.proxmoxve_api_token_secret.placeholder": "Please enter Proxmox VE API token secret", + "access.form.proxmoxve_api_token_secret.tooltip": "For more information, see https://pve.proxmox.com/pve-docs/pve-admin-guide.html#pveum_tokens", + "access.form.proxmoxve_allow_insecure_conns.label": "Insecure SSL/TLS connections", + "access.form.proxmoxve_allow_insecure_conns.switch.on": "Allow", + "access.form.proxmoxve_allow_insecure_conns.switch.off": "Disallow", "access.form.qiniu_access_key.label": "Qiniu AccessKey", "access.form.qiniu_access_key.placeholder": "Please enter Qiniu AccessKey", "access.form.qiniu_access_key.tooltip": "For more information, see https://portal.qiniu.com/", @@ -284,12 +297,10 @@ "access.form.rainyun_api_key.tooltip": "For more information, see https://app.rainyun.com/account/settings/api-key", "access.form.safeline_api_url.label": "SafeLine URL", "access.form.safeline_api_url.placeholder": "Please enter SafeLine URL", - "access.form.safeline_api_url.tooltip": "For more information, see https://docs.waf.chaitin.com/en/tutorials/install", "access.form.safeline_api_token.label": "SafeLine API token", "access.form.safeline_api_token.placeholder": "Please enter SafeLine API token", "access.form.safeline_api_token.tooltip": "For more information, see https://docs.waf.chaitin.com/en/reference/articles/openapi", "access.form.safeline_allow_insecure_conns.label": "Insecure SSL/TLS connections", - "access.form.safeline_allow_insecure_conns.tooltip": "Allowing insecure connections may lead to data leak or tampering. Use this option only when under trusted networks.", "access.form.safeline_allow_insecure_conns.switch.on": "Allow", "access.form.safeline_allow_insecure_conns.switch.off": "Disallow", "access.form.ssh_host.label": "Server host", @@ -380,7 +391,6 @@ "access.form.webhook_preset_data.option.serverchan.label": "ServerChan", "access.form.webhook_preset_data.option.common.label": "General template", "access.form.webhook_allow_insecure_conns.label": "Insecure SSL/TLS connections", - "access.form.webhook_allow_insecure_conns.tooltip": "Allowing insecure connections may lead to data leak or tampering. Use this option only when under trusted networks.", "access.form.webhook_allow_insecure_conns.switch.on": "Allow", "access.form.webhook_allow_insecure_conns.switch.off": "Disallow", "access.form.wecombot_webhook_url.label": "WeCom bot Webhook URL", diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index 8a191665..0c140684 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -93,6 +93,7 @@ "provider.ns1": "NS1 (IBM NS1 Connect)", "provider.porkbun": "Porkbun", "provider.powerdns": "PowerDNS", + "provider.proxmoxve": "Proxmox VE", "provider.qiniu": "Qiniu", "provider.qiniu.cdn": "Qiniu - CDN (Content Delivery Network)", "provider.qiniu.kodo": "Qiniu - Kodo", @@ -148,6 +149,7 @@ "provider.category.av": "Audio/Video", "provider.category.serverless": "Serverless", "provider.category.website": "Website", + "provider.category.nas": "NAS", "provider.category.other": "Other", "provider.default_ca_provider.label": "(Default) Follow global settings" diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json index 5f792a7c..da776fc9 100644 --- a/ui/src/i18n/locales/en/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json @@ -477,6 +477,9 @@ "workflow_node.deploy.form.local_preset_scripts.option.ps_binding_iis.label": "PowerShell - Binding IIS", "workflow_node.deploy.form.local_preset_scripts.option.ps_binding_netsh.label": "PowerShell - Binding netsh", "workflow_node.deploy.form.local_preset_scripts.option.ps_.label": "PowerShell - Binding RDP", + "workflow_node.deploy.form.proxmoxve_node_name.label": "Proxmox VE cluster node name", + "workflow_node.deploy.form.proxmoxve_node_name.placeholder": "Please enter Proxmox VE cluster node name", + "workflow_node.deploy.form.proxmoxve_auto_restart.label": "Auto restart after deployment", "workflow_node.deploy.form.qiniu_cdn_domain.label": "Qiniu CDN domain", "workflow_node.deploy.form.qiniu_cdn_domain.placeholder": "Please enter Qiniu CDN domain name", "workflow_node.deploy.form.qiniu_cdn_domain.tooltip": "For more information, see https://portal.qiniu.com/cdn", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index 5cb1a038..bae29d27 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -35,12 +35,10 @@ "access.form.notification_channel.placeholder": "请选择通知渠道", "access.form.1panel_api_url.label": "1Panel URL", "access.form.1panel_api_url.placeholder": "请输入 1Panel URL", - "access.form.1panel_api_url.tooltip": "这是什么?请参阅 https://1panel.cn/docs/dev_manual/api_manual/", "access.form.1panel_api_key.label": "1Panel 接口密钥", "access.form.1panel_api_key.placeholder": "请输入 1Panel 接口密钥", "access.form.1panel_api_key.tooltip": "这是什么?请参阅 https://1panel.cn/docs/dev_manual/api_manual/", "access.form.1panel_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", - "access.form.1panel_allow_insecure_conns.tooltip": "忽略 SSL/TLS 证书错误可能导致数据泄露或被篡改。建议仅在可信网络下启用。", "access.form.1panel_allow_insecure_conns.switch.on": "允许", "access.form.1panel_allow_insecure_conns.switch.off": "不允许", "access.form.acmehttpreq_endpoint.label": "服务端点", @@ -89,12 +87,10 @@ "access.form.baishan_api_token.placeholder": "请输入白山云 API Token", "access.form.baotapanel_api_url.label": "宝塔面板 URL", "access.form.baotapanel_api_url.placeholder": "请输入宝塔面板 URL", - "access.form.baotapanel_api_url.tooltip": "这是什么?请参阅 https://www.bt.cn/bbs/thread-20376-1-1.html", "access.form.baotapanel_api_key.label": "宝塔面板接口密钥", "access.form.baotapanel_api_key.placeholder": "请输入宝塔面板接口密钥", "access.form.baotapanel_api_key.tooltip": "这是什么?请参阅 https://www.bt.cn/bbs/thread-113890-1-1.html", "access.form.baotapanel_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", - "access.form.baotapanel_allow_insecure_conns.tooltip": "忽略 SSL/TLS 证书错误可能导致数据泄露或被篡改。建议仅在可信网络下启用。", "access.form.baotapanel_allow_insecure_conns.switch.on": "允许", "access.form.baotapanel_allow_insecure_conns.switch.off": "不允许", "access.form.bunny_api_key.label": "Bunny API Key", @@ -111,13 +107,15 @@ "access.form.cachefly_api_token.tooltip": "这是什么?请参阅 https://kb.cachefly.com/kb/guide/en/generating-tokens-and-keys-Oll9Irt5TI/Steps/2460228", "access.form.cdnfly_api_url.label": "Cdnfly API URL", "access.form.cdnfly_api_url.placeholder": "请输入 Cdnfly API URL", - "access.form.cdnfly_api_url.tooltip": "这是什么?请参阅 https://doc.cdnfly.cn/anzhuangshuoming.html", "access.form.cdnfly_api_key.label": "Cdnfly 用户端 API Key", "access.form.cdnfly_api_key.placeholder": "请输入 Cdnfly 用户端 API Key", "access.form.cdnfly_api_key.tooltip": "这是什么?请参阅 https://doc.cdnfly.cn/shiyongjieshao.html", "access.form.cdnfly_api_secret.label": "Cdnfly 用户端 API Secret", "access.form.cdnfly_api_secret.placeholder": "请输入 Cdnfly 用户端 API Secret", "access.form.cdnfly_api_secret.tooltip": "这是什么?请参阅 https://doc.cdnfly.cn/shiyongjieshao.html", + "access.form.cdnfly_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", + "access.form.cdnfly_allow_insecure_conns.switch.on": "允许", + "access.form.cdnfly_allow_insecure_conns.switch.off": "不允许", "access.form.cloudflare_dns_api_token.label": "Cloudflare DNS API 令牌", "access.form.cloudflare_dns_api_token.placeholder": "请输入 Cloudflare DNS API 令牌", "access.form.cloudflare_dns_api_token.tooltip": "这是什么?请参阅 https://developers.cloudflare.com/fundamentals/api/get-started/create-token/", @@ -196,13 +194,15 @@ "access.form.godaddy_api_secret.tooltip": "这是什么?请参阅 https://developer.godaddy.com/", "access.form.goedge_api_url.label": "GoEdge API URL", "access.form.goedge_api_url.placeholder": "请输入 GoEdge API URL", - "access.form.goedge_api_url.tooltip": "这是什么?请参阅 https://goedge.cloud/docs/API/Summary.md", "access.form.goedge_access_key_id.label": "GoEdge 用户 AccessKeyId", "access.form.goedge_access_key_id.placeholder": "请输入 GoEdge 用户 AccessKeyId", "access.form.goedge_access_key_id.tooltip": "这是什么?请参阅 https://goedge.cloud/docs/API/Auth.md", "access.form.goedge_access_key.label": "GoEdge 用户 AccessKey", "access.form.goedge_access_key.placeholder": "请输入 GoEdge 用户 AccessKey", "access.form.goedge_access_key.tooltip": "这是什么?请参阅 https://goedge.cloud/docs/API/Auth.md", + "access.form.goedge_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", + "access.form.goedge_allow_insecure_conns.switch.on": "允许", + "access.form.goedge_allow_insecure_conns.switch.off": "不允许", "access.form.googletrustservices_eab_kid.label": "ACME EAB KID", "access.form.googletrustservices_eab_kid.placeholder": "请输入 ACME EAB KID", "access.form.googletrustservices_eab_kid.tooltip": "这是什么?请参阅 https://cloud.google.com/certificate-manager/docs/public-ca-tutorial", @@ -263,10 +263,23 @@ "access.form.porkbun_secret_api_key.tooltip": "这是什么?请参阅 https://porkbun.com/api/json/v3/documentation", "access.form.powerdns_api_url.label": "PowerDNS API URL", "access.form.powerdns_api_url.placeholder": "请输入 PowerDNS API URL", - "access.form.powerdns_api_url.tooltip": "这是什么?请参阅 https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api", "access.form.powerdns_api_key.label": "PowerDNS API Key", "access.form.powerdns_api_key.placeholder": "请输入 PowerDNS API Key", "access.form.powerdns_api_key.tooltip": "这是什么?请参阅 https://doc.powerdns.com/authoritative/http-api/index.html#enabling-the-api", + "access.form.powerdns_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", + "access.form.powerdns_allow_insecure_conns.switch.on": "允许", + "access.form.powerdns_allow_insecure_conns.switch.off": "不允许", + "access.form.proxmoxve_api_url.label": "Proxmox VE URL", + "access.form.proxmoxve_api_url.placeholder": "请输入 Proxmox VE URL", + "access.form.proxmoxve_api_token.label": "Proxmox VE API Token", + "access.form.proxmoxve_api_token.placeholder": "请输入 Proxmox VE API Token", + "access.form.proxmoxve_api_token.tooltip": "这是什么?请参阅 https://pve.proxmox.com/pve-docs/pve-admin-guide.html#pveum_tokens", + "access.form.proxmoxve_api_token_secret.label": "Proxmox VE API Token Secret(可选)", + "access.form.proxmoxve_api_token_secret.placeholder": "请输入 Proxmox VE API Token Secret", + "access.form.proxmoxve_api_token_secret.tooltip": "这是什么?请参阅 https://pve.proxmox.com/pve-docs/pve-admin-guide.html#pveum_tokens", + "access.form.proxmoxve_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", + "access.form.proxmoxve_allow_insecure_conns.switch.on": "允许", + "access.form.proxmoxve_allow_insecure_conns.switch.off": "不允许", "access.form.qiniu_access_key.label": "七牛云 AccessKey", "access.form.qiniu_access_key.placeholder": "请输入七牛云 AccessKey", "access.form.qiniu_access_key.tooltip": "这是什么?请参阅 https://portal.qiniu.com/", @@ -278,12 +291,10 @@ "access.form.rainyun_api_key.tooltip": "这是什么?请参阅 https://app.rainyun.com/account/settings/api-key", "access.form.safeline_api_url.label": "雷池 URL", "access.form.safeline_api_url.placeholder": "请输入雷池 URL", - "access.form.safeline_api_url.tooltip": "这是什么?请参阅 https://docs.waf-ce.chaitin.cn/zh/上手指南/安装雷池", "access.form.safeline_api_token.label": "雷池 API Token", "access.form.safeline_api_token.placeholder": "请输入雷池 API Token", "access.form.safeline_api_token.tooltip": "这是什么?请参阅 https://docs.waf-ce.chaitin.cn/zh/更多技术文档/OPENAPI", "access.form.safeline_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", - "access.form.safeline_allow_insecure_conns.tooltip": "忽略 SSL/TLS 证书错误可能导致数据泄露或被篡改。建议仅在可信网络下启用。", "access.form.safeline_allow_insecure_conns.switch.on": "允许", "access.form.safeline_allow_insecure_conns.switch.off": "不允许", "access.form.ssh_host.label": "服务器地址", @@ -380,7 +391,6 @@ "access.form.webhook_preset_data.option.serverchan.label": "Server 酱", "access.form.webhook_preset_data.option.common.label": "通用模板", "access.form.webhook_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", - "access.form.webhook_allow_insecure_conns.tooltip": "忽略 SSL/TLS 证书错误可能导致数据泄露或被篡改。建议仅在可信网络下启用。", "access.form.webhook_allow_insecure_conns.switch.on": "允许", "access.form.webhook_allow_insecure_conns.switch.off": "不允许", "access.form.wecombot_webhook_url.label": "企业微信群机器人 Webhook 地址", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index 207dfc37..5626426e 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -93,6 +93,7 @@ "provider.ns1": "NS1 (IBM NS1 Connect)", "provider.porkbun": "Porkbun", "provider.powerdns": "PowerDNS", + "provider.proxmoxve": "Proxmox VE", "provider.qiniu": "七牛云", "provider.qiniu.cdn": "七牛云 - 内容分发网络 CDN", "provider.qiniu.kodo": "七牛云 - 对象存储 Kodo", @@ -148,6 +149,7 @@ "provider.category.av": "音视频", "provider.category.serverless": "Serverless", "provider.category.website": "网站托管", + "provider.category.nas": "NAS", "provider.category.other": "其他", "provider.default_ca_provider.label": "(默认)不指定,跟随全局设置" diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index 4b7b3349..3f38a490 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -109,7 +109,7 @@ "workflow_node.deploy.form.certificate.placeholder": "请选择待部署证书", "workflow_node.deploy.form.certificate.tooltip": "待部署证书来自之前的申请或上传节点。如果选项为空请先确保前序节点配置正确。", "workflow_node.deploy.form.params_config.label": "参数设置", - "workflow_node.deploy.form.1panel_console_auto_restart.label": "部署后自动重启面板服务", + "workflow_node.deploy.form.1panel_console_auto_restart.label": "部署后自动重启宝塔面板服务", "workflow_node.deploy.form.1panel_site_resource_type.label": "证书替换方式", "workflow_node.deploy.form.1panel_site_resource_type.placeholder": "请选择证书替换方式", "workflow_node.deploy.form.1panel_site_resource_type.option.website.label": "替换指定网站的证书", @@ -315,7 +315,7 @@ "workflow_node.deploy.form.baishan_cdn_certificate_id.label": "白山云 CDN 原证书 ID(可选)", "workflow_node.deploy.form.baishan_cdn_certificate_id.placeholder": "请输入白山云 CDN 原证书 ID", "workflow_node.deploy.form.baishan_cdn_certificate_id.tooltip": "这是什么?请参阅 https://cdnx.console.baishan.com/#/cdn/cert

不填写时,将上传新证书;否则,将替换原证书。", - "workflow_node.deploy.form.baotapanel_console_auto_restart.label": "部署后自动重启面板服务", + "workflow_node.deploy.form.baotapanel_console_auto_restart.label": "部署后自动重启 1Panel 服务", "workflow_node.deploy.form.baotapanel_site_type.label": "宝塔面板网站类型", "workflow_node.deploy.form.baotapanel_site_type.placeholder": "请选择宝塔面板网站类型", "workflow_node.deploy.form.baotapanel_site_type.option.php.label": "PHP", @@ -476,6 +476,9 @@ "workflow_node.deploy.form.local_preset_scripts.option.ps_binding_iis.label": "PowerShell - 导入并绑定到 IIS", "workflow_node.deploy.form.local_preset_scripts.option.ps_binding_netsh.label": "PowerShell - 导入并绑定到 netsh", "workflow_node.deploy.form.local_preset_scripts.option.ps_binding_rdp.label": "PowerShell - 导入并绑定到 RDP", + "workflow_node.deploy.form.proxmoxve_node_name.label": "Proxmox VE 集群节点名称", + "workflow_node.deploy.form.proxmoxve_node_name.placeholder": "请输入 Proxmox VE 集群节点名称", + "workflow_node.deploy.form.proxmoxve_auto_restart.label": "部署后自动重启 Proxmox VE 服务", "workflow_node.deploy.form.qiniu_cdn_domain.label": "七牛云 CDN 加速域名", "workflow_node.deploy.form.qiniu_cdn_domain.placeholder": "请输入七牛云 CDN 加速域名(支持泛域名)", "workflow_node.deploy.form.qiniu_cdn_domain.tooltip": "这是什么?请参阅 https://portal.qiniu.com/cdn",