Scert/backend/internal/dnsprovider/tester.go

68 lines
1.7 KiB
Go

package dnsprovider
import (
"context"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"strings"
"github.com/go-acme/lego/v5/challenge"
"git.pcux.cn/xuans/Scert/backend/internal/domain"
)
type Factory interface {
Create(providerID string, credentials map[string]string) (challenge.Provider, error)
}
type Tester struct {
factory Factory
}
func NewTester(factory Factory) *Tester {
return &Tester{factory: factory}
}
func (t *Tester) Verify(ctx context.Context, providerID, testDomain string, credentials map[string]string) error {
if t == nil || t.factory == nil {
return errors.New("DNS 验证服务未初始化")
}
testDomain = strings.ToLower(strings.TrimSuffix(strings.TrimSpace(testDomain), "."))
if !domain.IsValidName(testDomain) {
return fmt.Errorf("DNS 测试域名格式无效:%s", testDomain)
}
cleaned, err := ValidateCredentials(providerID, credentials)
if err != nil {
return err
}
provider, err := t.factory.Create(providerID, cleaned)
if err != nil {
return err
}
token, err := randomValue(24)
if err != nil {
return fmt.Errorf("生成 DNS 测试标识失败:%w", err)
}
keyAuth, err := randomValue(48)
if err != nil {
return fmt.Errorf("生成 DNS 测试授权值失败:%w", err)
}
if err := provider.Present(ctx, testDomain, token, keyAuth); err != nil {
return fmt.Errorf("创建 DNS 测试记录失败:%w", err)
}
if err := provider.CleanUp(ctx, testDomain, token, keyAuth); err != nil {
return fmt.Errorf("DNS 测试记录已创建,但自动清理失败:%w", err)
}
return nil
}
func randomValue(size int) (string, error) {
data := make([]byte, size)
if _, err := rand.Read(data); err != nil {
return "", err
}
return base64.RawURLEncoding.EncodeToString(data), nil
}