feat: allow insecure connections on deployment to some self-hosted services

This commit is contained in:
Fu Diwei 2025-03-07 21:04:32 +08:00
parent 29dda4ec66
commit 1e2e88e299
33 changed files with 250 additions and 81 deletions

View File

@ -83,6 +83,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) {
deployer, err := p1PanelConsole.NewDeployer(&p1PanelConsole.DeployerConfig{ deployer, err := p1PanelConsole.NewDeployer(&p1PanelConsole.DeployerConfig{
ApiUrl: access.ApiUrl, ApiUrl: access.ApiUrl,
ApiKey: access.ApiKey, ApiKey: access.ApiKey,
AllowInsecureConnections: access.AllowInsecureConnections,
AutoRestart: maps.GetValueAsBool(options.ProviderDeployConfig, "autoRestart"), AutoRestart: maps.GetValueAsBool(options.ProviderDeployConfig, "autoRestart"),
}) })
return deployer, err return deployer, err
@ -91,6 +92,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) {
deployer, err := p1PanelSite.NewDeployer(&p1PanelSite.DeployerConfig{ deployer, err := p1PanelSite.NewDeployer(&p1PanelSite.DeployerConfig{
ApiUrl: access.ApiUrl, ApiUrl: access.ApiUrl,
ApiKey: access.ApiKey, ApiKey: access.ApiKey,
AllowInsecureConnections: access.AllowInsecureConnections,
WebsiteId: maps.GetValueAsInt64(options.ProviderDeployConfig, "websiteId"), WebsiteId: maps.GetValueAsInt64(options.ProviderDeployConfig, "websiteId"),
}) })
return deployer, err return deployer, err
@ -295,6 +297,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) {
deployer, err := pBaotaPanelConsole.NewDeployer(&pBaotaPanelConsole.DeployerConfig{ deployer, err := pBaotaPanelConsole.NewDeployer(&pBaotaPanelConsole.DeployerConfig{
ApiUrl: access.ApiUrl, ApiUrl: access.ApiUrl,
ApiKey: access.ApiKey, ApiKey: access.ApiKey,
AllowInsecureConnections: access.AllowInsecureConnections,
AutoRestart: maps.GetValueAsBool(options.ProviderDeployConfig, "autoRestart"), AutoRestart: maps.GetValueAsBool(options.ProviderDeployConfig, "autoRestart"),
}) })
return deployer, err return deployer, err
@ -303,6 +306,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) {
deployer, err := pBaotaPanelSite.NewDeployer(&pBaotaPanelSite.DeployerConfig{ deployer, err := pBaotaPanelSite.NewDeployer(&pBaotaPanelSite.DeployerConfig{
ApiUrl: access.ApiUrl, ApiUrl: access.ApiUrl,
ApiKey: access.ApiKey, ApiKey: access.ApiKey,
AllowInsecureConnections: access.AllowInsecureConnections,
SiteType: maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "siteType", "other"), SiteType: maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "siteType", "other"),
SiteName: maps.GetValueAsString(options.ProviderDeployConfig, "siteName"), SiteName: maps.GetValueAsString(options.ProviderDeployConfig, "siteName"),
SiteNames: slices.Filter(strings.Split(maps.GetValueAsString(options.ProviderDeployConfig, "siteNames"), ";"), func(s string) bool { return s != "" }), SiteNames: slices.Filter(strings.Split(maps.GetValueAsString(options.ProviderDeployConfig, "siteNames"), ";"), func(s string) bool { return s != "" }),
@ -584,6 +588,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) {
deployer, err := pSafeLine.NewDeployer(&pSafeLine.DeployerConfig{ deployer, err := pSafeLine.NewDeployer(&pSafeLine.DeployerConfig{
ApiUrl: access.ApiUrl, ApiUrl: access.ApiUrl,
ApiToken: access.ApiToken, ApiToken: access.ApiToken,
AllowInsecureConnections: access.AllowInsecureConnections,
ResourceType: pSafeLine.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), ResourceType: pSafeLine.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")),
CertificateId: maps.GetValueAsInt32(options.ProviderDeployConfig, "certificateId"), CertificateId: maps.GetValueAsInt32(options.ProviderDeployConfig, "certificateId"),
}) })
@ -825,6 +830,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) {
deployer, err := pWebhook.NewDeployer(&pWebhook.DeployerConfig{ deployer, err := pWebhook.NewDeployer(&pWebhook.DeployerConfig{
WebhookUrl: access.Url, WebhookUrl: access.Url,
WebhookData: maps.GetValueAsString(options.ProviderDeployConfig, "webhookData"), WebhookData: maps.GetValueAsString(options.ProviderDeployConfig, "webhookData"),
AllowInsecureConnections: access.AllowInsecureConnections,
}) })
return deployer, err return deployer, err
} }

View File

