diff --git a/cmd/dashboard/controller/controller.go b/cmd/dashboard/controller/controller.go index cb731b8..0cb1aae 100644 --- a/cmd/dashboard/controller/controller.go +++ b/cmd/dashboard/controller/controller.go @@ -155,6 +155,7 @@ func routers(r *gin.Engine, frontendDist fs.FS) { auth.POST("/domains", commonHandler(AddDomain)) auth.POST("/domains/:id/verify", commonHandler(VerifyDomain)) + auth.POST("/domains/:id/sync", commonHandler(SyncDomainWHOIS)) auth.PUT("/domains/:id", commonHandler(UpdateDomain)) auth.DELETE("/domains/:id", commonHandler(DeleteDomain)) diff --git a/cmd/dashboard/controller/domain.go b/cmd/dashboard/controller/domain.go index c2d60b3..c7273e6 100644 --- a/cmd/dashboard/controller/domain.go +++ b/cmd/dashboard/controller/domain.go @@ -118,3 +118,21 @@ func UpdateDomainInfo(c *gin.Context) (any, error) { return singleton.UpdateDomain(domainID, req) } + +func SyncDomainWHOIS(c *gin.Context) (any, error) { + domainID, err := strconv.ParseUint(c.Param("id"), 10, 64) + if err != nil { + return nil, newGormError("无效的域名ID") + } + + domain, err := singleton.GetDomainByID(domainID) + if err != nil { + return nil, newGormError("未找到域名: %s", err.Error()) + } + + if err := singleton.SyncDomainWHOIS(domain); err != nil { + return nil, newGormError("Whois 同步失败: %s", err.Error()) + } + + return domain, nil +} diff --git a/go.mod b/go.mod index 8771352..ba52717 100644 --- a/go.mod +++ b/go.mod @@ -85,6 +85,9 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/likexian/gokit v0.25.16 // indirect + github.com/likexian/whois v1.15.7 // indirect + github.com/likexian/whois-parser v1.24.21 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.37 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect diff --git a/go.sum b/go.sum index c4d0929..6df8934 100644 --- a/go.sum +++ b/go.sum @@ -155,6 +155,12 @@ github.com/libdns/he v1.2.1 h1:cjTZlxM5wv2lBPmtxsQCqMgmXMqTnmR4eLqUVwEkqis= github.com/libdns/he v1.2.1/go.mod h1:SWTm80gn+7sUASGsQbRHayenoW4QIw/iGmsrkDzFghM= github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U= github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= +github.com/likexian/gokit v0.25.16 h1:wwBeUIN/OdoPp6t00xTnZE8Di/+s969Bl5N2Kw6bzP8= +github.com/likexian/gokit v0.25.16/go.mod h1:Wqd4f+iifV0qxA1N3MqePJTUsmRy/lpst9/yXriDx/4= +github.com/likexian/whois v1.15.7 h1:sajjDhi2bVD71AHJhjV7jLYxN92H4AWhTwxM8hmj7c0= +github.com/likexian/whois v1.15.7/go.mod h1:kdPQtYb+7SQVftBEbCblDadUkycN7Mg1k1/Li/rwvmc= +github.com/likexian/whois-parser v1.24.21 h1:MxsrGRxDOiZIVp7q7N/yAIbKuN4QAkGjCpOtTDA5OsM= +github.com/likexian/whois-parser v1.24.21/go.mod h1:o3DUruO65Pb8WXCJCTlSVkTbwuYVrBCeoMTw2q0mxY4= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.37 h1:3DOZp4cXis1cUIpCfXLtmlGolNLp2VEqhiB/PARNBIg= diff --git a/service/singleton/domain.go b/service/singleton/domain.go index 019e02b..8dd9aac 100644 --- a/service/singleton/domain.go +++ b/service/singleton/domain.go @@ -14,8 +14,49 @@ import ( "github.com/nezhahq/nezha/model" "gorm.io/datatypes" + + whois "github.com/likexian/whois" + whoisparser "github.com/likexian/whois-parser" ) + +// SyncDomainWHOIS 从 Whois 获取域名信息并同步到 BillingData +func SyncDomainWHOIS(d *model.Domain) error { + raw, err := whois.Whois(d.Domain) + if err != nil { + return fmt.Errorf("Whois查询失败: %w", err) + } + + result, err := whoisparser.Parse(raw) + if err != nil { + return fmt.Errorf("Whois解析失败: %w", err) + } + + var billing model.BillingDataMod + if d.BillingData != nil && len(d.BillingData) > 0 { + json.Unmarshal(d.BillingData, &billing) + } + + // 填充信息 + if result.Registrar.Name != "" { + billing.Registrar = result.Registrar.Name + } + if result.Domain.ExpirationDate != "" { + billing.EndDate = result.Domain.ExpirationDate + } + if result.Domain.CreatedDate != "" { + billing.RegisteredDate = result.Domain.CreatedDate + } + + newBillingData, err := json.Marshal(billing) + if err != nil { + return err + } + + d.BillingData = newBillingData + return DB.Save(d).Error +} + // GetDomains 获取所有域名记录 func GetDomains(scope string) ([]model.Domain, error) { var domains []model.Domain @@ -81,13 +122,23 @@ func VerifyDomain(id uint64) (bool, error) { return false, fmt.Errorf("DNS查询失败: %w", err) } + found := false for _, record := range txtRecords { if record == domain.VerifyToken { domain.Status = "verified" - return true, DB.Save(domain).Error + found = true + break } } + if found { + // 自动同步 Whois 信息 + if err := SyncDomainWHOIS(domain); err != nil { + log.Printf("NEZHA>> 域名 %s 验证成功但 Whois 同步失败: %v", domain.Domain, err) + } + return true, DB.Save(domain).Error + } + return false, nil }