diff --git a/backend/app/dto/website_ssl.go b/backend/app/dto/website_ssl.go index 31e0ff16f..09f4a2d80 100644 --- a/backend/app/dto/website_ssl.go +++ b/backend/app/dto/website_ssl.go @@ -38,9 +38,10 @@ type WebsiteDNSReq struct { } type WebsiteDNSRes struct { - Key string `json:"resolve"` - Value string `json:"value"` - Type string `json:"type"` + Key string `json:"resolve"` + Value string `json:"value"` + Domain string `json:"domain"` + Err string `json:"err"` } type WebsiteSSLRenew struct { diff --git a/backend/app/service/website_ssl.go b/backend/app/service/website_ssl.go index b8a53de6c..6842382b9 100644 --- a/backend/app/service/website_ssl.go +++ b/backend/app/service/website_ssl.go @@ -168,24 +168,29 @@ func (w WebSiteSSLService) Renew(sslId uint) error { return websiteSSLRepo.Save(websiteSSL) } -func (w WebSiteSSLService) GetDNSResolve(req dto.WebsiteDNSReq) (dto.WebsiteDNSRes, error) { +func (w WebSiteSSLService) GetDNSResolve(req dto.WebsiteDNSReq) ([]dto.WebsiteDNSRes, error) { acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(req.AcmeAccountID)) if err != nil { - return dto.WebsiteDNSRes{}, err + return nil, err } client, err := ssl.NewPrivateKeyClient(acmeAccount.Email, acmeAccount.PrivateKey) if err != nil { - return dto.WebsiteDNSRes{}, err + return nil, err } - re, err := client.UseManualDns(req.Domains) + resolves, err := client.GetDNSResolve(req.Domains) if err != nil { - return dto.WebsiteDNSRes{}, err + return nil, err + } + var res []dto.WebsiteDNSRes + for k, v := range resolves { + res = append(res, dto.WebsiteDNSRes{ + Domain: k, + Key: v.Key, + Value: v.Value, + Err: v.Err, + }) } - var res dto.WebsiteDNSRes - res.Key = re.Key - res.Value = re.Value - res.Type = "TXT" return res, nil } diff --git a/backend/utils/nginx/private.key b/backend/utils/nginx/private.key index 631b12085..32f7366f7 100644 --- a/backend/utils/nginx/private.key +++ b/backend/utils/nginx/private.key @@ -1,27 +1,27 @@ -----BEGIN privateKey----- -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 -----END privateKey----- diff --git a/backend/utils/ssl/client.go b/backend/utils/ssl/client.go index d4b29336b..754b47015 100644 --- a/backend/utils/ssl/client.go +++ b/backend/utils/ssl/client.go @@ -3,6 +3,8 @@ package ssl import ( "crypto" "encoding/json" + "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" @@ -166,6 +168,7 @@ func (c *AcmeClient) RenewSSL(certUrl string) (certificate.Resource, error) { type Resolve struct { Key string Value string + Err string } type manualDnsProvider struct { @@ -173,11 +176,6 @@ type manualDnsProvider struct { } func (p *manualDnsProvider) Present(domain, token, keyAuth string) error { - fqdn, value := dns01.GetRecord(domain, keyAuth) - p.Resolve = &Resolve{ - Key: fqdn, - Value: value, - } return nil } @@ -185,6 +183,60 @@ func (p *manualDnsProvider) CleanUp(domain, token, keyAuth string) error { return nil } -func (c *AcmeClient) GetDNSResolve() { +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 { + panic(err) + } + order, err := core.Orders.New(domains) + if err != nil { + panic(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 + } + fqdn, value := dns01.GetRecord(domain, keyAuth) + resolves[domain] = Resolve{ + Key: fqdn, + Value: value, + } + } + + return resolves, nil } diff --git a/backend/utils/ssl/obtain_err.go b/backend/utils/ssl/obtain_err.go new file mode 100644 index 000000000..c3f87cd3f --- /dev/null +++ b/backend/utils/ssl/obtain_err.go @@ -0,0 +1,29 @@ +package ssl + +import ( + "bytes" + "fmt" + "sort" +) + +type obtainError map[string]error + +func (e obtainError) Error() string { + buffer := bytes.NewBufferString("error: one or more domains had a problem:\n") + + var domains []string + for domain := range e { + domains = append(domains, domain) + } + sort.Strings(domains) + + for _, domain := range domains { + buffer.WriteString(fmt.Sprintf("[%s] %s\n", domain, e[domain])) + } + return buffer.String() +} + +type domainError struct { + Domain string + Error error +} diff --git a/frontend/src/api/interface/website.ts b/frontend/src/api/interface/website.ts index f5477fbc2..fcd56894c 100644 --- a/frontend/src/api/interface/website.ts +++ b/frontend/src/api/interface/website.ts @@ -160,9 +160,10 @@ export namespace WebSite { } export interface DNSResolve { - key: string; + resolve: string; value: string; - type: string; + domain: string; + err: string; } export interface SSLReq { diff --git a/frontend/src/api/modules/website.ts b/frontend/src/api/modules/website.ts index 30da5acb9..36da3aae8 100644 --- a/frontend/src/api/modules/website.ts +++ b/frontend/src/api/modules/website.ts @@ -120,7 +120,7 @@ export const RenewSSL = (req: WebSite.SSLRenew) => { }; export const GetDnsResolve = (req: WebSite.DNSResolveReq) => { - return http.post(`/websites/ssl/resolve`, req); + return http.post(`/websites/ssl/resolve`, req); }; export const GetHTTPSConfig = (id: number) => { diff --git a/frontend/src/views/website/ssl/create/index.vue b/frontend/src/views/website/ssl/create/index.vue index 042630815..ad226df8f 100644 --- a/frontend/src/views/website/ssl/create/index.vue +++ b/frontend/src/views/website/ssl/create/index.vue @@ -1,10 +1,10 @@