@ -27,6 +27,7 @@ func (a *Access) UnmarshalConfigToMap() (map[string]any, error) {
type AccessConfigFor1Panel struct { type AccessConfigFor1Panel struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
} }
type AccessConfigForACMEHttpReq struct { type AccessConfigForACMEHttpReq struct {
@ -65,6 +66,7 @@ type AccessConfigForBaishan struct {
type AccessConfigForBaotaPanel struct { type AccessConfigForBaotaPanel struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
} }
type AccessConfigForBytePlus struct { type AccessConfigForBytePlus struct {
@ -176,6 +178,7 @@ type AccessConfigForRainYun struct {
type AccessConfigForSafeLine struct { type AccessConfigForSafeLine struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
ApiToken string `json:"apiToken"` ApiToken string `json:"apiToken"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
} }
type AccessConfigForSSH struct { type AccessConfigForSSH struct {
@ -205,6 +208,7 @@ type AccessConfigForVolcEngine struct {
type AccessConfigForWebhook struct { type AccessConfigForWebhook struct {
Url string `json:"url"` Url string `json:"url"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
} }
type AccessConfigForWestcn struct { type AccessConfigForWestcn struct {

View File

@ -64,6 +64,7 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a
case domain.NotifyChannelTypeWebhook: case domain.NotifyChannelTypeWebhook:
return pWebhook.NewNotifier(&pWebhook.NotifierConfig{ return pWebhook.NewNotifier(&pWebhook.NotifierConfig{
Url: maps.GetValueAsString(channelConfig, "url"), Url: maps.GetValueAsString(channelConfig, "url"),
AllowInsecureConnections: maps.GetValueAsBool(channelConfig, "allowInsecureConnections"),
}) })
case domain.NotifyChannelTypeWeCom: case domain.NotifyChannelTypeWeCom:

View File

@ -2,6 +2,7 @@
import ( import (
"context" "context"
"crypto/tls"
"errors" "errors"
"net/url" "net/url"
@ -17,6 +18,8 @@ type DeployerConfig struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
// 1Panel 接口密钥。 // 1Panel 接口密钥。
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
// 是否允许不安全的连接。
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
// 是否自动重启。 // 是否自动重启。
AutoRestart bool `json:"autoRestart"` AutoRestart bool `json:"autoRestart"`
} }
@ -34,7 +37,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
panic("config is nil") panic("config is nil")
} }
client, err := createSdkClient(config.ApiUrl, config.ApiKey) client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, xerrors.Wrap(err, "failed to create sdk client")
} }
@ -74,7 +77,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
} }
func createSdkClient(apiUrl, apiKey string) (*opsdk.Client, error) { func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil { if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid 1panel api url") return nil, errors.New("invalid 1panel api url")
} }
@ -84,5 +87,9 @@ func createSdkClient(apiUrl, apiKey string) (*opsdk.Client, error) {
} }
client := opsdk.NewClient(apiUrl, apiKey) client := opsdk.NewClient(apiUrl, apiKey)
if allowInsecure {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
}
return client, nil return client, nil
} }

View File

@ -51,6 +51,7 @@ func TestDeploy(t *testing.T) {
deployer, err := provider.NewDeployer(&provider.DeployerConfig{ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
ApiUrl: fApiUrl, ApiUrl: fApiUrl,
ApiKey: fApiKey, ApiKey: fApiKey,
AllowInsecureConnections: true,
AutoRestart: true, AutoRestart: true,
}) })
if err != nil { if err != nil {

View File

@ -2,6 +2,7 @@
import ( import (
"context" "context"
"crypto/tls"
"errors" "errors"
"net/url" "net/url"
"strconv" "strconv"
@ -20,6 +21,8 @@ type DeployerConfig struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
// 1Panel 接口密钥。 // 1Panel 接口密钥。
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
// 是否允许不安全的连接。
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
// 网站 ID。 // 网站 ID。
WebsiteId int64 `json:"websiteId"` WebsiteId int64 `json:"websiteId"`
} }
@ -38,7 +41,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
panic("config is nil") panic("config is nil")
} }
client, err := createSdkClient(config.ApiUrl, config.ApiKey) client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, xerrors.Wrap(err, "failed to create sdk client")
} }
@ -106,7 +109,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
} }
func createSdkClient(apiUrl, apiKey string) (*opsdk.Client, error) { func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil { if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid 1panel api url") return nil, errors.New("invalid 1panel api url")
} }
@ -116,5 +119,9 @@ func createSdkClient(apiUrl, apiKey string) (*opsdk.Client, error) {
} }
client := opsdk.NewClient(apiUrl, apiKey) client := opsdk.NewClient(apiUrl, apiKey)
if allowInsecure {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
}
return client, nil return client, nil
} }

View File

@ -56,6 +56,7 @@ func TestDeploy(t *testing.T) {
ApiUrl: fApiUrl, ApiUrl: fApiUrl,
ApiKey: fApiKey, ApiKey: fApiKey,
WebsiteId: fWebsiteId, WebsiteId: fWebsiteId,
AllowInsecureConnections: true,
}) })
if err != nil { if err != nil {
t.Errorf("err: %+v", err) t.Errorf("err: %+v", err)

View File

@ -2,6 +2,7 @@
import ( import (
"context" "context"
"crypto/tls"
"errors" "errors"
"net/url" "net/url"
@ -17,6 +18,8 @@ type DeployerConfig struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
// 宝塔面板接口密钥。 // 宝塔面板接口密钥。
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
// 是否允许不安全的连接。
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
// 是否自动重启。 // 是否自动重启。
AutoRestart bool `json:"autoRestart"` AutoRestart bool `json:"autoRestart"`
} }
@ -34,7 +37,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
panic("config is nil") panic("config is nil")
} }
client, err := createSdkClient(config.ApiUrl, config.ApiKey) client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, xerrors.Wrap(err, "failed to create sdk client")
} }
@ -79,7 +82,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
} }
func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) { func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil { if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid baota api url") return nil, errors.New("invalid baota api url")
} }
@ -89,5 +92,9 @@ func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) {
} }
client := btsdk.NewClient(apiUrl, apiKey) client := btsdk.NewClient(apiUrl, apiKey)
if allowInsecure {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
}
return client, nil return client, nil
} }

View File

