Skip to content

Commit 569c5b6

Browse files
committed
fix http-req acme can use multiple validation strings for wildcards
1 parent 18c9897 commit 569c5b6

File tree

3 files changed

+31
-17
lines changed

3 files changed

+31
-17
lines changed

internal/server/server.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func RegisterEndpoints(srv *fuego.Server, htp htpasswd.HTPasswd, zctl zone.Contr
177177
return
178178
}
179179

180-
err = zctl.UpdateACMEChallenge(ctx, req.Subdomain, req.TXT)
180+
err = zctl.UpdateACMEChallenge(ctx, req.Subdomain, req.TXT, "")
181181
if err != nil {
182182
fuego.SendError(w, r, err)
183183
return
@@ -224,7 +224,7 @@ func RegisterEndpoints(srv *fuego.Server, htp htpasswd.HTPasswd, zctl zone.Contr
224224
return
225225
}
226226

227-
err = zctl.UpdateACMEChallenge(ctx, req.Fqdn, req.Value)
227+
err = zctl.UpdateACMEChallenge(ctx, req.Fqdn, req.Value, zone.EmptyPlaceholder)
228228
if err != nil {
229229
fuego.SendError(w, r, err)
230230
return
@@ -267,7 +267,7 @@ func RegisterEndpoints(srv *fuego.Server, htp htpasswd.HTPasswd, zctl zone.Contr
267267
}
268268

269269
// NOTE: lego sends which txt value to remove, but i do not support multiple ACME TXTs anyway
270-
err = zctl.UpdateACMEChallenge(ctx, req.Fqdn, "")
270+
err = zctl.UpdateACMEChallenge(ctx, req.Fqdn, "", req.Value)
271271
if err != nil {
272272
fuego.SendError(w, r, err)
273273
return

internal/zone/controller.go

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type Controller interface {
3232
// UpdateDDNSAddress changes DDNS A/AAAA records
3333
UpdateDDNSAddress(ctx context.Context, domain string, addrs []netip.Addr) error
3434
// UpdateACMEChallenge changes ACME TXT record for DNS-01 challenge
35-
UpdateACMEChallenge(ctx context.Context, domain string, token string) error
35+
UpdateACMEChallenge(ctx context.Context, domain string, newToken, oldToken string) error
3636
}
3737

3838
type File struct {
@@ -91,7 +91,7 @@ func (s *DomainCtrl) UpdateDDNSAddress(ctx context.Context, domain string, addrs
9191
}
9292
}
9393

94-
func (s *DomainCtrl) UpdateACMEChallenge(ctx context.Context, domain string, token string) error {
94+
func (s *DomainCtrl) UpdateACMEChallenge(ctx context.Context, domain string, newToken, oldToken string) error {
9595

9696
lg := slog.Default().With("domain", domain)
9797

@@ -108,7 +108,7 @@ func (s *DomainCtrl) UpdateACMEChallenge(ctx context.Context, domain string, tok
108108
lg.DebugContext(ctx, "Check file", "file_origin", fl.origin)
109109
if strings.HasSuffix(domainDot, fl.origin) {
110110
lg.InfoContext(ctx, "Zone file found", "zonefile", path.Base(fl.path))
111-
return fl.UpdateACMEChallenge(ctx, domainDot, token)
111+
return fl.UpdateACMEChallenge(ctx, domainDot, newToken, oldToken)
112112
}
113113
}
114114

@@ -314,7 +314,7 @@ func (s *File) UpdateDDNSAddress(ctx context.Context, domain string, addrs []net
314314
return nil
315315
}
316316

317-
func (s *File) UpdateACMEChallenge(ctx context.Context, domain string, token string) error {
317+
func (s *File) UpdateACMEChallenge(ctx context.Context, domain string, newToken, oldToken string) error {
318318
s.mu.Lock()
319319
defer s.mu.Unlock()
320320

@@ -323,9 +323,10 @@ func (s *File) UpdateACMEChallenge(ctx context.Context, domain string, token str
323323
return err
324324
}
325325

326-
if token == "" {
327-
s.lg.Warn("Use placeholder for empty TXT record", "domain", domain)
328-
token = EmptyPlaceholder
326+
lg := s.lg.With("domain", domain)
327+
if newToken == "" {
328+
lg.Warn("Use placeholder for empty TXT record")
329+
newToken = EmptyPlaceholder
329330
}
330331

331332
shortDomain := []byte(StripOrigin(domain, s.origin))
@@ -340,12 +341,25 @@ func (s *File) UpdateACMEChallenge(ctx context.Context, domain string, token str
340341
}
341342

342343
if ent.RRType() == dns.TypeTXT {
343-
entTXT = append(entTXT, &ent)
344+
if oldToken == "" {
345+
// ACMEDNS mode - replace all TXTs
346+
entTXT = append(entTXT, &ent)
347+
} else {
348+
// HTTP-REQ mode - replace only matching TXTs
349+
vals := ent.Values()
350+
if len(vals) == 1 && bytes.Equal(vals[0], []byte(oldToken)) {
351+
entTXT = append(entTXT, &ent)
352+
if oldToken == EmptyPlaceholder {
353+
// leave other placeholders for next requests
354+
break
355+
}
356+
}
357+
}
344358
}
345359
}
346360

347361
if len(entTXT) < 1 {
348-
newent = fmt.Appendf(newent, "\n%s IN TXT %v\n", shortDomain, quoteTXT(token))
362+
newent = fmt.Appendf(newent, "\n%s IN TXT %v\n", shortDomain, quoteTXT(newToken))
349363
}
350364

351365
if len(newent) > 0 {
@@ -365,12 +379,12 @@ func (s *File) UpdateACMEChallenge(ctx context.Context, domain string, token str
365379
for _, ent := range entTXT {
366380
vals := ent.Values()
367381
if len(vals) == 1 {
368-
s.lg.Info("Replace value", "old_value", string(vals[0]), "new_value", token)
382+
lg.Info("Replace value", "old_value", string(vals[0]), "new_value", newToken)
369383
} else if len(vals) > 1 {
370-
s.lg.Warn("Possibly bad record matched", "vals", vals)
384+
lg.Warn("Possibly bad record matched", "vals", vals)
371385
}
372386

373-
err := ent.SetValue(0, []byte(token))
387+
err := ent.SetValue(0, []byte(newToken))
374388
if err != nil {
375389
return err
376390
}
@@ -389,7 +403,7 @@ func (s *File) UpdateACMEChallenge(ctx context.Context, domain string, token str
389403

390404
err = os.WriteFile(s.path, ret.Bytes(), 0644)
391405
if err != nil {
392-
s.lg.ErrorContext(ctx, "Failed to save file", "error", err)
406+
lg.ErrorContext(ctx, "Failed to save file", "error", err)
393407
return err
394408
}
395409

internal/zone/controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func TestFile_UpdateACMEChallenge(t *testing.T) {
9898
ctx := context.TODO()
9999
f := newZoneTemp(t, tc.file)
100100

101-
err := f.UpdateACMEChallenge(ctx, tc.domain, tc.token)
101+
err := f.UpdateACMEChallenge(ctx, tc.domain, tc.token, "")
102102
assert.NoError(err)
103103
assertFiles(t, tc.expectedFile, f.path)
104104
})

0 commit comments

Comments
 (0)