feat: Refactor manual mode certificate application to increase succes rate (#8799)

This commit is contained in:
CityFun 2025-05-23 18:52:13 +08:00 committed by GitHub
parent 9d692b76bf
commit 61ef754a1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 443 additions and 230 deletions

View file

@ -30,8 +30,8 @@ type WebsiteSSLCreate struct {
}
type WebsiteDNSReq struct {
Domains []string `json:"domains" validate:"required"`
AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
WebsiteSSLID uint `json:"websiteSSLId" validate:"required"`
}
type WebsiteSSLRenew struct {
@ -45,6 +45,11 @@ type WebsiteSSLApply struct {
DisableLog bool `json:"disableLog"`
}
type WebsiteSSLObtain struct {
ID uint `json:"ID" validate:"required"`
TXTRecords map[string]string
}
type WebsiteAcmeAccountCreate struct {
Email string `json:"email" validate:"required"`
Type string `json:"type" validate:"required,oneof=letsencrypt zerossl buypass google custom"`

View file

@ -2,10 +2,10 @@ package service
import (
"context"
"crypto"
"crypto/x509"
"encoding/pem"
"fmt"
"github.com/go-acme/lego/v4/certificate"
"log"
"os"
"path"
@ -26,7 +26,6 @@ import (
"github.com/1Panel-dev/1Panel/agent/utils/files"
"github.com/1Panel-dev/1Panel/agent/utils/req_helper"
"github.com/1Panel-dev/1Panel/agent/utils/ssl"
"github.com/go-acme/lego/v4/certcrypto"
legoLogger "github.com/go-acme/lego/v4/log"
"github.com/jinzhu/gorm"
)
@ -230,10 +229,13 @@ func reloadSystemSSL(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
var (
err error
websiteSSL *model.WebsiteSSL
acmeAccount *model.WebsiteAcmeAccount
dnsAccount *model.WebsiteDnsAccount
err error
websiteSSL *model.WebsiteSSL
acmeAccount *model.WebsiteAcmeAccount
dnsAccount *model.WebsiteDnsAccount
client *ssl.AcmeClient
manualClient *ssl.ManualClient
resource certificate.Resource
)
websiteSSL, err = websiteSSLRepo.GetFirst(repo.WithByID(apply.ID))
@ -244,75 +246,43 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
if err != nil {
return err
}
client, err := ssl.NewAcmeClient(acmeAccount, getSystemProxy(acmeAccount.UseProxy))
if err != nil {
return err
}
domains := []string{websiteSSL.PrimaryDomain}
if websiteSSL.Domains != "" {
domains = append(domains, strings.Split(websiteSSL.Domains, ",")...)
}
if websiteSSL.Provider != constant.DnsManual {
client, err = ssl.NewAcmeClient(acmeAccount, getSystemProxy(acmeAccount.UseProxy))
if err != nil {
return err
}
switch websiteSSL.Provider {
case constant.DNSAccount:
dnsAccount, err = websiteDnsRepo.GetFirst(repo.WithByID(websiteSSL.DnsAccountID))
if err != nil {
return err
}
if err = client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization, *websiteSSL); err != nil {
return err
}
case constant.Http:
appInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
if gorm.IsRecordNotFoundError(err) {
return buserr.New("ErrOpenrestyNotFound")
switch websiteSSL.Provider {
case constant.DNSAccount:
dnsAccount, err = websiteDnsRepo.GetFirst(repo.WithByID(websiteSSL.DnsAccountID))
if err != nil {
return err
}
return err
}
for _, domain := range domains {
if strings.Contains(domain, "*") {
return buserr.New("ErrWildcardDomain")
if err = client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization, *websiteSSL); err != nil {
return err
}
case constant.Http:
appInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
if gorm.IsRecordNotFoundError(err) {
return buserr.New("ErrOpenrestyNotFound")
}
return err
}
for _, domain := range domains {
if strings.Contains(domain, "*") {
return buserr.New("ErrWildcardDomain")
}
}
if err := client.UseHTTP(path.Join(appInstall.GetPath(), "root")); err != nil {
return err
}
}
if err := client.UseHTTP(path.Join(appInstall.GetPath(), "root")); err != nil {
return err
}
case constant.DnsManual:
if err := client.UseManualDns(*websiteSSL); err != nil {
return err
}
}
var privateKey crypto.PrivateKey
if websiteSSL.PrivateKey == "" {
privateKey, err = certcrypto.GeneratePrivateKey(ssl.KeyType(websiteSSL.KeyType))
if err != nil {
return err
}
} else {
block, _ := pem.Decode([]byte(websiteSSL.PrivateKey))
if block == nil {
return buserr.New("invalid PEM block")
}
var privKey crypto.PrivateKey
keyType := ssl.KeyType(websiteSSL.KeyType)
switch keyType {
case certcrypto.EC256, certcrypto.EC384:
privKey, err = x509.ParseECPrivateKey(block.Bytes)
if err != nil {
return nil
}
case certcrypto.RSA2048, certcrypto.RSA3072, certcrypto.RSA4096:
privKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil
}
}
privateKey = privKey
}
websiteSSL.Status = constant.SSLApply
err = websiteSSLRepo.Save(websiteSSL)
if err != nil {
@ -329,13 +299,32 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
if websiteSSL.Provider == constant.DNSAccount {
startMsg = startMsg + i18n.GetMsgWithMap("DNSAccountName", map[string]interface{}{"name": dnsAccount.Name, "type": dnsAccount.Type})
}
legoLogger.Logger.Println(startMsg)
logger.Println(startMsg)
}
resource, err := client.ObtainSSL(domains, privateKey)
if err != nil {
handleError(websiteSSL, err)
return
if websiteSSL.Provider != constant.DnsManual {
privateKey, err := ssl.GetPrivateKeyByType(websiteSSL.KeyType, websiteSSL.PrivateKey)
if err != nil {
handleError(websiteSSL, err)
return
}
resource, err = client.ObtainSSL(domains, privateKey)
if err != nil {
handleError(websiteSSL, err)
return
}
} else {
manualClient, err = ssl.NewCustomAcmeClient(acmeAccount, logger)
if err != nil {
handleError(websiteSSL, err)
return
}
resource, err = manualClient.RequestCertificate(context.Background(), websiteSSL)
if err != nil {
handleError(websiteSSL, err)
return
}
}
websiteSSL.PrivateKey = string(resource.PrivateKey)
websiteSSL.Pem = string(resource.Certificate)
websiteSSL.CertURL = resource.CertURL
@ -414,12 +403,15 @@ func (w WebsiteSSLService) GetDNSResolve(req request.WebsiteDNSReq) ([]response.
if err != nil {
return nil, err
}
client, err := ssl.NewAcmeClient(acmeAccount, getSystemProxy(acmeAccount.UseProxy))
client, err := ssl.NewCustomAcmeClient(acmeAccount, nil)
if err != nil {
return nil, err
}
resolves, err := client.GetDNSResolve(req.Domains)
websiteSSL, err := websiteSSLRepo.GetFirst(repo.WithByID(req.WebsiteSSLID))
if err != nil {
return nil, err
}
resolves, err := client.GetDNSResolve(context.TODO(), websiteSSL)
if err != nil {
return nil, err
}

View file

@ -10,6 +10,8 @@ import (
"encoding/pem"
"fmt"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/buserr"
"golang.org/x/crypto/acme"
"io"
"net"
"net/http"
@ -25,6 +27,8 @@ import (
"github.com/go-acme/lego/v4/registration"
)
var Orders = make(map[uint]*acme.Order)
type domainError struct {
Domain string
Error error
@ -173,13 +177,8 @@ func NewRegisterClient(acmeAccount *model.WebsiteAcmeAccount, proxy *dto.SystemP
return acmeClient, nil
}
func NewConfigWithProxy(user registration.User, accountType, customCaURL string, systemProxy *dto.SystemProxy) *lego.Config {
var (
caDirURL string
proxyURL string
proxyUser string
proxyPassword string
)
func getCaDirURL(accountType, customCaURL string) string {
var caDirURL string
switch accountType {
case "letsencrypt":
caDirURL = "https://acme-v02.api.letsencrypt.org/directory"
@ -194,6 +193,17 @@ func NewConfigWithProxy(user registration.User, accountType, customCaURL string,
case "custom":
caDirURL = customCaURL
}
return caDirURL
}
func NewConfigWithProxy(user registration.User, accountType, customCaURL string, systemProxy *dto.SystemProxy) *lego.Config {
var (
caDirURL string
proxyURL string
proxyUser string
proxyPassword string
)
caDirURL = getCaDirURL(accountType, customCaURL)
if systemProxy != nil {
proxyURL = fmt.Sprintf("%s://%s:%s", systemProxy.Type, systemProxy.URL, systemProxy.Port)
proxyUser = systemProxy.User
@ -305,3 +315,45 @@ func getZeroSSLEabCredentials(email string) (*zeroSSLRes, error) {
return &result, nil
}
func GetPrivateKeyByType(keyType, sslPrivateKey string) (crypto.PrivateKey, error) {
var (
privateKey crypto.PrivateKey
err error
)
kType := KeyType(keyType)
if sslPrivateKey == "" {
privateKey, err = certcrypto.GeneratePrivateKey(kType)
if err != nil {
return nil, err
}
return privateKey, nil
}
block, _ := pem.Decode([]byte(sslPrivateKey))
if block == nil {
return nil, buserr.New("invalid PEM block")
}
var privKey crypto.PrivateKey
switch kType {
case certcrypto.EC256, certcrypto.EC384:
privKey, err = x509.ParseECPrivateKey(block.Bytes)
if err != nil {
return nil, err
}
case certcrypto.RSA2048, certcrypto.RSA3072, certcrypto.RSA4096:
privKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
}
privateKey = privKey
return privateKey, nil
}
func getWebsiteSSLDomains(websiteSSL *model.WebsiteSSL) []string {
domains := []string{websiteSSL.PrimaryDomain}
if websiteSSL.Domains != "" {
domains = append(domains, strings.Split(websiteSSL.Domains, ",")...)
}
return domains
}

View file

@ -3,19 +3,13 @@ package ssl
import (
"crypto"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"os"
"strings"
"time"
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/acme/api"
"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/providers/http/webroot"
"github.com/pkg/errors"
"os"
)
type AcmeClientOption func(*AcmeClientOptions)
@ -70,38 +64,6 @@ func (c *AcmeClient) UseDns(dnsType DnsType, params string, websiteSSL model.Web
)
}
func (c *AcmeClient) UseManualDns(websiteSSL model.WebsiteSSL) error {
p, err := NewCustomDNSProviderManual(&ManualConfig{
PropagationTimeout: 20 * time.Minute,
PollingInterval: pollingInterval,
TTL: ttl,
})
if err != nil {
return err
}
var nameservers []string
if websiteSSL.Nameserver1 != "" {
nameservers = append(nameservers, websiteSSL.Nameserver1)
}
if websiteSSL.Nameserver2 != "" {
nameservers = append(nameservers, websiteSSL.Nameserver2)
}
if websiteSSL.DisableCNAME {
_ = os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "true")
} else {
_ = os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "false")
}
if err = c.Client.Challenge.SetDNS01Provider(p,
dns01.CondOption(len(nameservers) > 0,
dns01.AddRecursiveNameservers(nameservers)),
dns01.CondOption(websiteSSL.SkipDNS,
dns01.DisableAuthoritativeNssPropagationRequirement()),
dns01.AddDNSTimeout(dnsTimeOut)); err != nil {
return err
}
return nil
}
func (c *AcmeClient) UseHTTP(path string) error {
httpProvider, err := webroot.NewHTTPProvider(path)
if err != nil {
@ -133,70 +95,3 @@ func (c *AcmeClient) ObtainSSL(domains []string, privateKey crypto.PrivateKey) (
func (c *AcmeClient) RevokeSSL(pemSSL []byte) error {
return c.Client.Certificate.Revoke(pemSSL)
}
type Resolve struct {
Key string
Value string
Err string
}
func (c *AcmeClient) GetDNSResolve(domains []string) (map[string]Resolve, error) {
core, err := api.New(c.Config.HTTPClient, c.Config.UserAgent, c.Config.CADirURL, c.User.Registration.URI, c.User.Key)
if err != nil {
return nil, err
}
order, err := core.Orders.New(domains)
if err != nil {
return nil, err
}
resolves := make(map[string]Resolve)
resc, errc := make(chan acme.Authorization), make(chan domainError)
for _, authzURL := range order.Authorizations {
go func(authzURL string) {
authz, err := core.Authorizations.Get(authzURL)
if err != nil {
errc <- domainError{Domain: authz.Identifier.Value, Error: err}
return
}
resc <- authz
}(authzURL)
}
var responses []acme.Authorization
for i := 0; i < len(order.Authorizations); i++ {
select {
case res := <-resc:
responses = append(responses, res)
case err := <-errc:
resolves[err.Domain] = Resolve{Err: err.Error.Error()}
}
}
close(resc)
close(errc)
for _, auth := range responses {
domain := challenge.GetTargetedDomain(auth)
chlng, err := challenge.FindChallenge(challenge.DNS01, auth)
if err != nil {
resolves[domain] = Resolve{Err: err.Error()}
continue
}
keyAuth, err := core.GetKeyAuthorization(chlng.Token)
if err != nil {
resolves[domain] = Resolve{Err: err.Error()}
continue
}
challengeInfo := dns01.GetChallengeInfo(domain, keyAuth)
fqdn := challengeInfo.FQDN
if strings.HasPrefix(domain, "*.") && strings.Contains(fqdn, "*.") {
fqdn = strings.Replace(fqdn, "*.", "", 1)
}
_, _ = dns01.FindZoneByFqdn(challengeInfo.EffectiveFQDN)
resolves[domain] = Resolve{
Key: fqdn,
Value: challengeInfo.Value,
}
}
return resolves, nil
}

View file

@ -1,33 +0,0 @@
package ssl
import "time"
type ManualConfig struct {
TTL int
PropagationTimeout time.Duration
PollingInterval time.Duration
}
type CustomManualDnsProvider struct {
config *ManualConfig
}
func NewCustomDNSProviderManual(config *ManualConfig) (*CustomManualDnsProvider, error) {
return &CustomManualDnsProvider{config}, nil
}
func (p *CustomManualDnsProvider) Present(domain, token, keyAuth string) error {
return nil
}
func (p *CustomManualDnsProvider) CleanUp(domain, token, keyAuth string) error {
return nil
}
func (p *CustomManualDnsProvider) Sequential() time.Duration {
return manualDnsTimeout
}
func (p *CustomManualDnsProvider) Timeout() (timeout, interval time.Duration) {
return p.config.PropagationTimeout, p.config.PollingInterval
}

View file

@ -0,0 +1,308 @@
package ssl
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/go-acme/lego/v4/certificate"
"golang.org/x/crypto/acme"
"log"
"net"
"strings"
"time"
)
type ManualClient struct {
client *acme.Client
account *model.WebsiteAcmeAccount
logger *log.Logger
}
type RequestCertRequest struct {
WebsiteSSL *model.WebsiteSSL
}
func NewCustomAcmeClient(acmeAccount *model.WebsiteAcmeAccount, logger *log.Logger) (*ManualClient, error) {
var (
key crypto.PrivateKey
err error
)
switch KeyType(acmeAccount.KeyType) {
case KeyEC256, KeyEC384:
block, _ := pem.Decode([]byte(acmeAccount.PrivateKey))
key, err = x509.ParseECPrivateKey(block.Bytes)
if err != nil {
return nil, err
}
case KeyRSA2048, KeyRSA3072, KeyRSA4096:
block, _ := pem.Decode([]byte(acmeAccount.PrivateKey))
key, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
}
if logger == nil {
logger = log.Default()
}
client := &acme.Client{
Key: key.(crypto.Signer),
DirectoryURL: getCaDirURL(acmeAccount.Type, acmeAccount.CaDirURL),
}
return &ManualClient{
client: client,
account: acmeAccount,
logger: logger,
}, nil
}
type Resolve struct {
Key string
Value string
Err string
}
func (c *ManualClient) GetDNSResolve(ctx context.Context, websiteSSL *model.WebsiteSSL) (map[string]Resolve, error) {
order, err := c.client.AuthorizeOrder(ctx, acme.DomainIDs(getWebsiteSSLDomains(websiteSSL)...))
if err != nil {
return nil, err
}
Orders[websiteSSL.ID] = order
records := make(map[string]Resolve)
for _, authzURL := range order.AuthzURLs {
authz, err := c.client.GetAuthorization(ctx, authzURL)
if err != nil {
return nil, err
}
domain := authz.Identifier.Value
var dnsChallenge *acme.Challenge
for _, challenge := range authz.Challenges {
if challenge.Type == "dns-01" {
dnsChallenge = challenge
break
}
}
if dnsChallenge == nil {
return nil, fmt.Errorf("no DNS-01 challenge found for domain %s", domain)
}
txtValue, err := c.client.DNS01ChallengeRecord(dnsChallenge.Token)
if err != nil {
return nil, err
}
records[domain] = Resolve{
Key: fmt.Sprintf("_acme-challenge.%s", domain),
Value: txtValue,
}
}
return records, nil
}
func queryDNSRecords(domain string) (map[string]string, error) {
recordName := fmt.Sprintf("_acme-challenge.%s", domain)
txts, err := net.LookupTXT(recordName)
if err != nil {
return nil, err
}
records := make(map[string]string)
if len(txts) > 0 {
records[recordName] = txts[0]
}
return records, nil
}
func (c *ManualClient) handleAuthorization(ctx context.Context, authzURL string) error {
authz, err := c.client.GetAuthorization(ctx, authzURL)
if err != nil {
return fmt.Errorf("failed to get authorization: %v", err)
}
domain := authz.Identifier.Value
c.logger.Printf("[INFO] [%s] AuthURL: %s", domain, authzURL)
if authz.Status == acme.StatusValid {
return nil
}
var dnsChallenge *acme.Challenge
for _, challenge := range authz.Challenges {
if challenge.Type == "dns-01" {
dnsChallenge = challenge
break
}
}
c.logger.Printf("[INFO] [%s] acme: use dns-01 solver", domain)
if dnsChallenge == nil {
return fmt.Errorf("no DNS-01 challenge found for domain %s", domain)
}
deadline := time.Now().Add(manualDnsTimeout)
expectedRecord, err := c.client.DNS01ChallengeRecord(dnsChallenge.Token)
if err != nil {
return fmt.Errorf("failed to compute DNS challenge record: %v", err)
}
c.logger.Printf("[INFO] [%s] acme: Checking TXT record %s", domain, expectedRecord)
for {
c.logger.Printf("[INFO] [%s] acme: Checking DNS record propagation.", domain)
currentRecords, err := queryDNSRecords(domain)
if err != nil {
return fmt.Errorf("failed to query DNS records: %v", err)
}
recordName := fmt.Sprintf("_acme-challenge.%s", domain)
providedRecord, exists := currentRecords[recordName]
if exists && providedRecord == expectedRecord {
break
}
if time.Now().After(deadline) {
if !exists {
return fmt.Errorf("TXT record not provided for domain %s after retrying", domain)
}
c.logger.Printf("[INFO] [%s] TXT record mismatch for %s: expected %s, got %s\"", domain, domain, expectedRecord, providedRecord)
return fmt.Errorf("TXT record mismatch for %s: expected %s, got %s", domain, expectedRecord, providedRecord)
}
time.Sleep(pollingInterval)
}
_, err = c.client.Accept(ctx, dnsChallenge)
if err != nil {
return fmt.Errorf("failed to accept challenge: %v", err)
}
for {
time.Sleep(pollingInterval)
authz, err = c.client.GetAuthorization(ctx, authzURL)
if err != nil {
return fmt.Errorf("failed to get authorization while polling: %v", err)
}
if authz.Status == acme.StatusValid {
break
} else if authz.Status == acme.StatusInvalid {
return fmt.Errorf("authorization failed for domain %s", domain)
}
}
return nil
}
func (c *ManualClient) createCSR(keyType string, privateKey string, domains []string) ([]byte, crypto.PrivateKey, error) {
var certKey crypto.PrivateKey
var err error
certKey, err = GetPrivateKeyByType(keyType, privateKey)
if err != nil {
return nil, nil, err
}
template := x509.CertificateRequest{
Subject: pkix.Name{CommonName: domains[0]},
DNSNames: domains,
}
csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &template, certKey)
if err != nil {
return nil, nil, err
}
return csrBytes, certKey, nil
}
func (c *ManualClient) encodePrivateKey(key crypto.PrivateKey) (string, error) {
var keyBytes []byte
var keyType string
var err error
switch k := key.(type) {
case *ecdsa.PrivateKey:
keyBytes, err = x509.MarshalECPrivateKey(k)
keyType = "EC PRIVATE KEY"
case *rsa.PrivateKey:
keyBytes = x509.MarshalPKCS1PrivateKey(k)
keyType = "RSA PRIVATE KEY"
default:
return "", fmt.Errorf("unsupported key type")
}
if err != nil {
return "", err
}
block := &pem.Block{
Type: keyType,
Bytes: keyBytes,
}
return string(pem.EncodeToMemory(block)), nil
}
func (c *ManualClient) RequestCertificate(ctx context.Context, websiteSSL *model.WebsiteSSL) (certificate.Resource, error) {
var res certificate.Resource
domains := []string{websiteSSL.PrimaryDomain}
if websiteSSL.Domains != "" {
domains = append(domains, strings.Split(websiteSSL.Domains, ",")...)
}
c.logger.Printf("[INFO] Requesting certificate for domains: %v\n", domains)
csr, certKey, err := c.createCSR(websiteSSL.KeyType, websiteSSL.PrivateKey, domains)
if err != nil {
return res, err
}
order, ok := Orders[websiteSSL.ID]
if !ok {
return res, fmt.Errorf("order not found")
}
defer delete(Orders, websiteSSL.ID)
for _, authzURL := range order.AuthzURLs {
if err := c.handleAuthorization(ctx, authzURL); err != nil {
return res, err
}
}
c.logger.Printf("[INFO] acme: Validations succeeded; requesting certificates")
order, err = c.client.WaitOrder(ctx, order.URI)
if err != nil {
return res, err
}
if order.Status != acme.StatusReady {
return res, fmt.Errorf("order not ready: %s", order.Status)
}
certBytes, certURL, err := c.client.CreateOrderCert(ctx, order.FinalizeURL, csr, true)
if err != nil {
return res, fmt.Errorf("failed to finalize order: %v", err)
}
privateKeyPEM, err := c.encodePrivateKey(certKey)
if err != nil {
return res, err
}
var certPEM []byte
for _, cert := range certBytes {
block := &pem.Block{
Type: "CERTIFICATE",
Bytes: cert,
}
certPEM = append(certPEM, pem.EncodeToMemory(block)...)
}
c.logger.Printf("[INFO] acme: Server responded with a certificate.")
resource := certificate.Resource{
Domain: domains[0],
CertURL: certURL,
CertStableURL: certURL,
PrivateKey: []byte(privateKeyPEM),
Certificate: certPEM,
CSR: csr,
}
return resource, nil
}

View file

@ -281,8 +281,8 @@ export namespace Website {
}
export interface DNSResolveReq {
domains: string[];
acmeAccountId: number;
websiteSSLId: number;
}
export interface DNSResolve {

View file

@ -65,14 +65,8 @@ const acceptParams = async (props: RenewProps) => {
const getDnsResolveRes = async (row: Website.SSL) => {
loading.value = true;
let domains = [row.primaryDomain];
if (row.domains != '') {
let otherDomains = row.domains.split(',');
domains = domains.concat(otherDomains);
}
try {
const res = await getDnsResolve({ acmeAccountId: row.acmeAccountId, domains: domains });
const res = await getDnsResolve({ acmeAccountId: row.acmeAccountId, websiteSSLId: row.id });
if (res.data) {
dnsResolve.value = res.data;
}