@ -51,6 +51,7 @@ func TestDeploy(t *testing.T) {
deployer, err := provider.NewDeployer(&provider.DeployerConfig{ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
ApiUrl: fApiUrl, ApiUrl: fApiUrl,
ApiKey: fApiKey, ApiKey: fApiKey,
AllowInsecureConnections: true,
AutoRestart: true, AutoRestart: true,
}) })
if err != nil { if err != nil {

View File

@ -2,6 +2,7 @@
import ( import (
"context" "context"
"crypto/tls"
"errors" "errors"
"fmt" "fmt"
"net/url" "net/url"
@ -19,6 +20,8 @@ type DeployerConfig struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
// 宝塔面板接口密钥。 // 宝塔面板接口密钥。
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
// 是否允许不安全的连接。
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
// 站点类型。 // 站点类型。
SiteType string `json:"siteType"` SiteType string `json:"siteType"`
// 站点名称(单个)。 // 站点名称(单个)。
@ -40,7 +43,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
panic("config is nil") panic("config is nil")
} }
client, err := createSdkClient(config.ApiUrl, config.ApiKey) client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client") return nil, xerrors.Wrap(err, "failed to create sdk client")
} }
@ -122,7 +125,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
return &deployer.DeployResult{}, nil return &deployer.DeployResult{}, nil
} }
func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) { func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil { if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid baota api url") return nil, errors.New("invalid baota api url")
} }
@ -132,5 +135,9 @@ func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) {
} }
client := btsdk.NewClient(apiUrl, apiKey) client := btsdk.NewClient(apiUrl, apiKey)
if allowInsecure {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
}
return client, nil return client, nil
} }

View File

@ -59,6 +59,7 @@ func TestDeploy(t *testing.T) {
deployer, err := provider.NewDeployer(&provider.DeployerConfig{ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
ApiUrl: fApiUrl, ApiUrl: fApiUrl,
ApiKey: fApiKey, ApiKey: fApiKey,
AllowInsecureConnections: true,
SiteType: fSiteType, SiteType: fSiteType,
SiteName: fSiteName, SiteName: fSiteName,
SiteNames: []string{fSiteName}, SiteNames: []string{fSiteName},

View File

@ -2,6 +2,7 @@
import ( import (
"context" "context"
"crypto/tls"
"errors" "errors"
"fmt" "fmt"
"net/url" "net/url"
@ -18,6 +19,8 @@ type DeployerConfig struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
// 雷池 API Token。 // 雷池 API Token。
ApiToken string `json:"apiToken"` ApiToken string `json:"apiToken"`
// 是否允许不安全的连接。
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
// 部署资源类型。 // 部署资源类型。
ResourceType ResourceType `json:"resourceType"` ResourceType ResourceType `json:"resourceType"`
// 证书 ID。 // 证书 ID。
@ -38,7 +41,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
panic("config is nil") panic("config is nil")
} }
client, err := createSdkClient(config.ApiUrl, config.ApiToken) client, err := createSdkClient(config.ApiUrl, config.ApiToken, config.AllowInsecureConnections)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk clients") return nil, xerrors.Wrap(err, "failed to create sdk clients")
} }
@ -94,7 +97,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem stri
return nil return nil
} }
func createSdkClient(apiUrl, apiToken string) (*safelinesdk.Client, error) { func createSdkClient(apiUrl, apiToken string, allowInsecure bool) (*safelinesdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil { if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid safeline api url") return nil, errors.New("invalid safeline api url")
} }
@ -104,5 +107,9 @@ func createSdkClient(apiUrl, apiToken string) (*safelinesdk.Client, error) {
} }
client := safelinesdk.NewClient(apiUrl, apiToken) client := safelinesdk.NewClient(apiUrl, apiToken)
if allowInsecure {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
}
return client, nil return client, nil
} }

View File

