diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index 0cf989a9..15a8f370 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -35,6 +35,7 @@ import ( pBaishanCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baishan-cdn" pBaotaPanelConsole "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-console" pBaotaPanelSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-site" + pBaotaWAFConsole "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-console" pBaotaWAFSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-site" pBunnyCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/bunny-cdn" pBytePlusCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/byteplus-cdn" @@ -476,7 +477,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer } } - case domain.DeploymentProviderTypeBaotaWAFSite: + case domain.DeploymentProviderTypeBaotaWAFConsole, domain.DeploymentProviderTypeBaotaWAFSite: { access := domain.AccessConfigForBaotaWAF{} if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { @@ -484,6 +485,14 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer } switch options.Provider { + case domain.DeploymentProviderTypeBaotaWAFConsole: + deployer, err := pBaotaWAFConsole.NewDeployer(&pBaotaWAFConsole.DeployerConfig{ + ApiUrl: access.ApiUrl, + ApiKey: access.ApiKey, + AllowInsecureConnections: access.AllowInsecureConnections, + }) + return deployer, err + case domain.DeploymentProviderTypeBaotaWAFSite: deployer, err := pBaotaWAFSite.NewDeployer(&pBaotaWAFSite.DeployerConfig{ ApiUrl: access.ApiUrl, diff --git a/internal/domain/provider.go b/internal/domain/provider.go index b825b823..db0de59d 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -191,6 +191,7 @@ const ( DeploymentProviderTypeBaishanCDN = DeploymentProviderType(AccessProviderTypeBaishan + "-cdn") DeploymentProviderTypeBaotaPanelConsole = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-console") DeploymentProviderTypeBaotaPanelSite = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-site") + DeploymentProviderTypeBaotaWAFConsole = DeploymentProviderType(AccessProviderTypeBaotaWAF + "-console") DeploymentProviderTypeBaotaWAFSite = DeploymentProviderType(AccessProviderTypeBaotaWAF + "-site") DeploymentProviderTypeBunnyCDN = DeploymentProviderType(AccessProviderTypeBunny + "-cdn") DeploymentProviderTypeBytePlusCDN = DeploymentProviderType(AccessProviderTypeBytePlus + "-cdn") diff --git a/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console.go b/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console.go new file mode 100644 index 00000000..811b350b --- /dev/null +++ b/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console.go @@ -0,0 +1,88 @@ +package baotapanelconsole + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "log/slog" + "net/url" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + btsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/btwaf" +) + +type DeployerConfig struct { + // 堡塔云 WAF 地址。 + ApiUrl string `json:"apiUrl"` + // 堡塔云 WAF 接口密钥。 + ApiKey string `json:"apiKey"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sdkClient *btsdk.Client +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections) + if err != nil { + return nil, fmt.Errorf("failed to create sdk client: %w", err) + } + + return &DeployerProvider{ + config: config, + logger: slog.Default(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) { + // 设置面板 SSL + configSetSSLReq := &btsdk.ConfigSetSSLRequest{ + CertContent: certPEM, + KeyContent: privkeyPEM, + } + configSetSSLResp, err := d.sdkClient.ConfigSetSSL(configSetSSLReq) + d.logger.Debug("sdk request 'bt.ConfigSetSSL'", slog.Any("request", configSetSSLReq), slog.Any("response", configSetSSLResp)) + if err != nil { + return nil, fmt.Errorf("failed to execute sdk request 'bt.ConfigSetSSL': %w", err) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid baota api url") + } + + if apiKey == "" { + return nil, errors.New("invalid baota api key") + } + + client := btsdk.NewClient(apiUrl, apiKey) + if skipTlsVerify { + client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) + } + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console_test.go b/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console_test.go new file mode 100644 index 00000000..ba6ddd26 --- /dev/null +++ b/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console_test.go @@ -0,0 +1,73 @@ +package baotapanelconsole_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-console" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiUrl string + fApiKey string + fSiteName string + fSitePort int64 +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") + flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "") +} + +/* +Shell command to run this test: + + go test -v ./baotawaf_console_test.go -args \ + --CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_APIURL="http://127.0.0.1:8888" \ + --CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_APIKEY="your-api-key" +*/ +func TestDeploy(t *testing.T) { + flag.Parse() + + t.Run("Deploy", func(t *testing.T) { + t.Log(strings.Join([]string{ + "args:", + fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath), + fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), + fmt.Sprintf("APIURL: %v", fApiUrl), + fmt.Sprintf("APIKEY: %v", fApiKey), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiUrl: fApiUrl, + ApiKey: fApiKey, + AllowInsecureConnections: true, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + t.Logf("ok: %v", res) + }) +} diff --git a/ui/src/components/access/AccessFormACMECAConfig.tsx b/ui/src/components/access/AccessFormACMECAConfig.tsx index ac4a32c2..d3075f22 100644 --- a/ui/src/components/access/AccessFormACMECAConfig.tsx +++ b/ui/src/components/access/AccessFormACMECAConfig.tsx @@ -1,5 +1,5 @@ import { useTranslation } from "react-i18next"; -import { Form, type FormInstance, Input, Select } from "antd"; +import { Form, type FormInstance, Input } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 3cb52e9f..15542455 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -373,6 +373,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({ BAISHAN_CDN: `${ACCESS_PROVIDERS.BAISHAN}-cdn`, BAOTAPANEL_CONSOLE: `${ACCESS_PROVIDERS.BAOTAPANEL}-console`, BAOTAPANEL_SITE: `${ACCESS_PROVIDERS.BAOTAPANEL}-site`, + BAOTAWAF_CONSOLE: `${ACCESS_PROVIDERS.BAOTAWAF}-console`, BAOTAWAF_SITE: `${ACCESS_PROVIDERS.BAOTAWAF}-site`, BUNNY_CDN: `${ACCESS_PROVIDERS.BUNNY}-cdn`, BYTEPLUS_CDN: `${ACCESS_PROVIDERS.BYTEPLUS}-cdn`, @@ -551,6 +552,7 @@ export const deploymentProvidersMap: Map [ diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index 2493af42..a3bbfecc 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -43,6 +43,7 @@ "provider.baotapanel.console": "aaPanel (aka BaoTaPanel) - Console", "provider.baotapanel.site": "aaPanel (aka BaoTaPanel) - Website", "provider.baotawaf": "aaWAF (aka BaotaWAF)", + "provider.baotawaf.console": "aaWAF (aka BaotaWAF) - Console", "provider.baotawaf.site": "aaWAF (aka BaotaWAF) - Website", "provider.bunny": "Bunny", "provider.bunny.cdn": "Bunny - CDN (Content Delivery Network)", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index 7f57b7e1..b9fb8777 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -1,6 +1,6 @@ { "provider.1panel": "1Panel", - "provider.1panel.console": "1Panel - 面板", + "provider.1panel.console": "1Panel - 控制台", "provider.1panel.site": "1Panel - 网站", "provider.acmeca": "ACME 自定义 CA 端点", "provider.acmehttpreq": "ACME 自定义 HTTP 端点", @@ -40,9 +40,10 @@ "provider.baishan": "白山云", "provider.baishan.cdn": "白山云 - 内容分发网络 CDN", "provider.baotapanel": "宝塔面板", - "provider.baotapanel.console": "宝塔面板 - 面板", + "provider.baotapanel.console": "宝塔面板 - 控制台", "provider.baotapanel.site": "宝塔面板 - 网站", "provider.baotawaf": "堡塔云 WAF", + "provider.baotawaf.console": "堡塔云 WAF - 控制台", "provider.baotawaf.site": "堡塔云 WAF - 网站", "provider.bunny": "Bunny", "provider.bunny.cdn": "Bunny - 内容分发网络 CDN", @@ -110,7 +111,7 @@ "provider.rainyun": "雨云", "provider.rainyun.rcdn": "雨云 - 雨盾 CDN", "provider.ratpanel": "耗子面板", - "provider.ratpanel.console": "耗子面板 - 面板", + "provider.ratpanel.console": "耗子面板 - 控制台", "provider.ratpanel.site": "耗子面板 - 网站", "provider.safeline": "雷池", "provider.ssh": "SSH 部署",