1128 lines
29 KiB
Go
1128 lines
29 KiB
Go
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||
//go:build plus
|
||
|
||
package nameservers
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/nameservers"
|
||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
|
||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||
"github.com/iwind/TeaGo/dbs"
|
||
"github.com/iwind/TeaGo/lists"
|
||
"github.com/iwind/TeaGo/types"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// NSDomainService 域名相关服务
|
||
type NSDomainService struct {
|
||
services.BaseService
|
||
}
|
||
|
||
// CreateNSDomain 创建域名
|
||
func (this *NSDomainService) CreateNSDomain(ctx context.Context, req *pb.CreateNSDomainRequest) (*pb.CreateNSDomainResponse, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
adminId, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var isAdminRequest = adminId > 0
|
||
|
||
if userId > 0 {
|
||
req.UserId = userId
|
||
}
|
||
|
||
req.Name = strings.ToLower(req.Name)
|
||
|
||
// 检查 req.NsDomainGroupIds 有效性
|
||
var tx = this.NullTx()
|
||
if req.UserId > 0 && len(req.NsDomainGroupIds) > 0 {
|
||
for _, groupId := range req.NsDomainGroupIds {
|
||
err = nameservers.SharedNSDomainGroupDAO.CheckUserGroup(tx, req.UserId, groupId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检查clusterId
|
||
var shouldValidate = false
|
||
if req.UserId > 0 && !isAdminRequest {
|
||
userConfig, err := models.SharedSysSettingDAO.ReadNSUserConfig(tx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
req.NsClusterId = userConfig.DefaultClusterId
|
||
shouldValidate = userConfig.DomainValidation != nil && userConfig.DomainValidation.IsOn
|
||
}
|
||
|
||
if req.NsClusterId <= 0 {
|
||
return nil, errors.New("'nsClusterId' required")
|
||
}
|
||
|
||
// 是否已经在当前用户账户里存在
|
||
exists, err := nameservers.SharedNSDomainDAO.ExistUserDomain(tx, req.UserId, req.Name)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if exists {
|
||
return nil, errors.New("domain '" + req.Name + "' already exists")
|
||
}
|
||
|
||
// 管理员添加时检查是否在别的用户账户里已经存在
|
||
// 允许用户添加重复的域名,只需要后续进行TXT验证即可
|
||
if userId == 0 {
|
||
exists, err = nameservers.SharedNSDomainDAO.ExistVerifiedDomain(tx, req.Name)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if exists {
|
||
return nil, errors.New("domain '" + req.Name + "' already exists")
|
||
}
|
||
}
|
||
|
||
// 状态
|
||
var status = dnsconfigs.NSDomainStatusNone
|
||
if isAdminRequest || !shouldValidate {
|
||
status = dnsconfigs.NSDomainStatusVerified
|
||
}
|
||
|
||
// 创建
|
||
domainId, err := nameservers.SharedNSDomainDAO.CreateDomain(tx, req.NsClusterId, req.UserId, req.NsDomainGroupIds, req.Name, status)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &pb.CreateNSDomainResponse{NsDomainId: domainId}, nil
|
||
}
|
||
|
||
// CreateNSDomains 批量创建域名
|
||
func (this *NSDomainService) CreateNSDomains(ctx context.Context, req *pb.CreateNSDomainsRequest) (*pb.CreateNSDomainsResponse, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
adminId, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var isAdminRequest = adminId > 0
|
||
|
||
if userId > 0 {
|
||
req.UserId = userId
|
||
}
|
||
|
||
// 检查分组有效性
|
||
var tx = this.NullTx()
|
||
if req.UserId > 0 {
|
||
for _, groupId := range req.NsDomainGroupIds {
|
||
err = nameservers.SharedNSDomainGroupDAO.CheckUserGroup(tx, req.UserId, groupId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检查集群
|
||
var shouldValidate = false
|
||
if req.UserId > 0 && !isAdminRequest {
|
||
userConfig, err := models.SharedSysSettingDAO.ReadNSUserConfig(tx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
req.NsClusterId = userConfig.DefaultClusterId
|
||
shouldValidate = userConfig.DomainValidation != nil && userConfig.DomainValidation.IsOn
|
||
}
|
||
|
||
if req.NsClusterId <= 0 {
|
||
return nil, errors.New("'nsClusterId' required")
|
||
}
|
||
|
||
var domainIds = []int64{}
|
||
var domainMap = map[string]bool{} // domainName => bool
|
||
err = this.RunTx(func(tx *dbs.Tx) error {
|
||
for _, name := range req.Names {
|
||
name = strings.ToLower(name)
|
||
|
||
// 检查是否已添加
|
||
_, ok := domainMap[name]
|
||
if ok {
|
||
return nil
|
||
}
|
||
|
||
domainMap[name] = true
|
||
|
||
// 是否已经存在
|
||
exists, err := nameservers.SharedNSDomainDAO.ExistUserDomain(tx, req.UserId, name)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if exists {
|
||
return errors.New("domain '" + name + "' already exists")
|
||
}
|
||
|
||
// 管理员添加时验证域名是否已由别的用户添加过
|
||
if userId == 0 {
|
||
exists, err = nameservers.SharedNSDomainDAO.ExistVerifiedDomain(tx, name)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if exists {
|
||
return errors.New("domain '" + name + "' already exists")
|
||
}
|
||
}
|
||
|
||
// 状态
|
||
var status = dnsconfigs.NSDomainStatusNone
|
||
if isAdminRequest || !shouldValidate {
|
||
status = dnsconfigs.NSDomainStatusVerified
|
||
}
|
||
|
||
// 创建
|
||
domainId, err := nameservers.SharedNSDomainDAO.CreateDomain(tx, req.NsClusterId, req.UserId, req.NsDomainGroupIds, name, status)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
domainIds = append(domainIds, domainId)
|
||
}
|
||
return nil
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &pb.CreateNSDomainsResponse{NsDomainIds: domainIds}, nil
|
||
}
|
||
|
||
// UpdateNSDomain 修改域名
|
||
func (this *NSDomainService) UpdateNSDomain(ctx context.Context, req *pb.UpdateNSDomainRequest) (*pb.RPCSuccess, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if userId > 0 {
|
||
req.UserId = userId
|
||
}
|
||
|
||
var tx = this.NullTx()
|
||
|
||
if userId > 0 {
|
||
err = nameservers.SharedNSDomainDAO.CheckUserDomain(tx, userId, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
if req.UserId > 0 {
|
||
// 检查分组有效性
|
||
for _, groupId := range req.NsDomainGroupIds {
|
||
err = nameservers.SharedNSDomainGroupDAO.CheckUserGroup(tx, req.UserId, groupId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
|
||
err = nameservers.SharedNSDomainDAO.UpdateDomain(tx, req.NsDomainId, req.NsClusterId, req.UserId, req.NsDomainGroupIds, req.IsOn)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return this.Success()
|
||
}
|
||
|
||
// UpdateNSDomainStatus 修改域名状态
|
||
func (this *NSDomainService) UpdateNSDomainStatus(ctx context.Context, req *pb.UpdateNSDomainStatusRequest) (*pb.RPCSuccess, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
_, err := this.ValidateAdmin(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if req.NsDomainId <= 0 {
|
||
return nil, errors.New("invalid nsDomainId")
|
||
}
|
||
|
||
if !dnsconfigs.NSDomainStatusIsValid(req.Status) {
|
||
return nil, errors.New("invalid status '" + req.Status + "'")
|
||
}
|
||
|
||
var tx = this.NullTx()
|
||
err = nameservers.SharedNSDomainDAO.UpdateDomainStatus(tx, req.NsDomainId, req.Status)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return this.Success()
|
||
}
|
||
|
||
// DeleteNSDomain 删除域名
|
||
func (this *NSDomainService) DeleteNSDomain(ctx context.Context, req *pb.DeleteNSDomainRequest) (*pb.RPCSuccess, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var tx = this.NullTx()
|
||
if userId > 0 {
|
||
err = nameservers.SharedNSDomainDAO.CheckUserDomain(tx, userId, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
err = nameservers.SharedNSDomainDAO.DisableNSDomain(tx, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return this.Success()
|
||
}
|
||
|
||
// DeleteNSDomains 批量删除域名
|
||
func (this *NSDomainService) DeleteNSDomains(ctx context.Context, req *pb.DeleteNSDomainsRequest) (*pb.RPCSuccess, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if userId > 0 {
|
||
req.UserId = userId
|
||
}
|
||
|
||
var tx = this.NullTx()
|
||
for _, name := range req.Names {
|
||
name = strings.ToLower(strings.TrimSpace(name))
|
||
if len(name) == 0 {
|
||
continue
|
||
}
|
||
|
||
if req.UserId > 0 {
|
||
err = nameservers.SharedNSDomainDAO.DisableUserDomainWithName(tx, req.UserId, name)
|
||
} else {
|
||
err = nameservers.SharedNSDomainDAO.DisableDomainWithName(tx, name)
|
||
}
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
return this.Success()
|
||
}
|
||
|
||
// FindNSDomain 查找单个域名
|
||
func (this *NSDomainService) FindNSDomain(ctx context.Context, req *pb.FindNSDomainRequest) (*pb.FindNSDomainResponse, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var tx = this.NullTx()
|
||
|
||
// 检查用户权限
|
||
if userId > 0 {
|
||
err = nameservers.SharedNSDomainDAO.CheckUserDomain(tx, userId, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
domain, err := nameservers.SharedNSDomainDAO.FindEnabledNSDomain(tx, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if domain == nil {
|
||
return &pb.FindNSDomainResponse{NsDomain: nil}, nil
|
||
}
|
||
|
||
// 集群
|
||
cluster, err := models.SharedNSClusterDAO.FindEnabledNSCluster(tx, int64(domain.ClusterId))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if cluster == nil {
|
||
return &pb.FindNSDomainResponse{NsDomain: nil}, nil
|
||
}
|
||
|
||
// 用户
|
||
var pbUser *pb.User
|
||
if domain.UserId > 0 {
|
||
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(domain.UserId), nil)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if user == nil {
|
||
return &pb.FindNSDomainResponse{NsDomain: nil}, nil
|
||
}
|
||
pbUser = &pb.User{
|
||
Id: int64(user.Id),
|
||
Username: user.Username,
|
||
Fullname: user.Fullname,
|
||
}
|
||
}
|
||
|
||
// groups
|
||
var pbGroups = []*pb.NSDomainGroup{}
|
||
var groupIds = domain.DecodeGroupIds()
|
||
for _, groupId := range groupIds {
|
||
group, err := nameservers.SharedNSDomainGroupDAO.FindEnabledNSDomainGroup(tx, groupId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if group != nil && group.IsOn {
|
||
pbGroups = append(pbGroups, &pb.NSDomainGroup{
|
||
Id: int64(group.Id),
|
||
Name: group.Name,
|
||
IsOn: group.IsOn,
|
||
UserId: int64(group.UserId),
|
||
})
|
||
}
|
||
}
|
||
|
||
return &pb.FindNSDomainResponse{
|
||
NsDomain: &pb.NSDomain{
|
||
Id: int64(domain.Id),
|
||
Name: domain.Name,
|
||
IsOn: domain.IsOn,
|
||
TsigJSON: domain.Tsig,
|
||
RecordsHealthCheckJSON: domain.RecordsHealthCheck,
|
||
CreatedAt: int64(domain.CreatedAt),
|
||
Status: domain.Status,
|
||
NsCluster: &pb.NSCluster{
|
||
Id: int64(cluster.Id),
|
||
IsOn: cluster.IsOn,
|
||
Name: cluster.Name,
|
||
},
|
||
UserId: int64(domain.UserId),
|
||
User: pbUser,
|
||
NsDomainGroupIds: groupIds,
|
||
NsDomainGroups: pbGroups,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// FindNSDomainWithName 根据域名名称查找域名
|
||
func (this *NSDomainService) FindNSDomainWithName(ctx context.Context, req *pb.FindNSDomainWithNameRequest) (*pb.FindNSDomainWithNameResponse, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if userId == 0 {
|
||
userId = req.UserId
|
||
}
|
||
|
||
var isUserRequest = userId > 0
|
||
|
||
if len(req.Name) == 0 {
|
||
return &pb.FindNSDomainWithNameResponse{
|
||
NsDomain: nil,
|
||
}, nil
|
||
}
|
||
|
||
var tx = this.NullTx()
|
||
domain, err := nameservers.SharedNSDomainDAO.FindDomainWithName(tx, userId, req.Name)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if domain == nil {
|
||
return &pb.FindNSDomainWithNameResponse{NsDomain: nil}, nil
|
||
}
|
||
|
||
// 集群
|
||
var pbCluster *pb.NSCluster
|
||
if !isUserRequest {
|
||
cluster, err := models.SharedNSClusterDAO.FindEnabledNSCluster(tx, int64(domain.ClusterId))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if cluster == nil {
|
||
return &pb.FindNSDomainWithNameResponse{NsDomain: nil}, nil
|
||
}
|
||
pbCluster = &pb.NSCluster{
|
||
Id: int64(cluster.Id),
|
||
IsOn: cluster.IsOn,
|
||
Name: cluster.Name,
|
||
}
|
||
}
|
||
|
||
// 用户
|
||
var pbUser *pb.User
|
||
if domain.UserId > 0 && !isUserRequest {
|
||
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(domain.UserId), nil)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if user == nil {
|
||
return &pb.FindNSDomainWithNameResponse{NsDomain: nil}, nil
|
||
}
|
||
pbUser = &pb.User{
|
||
Id: int64(user.Id),
|
||
Username: user.Username,
|
||
Fullname: user.Fullname,
|
||
}
|
||
}
|
||
|
||
// groups
|
||
var pbGroups = []*pb.NSDomainGroup{}
|
||
var groupIds = domain.DecodeGroupIds()
|
||
for _, groupId := range groupIds {
|
||
group, err := nameservers.SharedNSDomainGroupDAO.FindEnabledNSDomainGroup(tx, groupId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if group != nil && group.IsOn {
|
||
pbGroups = append(pbGroups, &pb.NSDomainGroup{
|
||
Id: int64(group.Id),
|
||
Name: group.Name,
|
||
IsOn: group.IsOn,
|
||
UserId: int64(group.UserId),
|
||
})
|
||
}
|
||
}
|
||
|
||
return &pb.FindNSDomainWithNameResponse{
|
||
NsDomain: &pb.NSDomain{
|
||
Id: int64(domain.Id),
|
||
Name: domain.Name,
|
||
IsOn: domain.IsOn,
|
||
TsigJSON: domain.Tsig,
|
||
Status: domain.Status,
|
||
CreatedAt: int64(domain.CreatedAt),
|
||
NsCluster: pbCluster,
|
||
User: pbUser,
|
||
NsDomainGroupIds: groupIds,
|
||
NsDomainGroups: pbGroups,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// FindVerifiedNSDomainOnCluster 根据域名名称查找集群中的已验证域名
|
||
func (this *NSDomainService) FindVerifiedNSDomainOnCluster(ctx context.Context, req *pb.FindVerifiedNSDomainOnClusterRequest) (*pb.FindVerifiedNSDomainOnClusterResponse, error) {
|
||
_, err := this.ValidateAdmin(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var tx = this.NullTx()
|
||
domain, err := nameservers.SharedNSDomainDAO.FindVerifiedDomainWithNameOnCluster(tx, req.NsClusterId, req.Name)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if domain == nil {
|
||
return &pb.FindVerifiedNSDomainOnClusterResponse{
|
||
NsDomain: nil,
|
||
}, nil
|
||
}
|
||
|
||
return &pb.FindVerifiedNSDomainOnClusterResponse{
|
||
NsDomain: &pb.NSDomain{
|
||
Id: int64(domain.Id),
|
||
Name: domain.Name,
|
||
IsOn: domain.IsOn,
|
||
Status: domain.Status,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// CountAllNSDomains 计算域名数量
|
||
func (this *NSDomainService) CountAllNSDomains(ctx context.Context, req *pb.CountAllNSDomainsRequest) (*pb.RPCCountResponse, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var tx = this.NullTx()
|
||
if userId > 0 {
|
||
req.UserId = userId
|
||
|
||
// 检查分组
|
||
if req.NsDomainGroupId > 0 {
|
||
err = nameservers.SharedNSDomainGroupDAO.CheckUserGroup(tx, userId, req.NsDomainGroupId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
|
||
count, err := nameservers.SharedNSDomainDAO.CountAllEnabledDomains(tx, req.NsClusterId, req.UserId, req.NsDomainGroupId, req.Status, req.Keyword)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return this.SuccessCount(count)
|
||
}
|
||
|
||
// ListNSDomains 列出单页域名
|
||
func (this *NSDomainService) ListNSDomains(ctx context.Context, req *pb.ListNSDomainsRequest) (*pb.ListNSDomainsResponse, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var isUserRequest = userId > 0
|
||
|
||
var tx = this.NullTx()
|
||
|
||
if userId > 0 {
|
||
req.UserId = userId
|
||
|
||
// 检查分组
|
||
if req.NsDomainGroupId > 0 {
|
||
err = nameservers.SharedNSDomainGroupDAO.CheckUserGroup(tx, userId, req.NsDomainGroupId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
|
||
domains, err := nameservers.SharedNSDomainDAO.ListEnabledDomains(tx, req.NsClusterId, req.UserId, req.NsDomainGroupId, req.Keyword, req.Offset, req.Size)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var pbDomains = []*pb.NSDomain{}
|
||
var cacheMap = utils.NewCacheMap()
|
||
for _, domain := range domains {
|
||
// 集群
|
||
cluster, err := models.SharedNSClusterDAO.FindEnabledNSCluster(tx, int64(domain.ClusterId))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if cluster == nil {
|
||
continue
|
||
}
|
||
|
||
// 用户
|
||
var pbUser *pb.User
|
||
if domain.UserId > 0 && !isUserRequest {
|
||
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(domain.UserId), cacheMap)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if user == nil {
|
||
continue
|
||
}
|
||
pbUser = &pb.User{
|
||
Id: int64(user.Id),
|
||
Username: user.Username,
|
||
Fullname: user.Fullname,
|
||
}
|
||
}
|
||
|
||
// groups
|
||
var pbGroups = []*pb.NSDomainGroup{}
|
||
var groupIds = domain.DecodeGroupIds()
|
||
for _, groupId := range groupIds {
|
||
group, err := nameservers.SharedNSDomainGroupDAO.FindEnabledNSDomainGroup(tx, groupId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if group != nil && group.IsOn {
|
||
pbGroups = append(pbGroups, &pb.NSDomainGroup{
|
||
Id: int64(group.Id),
|
||
Name: group.Name,
|
||
IsOn: group.IsOn,
|
||
UserId: int64(group.UserId),
|
||
})
|
||
}
|
||
}
|
||
|
||
var pbCluster *pb.NSCluster
|
||
if !isUserRequest {
|
||
pbCluster = &pb.NSCluster{
|
||
Id: int64(cluster.Id),
|
||
IsOn: cluster.IsOn,
|
||
Name: cluster.Name,
|
||
}
|
||
}
|
||
|
||
pbDomains = append(pbDomains, &pb.NSDomain{
|
||
Id: int64(domain.Id),
|
||
Name: domain.Name,
|
||
Status: domain.Status,
|
||
IsOn: domain.IsOn,
|
||
CreatedAt: int64(domain.CreatedAt),
|
||
TsigJSON: domain.Tsig,
|
||
NsCluster: pbCluster,
|
||
User: pbUser,
|
||
NsDomainGroupIds: groupIds,
|
||
NsDomainGroups: pbGroups,
|
||
})
|
||
}
|
||
|
||
return &pb.ListNSDomainsResponse{NsDomains: pbDomains}, nil
|
||
}
|
||
|
||
// ListNSDomainsAfterVersion 根据版本列出一组域名
|
||
func (this *NSDomainService) ListNSDomainsAfterVersion(ctx context.Context, req *pb.ListNSDomainsAfterVersionRequest) (*pb.ListNSDomainsAfterVersionResponse, error) {
|
||
_, _, err := this.ValidateNodeId(ctx, rpcutils.UserTypeDNS)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return &pb.ListNSDomainsAfterVersionResponse{
|
||
NsDomains: nil,
|
||
}, nil
|
||
}
|
||
|
||
// 集群ID
|
||
var tx = this.NullTx()
|
||
if req.Size <= 0 {
|
||
req.Size = 2000
|
||
}
|
||
domains, err := nameservers.SharedNSDomainDAO.ListDomainsAfterVersion(tx, req.Version, req.Size)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var pbDomains []*pb.NSDomain
|
||
for _, domain := range domains {
|
||
pbDomains = append(pbDomains, &pb.NSDomain{
|
||
Id: int64(domain.Id),
|
||
Name: domain.Name,
|
||
IsOn: domain.IsOn,
|
||
Status: domain.Status,
|
||
IsDeleted: domain.State == nameservers.NSDomainStateDisabled || domain.Status != dnsconfigs.NSDomainStatusVerified,
|
||
Version: int64(domain.Version),
|
||
UserId: types.Int64(domain.UserId),
|
||
TsigJSON: domain.Tsig,
|
||
NsCluster: &pb.NSCluster{Id: int64(domain.ClusterId)},
|
||
User: nil,
|
||
})
|
||
}
|
||
return &pb.ListNSDomainsAfterVersionResponse{NsDomains: pbDomains}, nil
|
||
}
|
||
|
||
// FindNSDomainTSIG 查找TSIG配置
|
||
func (this *NSDomainService) FindNSDomainTSIG(ctx context.Context, req *pb.FindNSDomainTSIGRequest) (*pb.FindNSDomainTSIGResponse, error) {
|
||
_, err := this.ValidateAdmin(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var tx = this.NullTx()
|
||
tsig, err := nameservers.SharedNSDomainDAO.FindEnabledDomainTSIG(tx, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &pb.FindNSDomainTSIGResponse{TsigJSON: tsig}, nil
|
||
}
|
||
|
||
// UpdateNSDomainTSIG 修改TSIG配置
|
||
func (this *NSDomainService) UpdateNSDomainTSIG(ctx context.Context, req *pb.UpdateNSDomainTSIGRequest) (*pb.RPCSuccess, error) {
|
||
_, err := this.ValidateAdmin(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var tx = this.NullTx()
|
||
err = nameservers.SharedNSDomainDAO.UpdateDomainTSIG(tx, req.NsDomainId, req.TsigJSON)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return this.Success()
|
||
}
|
||
|
||
// ExistNSDomains 检查一组域名是否在用户账户中存在
|
||
func (this *NSDomainService) ExistNSDomains(ctx context.Context, req *pb.ExistNSDomainsRequest) (*pb.ExistNSDomainsResponse, error) {
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if userId > 0 {
|
||
req.UserId = userId
|
||
}
|
||
|
||
var existingDomains = []string{}
|
||
|
||
var tx = this.NullTx()
|
||
for _, domainName := range req.Names {
|
||
domainName = strings.ToLower(domainName)
|
||
b, err := nameservers.SharedNSDomainDAO.ExistUserDomain(tx, req.UserId, domainName)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if b {
|
||
existingDomains = append(existingDomains, domainName)
|
||
}
|
||
}
|
||
|
||
return &pb.ExistNSDomainsResponse{ExistingNames: existingDomains}, nil
|
||
}
|
||
|
||
// ExistVerifiedNSDomains 检查一组域名是否已通过验证
|
||
func (this *NSDomainService) ExistVerifiedNSDomains(ctx context.Context, req *pb.ExistVerifiedNSDomainsRequest) (*pb.ExistVerifiedNSDomainsResponse, error) {
|
||
_, _, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var existingDomains = []string{}
|
||
|
||
var tx = this.NullTx()
|
||
for _, domainName := range req.Names {
|
||
domainName = strings.ToLower(domainName)
|
||
b, err := nameservers.SharedNSDomainDAO.ExistVerifiedDomain(tx, domainName)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if b {
|
||
existingDomains = append(existingDomains, domainName)
|
||
}
|
||
}
|
||
|
||
return &pb.ExistVerifiedNSDomainsResponse{ExistingNames: existingDomains}, nil
|
||
}
|
||
|
||
// FindNSDomainVerifyingInfo 获取域名验证信息
|
||
func (this *NSDomainService) FindNSDomainVerifyingInfo(ctx context.Context, req *pb.FindNSDomainVerifyingInfoRequest) (*pb.FindNSDomainVerifyingInfoResponse, error) {
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 检查权限
|
||
var tx = this.NullTx()
|
||
if userId > 0 {
|
||
err = nameservers.SharedNSDomainDAO.CheckUserDomain(tx, userId, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
// 检查域名是否已被别的用户验证
|
||
domainName, err := nameservers.SharedNSDomainDAO.FindNSDomainName(tx, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if len(domainName) == 0 {
|
||
return nil, errors.New("could not find domain name with id '" + types.String(req.NsDomainId) + "'")
|
||
}
|
||
|
||
verifiedDomain, err := nameservers.SharedNSDomainDAO.FindVerifiedDomainWithName(tx, domainName)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if verifiedDomain == nil || int64(verifiedDomain.UserId) == userId {
|
||
// 如果当前域名没有验证过,或者是自己的验证过的域名,则直接不需要通过TXT再次验证
|
||
return &pb.FindNSDomainVerifyingInfoResponse{
|
||
RequireTXT: false,
|
||
}, nil
|
||
}
|
||
|
||
// 生成TXT
|
||
domain, err := nameservers.SharedNSDomainDAO.FindDomainVerifyingInfo(tx, req.NsDomainId, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if domain == nil {
|
||
return &pb.FindNSDomainVerifyingInfoResponse{
|
||
Txt: "",
|
||
ExpiresAt: 0,
|
||
Status: "",
|
||
}, nil
|
||
}
|
||
|
||
return &pb.FindNSDomainVerifyingInfoResponse{
|
||
RequireTXT: true,
|
||
Txt: domain.VerifyTXT,
|
||
ExpiresAt: int64(domain.VerifyExpiresAt),
|
||
Status: domain.Status,
|
||
}, nil
|
||
}
|
||
|
||
// VerifyNSDomain 验证域名信息
|
||
func (this *NSDomainService) VerifyNSDomain(ctx context.Context, req *pb.VerifyNSDomainRequest) (*pb.VerifyNSDomainResponse, error) {
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 检查权限
|
||
var tx = this.NullTx()
|
||
if userId > 0 {
|
||
err = nameservers.SharedNSDomainDAO.CheckUserDomain(tx, userId, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
// 客户端需要处理的错误代号列表
|
||
const (
|
||
ErrorCodeDomainNotFound = "DomainNotFound"
|
||
ErrorCodeInvalidStatus = "InvalidStatus"
|
||
ErrorCodeInvalidDNSHosts = "InvalidDNSHosts"
|
||
ErrorCodeInvalidTXT = "InvalidTXT"
|
||
ErrorCodeTXTNotFound = "TXTNotFound"
|
||
ErrorCodeTXTExpired = "TXTExpired"
|
||
)
|
||
|
||
// 验证状态
|
||
domain, err := nameservers.SharedNSDomainDAO.FindEnabledNSDomain(tx, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if domain == nil {
|
||
return &pb.VerifyNSDomainResponse{
|
||
ErrorCode: ErrorCodeDomainNotFound,
|
||
}, nil
|
||
}
|
||
|
||
if domain.Status != dnsconfigs.NSDomainStatusNone {
|
||
return &pb.VerifyNSDomainResponse{
|
||
ErrorCode: ErrorCodeInvalidStatus,
|
||
ErrorMessage: "invalid status '" + domain.Status + "'",
|
||
}, nil
|
||
}
|
||
|
||
// 检查是否已被别的用户所验证
|
||
var requireTXT = true
|
||
var oldDomainId int64
|
||
if userId > 0 {
|
||
verifiedDomain, err := nameservers.SharedNSDomainDAO.FindVerifiedDomainWithName(tx, domain.Name)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if verifiedDomain == nil || int64(verifiedDomain.UserId) == userId {
|
||
requireTXT = false
|
||
}
|
||
if verifiedDomain != nil {
|
||
oldDomainId = int64(verifiedDomain.Id)
|
||
}
|
||
}
|
||
|
||
if requireTXT && (len(domain.VerifyTXT) == 0 || int64(domain.VerifyExpiresAt) < time.Now().Unix()) {
|
||
return &pb.VerifyNSDomainResponse{
|
||
ErrorCode: ErrorCodeTXTExpired,
|
||
}, nil
|
||
}
|
||
|
||
// 当前集群的DNS Hosts
|
||
userConfig, err := models.SharedSysSettingDAO.ReadNSUserConfig(tx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if userConfig == nil {
|
||
return nil, errors.New("invalid NSUserConfig")
|
||
}
|
||
|
||
// 是否需要验证
|
||
var shouldValidate = userConfig.DomainValidation != nil && userConfig.DomainValidation.IsOn
|
||
if !shouldValidate {
|
||
// 设置为验证通过
|
||
err = nameservers.SharedNSDomainDAO.UpdateDomainStatus(tx, req.NsDomainId, dnsconfigs.NSDomainStatusVerified)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &pb.VerifyNSDomainResponse{
|
||
IsOk: true,
|
||
}, nil
|
||
}
|
||
|
||
userHosts, err := models.SharedNSClusterDAO.FindClusterHosts(tx, int64(domain.ClusterId))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if len(userHosts) == 0 {
|
||
return nil, errors.New("no hosts in the ns cluster")
|
||
}
|
||
|
||
// 验证主机地址
|
||
nsHosts, err := utils.LookupNS(domain.Name, userConfig.DomainValidation.Resolvers)
|
||
if err != nil {
|
||
remotelogs.Error("NSDomainService", "lookup NS '"+domain.Name+"' failed: "+err.Error())
|
||
return &pb.VerifyNSDomainResponse{
|
||
ErrorCode: ErrorCodeInvalidDNSHosts,
|
||
}, nil
|
||
}
|
||
|
||
if len(nsHosts) == 0 {
|
||
return &pb.VerifyNSDomainResponse{
|
||
ErrorCode: ErrorCodeInvalidDNSHosts,
|
||
CurrentNSValues: nsHosts,
|
||
}, nil
|
||
}
|
||
|
||
if len(nsHosts) > 0 {
|
||
for _, host := range nsHosts {
|
||
host = strings.TrimSuffix(host, ".")
|
||
if !lists.ContainsString(userHosts, host) {
|
||
return &pb.VerifyNSDomainResponse{
|
||
ErrorCode: ErrorCodeInvalidDNSHosts,
|
||
ErrorMessage: "invalid dns host '" + host + "'",
|
||
CurrentNSValues: nsHosts,
|
||
}, nil
|
||
}
|
||
}
|
||
}
|
||
|
||
// 验证TXT
|
||
if requireTXT {
|
||
txtList, err := utils.LookupTXT("yanzheng."+domain.Name, userConfig.DomainValidation.Resolvers)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if len(txtList) == 0 {
|
||
return &pb.VerifyNSDomainResponse{
|
||
ErrorCode: ErrorCodeTXTNotFound,
|
||
ErrorMessage: "",
|
||
}, nil
|
||
}
|
||
|
||
if !lists.ContainsString(txtList, domain.VerifyTXT) {
|
||
return &pb.VerifyNSDomainResponse{
|
||
ErrorCode: ErrorCodeInvalidTXT,
|
||
ErrorMessage: strings.Join(txtList, ", "),
|
||
CurrentTXTValues: txtList,
|
||
}, nil
|
||
}
|
||
}
|
||
|
||
// 取消原有老的验证过的同名域名
|
||
if oldDomainId > 0 {
|
||
err = nameservers.SharedNSDomainDAO.DisableNSDomain(tx, oldDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
// 设置为验证通过
|
||
err = nameservers.SharedNSDomainDAO.UpdateDomainStatus(tx, req.NsDomainId, dnsconfigs.NSDomainStatusVerified)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &pb.VerifyNSDomainResponse{
|
||
IsOk: true,
|
||
}, nil
|
||
}
|
||
|
||
// FindNSDomainRecordsHealthCheck 查询记录健康检查全局设置
|
||
func (this *NSDomainService) FindNSDomainRecordsHealthCheck(ctx context.Context, req *pb.FindNSDomainRecordsHealthCheckRequest) (*pb.FindNSDomainRecordsHealthCheckResponse, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 检查权限
|
||
var tx = this.NullTx()
|
||
if userId > 0 {
|
||
err = nameservers.SharedNSDomainDAO.CheckUserDomain(tx, userId, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// TODO 检查套餐
|
||
}
|
||
|
||
config, err := nameservers.SharedNSDomainDAO.FindRecordsHealthCheckConfig(tx, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
configJSON, err := json.Marshal(config)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &pb.FindNSDomainRecordsHealthCheckResponse{NsDomainRecordsHealthCheckJSON: configJSON}, nil
|
||
}
|
||
|
||
// UpdateNSDomainRecordsHealthCheck 修改记录健康检查全局设置
|
||
func (this *NSDomainService) UpdateNSDomainRecordsHealthCheck(ctx context.Context, req *pb.UpdateNSDomainRecordsHealthCheckRequest) (*pb.RPCSuccess, error) {
|
||
// 检查是否为商业用户
|
||
if !teaconst.IsPlus {
|
||
return nil, errors.New("non commercial user")
|
||
}
|
||
|
||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 检查权限
|
||
var tx = this.NullTx()
|
||
if userId > 0 {
|
||
err = nameservers.SharedNSDomainDAO.CheckUserDomain(tx, userId, req.NsDomainId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// TODO 检查套餐
|
||
}
|
||
|
||
if len(req.NsDomainRecordsHealthCheckJSON) == 0 {
|
||
return nil, errors.New("invalid 'nsDomainRecordsHealthCheckJSON'")
|
||
}
|
||
|
||
var config = dnsconfigs.NewNSRecordsHealthCheckConfig()
|
||
err = json.Unmarshal(req.NsDomainRecordsHealthCheckJSON, config)
|
||
if err != nil {
|
||
return nil, errors.New("decode 'nsDomainRecordsHealthCheckJSON' failed: " + err.Error())
|
||
}
|
||
|
||
err = nameservers.SharedNSDomainDAO.UpdateRecordsHealthCheckConfig(tx, req.NsDomainId, config)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return this.Success()
|
||
}
|