@ -55,8 +55,9 @@ func TestDeploy(t *testing.T) {
deployer, err := provider.NewDeployer(&provider.DeployerConfig{ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
ApiUrl: fApiUrl, ApiUrl: fApiUrl,
ApiToken: fApiToken, ApiToken: fApiToken,
AllowInsecureConnections: true,
ResourceType: provider.ResourceType("certificate"), ResourceType: provider.ResourceType("certificate"),
CertificateId: fCertificateId, CertificateId: int32(fCertificateId),
}) })
if err != nil { if err != nil {
t.Errorf("err: %+v", err) t.Errorf("err: %+v", err)

View File

@ -2,6 +2,7 @@ package webhook
import ( import (
"context" "context"
"crypto/tls"
"encoding/json" "encoding/json"
"strings" "strings"
"time" "time"
@ -19,6 +20,8 @@ type DeployerConfig struct {
WebhookUrl string `json:"webhookUrl"` WebhookUrl string `json:"webhookUrl"`
// Webhook 回调数据JSON 格式)。 // Webhook 回调数据JSON 格式)。
WebhookData string `json:"webhookData,omitempty"` WebhookData string `json:"webhookData,omitempty"`
// 是否允许不安全的连接。
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
} }
type DeployerProvider struct { type DeployerProvider struct {
@ -38,6 +41,9 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
SetTimeout(30 * time.Second). SetTimeout(30 * time.Second).
SetRetryCount(3). SetRetryCount(3).
SetRetryWaitTime(5 * time.Second) SetRetryWaitTime(5 * time.Second)
if config.AllowInsecureConnections {
client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
}
return &DeployerProvider{ return &DeployerProvider{
config: config, config: config,

View File

@ -51,6 +51,7 @@ func TestDeploy(t *testing.T) {
deployer, err := provider.NewDeployer(&provider.DeployerConfig{ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
WebhookUrl: fWebhookUrl, WebhookUrl: fWebhookUrl,
WebhookData: fWebhookData, WebhookData: fWebhookData,
AllowInsecureConnections: true,
}) })
if err != nil { if err != nil {
t.Errorf("err: %+v", err) t.Errorf("err: %+v", err)

View File

@ -2,8 +2,10 @@
import ( import (
"context" "context"
"crypto/tls"
"net/http"
"github.com/nikoksr/notify/service/http" webhook "github.com/nikoksr/notify/service/http"
"github.com/usual2970/certimate/internal/pkg/core/notifier" "github.com/usual2970/certimate/internal/pkg/core/notifier"
) )
@ -11,6 +13,8 @@ import (
type NotifierConfig struct { type NotifierConfig struct {
// Webhook URL。 // Webhook URL。
Url string `json:"url"` Url string `json:"url"`
// 是否允许不安全的连接。
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
} }
type NotifierProvider struct { type NotifierProvider struct {
@ -30,10 +34,16 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
} }
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
srv := http.New() srv := webhook.New()
srv.AddReceiversURLs(n.config.Url) srv.AddReceiversURLs(n.config.Url)
if n.config.AllowInsecureConnections {
tlsConfig := &tls.Config{InsecureSkipVerify: true}
transport := &http.Transport{TLSClientConfig: tlsConfig}
client := &http.Client{Transport: transport}
srv.WithClient(client)
}
err = srv.Send(ctx, subject, message) err = srv.Send(ctx, subject, message)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -40,6 +40,7 @@ func TestNotify(t *testing.T) {
notifier, err := provider.NewNotifier(&provider.NotifierConfig{ notifier, err := provider.NewNotifier(&provider.NotifierConfig{
Url: fUrl, Url: fUrl,
AllowInsecureConnections: true,
}) })
if err != nil { if err != nil {
t.Errorf("err: %+v", err) t.Errorf("err: %+v", err)

View File

@ -35,7 +35,7 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
return c return c
} }
func (c *Client) WithTlsConfig(config *tls.Config) *Client { func (c *Client) WithTLSConfig(config *tls.Config) *Client {
c.client.SetTLSClientConfig(config) c.client.SetTLSClientConfig(config)
return c return c
} }

View File

@ -2,6 +2,7 @@ package btpanelsdk
import ( import (
"crypto/md5" "crypto/md5"
"crypto/tls"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -34,6 +35,11 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
return c return c
} }
func (c *Client) WithTLSConfig(config *tls.Config) *Client {
c.client.SetTLSClientConfig(config)
return c
}
func (c *Client) generateSignature(timestamp string) string { func (c *Client) generateSignature(timestamp string) string {
keyMd5 := md5.Sum([]byte(c.apiKey)) keyMd5 := md5.Sum([]byte(c.apiKey))
keyMd5Hex := strings.ToLower(hex.EncodeToString(keyMd5[:])) keyMd5Hex := strings.ToLower(hex.EncodeToString(keyMd5[:]))

View File

@ -1,6 +1,7 @@
package safelinesdk package safelinesdk
import ( import (
"crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings" "strings"
@ -31,6 +32,11 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
return c return c
} }
func (c *Client) WithTLSConfig(config *tls.Config) *Client {
c.client.SetTLSClientConfig(config)
return c
}
func (c *Client) sendRequest(path string, params interface{}) (*resty.Response, error) { func (c *Client) sendRequest(path string, params interface{}) (*resty.Response, error) {
url := c.apiHost + path url := c.apiHost + path
req := c.client.R(). req := c.client.R().

View File

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next"; 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 { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
@ -32,6 +32,7 @@ const AccessForm1PanelConfig = ({ form: formInst, formName, disabled, initialVal
.min(1, t("access.form.1panel_api_key.placeholder")) .min(1, t("access.form.1panel_api_key.placeholder"))
.max(64, t("common.errmsg.string_max", { max: 64 })) .max(64, t("common.errmsg.string_max", { max: 64 }))
.trim(), .trim(),
allowInsecureConnections: z.boolean().nullish(),
}); });
const formRule = createSchemaFieldRule(formSchema); const formRule = createSchemaFieldRule(formSchema);
@ -65,6 +66,18 @@ const AccessForm1PanelConfig = ({ form: formInst, formName, disabled, initialVal
> >
<Input.Password autoComplete="new-password" placeholder={t("access.form.1panel_api_key.placeholder")} /> <Input.Password autoComplete="new-password" placeholder={t("access.form.1panel_api_key.placeholder")} />
</Form.Item> </Form.Item>
<Form.Item
name="allowInsecureConnections"
label={t("access.form.1panel_allow_insecure_conns.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.1panel_allow_insecure_conns.tooltip") }}></span>}
>
<Switch
checkedChildren={t("access.form.1panel_allow_insecure_conns.switch.on")}
unCheckedChildren={t("access.form.1panel_allow_insecure_conns.switch.off")}
/>
</Form.Item>
</Form> </Form>
); );
}; };

View File

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next"; 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 { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
@ -32,6 +32,7 @@ const AccessFormBaotaPanelConfig = ({ form: formInst, formName, disabled, initia
.min(1, t("access.form.baotapanel_api_key.placeholder")) .min(1, t("access.form.baotapanel_api_key.placeholder"))
.max(64, t("common.errmsg.string_max", { max: 64 })) .max(64, t("common.errmsg.string_max", { max: 64 }))
.trim(), .trim(),
allowInsecureConnections: z.boolean().nullish(),
}); });
const formRule = createSchemaFieldRule(formSchema); const formRule = createSchemaFieldRule(formSchema);
@ -65,6 +66,18 @@ const AccessFormBaotaPanelConfig = ({ form: formInst, formName, disabled, initia
> >
<Input.Password autoComplete="new-password" placeholder={t("access.form.baotapanel_api_key.placeholder")} /> <Input.Password autoComplete="new-password" placeholder={t("access.form.baotapanel_api_key.placeholder")} />
</Form.Item> </Form.Item>
<Form.Item
name="allowInsecureConnections"
label={t("access.form.baotapanel_allow_insecure_conns.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.baotapanel_allow_insecure_conns.tooltip") }}></span>}
>
<Switch
checkedChildren={t("access.form.baotapanel_allow_insecure_conns.switch.on")}
unCheckedChildren={t("access.form.baotapanel_allow_insecure_conns.switch.off")}
/>
</Form.Item>
</Form> </Form>
); );
}; };

View File

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next"; 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 { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
@ -32,6 +32,7 @@ const AccessFormSafeLineConfig = ({ form: formInst, formName, disabled, initialV
.min(1, t("access.form.safeline_api_token.placeholder")) .min(1, t("access.form.safeline_api_token.placeholder"))
.max(64, t("common.errmsg.string_max", { max: 64 })) .max(64, t("common.errmsg.string_max", { max: 64 }))
.trim(), .trim(),
allowInsecureConnections: z.boolean().nullish(),
}); });
const formRule = createSchemaFieldRule(formSchema); const formRule = createSchemaFieldRule(formSchema);
@ -65,6 +66,18 @@ const AccessFormSafeLineConfig = ({ form: formInst, formName, disabled, initialV
> >
<Input.Password autoComplete="new-password" placeholder={t("access.form.safeline_api_token.placeholder")} /> <Input.Password autoComplete="new-password" placeholder={t("access.form.safeline_api_token.placeholder")} />
</Form.Item> </Form.Item>
<Form.Item
name="allowInsecureConnections"
label={t("access.form.safeline_allow_insecure_conns.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.safeline_allow_insecure_conns.tooltip") }}></span>}
>
<Switch
checkedChildren={t("access.form.safeline_allow_insecure_conns.switch.on")}
unCheckedChildren={t("access.form.safeline_allow_insecure_conns.switch.off")}
/>
</Form.Item>
</Form> </Form>
); );
}; };

