mirror of
https://github.com/go-acme/lego
synced 2024-05-19 19:36:33 +02:00
Compare commits
3 commits
29fc4d848f
...
b3a32cc286
Author | SHA1 | Date | |
---|---|---|---|
b3a32cc286 | |||
983c181e45 | |||
f6d1413a3f |
|
@ -21,6 +21,12 @@ type RenewalInfoRequest struct {
|
|||
// RenewalInfoResponse is a wrapper around acme.RenewalInfoResponse that provides a method for determining when to renew a certificate.
|
||||
type RenewalInfoResponse struct {
|
||||
acme.RenewalInfoResponse
|
||||
|
||||
// RetryAfter header indicating the polling interval that the ACME server recommends.
|
||||
// Conforming clients SHOULD query the renewalInfo URL again after the RetryAfter period has passed,
|
||||
// as the server may provide a different suggestedWindow.
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-4.2
|
||||
RetryAfter time.Duration
|
||||
}
|
||||
|
||||
// ShouldRenewAt determines the optimal renewal time based on the current time (UTC),renewal window suggest by ARI, and the client's willingness to sleep.
|
||||
|
@ -81,6 +87,14 @@ func (c *Certifier) GetRenewalInfo(req RenewalInfoRequest) (*RenewalInfoResponse
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if retry := resp.Header.Get("Retry-After"); retry != "" {
|
||||
info.RetryAfter, err = time.ParseDuration(retry + "s")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ func TestCertifier_GetRenewalInfo(t *testing.T) {
|
|||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Retry-After", "21600")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, wErr := w.Write([]byte(`{
|
||||
"suggestedWindow": {
|
||||
|
@ -76,6 +77,7 @@ func TestCertifier_GetRenewalInfo(t *testing.T) {
|
|||
assert.Equal(t, "2020-03-17T17:51:09Z", ri.SuggestedWindow.Start.Format(time.RFC3339))
|
||||
assert.Equal(t, "2020-03-17T18:21:09Z", ri.SuggestedWindow.End.Format(time.RFC3339))
|
||||
assert.Equal(t, "https://aricapable.ca/docs/renewal-advice/", ri.ExplanationURL)
|
||||
assert.Equal(t, time.Duration(21600000000000), ri.RetryAfter)
|
||||
}
|
||||
|
||||
func TestCertifier_GetRenewalInfo_errors(t *testing.T) {
|
||||
|
@ -135,13 +137,14 @@ func TestRenewalInfoResponse_ShouldRenew(t *testing.T) {
|
|||
|
||||
t.Run("Window is in the past", func(t *testing.T) {
|
||||
ri := RenewalInfoResponse{
|
||||
acme.RenewalInfoResponse{
|
||||
RenewalInfoResponse: acme.RenewalInfoResponse{
|
||||
SuggestedWindow: acme.Window{
|
||||
Start: now.Add(-2 * time.Hour),
|
||||
End: now.Add(-1 * time.Hour),
|
||||
},
|
||||
ExplanationURL: "",
|
||||
},
|
||||
RetryAfter: 0,
|
||||
}
|
||||
|
||||
rt := ri.ShouldRenewAt(now, 0)
|
||||
|
@ -151,13 +154,14 @@ func TestRenewalInfoResponse_ShouldRenew(t *testing.T) {
|
|||
|
||||
t.Run("Window is in the future", func(t *testing.T) {
|
||||
ri := RenewalInfoResponse{
|
||||
acme.RenewalInfoResponse{
|
||||
RenewalInfoResponse: acme.RenewalInfoResponse{
|
||||
SuggestedWindow: acme.Window{
|
||||
Start: now.Add(1 * time.Hour),
|
||||
End: now.Add(2 * time.Hour),
|
||||
},
|
||||
ExplanationURL: "",
|
||||
},
|
||||
RetryAfter: 0,
|
||||
}
|
||||
|
||||
rt := ri.ShouldRenewAt(now, 0)
|
||||
|
@ -166,13 +170,14 @@ func TestRenewalInfoResponse_ShouldRenew(t *testing.T) {
|
|||
|
||||
t.Run("Window is in the future, but caller is willing to sleep", func(t *testing.T) {
|
||||
ri := RenewalInfoResponse{
|
||||
acme.RenewalInfoResponse{
|
||||
RenewalInfoResponse: acme.RenewalInfoResponse{
|
||||
SuggestedWindow: acme.Window{
|
||||
Start: now.Add(1 * time.Hour),
|
||||
End: now.Add(2 * time.Hour),
|
||||
},
|
||||
ExplanationURL: "",
|
||||
},
|
||||
RetryAfter: 0,
|
||||
}
|
||||
|
||||
rt := ri.ShouldRenewAt(now, 2*time.Hour)
|
||||
|
@ -182,13 +187,14 @@ func TestRenewalInfoResponse_ShouldRenew(t *testing.T) {
|
|||
|
||||
t.Run("Window is in the future, but caller isn't willing to sleep long enough", func(t *testing.T) {
|
||||
ri := RenewalInfoResponse{
|
||||
acme.RenewalInfoResponse{
|
||||
RenewalInfoResponse: acme.RenewalInfoResponse{
|
||||
SuggestedWindow: acme.Window{
|
||||
Start: now.Add(1 * time.Hour),
|
||||
End: now.Add(2 * time.Hour),
|
||||
},
|
||||
ExplanationURL: "",
|
||||
},
|
||||
RetryAfter: 0,
|
||||
}
|
||||
|
||||
rt := ri.ShouldRenewAt(now, 59*time.Minute)
|
||||
|
|
|
@ -213,7 +213,11 @@ func getCredentials(config *Config) (azcore.TokenCredential, error) {
|
|||
return &timeoutTokenCredential{cred: cred, timeout: config.AuthMSITimeout}, nil
|
||||
|
||||
case "cli":
|
||||
return azidentity.NewAzureCLICredential(nil)
|
||||
var credOptions *azidentity.AzureCLICredentialOptions
|
||||
if config.TenantID != "" {
|
||||
credOptions = &azidentity.AzureCLICredentialOptions{TenantID: config.TenantID}
|
||||
}
|
||||
return azidentity.NewAzureCLICredential(credOptions)
|
||||
|
||||
case "oidc":
|
||||
err := checkOIDCConfig(config)
|
||||
|
|
|
@ -127,38 +127,16 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
return fmt.Errorf("exoscale: zone %q not found", zoneName)
|
||||
}
|
||||
|
||||
recordID, err := d.findExistingRecordID(deref(zone.ID), recordName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("exoscale: %w", err)
|
||||
}
|
||||
|
||||
if recordID == "" {
|
||||
record := egoscale.DNSDomainRecord{
|
||||
Name: pointer(recordName),
|
||||
TTL: pointer(d.config.TTL),
|
||||
Content: pointer(info.Value),
|
||||
Type: pointer("TXT"),
|
||||
}
|
||||
|
||||
_, err = d.client.CreateDNSDomainRecord(ctx, d.apiZone, deref(zone.ID), &record)
|
||||
if err != nil {
|
||||
return fmt.Errorf("exoscale: error while creating DNS record: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
record := egoscale.DNSDomainRecord{
|
||||
ID: pointer(recordID),
|
||||
Name: pointer(recordName),
|
||||
TTL: pointer(d.config.TTL),
|
||||
Content: pointer(info.Value),
|
||||
Type: pointer("TXT"),
|
||||
}
|
||||
|
||||
err = d.client.UpdateDNSDomainRecord(ctx, d.apiZone, deref(zone.ID), &record)
|
||||
_, err = d.client.CreateDNSDomainRecord(ctx, d.apiZone, deref(zone.ID), &record)
|
||||
if err != nil {
|
||||
return fmt.Errorf("exoscale: error while updating DNS record: %w", err)
|
||||
return fmt.Errorf("exoscale: error while creating DNS record: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -182,7 +160,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
return fmt.Errorf("exoscale: zone %q not found", zoneName)
|
||||
}
|
||||
|
||||
recordID, err := d.findExistingRecordID(deref(zone.ID), recordName)
|
||||
recordID, err := d.findExistingRecordID(deref(zone.ID), recordName, info.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -224,7 +202,7 @@ func (d *DNSProvider) findExistingZone(zoneName string) (*egoscale.DNSDomain, er
|
|||
|
||||
// findExistingRecordID Query Exoscale to find an existing record for this name.
|
||||
// Returns empty result if no record could be found.
|
||||
func (d *DNSProvider) findExistingRecordID(zoneID, recordName string) (string, error) {
|
||||
func (d *DNSProvider) findExistingRecordID(zoneID, recordName, value string) (string, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
records, err := d.client.ListDNSDomainRecords(ctx, d.apiZone, zoneID)
|
||||
|
@ -233,8 +211,7 @@ func (d *DNSProvider) findExistingRecordID(zoneID, recordName string) (string, e
|
|||
}
|
||||
|
||||
for _, record := range records {
|
||||
if deref(record.Name) == recordName &&
|
||||
deref(record.Type) == "TXT" {
|
||||
if deref(record.Name) == recordName && deref(record.Type) == "TXT" && deref(record.Content) == value {
|
||||
return deref(record.ID), nil
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue