【修复】长期持有tcp连接未关闭

【新增】支持通过webhook调用自己的服务解析dns记录
【新增】支持通过webhook推送证书和密钥
【新增】导入导出工作流、通知、证书、api授权数据
【新增】支持自定义插件目录
This commit is contained in:
v-me-50
2025-08-14 16:41:29 +08:00
parent e939724f37
commit 6d0732fc31
16 changed files with 377 additions and 42 deletions

View File

@@ -4,7 +4,9 @@ import (
"ALLinSSL/backend/internal/access"
"ALLinSSL/backend/internal/cert"
"ALLinSSL/backend/internal/cert/apply/lego/jdcloud"
"ALLinSSL/backend/internal/cert/apply/lego/webhook"
"ALLinSSL/backend/public"
"crypto/tls"
"encoding/json"
"fmt"
azcorecloud "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
@@ -202,6 +204,10 @@ func GetDNSProvider(providerName string, creds map[string]string, httpClient *ht
config.SecretKey = creds["secret_key"]
config.PropagationTimeout = maxWait
return constellix.NewDNSProviderConfig(config)
case "webhook":
config := webhook.NewConfig(creds)
config.PropagationTimeout = maxWait
return webhook.NewDNSProviderConfig(config)
default:
return nil, fmt.Errorf("不支持的 DNS Provider: %s", providerName)
@@ -495,7 +501,9 @@ func Apply(cfg map[string]any, logger *public.Logger) (map[string]any, error) {
}
httpClient = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
},
Timeout: 30 * time.Second,
}

View File

@@ -0,0 +1,77 @@
package webhook
import (
"ALLinSSL/backend/public"
"fmt"
"github.com/go-acme/lego/v4/challenge/dns01"
"time"
)
var configData string
type Config struct {
WebhookConfig *public.WebhookConfig
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
HTTPTimeout time.Duration
}
type DNSProvider struct {
config *Config
}
func NewConfig(WebhookConfigStr map[string]string) *Config {
fmt.Println(WebhookConfigStr)
WebhookConfig := &public.WebhookConfig{
Url: WebhookConfigStr["url"],
Data: WebhookConfigStr["data"],
Method: WebhookConfigStr["method"],
Headers: WebhookConfigStr["headers"],
IgnoreSSL: WebhookConfigStr["ignore_ssl"] == "true",
}
fmt.Println(WebhookConfig.Url)
return &Config{
WebhookConfig: WebhookConfig,
TTL: 600,
PropagationTimeout: dns01.DefaultPropagationTimeout,
PollingInterval: dns01.DefaultPollingInterval,
HTTPTimeout: 30 * time.Second,
}
}
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config == nil {
return nil, fmt.Errorf("配置不能为空")
}
return &DNSProvider{config: config}, nil
}
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval
}
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fmt.Println(d.config.WebhookConfig.Url)
configData = d.config.WebhookConfig.Data
return d.send(domain, token, keyAuth, "present")
}
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.config.WebhookConfig.Data = configData
return d.send(domain, token, keyAuth, "cleanup")
}
func (d *DNSProvider) send(domain, token, keyAuth, action string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
data, err := public.ReplaceJSONPlaceholders(d.config.WebhookConfig.Data, map[string]interface{}{"domain": info.EffectiveFQDN, "token": token, "keyAuth": info.Value, "action": action})
if err != nil {
return fmt.Errorf("替换JSON占位符失败: %w", err)
}
d.config.WebhookConfig.Data = data
return d.config.WebhookConfig.Send()
}

View File

@@ -91,7 +91,8 @@ func Request1panel(data *map[string]any, method, providerID, requestUrl string)
ignoreSsl = true
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
DisableKeepAlives: true,
}
client := &http.Client{Transport: tr}
@@ -269,7 +270,7 @@ func OnePanelSiteList(providerID string) ([]response.AccessSiteList, error) {
if err != nil {
return nil, fmt.Errorf("获取网站列表失败 %v", err)
}
var result []response.AccessSiteList
sites, ok := siteList["data"].(map[string]any)["items"].([]any)
if !ok {

View File

@@ -65,7 +65,8 @@ func RequestBt(data *url.Values, method, providerID, requestUrl string) (map[str
ignoreSsl = true
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
DisableKeepAlives: true,
}
client := &http.Client{Transport: tr}

View File

@@ -65,7 +65,8 @@ func RequestBtWaf(data *map[string]any, method, providerID, requestUrl string) (
ignoreSsl = true
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
DisableKeepAlives: true,
}
client := &http.Client{Transport: tr}
@@ -207,4 +208,4 @@ func BtWafAPITest(providerID string) error {
return fmt.Errorf("测试请求失败: %v", err)
}
return nil
}
}

View File

@@ -5,6 +5,7 @@ import (
"ALLinSSL/backend/internal/cert/deploy/doge"
"ALLinSSL/backend/internal/cert/deploy/lecdn"
"ALLinSSL/backend/internal/cert/deploy/plugin"
"ALLinSSL/backend/internal/cert/deploy/webhook"
"ALLinSSL/backend/public"
"fmt"
)
@@ -106,6 +107,9 @@ func Deploy(cfg map[string]any, logger *public.Logger) error {
case "plugin":
logger.Debug("使用插件部署...")
return plugin.Deploy(cfg, logger)
case "webhook":
logger.Debug("通过Webhook推送证书...")
return webhook.Deploy(cfg)
default:
return fmt.Errorf("不支持的部署: %s", providerName)
}

View File

@@ -53,7 +53,8 @@ func requestLecdn(url, method, token string, params map[string]any, ignoreSsl bo
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
DisableKeepAlives: true,
},
}

View File

@@ -50,7 +50,8 @@ func RequestSafeLineWaf(data *map[string]any, method, providerID, requestUrl str
ignoreSsl = true
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
DisableKeepAlives: true,
}
client := &http.Client{Transport: tr}
@@ -211,4 +212,4 @@ func SafeLineAPITest(providerID string) error {
return fmt.Errorf("测试请求失败: %v", err)
}
return nil
}
}

View File

@@ -0,0 +1,57 @@
package webhook
import (
"ALLinSSL/backend/internal/access"
"ALLinSSL/backend/public"
"encoding/json"
"fmt"
"strconv"
)
func Deploy(cfg map[string]any) error {
cert, ok := cfg["certificate"].(map[string]any)
if !ok {
return fmt.Errorf("证书不存在")
}
var providerID string
switch v := cfg["provider_id"].(type) {
case float64:
providerID = strconv.Itoa(int(v))
case string:
providerID = v
default:
return fmt.Errorf("参数错误provider_id")
}
//
providerData, err := access.GetAccess(providerID)
if err != nil {
return err
}
providerConfigStr, ok := providerData["config"].(string)
if !ok {
return fmt.Errorf("api配置错误")
}
// 解析 JSON 配置
var providerConfig public.WebhookConfig
err = json.Unmarshal([]byte(providerConfigStr), &providerConfig)
if err != nil {
return err
}
certStr, ok := cert["cert"].(string)
if !ok || certStr == "" {
return fmt.Errorf("cert is required and must be a string")
}
keyStr, ok := cert["key"].(string)
if !ok || keyStr == "" {
return fmt.Errorf("key is required and must be a string")
}
data, err := public.ReplaceJSONPlaceholders(providerConfig.Data, map[string]interface{}{"key": keyStr, "cert": certStr})
if err != nil {
return fmt.Errorf("替换JSON占位符失败: %w", err)
}
providerConfig.Data = data
return providerConfig.Send()
}