View File

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next"; 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 { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
@ -26,6 +26,7 @@ const AccessFormWebhookConfig = ({ form: formInst, formName, disabled, initialVa
const formSchema = z.object({ const formSchema = z.object({
url: z.string({ message: t("access.form.webhook_url.placeholder") }).url(t("common.errmsg.url_invalid")), url: z.string({ message: t("access.form.webhook_url.placeholder") }).url(t("common.errmsg.url_invalid")),
allowInsecureConnections: z.boolean().nullish(),
}); });
const formRule = createSchemaFieldRule(formSchema); const formRule = createSchemaFieldRule(formSchema);
@ -45,6 +46,18 @@ const AccessFormWebhookConfig = ({ form: formInst, formName, disabled, initialVa
<Form.Item name="url" label={t("access.form.webhook_url.label")} rules={[formRule]}> <Form.Item name="url" label={t("access.form.webhook_url.label")} rules={[formRule]}>
<Input placeholder={t("access.form.webhook_url.placeholder")} /> <Input placeholder={t("access.form.webhook_url.placeholder")} />
</Form.Item> </Form.Item>
<Form.Item
name="allowInsecureConnections"
label={t("access.form.webhook_allow_insecure_conns.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.webhook_allow_insecure_conns.tooltip") }}></span>}
>
<Switch
checkedChildren={t("access.form.webhook_allow_insecure_conns.switch.on")}
unCheckedChildren={t("access.form.webhook_allow_insecure_conns.switch.off")}
/>
</Form.Item>
</Form> </Form>
); );
}; };

View File

