From bd4aa4806f3ddbbadf79fd1249ac368620ac9fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Fri, 16 May 2025 02:33:46 +0800 Subject: [PATCH 1/3] feat: backend support for ratpanel --- internal/deployer/providers.go | 34 ++++ internal/domain/access.go | 7 + internal/domain/provider.go | 3 + .../ratpanel-console/ratpanel_console.go | 93 +++++++++++ .../ratpanel-console/ratpanel_console_test.go | 72 +++++++++ .../providers/ratpanel-site/ratpanel_site.go | 100 ++++++++++++ .../ratpanel-site/ratpanel_site_test.go | 82 ++++++++++ internal/pkg/sdk3rd/ratpanel/api.go | 15 ++ internal/pkg/sdk3rd/ratpanel/client.go | 145 ++++++++++++++++++ internal/pkg/sdk3rd/ratpanel/models.go | 35 +++++ 10 files changed, 586 insertions(+) create mode 100644 internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go create mode 100644 internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go create mode 100644 internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go create mode 100644 internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go create mode 100644 internal/pkg/sdk3rd/ratpanel/api.go create mode 100644 internal/pkg/sdk3rd/ratpanel/client.go create mode 100644 internal/pkg/sdk3rd/ratpanel/models.go diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index d69b05b7..d4c61a31 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -57,6 +57,8 @@ import ( 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" + pRatPanelConsole "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ratpanel-console" + pRatPanelSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ratpanel-site" pSafeLine "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/safeline" pSSH "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ssh" pTencentCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-cdn" @@ -813,6 +815,38 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer } } + case domain.DeploymentProviderTypeRatPanelConsole, domain.DeploymentProviderTypeRatPanelSite: + { + access := domain.AccessConfigForRatPanel{} + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + switch options.Provider { + case domain.DeploymentProviderTypeRatPanelConsole: + deployer, err := pRatPanelConsole.NewDeployer(&pRatPanelConsole.DeployerConfig{ + ApiUrl: access.ApiUrl, + AccessTokenId: access.AccessTokenId, + AccessToken: access.AccessToken, + AllowInsecureConnections: access.AllowInsecureConnections, + }) + return deployer, err + + case domain.DeploymentProviderTypeRatPanelSite: + deployer, err := pRatPanelSite.NewDeployer(&pRatPanelSite.DeployerConfig{ + ApiUrl: access.ApiUrl, + AccessTokenId: access.AccessTokenId, + AccessToken: access.AccessToken, + AllowInsecureConnections: access.AllowInsecureConnections, + SiteName: maputil.GetString(options.ProviderExtendedConfig, "siteName"), + }) + return deployer, err + + default: + break + } + } + case domain.DeploymentProviderTypeSafeLine: { access := domain.AccessConfigForSafeLine{} diff --git a/internal/domain/access.go b/internal/domain/access.go index 35dd9b0a..f69dd75e 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -240,6 +240,13 @@ type AccessConfigForRainYun struct { ApiKey string `json:"apiKey"` } +type AccessConfigForRatPanel struct { + ApiUrl string `json:"apiUrl"` + AccessTokenId uint `json:"accessTokenId"` + AccessToken string `json:"accessToken"` + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` +} + type AccessConfigForSafeLine struct { ApiUrl string `json:"apiUrl"` ApiToken string `json:"apiToken"` diff --git a/internal/domain/provider.go b/internal/domain/provider.go index dd6d8ec6..7dc725b0 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -61,6 +61,7 @@ const ( AccessProviderTypeQiniu = AccessProviderType("qiniu") AccessProviderTypeQingCloud = AccessProviderType("qingcloud") // 青云(预留) AccessProviderTypeRainYun = AccessProviderType("rainyun") + AccessProviderTypeRatPanel = AccessProviderType("ratpanel") AccessProviderTypeSafeLine = AccessProviderType("safeline") AccessProviderTypeSSH = AccessProviderType("ssh") AccessProviderTypeSSLCOM = AccessProviderType("sslcom") @@ -208,6 +209,8 @@ const ( DeploymentProviderTypeQiniuKodo = DeploymentProviderType(AccessProviderTypeQiniu + "-kodo") DeploymentProviderTypeQiniuPili = DeploymentProviderType(AccessProviderTypeQiniu + "-pili") DeploymentProviderTypeRainYunRCDN = DeploymentProviderType(AccessProviderTypeRainYun + "-rcdn") + DeploymentProviderTypeRatPanelConsole = DeploymentProviderType(AccessProviderTypeRatPanel + "-console") + DeploymentProviderTypeRatPanelSite = DeploymentProviderType(AccessProviderTypeRatPanel + "-site") DeploymentProviderTypeSafeLine = DeploymentProviderType(AccessProviderTypeSafeLine) DeploymentProviderTypeSSH = DeploymentProviderType(AccessProviderTypeSSH) DeploymentProviderTypeTencentCloudCDN = DeploymentProviderType(AccessProviderTypeTencentCloud + "-cdn") diff --git a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go new file mode 100644 index 00000000..ba9f5949 --- /dev/null +++ b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go @@ -0,0 +1,93 @@ +package baotapanelconsole + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "log/slog" + "net/url" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + rpsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/ratpanel" +) + +type DeployerConfig struct { + // 耗子面板地址。 + ApiUrl string `json:"apiUrl"` + // 耗子面板访问令牌ID。 + AccessTokenId uint `json:"accessTokenId"` + // 耗子面板访问令牌。 + AccessToken string `json:"accessToken"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sdkClient *rpsdk.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.AccessTokenId, config.AccessToken, 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 证书 + settingCertReq := &rpsdk.SettingCertRequest{ + Certificate: certPEM, + PrivateKey: privkeyPEM, + } + settingCertResp, err := d.sdkClient.SettingCert(settingCertReq) + d.logger.Debug("sdk request 'ratpanel.SettingCertRequest'", slog.Any("request", settingCertReq), slog.Any("response", settingCertResp)) + if err != nil { + return nil, fmt.Errorf("failed to execute sdk request 'ratpanel.SettingCertRequest': %w", err) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiUrl string, accessTokenId uint, accessToken string, skipTlsVerify bool) (*rpsdk.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid ratpanel api url") + } + + if accessTokenId == 0 { + return nil, errors.New("invalid ratpanel access token id") + } + if accessToken == "" { + return nil, errors.New("invalid ratpanel access token") + } + + client := rpsdk.NewClient(apiUrl, accessTokenId, accessToken) + if skipTlsVerify { + client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) + } + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go new file mode 100644 index 00000000..5f3845e4 --- /dev/null +++ b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go @@ -0,0 +1,72 @@ +package baotapanelconsole_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-console" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiUrl string + fApiKey string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_" + + 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 ./baotapanel_console_test.go -args \ + --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_APIURL="http://127.0.0.1:8888" \ + --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_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, + 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/ratpanel-site/ratpanel_site.go b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go new file mode 100644 index 00000000..639470e1 --- /dev/null +++ b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go @@ -0,0 +1,100 @@ +package baotapanelsite + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "log/slog" + "net/url" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + rpsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/ratpanel" +) + +type DeployerConfig struct { + // 耗子面板地址。 + ApiUrl string `json:"apiUrl"` + // 耗子面板访问令牌ID。 + AccessTokenId uint `json:"accessTokenId"` + // 耗子面板访问令牌。 + AccessToken string `json:"accessToken"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` + // 网站名称。 + SiteName string `json:"siteName,omitempty"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sdkClient *rpsdk.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.AccessTokenId, config.AccessToken, 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.SiteName == "" { + return nil, errors.New("config `siteName` is required") + } + + // 设置站点 SSL 证书 + websiteCertReq := &rpsdk.WebsiteCertRequest{ + SiteName: d.config.SiteName, + Certificate: certPEM, + PrivateKey: privkeyPEM, + } + websiteCertResp, err := d.sdkClient.WebsiteCert(websiteCertReq) + d.logger.Debug("sdk request 'ratpanel.WebsiteCertRequest'", slog.Any("request", websiteCertReq), slog.Any("response", websiteCertResp)) + if err != nil { + return nil, fmt.Errorf("failed to execute sdk request 'ratpanel.WebsiteCertRequest': %w", err) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiUrl string, accessTokenId uint, accessToken string, skipTlsVerify bool) (*rpsdk.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid ratpanel api url") + } + + if accessTokenId == 0 { + return nil, errors.New("invalid ratpanel access token id") + } + if accessToken == "" { + return nil, errors.New("invalid ratpanel access token") + } + + client := rpsdk.NewClient(apiUrl, accessTokenId, accessToken) + if skipTlsVerify { + client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) + } + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go new file mode 100644 index 00000000..5fece978 --- /dev/null +++ b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go @@ -0,0 +1,82 @@ +package baotapanelsite_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-site" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiUrl string + fApiKey string + fSiteType string + fSiteName string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_BAOTAPANELSITE_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") + flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "") + flag.StringVar(&fSiteType, argsPrefix+"SITETYPE", "", "") + flag.StringVar(&fSiteName, argsPrefix+"SITENAME", "", "") +} + +/* +Shell command to run this test: + + go test -v ./baotapanel_site_test.go -args \ + --CERTIMATE_DEPLOYER_BAOTAPANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_BAOTAPANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIURL="http://127.0.0.1:8888" \ + --CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIKEY="your-api-key" \ + --CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITETYPE="php" \ + --CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITENAME="your-site-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("APIKEY: %v", fApiKey), + fmt.Sprintf("SITETYPE: %v", fSiteType), + fmt.Sprintf("SITENAME: %v", fSiteName), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiUrl: fApiUrl, + ApiKey: fApiKey, + AllowInsecureConnections: true, + SiteType: fSiteType, + SiteName: fSiteName, + SiteNames: []string{fSiteName}, + }) + 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/sdk3rd/ratpanel/api.go b/internal/pkg/sdk3rd/ratpanel/api.go new file mode 100644 index 00000000..764dd6bd --- /dev/null +++ b/internal/pkg/sdk3rd/ratpanel/api.go @@ -0,0 +1,15 @@ +package btpanelsdk + +import "net/http" + +func (c *Client) SettingCert(req *SettingCertRequest) (*SettingCertResponse, error) { + resp := &SettingCertResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/setting/cert", req, resp) + return resp, err +} + +func (c *Client) WebsiteCert(req *SiteCertRequest) (*SiteCertResponse, error) { + resp := &SiteCertResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/website/cert", req, resp) + return resp, err +} diff --git a/internal/pkg/sdk3rd/ratpanel/client.go b/internal/pkg/sdk3rd/ratpanel/client.go new file mode 100644 index 00000000..2b2efdd2 --- /dev/null +++ b/internal/pkg/sdk3rd/ratpanel/client.go @@ -0,0 +1,145 @@ +package btpanelsdk + +import ( + "bytes" + "crypto/hmac" + "crypto/sha256" + "crypto/tls" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" + + "github.com/go-resty/resty/v2" +) + +type Client struct { + client *resty.Client +} + +func NewClient(apiHost string, accessTokenId uint, accessToken string) *Client { + client := resty.New(). + SetBaseURL(strings.TrimRight(apiHost, "/")+"/api"). + SetHeader("Accept", "application/json"). + SetHeader("Content-Type", "application/json"). + SetPreRequestHook(func(c *resty.Client, req *http.Request) error { + var body []byte + var err error + + if req.Body != nil { + body, err = io.ReadAll(req.Body) + if err != nil { + return err + } + req.Body = io.NopCloser(bytes.NewReader(body)) + } + + canonicalPath := req.URL.Path + if !strings.HasPrefix(canonicalPath, "/api") { + index := strings.Index(canonicalPath, "/api") + if index != -1 { + canonicalPath = canonicalPath[index:] + } + } + + canonicalRequest := fmt.Sprintf("%s\n%s\n%s\n%s", + req.Method, + canonicalPath, + req.URL.Query().Encode(), + sha256Sum(string(body))) + + timestamp := time.Now().Unix() + req.Header.Set("X-Timestamp", fmt.Sprintf("%d", timestamp)) + + stringToSign := fmt.Sprintf("%s\n%d\n%s", + "HMAC-SHA256", + timestamp, + sha256Sum(canonicalRequest)) + signature := hmacSha256(stringToSign, accessToken) + req.Header.Set("Authorization", fmt.Sprintf("HMAC-SHA256 Credential=%d, Signature=%s", accessTokenId, signature)) + + return nil + }) + + return &Client{ + client: client, + } +} + +func (c *Client) WithTimeout(timeout time.Duration) *Client { + c.client.SetTimeout(timeout) + 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 + req.URL = path + if strings.EqualFold(method, http.MethodGet) { + qs := make(map[string]string) + if params != nil { + temp := make(map[string]any) + jsonb, _ := json.Marshal(params) + json.Unmarshal(jsonb, &temp) + for k, v := range temp { + if v != nil { + qs[k] = fmt.Sprintf("%v", v) + } + } + } + + req = req.SetQueryParams(qs) + } else { + req = req. + SetHeader("Content-Type", "application/json"). + SetBody(params) + } + + resp, err := req.Send() + if err != nil { + return resp, fmt.Errorf("ratpanel api error: failed to send request: %w", err) + } else if resp.IsError() { + return resp, fmt.Errorf("ratpanel api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.Body()) + } + + return resp, nil +} + +func (c *Client) sendRequestWithResult(method string, path string, params interface{}, result BaseResponse) error { + resp, err := c.sendRequest(method, path, params) + if err != nil { + if resp != nil { + json.Unmarshal(resp.Body(), &result) + } + return err + } + + if err = json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("ratpanel api error: failed to parse response: %w", err) + } else if errmessage := result.GetMessage(); errmessage != "success" { + return fmt.Errorf("ratpanel api error: %d - %s", resp.StatusCode(), errmessage) + } + + return nil +} + +func sha256Sum(str string) string { + sum := sha256.Sum256([]byte(str)) + dst := make([]byte, hex.EncodedLen(len(sum))) + hex.Encode(dst, sum[:]) + return string(dst) +} + +func hmacSha256(data string, secret string) string { + h := hmac.New(sha256.New, []byte(secret)) + h.Write([]byte(data)) + return hex.EncodeToString(h.Sum(nil)) +} diff --git a/internal/pkg/sdk3rd/ratpanel/models.go b/internal/pkg/sdk3rd/ratpanel/models.go new file mode 100644 index 00000000..2608300a --- /dev/null +++ b/internal/pkg/sdk3rd/ratpanel/models.go @@ -0,0 +1,35 @@ +package btpanelsdk + +type BaseResponse interface { + GetMessage() string +} + +type baseResponse struct { + Message *string `json:"msg,omitempty"` +} + +func (r *baseResponse) GetMessage() string { + if r.Message != nil { + return *r.Message + } + return "" +} + +type SettingCertRequest struct { + Certificate string `json:"cert"` + PrivateKey string `json:"key"` +} + +type SettingCertResponse struct { + baseResponse +} + +type WebsiteCertRequest struct { + SiteName string `json:"name"` + Certificate string `json:"cert"` + PrivateKey string `json:"key"` +} + +type WebsiteCertResponse struct { + baseResponse +} From 8014abc836ee22ba8adc513b18d67905392f4512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Fri, 16 May 2025 18:43:50 +0800 Subject: [PATCH 2/3] feat: add test cases --- .../ratpanel-console/ratpanel_console.go | 2 +- .../ratpanel-console/ratpanel_console_test.go | 28 ++++++++------- .../providers/ratpanel-site/ratpanel_site.go | 2 +- .../ratpanel-site/ratpanel_site_test.go | 35 +++++++++---------- internal/pkg/sdk3rd/ratpanel/api.go | 2 +- internal/pkg/sdk3rd/ratpanel/client.go | 2 +- internal/pkg/sdk3rd/ratpanel/models.go | 2 +- 7 files changed, 38 insertions(+), 35 deletions(-) diff --git a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go index ba9f5949..ceb31771 100644 --- a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go +++ b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go @@ -1,4 +1,4 @@ -package baotapanelconsole +package ratpanelconsole import ( "context" diff --git a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go index 5f3845e4..6303aa25 100644 --- a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go +++ b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go @@ -1,4 +1,4 @@ -package baotapanelconsole_test +package ratpanelconsole_test import ( "context" @@ -8,33 +8,36 @@ import ( "strings" "testing" - provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-console" + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ratpanel-console" ) var ( fInputCertPath string fInputKeyPath string fApiUrl string - fApiKey string + fTokenId uint + fToken string ) func init() { - argsPrefix := "CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_" + argsPrefix := "CERTIMATE_DEPLOYER_RATPANELCONSOLE_" flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") - flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "") + flag.UintVar(&fTokenId, argsPrefix+"TOKENID", 0, "") + flag.StringVar(&fToken, argsPrefix+"TOKEN", "", "") } /* Shell command to run this test: go test -v ./baotapanel_console_test.go -args \ - --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ - --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \ - --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_APIURL="http://127.0.0.1:8888" \ - --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_APIKEY="your-api-key" + --CERTIMATE_DEPLOYER_RATPANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_RATPANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_RATPANELCONSOLE_APIURL="http://127.0.0.1:8888" \ + --CERTIMATE_DEPLOYER_RATPANELSITE_TOKENID="your-access-token-id" \ + --CERTIMATE_DEPLOYER_RATPANELSITE_TOKEN="your-access-token" \ */ func TestDeploy(t *testing.T) { flag.Parse() @@ -45,14 +48,15 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath), fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), fmt.Sprintf("APIURL: %v", fApiUrl), - fmt.Sprintf("APIKEY: %v", fApiKey), + fmt.Sprintf("TOKENID: %v", fTokenId), + fmt.Sprintf("TOKEN: %v", fToken), }, "\n")) deployer, err := provider.NewDeployer(&provider.DeployerConfig{ ApiUrl: fApiUrl, - ApiKey: fApiKey, + AccessTokenId: fTokenId, + AccessToken: fToken, AllowInsecureConnections: true, - AutoRestart: true, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go index 639470e1..85f54ab5 100644 --- a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go +++ b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go @@ -1,4 +1,4 @@ -package baotapanelsite +package ratpanelsite import ( "context" diff --git a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go index 5fece978..86c22e1e 100644 --- a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go +++ b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go @@ -1,4 +1,4 @@ -package baotapanelsite_test +package ratpanelsite_test import ( "context" @@ -8,26 +8,26 @@ import ( "strings" "testing" - provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-site" + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ratpanel-site" ) var ( fInputCertPath string fInputKeyPath string fApiUrl string - fApiKey string - fSiteType string + fTokenId uint + fToken string fSiteName string ) func init() { - argsPrefix := "CERTIMATE_DEPLOYER_BAOTAPANELSITE_" + argsPrefix := "CERTIMATE_DEPLOYER_RATPANELSITE_" flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") - flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "") - flag.StringVar(&fSiteType, argsPrefix+"SITETYPE", "", "") + flag.UintVar(&fTokenId, argsPrefix+"TOKENID", 0, "") + flag.StringVar(&fToken, argsPrefix+"TOKEN", "", "") flag.StringVar(&fSiteName, argsPrefix+"SITENAME", "", "") } @@ -35,12 +35,12 @@ func init() { Shell command to run this test: go test -v ./baotapanel_site_test.go -args \ - --CERTIMATE_DEPLOYER_BAOTAPANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ - --CERTIMATE_DEPLOYER_BAOTAPANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \ - --CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIURL="http://127.0.0.1:8888" \ - --CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIKEY="your-api-key" \ - --CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITETYPE="php" \ - --CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITENAME="your-site-name" + --CERTIMATE_DEPLOYER_RATPANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_RATPANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_RATPANELSITE_APIURL="http://127.0.0.1:8888" \ + --CERTIMATE_DEPLOYER_RATPANELSITE_TOKENID="your-access-token-id" \ + --CERTIMATE_DEPLOYER_RATPANELSITE_TOKEN="your-access-token" \ + --CERTIMATE_DEPLOYER_RATPANELSITE_SITENAME="your-site-name" */ func TestDeploy(t *testing.T) { flag.Parse() @@ -51,18 +51,17 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath), fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), fmt.Sprintf("APIURL: %v", fApiUrl), - fmt.Sprintf("APIKEY: %v", fApiKey), - fmt.Sprintf("SITETYPE: %v", fSiteType), + fmt.Sprintf("TOKENID: %v", fTokenId), + fmt.Sprintf("TOKEN: %v", fToken), fmt.Sprintf("SITENAME: %v", fSiteName), }, "\n")) deployer, err := provider.NewDeployer(&provider.DeployerConfig{ ApiUrl: fApiUrl, - ApiKey: fApiKey, + AccessTokenId: fTokenId, + AccessToken: fToken, AllowInsecureConnections: true, - SiteType: fSiteType, SiteName: fSiteName, - SiteNames: []string{fSiteName}, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/sdk3rd/ratpanel/api.go b/internal/pkg/sdk3rd/ratpanel/api.go index 764dd6bd..a2f15153 100644 --- a/internal/pkg/sdk3rd/ratpanel/api.go +++ b/internal/pkg/sdk3rd/ratpanel/api.go @@ -1,4 +1,4 @@ -package btpanelsdk +package ratpanelsdk import "net/http" diff --git a/internal/pkg/sdk3rd/ratpanel/client.go b/internal/pkg/sdk3rd/ratpanel/client.go index 2b2efdd2..e0562410 100644 --- a/internal/pkg/sdk3rd/ratpanel/client.go +++ b/internal/pkg/sdk3rd/ratpanel/client.go @@ -1,4 +1,4 @@ -package btpanelsdk +package ratpanelsdk import ( "bytes" diff --git a/internal/pkg/sdk3rd/ratpanel/models.go b/internal/pkg/sdk3rd/ratpanel/models.go index 2608300a..bf5f53fb 100644 --- a/internal/pkg/sdk3rd/ratpanel/models.go +++ b/internal/pkg/sdk3rd/ratpanel/models.go @@ -1,4 +1,4 @@ -package btpanelsdk +package ratpanelsdk type BaseResponse interface { GetMessage() string From 871d3ece904da90a5c33783bb59f65dce4e1693a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Fri, 16 May 2025 18:51:03 +0800 Subject: [PATCH 3/3] fix: test case --- .../providers/ratpanel-console/ratpanel_console_test.go | 6 +++--- .../deployer/providers/ratpanel-site/ratpanel_site_test.go | 4 ++-- internal/pkg/sdk3rd/ratpanel/api.go | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go index 6303aa25..40804f87 100644 --- a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go +++ b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go @@ -32,12 +32,12 @@ func init() { /* Shell command to run this test: - go test -v ./baotapanel_console_test.go -args \ + go test -v ./ratpanel_console_test.go -args \ --CERTIMATE_DEPLOYER_RATPANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ --CERTIMATE_DEPLOYER_RATPANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \ --CERTIMATE_DEPLOYER_RATPANELCONSOLE_APIURL="http://127.0.0.1:8888" \ - --CERTIMATE_DEPLOYER_RATPANELSITE_TOKENID="your-access-token-id" \ - --CERTIMATE_DEPLOYER_RATPANELSITE_TOKEN="your-access-token" \ + --CERTIMATE_DEPLOYER_RATPANELCONSOLE_TOKENID=your-access-token-id \ + --CERTIMATE_DEPLOYER_RATPANELCONSOLE_TOKEN="your-access-token" */ func TestDeploy(t *testing.T) { flag.Parse() diff --git a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go index 86c22e1e..a4cab040 100644 --- a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go +++ b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go @@ -34,11 +34,11 @@ func init() { /* Shell command to run this test: - go test -v ./baotapanel_site_test.go -args \ + go test -v ./ratpanel_site_test.go -args \ --CERTIMATE_DEPLOYER_RATPANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ --CERTIMATE_DEPLOYER_RATPANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \ --CERTIMATE_DEPLOYER_RATPANELSITE_APIURL="http://127.0.0.1:8888" \ - --CERTIMATE_DEPLOYER_RATPANELSITE_TOKENID="your-access-token-id" \ + --CERTIMATE_DEPLOYER_RATPANELSITE_TOKENID=your-access-token-id \ --CERTIMATE_DEPLOYER_RATPANELSITE_TOKEN="your-access-token" \ --CERTIMATE_DEPLOYER_RATPANELSITE_SITENAME="your-site-name" */ diff --git a/internal/pkg/sdk3rd/ratpanel/api.go b/internal/pkg/sdk3rd/ratpanel/api.go index a2f15153..17f8110f 100644 --- a/internal/pkg/sdk3rd/ratpanel/api.go +++ b/internal/pkg/sdk3rd/ratpanel/api.go @@ -8,8 +8,8 @@ func (c *Client) SettingCert(req *SettingCertRequest) (*SettingCertResponse, err return resp, err } -func (c *Client) WebsiteCert(req *SiteCertRequest) (*SiteCertResponse, error) { - resp := &SiteCertResponse{} +func (c *Client) WebsiteCert(req *WebsiteCertRequest) (*WebsiteCertResponse, error) { + resp := &WebsiteCertResponse{} err := c.sendRequestWithResult(http.MethodPost, "/website/cert", req, resp) return resp, err }