【调整】暗色主题样式

This commit is contained in:
cai
2025-12-12 17:39:52 +08:00
parent 13669666e4
commit d01b42139c
1199 changed files with 203816 additions and 4592 deletions

View File

@@ -0,0 +1,808 @@
package apply
import (
"ALLinSSL/backend/internal/access"
"ALLinSSL/backend/internal/cert"
"ALLinSSL/backend/internal/cert/apply/lego/bt"
"ALLinSSL/backend/internal/cert/apply/lego/jdcloud"
"ALLinSSL/backend/internal/cert/apply/lego/webhook"
"ALLinSSL/backend/public"
"crypto/tls"
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
azcorecloud "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/certificate"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/lego"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/providers/dns/alidns"
"github.com/go-acme/lego/v4/providers/dns/azuredns"
"github.com/go-acme/lego/v4/providers/dns/baiducloud"
"github.com/go-acme/lego/v4/providers/dns/bunny"
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
"github.com/go-acme/lego/v4/providers/dns/cloudns"
"github.com/go-acme/lego/v4/providers/dns/constellix"
"github.com/go-acme/lego/v4/providers/dns/gcore"
"github.com/go-acme/lego/v4/providers/dns/godaddy"
"github.com/go-acme/lego/v4/providers/dns/huaweicloud"
"github.com/go-acme/lego/v4/providers/dns/namecheap"
"github.com/go-acme/lego/v4/providers/dns/namedotcom"
"github.com/go-acme/lego/v4/providers/dns/namesilo"
"github.com/go-acme/lego/v4/providers/dns/ns1"
"github.com/go-acme/lego/v4/providers/dns/rainyun"
"github.com/go-acme/lego/v4/providers/dns/route53"
"github.com/go-acme/lego/v4/providers/dns/spaceship"
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
"github.com/go-acme/lego/v4/providers/dns/volcengine"
"github.com/go-acme/lego/v4/providers/dns/westcn"
"github.com/go-acme/lego/v4/registration"
)
var AlgorithmMap = map[string]certcrypto.KeyType{
"RSA2048": certcrypto.RSA2048,
"RSA3072": certcrypto.RSA3072,
"RSA4096": certcrypto.RSA4096,
"RSA8192": certcrypto.RSA8192,
"EC256": certcrypto.EC256,
"EC384": certcrypto.EC384,
}
var CADirURLMap = map[string]string{
"Let's Encrypt": "https://acme-v02.api.letsencrypt.org/directory",
"zerossl": "https://acme.zerossl.com/v2/DV90",
"google": "https://dv.acme-v02.api.pki.goog/directory",
"sslcom": "https://acme.ssl.com/sslcom-dv-rsa",
"sslcom-rsa": "https://acme.ssl.com/sslcom-dv-rsa",
"sslcom-ecc": "https://acme.ssl.com/sslcom-dv-ecc",
"buypass": "https://api.buypass.com/acme/directory",
}
func GetSqlite() (*public.Sqlite, error) {
s, err := public.NewSqlite("data/accounts.db", "")
if err != nil {
return nil, err
}
s.TableName = "accounts"
return s, nil
}
func GetDNSProvider(providerName string, creds map[string]string, httpClient *http.Client, maxWait time.Duration) (challenge.Provider, error) {
switch providerName {
case "tencentcloud":
config := tencentcloud.NewDefaultConfig()
config.SecretID = creds["secret_id"]
config.SecretKey = creds["secret_key"]
config.PropagationTimeout = maxWait
return tencentcloud.NewDNSProviderConfig(config)
case "cloudflare":
config := cloudflare.NewDefaultConfig()
if creds["email"] == "" {
config.AuthToken = creds["api_key"]
} else {
config.AuthEmail = creds["email"]
config.AuthKey = creds["api_key"]
}
config.PropagationTimeout = maxWait
return cloudflare.NewDNSProviderConfig(config)
case "aliyun":
config := alidns.NewDefaultConfig()
config.APIKey = creds["access_key_id"]
config.SecretKey = creds["access_key_secret"]
config.PropagationTimeout = maxWait
return alidns.NewDNSProviderConfig(config)
case "huaweicloud":
config := huaweicloud.NewDefaultConfig()
config.AccessKeyID = creds["access_key"]
config.SecretAccessKey = creds["secret_key"]
// 不传会报错
config.Region = "cn-north-1"
config.PropagationTimeout = maxWait
return huaweicloud.NewDNSProviderConfig(config)
case "baidu":
config := baiducloud.NewDefaultConfig()
config.AccessKeyID = creds["access_key"]
config.SecretAccessKey = creds["secret_key"]
config.PropagationTimeout = maxWait
return baiducloud.NewDNSProviderConfig(config)
case "westcn":
config := westcn.NewDefaultConfig()
config.Username = creds["username"]
config.Password = creds["password"]
config.PropagationTimeout = maxWait
return westcn.NewDNSProviderConfig(config)
case "volcengine":
config := volcengine.NewDefaultConfig()
config.AccessKey = creds["access_key"]
config.SecretKey = creds["secret_key"]
config.PropagationTimeout = maxWait
return volcengine.NewDNSProviderConfig(config)
case "godaddy":
config := godaddy.NewDefaultConfig()
config.APIKey = creds["api_key"]
config.APISecret = creds["api_secret"]
if httpClient != nil {
config.HTTPClient = httpClient
}
config.PropagationTimeout = maxWait
return godaddy.NewDNSProviderConfig(config)
case "namecheap":
config := namecheap.NewDefaultConfig()
config.APIUser = creds["api_user"]
config.APIKey = creds["api_key"]
config.PropagationTimeout = maxWait
return namecheap.NewDNSProviderConfig(config)
case "ns1":
config := ns1.NewDefaultConfig()
config.APIKey = creds["api_key"]
config.PropagationTimeout = maxWait
return ns1.NewDNSProviderConfig(config)
case "cloudns":
config := cloudns.NewDefaultConfig()
config.AuthID = creds["auth_id"]
config.AuthPassword = creds["auth_password"]
config.PropagationTimeout = maxWait
return cloudns.NewDNSProviderConfig(config)
case "aws":
config := route53.NewDefaultConfig()
config.AccessKeyID = creds["access_key_id"]
config.SecretAccessKey = creds["secret_access_key"]
config.Region = creds["region"]
config.PropagationTimeout = maxWait
return route53.NewDNSProviderConfig(config)
case "azure":
config := azuredns.NewDefaultConfig()
config.TenantID = creds["tenant_id"]
config.ClientID = creds["client_id"]
config.ClientSecret = creds["client_secret"]
switch strings.ToLower(creds["environment"]) {
case "", "default", "public", "azurecloud":
config.Environment = azcorecloud.AzurePublic
case "china", "chinacloud", "azurechina", "azurechinacloud":
config.Environment = azcorecloud.AzureChina
case "usgovernment", "government", "azureusgovernment", "azuregovernment":
config.Environment = azcorecloud.AzureGovernment
default:
return nil, fmt.Errorf("不支持的 Azure 环境: %s", creds["environment"])
}
config.PropagationTimeout = maxWait
return azuredns.NewDNSProviderConfig(config)
case "namesilo":
config := namesilo.NewDefaultConfig()
config.APIKey = creds["api_key"]
config.PropagationTimeout = maxWait
return namesilo.NewDNSProviderConfig(config)
case "namedotcom":
config := namedotcom.NewDefaultConfig()
config.Username = creds["username"]
config.APIToken = creds["api_token"]
config.PropagationTimeout = maxWait
return namedotcom.NewDNSProviderConfig(config)
case "bunny":
config := bunny.NewDefaultConfig()
config.APIKey = creds["api_key"]
config.PropagationTimeout = maxWait
return bunny.NewDNSProviderConfig(config)
case "gcore":
config := gcore.NewDefaultConfig()
config.APIToken = creds["api_token"]
config.PropagationTimeout = maxWait
return gcore.NewDNSProviderConfig(config)
case "jdcloud":
config := jdcloud.NewDefaultConfig()
config.AccessKeyID = creds["access_key_id"]
config.AccessKeySecret = creds["secret_access_key"]
config.RegionId = "cn-north-1"
config.PropagationTimeout = maxWait
return jdcloud.NewDNSProviderConfig(config)
case "constellix":
config := constellix.NewDefaultConfig()
config.APIKey = creds["api_key"]
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)
case "spaceship":
config := spaceship.NewDefaultConfig()
config.APIKey = creds["api_key"]
config.APISecret = creds["api_secret"]
config.PropagationTimeout = maxWait
return spaceship.NewDNSProviderConfig(config)
case "rainyun":
config := rainyun.NewDefaultConfig()
config.APIKey = creds["api_key"]
config.PropagationTimeout = maxWait
return rainyun.NewDNSProviderConfig(config)
case "btdomain":
config := bt.NewDefaultConfig()
config.AccountID = creds["account_id"]
config.AccessKey = creds["access_key"]
config.SecretKey = creds["secret_key"]
if creds["base_url"] != "" {
config.BaseURL = creds["base_url"]
}
config.PropagationTimeout = maxWait
return bt.NewDNSProviderConfig(config)
//case "edgeone":
//config :=
default:
return nil, fmt.Errorf("不支持的 DNS Provider: %s", providerName)
}
}
func GetZeroSSLEabFromEmail(email string, httpClient *http.Client) (map[string]any, error) {
APIPath := "https://api.zerossl.com/acme/eab-credentials-email"
data := map[string]any{
"email": email,
}
jsonData, err := json.Marshal(data)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", APIPath, strings.NewReader(string(jsonData)))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
if httpClient == nil {
httpClient = &http.Client{}
}
resp, err := httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("获取ZeroSSL EAB信息失败状态码%d", resp.StatusCode)
}
var result map[string]any
err = json.NewDecoder(resp.Body).Decode(&result)
if err != nil {
return nil, fmt.Errorf("解析ZeroSSL EAB信息失败%v", err)
}
if result["eab_kid"] == nil || result["eab_hmac_key"] == nil {
return nil, fmt.Errorf("ZeroSSL EAB信息不完整缺少kid或hmacEncoded")
}
return map[string]any{
"Kid": result["eab_kid"],
"HmacEncoded": result["eab_hmac_key"],
}, nil
}
func getEABFromAccData(accData map[string]any, eabData *map[string]any) bool {
if accData == nil {
return false
}
kid := accData["Kid"]
hmac := accData["HmacEncoded"]
if kid != nil && hmac != nil {
*eabData = map[string]any{
"Kid": kid,
"HmacEncoded": hmac,
}
return true
}
return false
}
func GetAcmeClient(email, algorithm, eabId, ca string, httpClient *http.Client, logger *public.Logger) (*lego.Client, error) {
var (
eabData map[string]any
err error
)
switch eabId {
case "":
if ca == "" || ca == "letsencrypt" {
ca = "Let's Encrypt"
}
case "let":
ca = "Let's Encrypt"
case "buy", "buypass":
ca = "buypass"
default:
eabData, err = access.GetEAB(eabId)
if err != nil {
return nil, err
}
if eabData == nil {
return nil, fmt.Errorf("未找到EAB信息")
}
if eabData["Kid"] == nil {
return nil, fmt.Errorf("Kid不能为空")
}
if eabData["HmacEncoded"] == nil {
return nil, fmt.Errorf("HmacEncoded不能为空")
}
ca = eabData["ca"].(string)
}
CADirURL := CADirURLMap[ca]
if ca == "sslcom" {
if algorithm == "EC256" || algorithm == "EC384" {
CADirURL = CADirURLMap["sslcom-ecc"]
} else {
CADirURL = CADirURLMap["sslcom-rsa"]
}
}
db, err := GetSqlite()
var accData map[string]any
if err != nil {
logger.Debug("获取数据库连接失败", err)
if ca != "Let's Encrypt" && ca != "zerossl" && ca != "buypass" {
return nil, fmt.Errorf("当前CA【%s】 需要从数据库获取预设账号但是连接数据库失败请稍后重试err:%w", ca, err)
}
} else {
defer db.Close()
accData, err = GetAccount(db, email, ca)
if err != nil || accData == nil {
logger.Debug("获取acme账号信息失败")
if ca != "Let's Encrypt" && ca != "zerossl" && ca != "buypass" {
return nil, fmt.Errorf("未找到%s账号信息请先在账号管理中添加%s账号, email:%s", ca, ca, email)
}
}
if CADirURL == "" {
accCADirURL, ok := accData["CADirURL"].(string)
if !ok || accCADirURL == "" {
logger.Debug("未找到此CA的请求地址")
return nil, fmt.Errorf("未找到CA【%s】请求地址请先在账号管理中检查%s账号, email:%s", ca, ca, email)
}
CADirURL = accCADirURL
}
}
user := GetAcmeUser(email, logger, accData)
config := lego.NewConfig(user)
config.Certificate.KeyType = AlgorithmMap[algorithm]
config.CADirURL = CADirURL
if httpClient != nil {
config.HTTPClient = httpClient
}
client, err := lego.NewClient(config)
if err != nil {
return nil, err
}
if user.Registration == nil {
logger.Debug("正在注册账号:" + email)
if eabData == nil {
// 走新的逻辑eab已合并到账号中
if !getEABFromAccData(accData, &eabData) {
switch ca {
case "zerossl":
eabData, err = GetZeroSSLEabFromEmail(email, httpClient)
if err != nil {
return nil, fmt.Errorf("获取ZeroSSL EAB信息失败: %v", err)
}
case "sslcom", "google":
return nil, fmt.Errorf("未找到EAB信息请在账号管理中添加%s账号", ca)
}
}
}
var (
reg *registration.Resource
Kid, HmacEncoded string
)
if eabData != nil {
Kid = eabData["Kid"].(string)
HmacEncoded = eabData["HmacEncoded"].(string)
}
if Kid != "" && HmacEncoded != "" {
Kid := eabData["Kid"].(string)
HmacEncoded := eabData["HmacEncoded"].(string)
reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
TermsOfServiceAgreed: true,
Kid: Kid,
HmacEncoded: HmacEncoded,
})
} else {
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
}
if err != nil {
return nil, err
}
user.Registration = reg
err = SaveUserToDB(db, user, ca)
if err != nil {
logger.Debug("acme账号注册成功但保存到数据库失败", err)
}
logger.Debug("acme账号注册并保存成功")
}
return client, nil
}
func GetCert(runId string, domainArr []string, endDay int, logger *public.Logger) (map[string]any, error) {
if runId == "" {
return nil, fmt.Errorf("参数错误_runId")
}
s, err := public.NewSqlite("data/data.db", "")
if err != nil {
return nil, err
}
s.TableName = "workflow_history"
defer s.Close()
// 查询 workflowId
wh, err := s.Where("id=?", []interface{}{runId}).Select()
if err != nil {
return nil, err
}
if len(wh) <= 0 {
return nil, fmt.Errorf("未获取到对应的workflowId")
}
s.TableName = "cert"
certs, err := s.Where("workflow_id=?", []interface{}{wh[0]["workflow_id"]}).Select()
if err != nil {
return nil, err
}
if len(certs) <= 0 {
return nil, fmt.Errorf("未获取到当前工作流下的证书")
}
layout := "2006-01-02 15:04:05"
var maxDays float64
var maxItem map[string]any
for i := range certs {
if !public.ContainsAllIgnoreBRepeats(strings.Split(certs[i]["domains"].(string), ","), domainArr) {
continue
}
endTimeStr, ok := certs[i]["end_time"].(string)
if !ok {
continue
}
endTime, err := time.Parse(layout, endTimeStr)
if err != nil {
continue
}
diff := endTime.Sub(time.Now()).Hours() / 24
if diff > maxDays {
maxDays = diff
maxItem = certs[i]
}
}
if maxItem == nil {
return nil, fmt.Errorf("未获取到对应的证书")
}
if int(maxDays) <= endDay {
return nil, fmt.Errorf("证书已过期或即将过期,剩余天数:%d 小于%d天", int(maxDays), endDay)
}
// 证书未过期,直接返回
logger.Debug(fmt.Sprintf("上次证书申请成功,域名:%s剩余天数%d 大于%d天已跳过申请复用此证书", maxItem["domains"], int(maxDays), endDay))
return map[string]any{
"cert": maxItem["cert"],
"key": maxItem["key"],
"issuerCert": maxItem["issuer_cert"],
"skip": true,
}, nil
}
func Apply(cfg map[string]any, logger *public.Logger) (map[string]any, error) {
log.Logger = logger.GetLogger()
var err error
email, ok := cfg["email"].(string)
if !ok {
return nil, fmt.Errorf("参数错误email")
}
domains, ok := cfg["domains"].(string)
if !ok {
return nil, fmt.Errorf("参数错误domains")
}
providerStr, ok := cfg["provider"].(string)
if !ok {
return nil, fmt.Errorf("参数错误provider")
}
endDay := 30
switch v := cfg["end_day"].(type) {
case float64:
endDay = int(v)
case int:
endDay = v
case string:
if v != "" {
endDay, err = strconv.Atoi(v)
if err != nil {
return nil, fmt.Errorf("参数错误end_day")
}
}
case int64:
endDay = int(v)
}
algorithm, ok := cfg["algorithm"].(string)
if !ok {
algorithm = "RSA2048"
}
var httpClient *http.Client
proxy, ok := cfg["proxy"].(string)
if ok && proxy != "" {
// 构建代理 HTTP 客户端
proxyURL, err := url.Parse(proxy) // 替换为你的代理地址
if err != nil {
return nil, fmt.Errorf("无效的代理地址: %v", err)
}
httpClient = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
},
Timeout: 30 * time.Second,
}
}
var eabId string
switch v := cfg["eabId"].(type) {
case float64:
eabId = strconv.Itoa(int(v))
case string:
eabId = v
default:
eabId = ""
}
ca, ok := cfg["ca"].(string)
if !ok {
ca = ""
}
var providerID string
switch v := cfg["provider_id"].(type) {
case float64:
providerID = strconv.Itoa(int(v))
case string:
providerID = v
default:
return nil, fmt.Errorf("参数错误provider_id")
}
var NameServers []string
if cfg["name_server"] == nil {
NameServers = []string{
"8.8.8.8:53",
"1.1.1.1:53",
}
} else {
if nameServerStr, ok := cfg["name_server"].(string); ok {
NameServers = strings.Split(nameServerStr, ",")
for i := range NameServers {
NameServers[i] = strings.TrimSpace(NameServers[i])
}
} else {
return nil, fmt.Errorf("参数错误name_server")
}
}
var skipCheck bool
if cfg["skip_check"] == nil {
// 默认跳过预检查
skipCheck = false
} else {
switch v := cfg["skip_check"].(type) {
case int:
if v > 0 {
skipCheck = true
} else {
skipCheck = false
}
case float64:
if v > 0 {
skipCheck = true
} else {
skipCheck = false
}
case string:
if v == "true" || v == "1" {
skipCheck = true
} else {
skipCheck = false
}
case bool:
skipCheck = v
default:
return nil, fmt.Errorf("参数错误skip_check")
}
}
var ignoreCheck bool
if cfg["ignore_check"] == nil {
// 默认不忽略预检查
ignoreCheck = false
} else {
switch v := cfg["ignore_check"].(type) {
case int:
if v > 0 {
ignoreCheck = true
} else {
ignoreCheck = false
}
case float64:
if v > 0 {
ignoreCheck = true
} else {
ignoreCheck = false
}
case string:
if v == "true" || v == "1" {
ignoreCheck = true
} else {
ignoreCheck = false
}
case bool:
ignoreCheck = v
default:
return nil, fmt.Errorf("参数错误ignore_check")
}
}
var closeCname bool
if cfg["close_cname"] == nil {
// 默认开启CNAME跟随
closeCname = false
} else {
switch v := cfg["close_cname"].(type) {
case int:
if v > 0 {
closeCname = true
} else {
closeCname = false
}
case float64:
if v > 0 {
closeCname = true
} else {
closeCname = false
}
case string:
if v == "true" || v == "1" {
closeCname = true
} else {
closeCname = false
}
case bool:
closeCname = v
default:
return nil, fmt.Errorf("参数错误close_cname")
}
}
var maxWait time.Duration
if cfg["max_wait"] == nil {
// 默认最大等待时间为2分钟
maxWait = 2 * time.Minute
} else {
switch v := cfg["max_wait"].(type) {
case int:
maxWait = time.Duration(v) * time.Second
case float64:
maxWait = time.Duration(v) * time.Second
case string:
maxWait = 2 * time.Minute // 默认值
if v != "" {
d, err := strconv.Atoi(v)
if err == nil {
maxWait = time.Duration(d) * time.Second
}
}
default:
maxWait = 2 * time.Minute
}
}
domainArr := strings.Split(domains, ",")
for i := range domainArr {
domainArr[i] = strings.TrimSpace(domainArr[i])
}
// 获取上次申请的证书
runId, ok := cfg["_runId"].(string)
if !ok {
return nil, fmt.Errorf("参数错误_runId")
}
certData, err := GetCert(runId, domainArr, endDay, logger)
if err != nil {
logger.Debug("未获取到符合条件的本地证书:" + err.Error())
} else {
return certData, nil
}
logger.Debug("正在申请证书,域名: " + domains)
os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", strconv.FormatBool(closeCname))
// 创建 ACME 客户端
client, err := GetAcmeClient(email, algorithm, eabId, ca, httpClient, logger)
if err != nil {
return nil, err
}
// 获取 DNS 验证提供者
providerData, err := access.GetAccess(providerID)
if err != nil {
return nil, err
}
providerConfigStr, ok := providerData["config"].(string)
if !ok {
return nil, fmt.Errorf("api配置错误")
}
// 解析 JSON 配置
var providerConfig map[string]string
err = json.Unmarshal([]byte(providerConfigStr), &providerConfig)
if err != nil {
return nil, err
}
// DNS 验证
provider, err := GetDNSProvider(providerStr, providerConfig, httpClient, maxWait)
if err != nil {
return nil, fmt.Errorf("创建 DNS provider 失败: %v", err)
}
if skipCheck {
// 跳过预检查
err = client.Challenge.SetDNS01Provider(provider,
dns01.WrapPreCheck(func(domain, fqdn, value string, check dns01.PreCheckFunc) (bool, error) {
return true, nil
}),
)
} else {
start := time.Now()
if ignoreCheck {
err = client.Challenge.SetDNS01Provider(provider,
dns01.AddRecursiveNameservers(NameServers),
dns01.WrapPreCheck(func(domain, fqdn, value string, check dns01.PreCheckFunc) (bool, error) {
ok, err := check(fqdn, value)
elapsed := time.Since(start)
if err != nil {
log.Printf("[WARN] DNS precheck error for %s: %v", fqdn, err)
if elapsed >= maxWait {
log.Printf("[WARN] Precheck error but forcing continue due to timeout for %s", fqdn)
return true, nil
}
return false, nil
}
if ok {
log.Printf("[OK] TXT record for %s is present.", fqdn)
return true, nil
}
if elapsed >= maxWait {
log.Printf("[WARN] TXT record for %s not found after %v, forcing continue.", fqdn, elapsed)
return true, nil
}
log.Printf("[INFO] TXT record for %s not yet found, waiting... elapsed %v", fqdn, elapsed)
return false, nil
}),
)
} else {
err = client.Challenge.SetDNS01Provider(provider,
dns01.AddRecursiveNameservers(NameServers),
)
}
}
if err != nil {
return nil, err
}
// fmt.Println(strings.Split(domains, ","))
request := certificate.ObtainRequest{
Domains: domainArr,
Bundle: true,
}
certObj, err := client.Certificate.Obtain(request)
if err != nil {
return nil, err
}
certStr := string(certObj.Certificate)
keyStr := string(certObj.PrivateKey)
issuerCertStr := string(certObj.IssuerCertificate)
// 保存证书和私钥
data := map[string]any{
"cert": certStr,
"key": keyStr,
"issuerCert": issuerCertStr,
}
_, err = cert.SaveCert("workflow", keyStr, certStr, issuerCertStr, runId)
if err != nil {
return nil, err
}
return data, nil
}