@ -98,8 +98,8 @@ const NotifyChannels = ({ className, classNames, style, styles }: NotifyChannels
<Switch <Switch
defaultChecked={channels[channel.type]?.enabled as boolean} defaultChecked={channels[channel.type]?.enabled as boolean}
disabled={channels[channel.type] == null} disabled={channels[channel.type] == null}
checkedChildren={t("settings.notification.channel.enabled.on")} checkedChildren={t("settings.notification.channel.switch.on")}
unCheckedChildren={t("settings.notification.channel.enabled.off")} unCheckedChildren={t("settings.notification.channel.switch.off")}
onChange={(checked) => handleSwitchChange(channel.type, checked)} onChange={(checked) => handleSwitchChange(channel.type, checked)}
/> />
</div> </div>

View File

@ -433,8 +433,8 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
<div>{t("workflow_node.deploy.form.skip_on_last_succeeded.prefix")}</div> <div>{t("workflow_node.deploy.form.skip_on_last_succeeded.prefix")}</div>
<Form.Item name="skipOnLastSucceeded" noStyle rules={[formRule]}> <Form.Item name="skipOnLastSucceeded" noStyle rules={[formRule]}>
<Switch <Switch
checkedChildren={t("workflow_node.deploy.form.skip_on_last_succeeded.enabled.on")} checkedChildren={t("workflow_node.deploy.form.skip_on_last_succeeded.switch.on")}
unCheckedChildren={t("workflow_node.deploy.form.skip_on_last_succeeded.enabled.off")} unCheckedChildren={t("workflow_node.deploy.form.skip_on_last_succeeded.switch.off")}
/> />
</Form.Item> </Form.Item>
<div>{t("workflow_node.deploy.form.skip_on_last_succeeded.suffix")}</div> <div>{t("workflow_node.deploy.form.skip_on_last_succeeded.suffix")}</div>

View File

@ -50,6 +50,7 @@ export interface AccessModel extends BaseModel {
export type AccessConfigFor1Panel = { export type AccessConfigFor1Panel = {
apiUrl: string; apiUrl: string;
apiKey: string; apiKey: string;
allowInsecureConnections?: boolean;
}; };
export type AccessConfigForACMEHttpReq = { export type AccessConfigForACMEHttpReq = {
@ -88,6 +89,7 @@ export type AccessConfigForBaishan = {
export type AccessConfigForBaotaPanel = { export type AccessConfigForBaotaPanel = {
apiUrl: string; apiUrl: string;
apiKey: string; apiKey: string;
allowInsecureConnections?: boolean;
}; };
export type AccessConfigForBytePlus = { export type AccessConfigForBytePlus = {
@ -199,6 +201,7 @@ export type AccessConfigForRainYun = {
export type AccessConfigForSafeLine = { export type AccessConfigForSafeLine = {
apiUrl: string; apiUrl: string;
apiToken: string; apiToken: string;
allowInsecureConnections?: boolean;
}; };
export type AccessConfigForSSH = { export type AccessConfigForSSH = {
@ -228,6 +231,7 @@ export type AccessConfigForVolcEngine = {
export type AccessConfigForWebhook = { export type AccessConfigForWebhook = {
url: string; url: string;
allowInsecureConnections?: boolean;
}; };
export type AccessConfigForWestcn = { export type AccessConfigForWestcn = {

View File

@ -29,6 +29,10 @@
"access.form.1panel_api_key.label": "1Panel API key", "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.placeholder": "Please enter 1Panel API key",
"access.form.1panel_api_key.tooltip": "For more information, see <a href=\"https://docs.1panel.pro/dev_manual/api_manual/\" target=\"_blank\">https://docs.1panel.pro/dev_manual/api_manual/</a>", "access.form.1panel_api_key.tooltip": "For more information, see <a href=\"https://docs.1panel.pro/dev_manual/api_manual/\" target=\"_blank\">https://docs.1panel.pro/dev_manual/api_manual/</a>",
"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", "access.form.acmehttpreq_endpoint.label": "Endpoint",
"access.form.acmehttpreq_endpoint.placeholder": "Please enter endpoint", "access.form.acmehttpreq_endpoint.placeholder": "Please enter endpoint",
"access.form.acmehttpreq_endpoint.tooltip": "For more information, see <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>", "access.form.acmehttpreq_endpoint.tooltip": "For more information, see <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
@ -79,6 +83,10 @@
"access.form.baotapanel_api_key.label": "aaPanel API key", "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.placeholder": "Please enter aaPanel API key",
"access.form.baotapanel_api_key.tooltip": "For more information, see <a href=\"https://www.bt.cn/bbs/thread-20376-1-1.html\" target=\"_blank\">https://www.bt.cn/bbs/thread-20376-1-1.html</a>", "access.form.baotapanel_api_key.tooltip": "For more information, see <a href=\"https://www.bt.cn/bbs/thread-20376-1-1.html\" target=\"_blank\">https://www.bt.cn/bbs/thread-20376-1-1.html</a>",
"access.form.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", "access.form.byteplus_access_key.label": "BytePlus AccessKey",
"access.form.byteplus_access_key.placeholder": "Please enter BytePlus AccessKey", "access.form.byteplus_access_key.placeholder": "Please enter BytePlus AccessKey",
"access.form.byteplus_access_key.tooltip": "For more information, see <a href=\"https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys\" target=\"_blank\">https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys</a>", "access.form.byteplus_access_key.tooltip": "For more information, see <a href=\"https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys\" target=\"_blank\">https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys</a>",
@ -200,6 +208,10 @@
"access.form.safeline_api_token.label": "SafeLine API token", "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.placeholder": "Please enter SafeLine API token",
"access.form.safeline_api_token.tooltip": "For more information, see <a href=\"https://docs.waf.chaitin.com/en/reference/articles/openapi\" target=\"_blank\">https://docs.waf.chaitin.com/en/reference/articles/openapi</a>", "access.form.safeline_api_token.tooltip": "For more information, see <a href=\"https://docs.waf.chaitin.com/en/reference/articles/openapi\" target=\"_blank\">https://docs.waf.chaitin.com/en/reference/articles/openapi</a>",
"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", "access.form.ssh_host.label": "Server host",
"access.form.ssh_host.placeholder": "Please enter server host", "access.form.ssh_host.placeholder": "Please enter server host",
"access.form.ssh_port.label": "Server port", "access.form.ssh_port.label": "Server port",
@ -239,6 +251,10 @@
"access.form.volcengine_secret_access_key.tooltip": "For more information, see <a href=\"https://www.volcengine.com/docs/6291/216571\" target=\"_blank\">https://www.volcengine.com/docs/6291/216571</a>", "access.form.volcengine_secret_access_key.tooltip": "For more information, see <a href=\"https://www.volcengine.com/docs/6291/216571\" target=\"_blank\">https://www.volcengine.com/docs/6291/216571</a>",
"access.form.webhook_url.label": "Webhook URL", "access.form.webhook_url.label": "Webhook URL",
"access.form.webhook_url.placeholder": "Please enter Webhook URL", "access.form.webhook_url.placeholder": "Please enter Webhook URL",
"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.westcn_username.label": "West.cn username", "access.form.westcn_username.label": "West.cn username",
"access.form.westcn_username.placeholder": "Please enter West.cn username", "access.form.westcn_username.placeholder": "Please enter West.cn username",
"access.form.westcn_username.tooltip": "For more information, see <a href=\"https://www.west.cn/CustomerCenter/doc/apiv2.html#12u3001u8eabu4efdu9a8cu8bc10a3ca20id3d12u3001u8eabu4efdu9a8cu8bc13e203ca3e\" target=\"_blank\">https://www.west.cn/CustomerCenter/doc/apiv2.html</a>", "access.form.westcn_username.tooltip": "For more information, see <a href=\"https://www.west.cn/CustomerCenter/doc/apiv2.html#12u3001u8eabu4efdu9a8cu8bc10a3ca20id3d12u3001u8eabu4efdu9a8cu8bc13e203ca3e\" target=\"_blank\">https://www.west.cn/CustomerCenter/doc/apiv2.html</a>",

View File

@ -24,8 +24,8 @@
"settings.notification.template.form.message.placeholder": "Please enter notification message", "settings.notification.template.form.message.placeholder": "Please enter notification message",
"settings.notification.template.form.message.extra": "Supported variables (${COUNT}: number of expiring soon. ${DOMAINS}: Domain list)", "settings.notification.template.form.message.extra": "Supported variables (${COUNT}: number of expiring soon. ${DOMAINS}: Domain list)",
"settings.notification.channels.card.title": "Channels", "settings.notification.channels.card.title": "Channels",
"settings.notification.channel.enabled.on": "On", "settings.notification.channel.switch.on": "On",
"settings.notification.channel.enabled.off": "Off", "settings.notification.channel.switch.off": "Off",
"settings.notification.push_test.button": "Send test notification", "settings.notification.push_test.button": "Send test notification",
"settings.notification.push_test.pushed": "Sent", "settings.notification.push_test.pushed": "Sent",
"settings.notification.channel.form.bark_server_url.label": "Server URL", "settings.notification.channel.form.bark_server_url.label": "Server URL",
@ -44,7 +44,7 @@
"settings.notification.channel.form.email_smtp_host.placeholder": "Please enter SMTP host", "settings.notification.channel.form.email_smtp_host.placeholder": "Please enter SMTP host",
"settings.notification.channel.form.email_smtp_port.label": "SMTP port", "settings.notification.channel.form.email_smtp_port.label": "SMTP port",
"settings.notification.channel.form.email_smtp_port.placeholder": "Please enter SMTP port", "settings.notification.channel.form.email_smtp_port.placeholder": "Please enter SMTP port",
"settings.notification.channel.form.email_smtp_tls.label": "Use TLS/SSL", "settings.notification.channel.form.email_smtp_tls.label": "Use SSL/TLS",
"settings.notification.channel.form.email_username.label": "Username", "settings.notification.channel.form.email_username.label": "Username",
"settings.notification.channel.form.email_username.placeholder": "please enter username", "settings.notification.channel.form.email_username.placeholder": "please enter username",
"settings.notification.channel.form.email_password.label": "Password", "settings.notification.channel.form.email_password.label": "Password",

View File

@ -533,8 +533,8 @@
"workflow_node.deploy.form.skip_on_last_succeeded.label": "Repeated deployment", "workflow_node.deploy.form.skip_on_last_succeeded.label": "Repeated deployment",
"workflow_node.deploy.form.skip_on_last_succeeded.prefix": "If the last deployment was successful, ", "workflow_node.deploy.form.skip_on_last_succeeded.prefix": "If the last deployment was successful, ",
"workflow_node.deploy.form.skip_on_last_succeeded.suffix": " to re-deploy.", "workflow_node.deploy.form.skip_on_last_succeeded.suffix": " to re-deploy.",
"workflow_node.deploy.form.skip_on_last_succeeded.enabled.on": "skip", "workflow_node.deploy.form.skip_on_last_succeeded.switch.on": "skip",
"workflow_node.deploy.form.skip_on_last_succeeded.enabled.off": "not skip", "workflow_node.deploy.form.skip_on_last_succeeded.switch.off": "not skip",
"workflow_node.notify.label": "Notification", "workflow_node.notify.label": "Notification",
"workflow_node.notify.form.subject.label": "Subject", "workflow_node.notify.form.subject.label": "Subject",

View File

@ -29,6 +29,10 @@
"access.form.1panel_api_key.label": "1Panel 接口密钥", "access.form.1panel_api_key.label": "1Panel 接口密钥",
"access.form.1panel_api_key.placeholder": "请输入 1Panel 接口密钥", "access.form.1panel_api_key.placeholder": "请输入 1Panel 接口密钥",
"access.form.1panel_api_key.tooltip": "这是什么?请参阅 <a href=\"https://1panel.cn/docs/dev_manual/api_manual/\" target=\"_blank\">https://1panel.cn/docs/dev_manual/api_manual/</a>", "access.form.1panel_api_key.tooltip": "这是什么?请参阅 <a href=\"https://1panel.cn/docs/dev_manual/api_manual/\" target=\"_blank\">https://1panel.cn/docs/dev_manual/api_manual/</a>",
"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": "服务端点", "access.form.acmehttpreq_endpoint.label": "服务端点",
"access.form.acmehttpreq_endpoint.placeholder": "请输入服务端点", "access.form.acmehttpreq_endpoint.placeholder": "请输入服务端点",
"access.form.acmehttpreq_endpoint.tooltip": "这是什么?请参阅 <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>", "access.form.acmehttpreq_endpoint.tooltip": "这是什么?请参阅 <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
@ -79,6 +83,10 @@
"access.form.baotapanel_api_key.label": "宝塔面板接口密钥", "access.form.baotapanel_api_key.label": "宝塔面板接口密钥",
"access.form.baotapanel_api_key.placeholder": "请输入宝塔面板接口密钥", "access.form.baotapanel_api_key.placeholder": "请输入宝塔面板接口密钥",
"access.form.baotapanel_api_key.tooltip": "这是什么?请参阅 <a href=\"https://www.bt.cn/bbs/thread-113890-1-1.html\" target=\"_blank\">https://www.bt.cn/bbs/thread-113890-1-1.html</a>", "access.form.baotapanel_api_key.tooltip": "这是什么?请参阅 <a href=\"https://www.bt.cn/bbs/thread-113890-1-1.html\" target=\"_blank\">https://www.bt.cn/bbs/thread-113890-1-1.html</a>",
"access.form.baotapanel_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.byteplus_access_key.label": "BytePlus AccessKey", "access.form.byteplus_access_key.label": "BytePlus AccessKey",
"access.form.byteplus_access_key.placeholder": "请输入 BytePlus AccessKey", "access.form.byteplus_access_key.placeholder": "请输入 BytePlus AccessKey",
"access.form.byteplus_access_key.tooltip": "这是什么?请参阅 <a href=\"https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys\" target=\"_blank\">https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys</a>", "access.form.byteplus_access_key.tooltip": "这是什么?请参阅 <a href=\"https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys\" target=\"_blank\">https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys</a>",
@ -200,6 +208,10 @@
"access.form.safeline_api_token.label": "雷池 API Token", "access.form.safeline_api_token.label": "雷池 API Token",
"access.form.safeline_api_token.placeholder": "请输入雷池 API Token", "access.form.safeline_api_token.placeholder": "请输入雷池 API Token",
"access.form.safeline_api_token.tooltip": "这是什么?请参阅 <a href=\"https://docs.waf-ce.chaitin.cn/zh/%E6%9B%B4%E5%A4%9A%E6%8A%80%E6%9C%AF%E6%96%87%E6%A1%A3/OPENAPI\" target=\"_blank\">https://docs.waf-ce.chaitin.cn/zh/更多技术文档/OPENAPI</a>", "access.form.safeline_api_token.tooltip": "这是什么?请参阅 <a href=\"https://docs.waf-ce.chaitin.cn/zh/%E6%9B%B4%E5%A4%9A%E6%8A%80%E6%9C%AF%E6%96%87%E6%A1%A3/OPENAPI\" target=\"_blank\">https://docs.waf-ce.chaitin.cn/zh/更多技术文档/OPENAPI</a>",
"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": "服务器地址", "access.form.ssh_host.label": "服务器地址",
"access.form.ssh_host.placeholder": "请输入服务器地址", "access.form.ssh_host.placeholder": "请输入服务器地址",
"access.form.ssh_port.label": "服务器端口", "access.form.ssh_port.label": "服务器端口",
@ -239,6 +251,10 @@
"access.form.volcengine_secret_access_key.tooltip": "这是什么?请参阅 <a href=\"https://www.volcengine.com/docs/6291/216571\" target=\"_blank\">https://www.volcengine.com/docs/6291/216571</a>", "access.form.volcengine_secret_access_key.tooltip": "这是什么?请参阅 <a href=\"https://www.volcengine.com/docs/6291/216571\" target=\"_blank\">https://www.volcengine.com/docs/6291/216571</a>",
"access.form.webhook_url.label": "Webhook 回调地址", "access.form.webhook_url.label": "Webhook 回调地址",
"access.form.webhook_url.placeholder": "请输入 Webhook 回调地址", "access.form.webhook_url.placeholder": "请输入 Webhook 回调地址",
"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.westcn_username.label": "西部数码用户名", "access.form.westcn_username.label": "西部数码用户名",
"access.form.westcn_username.placeholder": "请输入西部数码用户名", "access.form.westcn_username.placeholder": "请输入西部数码用户名",
"access.form.westcn_username.tooltip": "这是什么?请参阅 <a href=\"https://www.west.cn/CustomerCenter/doc/apiv2.html#12u3001u8eabu4efdu9a8cu8bc10a3ca20id3d12u3001u8eabu4efdu9a8cu8bc13e203ca3e\" target=\"_blank\">https://www.west.cn/CustomerCenter/doc/apiv2.html</a>", "access.form.westcn_username.tooltip": "这是什么?请参阅 <a href=\"https://www.west.cn/CustomerCenter/doc/apiv2.html#12u3001u8eabu4efdu9a8cu8bc10a3ca20id3d12u3001u8eabu4efdu9a8cu8bc13e203ca3e\" target=\"_blank\">https://www.west.cn/CustomerCenter/doc/apiv2.html</a>",

View File

@ -24,8 +24,8 @@
"settings.notification.template.form.message.placeholder": "请输入通知内容", "settings.notification.template.form.message.placeholder": "请输入通知内容",
"settings.notification.template.form.message.extra": "过期前 20 天发送通知。支持的变量(${COUNT}: 即将过期张数;${DOMAINS}: 域名列表)", "settings.notification.template.form.message.extra": "过期前 20 天发送通知。支持的变量(${COUNT}: 即将过期张数;${DOMAINS}: 域名列表)",
"settings.notification.channels.card.title": "通知渠道", "settings.notification.channels.card.title": "通知渠道",
"settings.notification.channel.enabled.on": "启用", "settings.notification.channel.switch.on": "启用",
"settings.notification.channel.enabled.off": "停用", "settings.notification.channel.switch.off": "停用",
"settings.notification.push_test.button": "推送测试消息", "settings.notification.push_test.button": "推送测试消息",
"settings.notification.push_test.pushed": "已推送", "settings.notification.push_test.pushed": "已推送",
"settings.notification.channel.form.bark_server_url.label": "服务器地址", "settings.notification.channel.form.bark_server_url.label": "服务器地址",
@ -44,7 +44,7 @@
"settings.notification.channel.form.email_smtp_host.placeholder": "请输入 SMTP 服务器地址", "settings.notification.channel.form.email_smtp_host.placeholder": "请输入 SMTP 服务器地址",
"settings.notification.channel.form.email_smtp_port.label": "SMTP 服务器端口", "settings.notification.channel.form.email_smtp_port.label": "SMTP 服务器端口",
"settings.notification.channel.form.email_smtp_port.placeholder": "请输入 SMTP 服务器端口", "settings.notification.channel.form.email_smtp_port.placeholder": "请输入 SMTP 服务器端口",
"settings.notification.channel.form.email_smtp_tls.label": "TLS/SSL 连接", "settings.notification.channel.form.email_smtp_tls.label": "SSL/TLS 连接",
"settings.notification.channel.form.email_username.label": "用户名", "settings.notification.channel.form.email_username.label": "用户名",
"settings.notification.channel.form.email_username.placeholder": "请输入用户名", "settings.notification.channel.form.email_username.placeholder": "请输入用户名",
"settings.notification.channel.form.email_password.label": "密码", "settings.notification.channel.form.email_password.label": "密码",

View File

@ -533,8 +533,8 @@
"workflow_node.deploy.form.skip_on_last_succeeded.label": "重复部署", "workflow_node.deploy.form.skip_on_last_succeeded.label": "重复部署",
"workflow_node.deploy.form.skip_on_last_succeeded.prefix": "当上次部署已成功时", "workflow_node.deploy.form.skip_on_last_succeeded.prefix": "当上次部署已成功时",
"workflow_node.deploy.form.skip_on_last_succeeded.suffix": "重新部署。", "workflow_node.deploy.form.skip_on_last_succeeded.suffix": "重新部署。",
"workflow_node.deploy.form.skip_on_last_succeeded.enabled.on": "跳过", "workflow_node.deploy.form.skip_on_last_succeeded.switch.on": "跳过",
"workflow_node.deploy.form.skip_on_last_succeeded.enabled.off": "不跳过", "workflow_node.deploy.form.skip_on_last_succeeded.switch.off": "不跳过",
"workflow_node.notify.label": "通知", "workflow_node.notify.label": "通知",
"workflow_node.notify.form.subject.label": "通知主题", "workflow_node.notify.form.subject.label": "通知主题",