Files
sslh-multiplex-lab/internal/providers/letsencrypt/namecheap_dns.go
2026-01-29 00:03:02 +00:00

95 lines
2.2 KiB
Go

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
}