package letsencrypt import ( "fmt" "time" "github.com/go-acme/lego/v4/challenge/dns01" "sslh-multiplex-lab/internal/providers/namecheap" ) type NamecheapDNSProvider struct { namecheapClient *namecheap.Client domain string txtRecords map[string]string } func NewNamecheapDNSProvider(namecheapClient *namecheap.Client, domain string) *NamecheapDNSProvider { return &NamecheapDNSProvider{ namecheapClient: namecheapClient, domain: domain, txtRecords: make(map[string]string), } } func (p *NamecheapDNSProvider) Present(domain, token, keyAuth string) error { fqdn, value := dns01.GetRecord(domain, keyAuth) subdomain := extractSubdomain(fqdn, p.domain) if subdomain == "" { return fmt.Errorf("failed to extract subdomain from %s for domain %s", fqdn, p.domain) } p.txtRecords[subdomain] = value _, err := p.namecheapClient.CreateOrUpdateDNSRecord(p.domain, subdomain, "TXT", value, 300) if err != nil { return fmt.Errorf("failed to create TXT record for %s: %w", subdomain, err) } time.Sleep(10 * time.Second) return nil } func (p *NamecheapDNSProvider) CleanUp(domain, token, keyAuth string) error { fqdn, _ := dns01.GetRecord(domain, keyAuth) subdomain := extractSubdomain(fqdn, p.domain) if subdomain == "" { return nil } records, err := p.namecheapClient.ListDNSRecords(p.domain) if err != nil { return fmt.Errorf("failed to list DNS records: %w", err) } for _, record := range records { if record.Name == subdomain && record.Type == "TXT" { if err := p.namecheapClient.DeleteDNSRecord(p.domain, record.ID); err != nil { return fmt.Errorf("failed to delete TXT record for %s: %w", subdomain, err) } } } delete(p.txtRecords, subdomain) return nil } func extractSubdomain(fqdn, domain string) string { if len(fqdn) <= len(domain) { return "" } suffix := "." + domain if !endsWith(fqdn, suffix) { return "" } subdomain := fqdn[:len(fqdn)-len(suffix)] if subdomain == "_acme-challenge" { return "_acme-challenge" } if len(subdomain) > len("_acme-challenge.") && subdomain[:len("_acme-challenge.")] == "_acme-challenge." { return subdomain } return "" } func endsWith(s, suffix string) bool { return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix }