Initial commit

This commit is contained in:
2026-06-30 15:14:37 +08:00
commit 15dab96872
311 changed files with 95639 additions and 0 deletions
+203
View File
@@ -0,0 +1,203 @@
package service
import (
"crypto/rand"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"time"
"git.zkcoi.com/zkcoi/meshray/internal/model"
sqlite "git.zkcoi.com/zkcoi/meshray/internal/store/sqlite"
"go.uber.org/zap"
"golang.org/x/crypto/ed25519"
"gorm.io/gorm"
)
// MeshSeedService MeshSeed 服务
type MeshSeedService struct {
store *sqlite.Store
logger *zap.Logger
signingKey ed25519.PrivateKey // Ed25519 签名密钥
issuerNodeID string // 签发节点 ID
}
// NewMeshSeedService 创建 MeshSeed 服务
func NewMeshSeedService(store *sqlite.Store, logger *zap.Logger, signingKey ed25519.PrivateKey, issuerNodeID string) *MeshSeedService {
return &MeshSeedService{
store: store,
logger: logger,
signingKey: signingKey,
issuerNodeID: issuerNodeID,
}
}
// GenerateMeshSeed 生成 MeshSeed
func (s *MeshSeedService) GenerateMeshSeed(networkID uint64, maxUses int, expiresAt time.Time, ddnsEnabled bool) (*model.MeshSeed, error) {
// 1. 验证网络是否存在
var network model.Network
if err := s.store.DB().First(&network, networkID).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("网络不存在")
}
return nil, fmt.Errorf("查询网络失败:%w", err)
}
// 2. 生成随机 SeedID16 字节随机数)
seedBytes := make([]byte, 16)
if _, err := rand.Read(seedBytes); err != nil {
return nil, fmt.Errorf("生成随机数失败:%w", err)
}
seedID := base64.RawURLEncoding.EncodeToString(seedBytes)
// 3. 构建 JoinToken(包含网络信息)
joinTokenData := map[string]interface{}{
"seed_id": seedID,
"network_id": networkID,
"network_name": network.Name,
"subnet_ipv4": network.SubnetIPv4,
"mode": network.Mode,
"ddns_enabled": ddnsEnabled,
"expires_at": expiresAt.Unix(),
"max_uses": maxUses,
}
// 序列化为 JSON
tokenJSON, err := json.Marshal(joinTokenData)
if err != nil {
return nil, fmt.Errorf("序列化 Token 失败:%w", err)
}
// Base64 编码
joinToken := base64.StdEncoding.EncodeToString(tokenJSON)
// 4. Ed25519 签名
signature := ed25519.Sign(s.signingKey, []byte(joinToken))
signatureStr := base64.StdEncoding.EncodeToString(signature)
// 5. 创建 MeshSeed 记录
meshSeed := &model.MeshSeed{
SeedID: seedID,
NetworkID: networkID,
JoinToken: joinToken,
Signature: signatureStr,
IssuerNodeID: s.issuerNodeID,
MaxUses: maxUses,
UsedCount: 0,
ExpiresAt: expiresAt,
DDNSEnabled: ddnsEnabled,
UpdateVersion: 0,
Revoked: false,
}
if err := s.store.DB().Create(meshSeed).Error; err != nil {
return nil, fmt.Errorf("创建 MeshSeed 失败:%w", err)
}
s.logger.Info("MeshSeed 已生成",
zap.String("seed_id", seedID),
zap.Uint64("network_id", networkID),
zap.Int("max_uses", maxUses),
zap.Time("expires_at", expiresAt))
return meshSeed, nil
}
// VerifyMeshSeed 验证 MeshSeed
func (s *MeshSeedService) VerifyMeshSeed(joinToken, signature string) (*model.MeshSeed, error) {
// 1. 解码 JoinToken
tokenBytes, err := base64.StdEncoding.DecodeString(joinToken)
if err != nil {
return nil, fmt.Errorf("解码 Token 失败:%w", err)
}
// 2. 解码签名
sigBytes, err := base64.StdEncoding.DecodeString(signature)
if err != nil {
return nil, fmt.Errorf("解码签名失败:%w", err)
}
// 3. 验证 Ed25519 签名
publicKey := s.signingKey.Public()
if !ed25519.Verify(publicKey.(ed25519.PublicKey), tokenBytes, sigBytes) {
return nil, fmt.Errorf("签名验证失败")
}
// 4. 解析 Token 内容
var tokenData map[string]interface{}
if err := json.Unmarshal(tokenBytes, &tokenData); err != nil {
return nil, fmt.Errorf("解析 Token 失败:%w", err)
}
seedID, ok := tokenData["seed_id"].(string)
if !ok {
return nil, fmt.Errorf("Token 格式错误")
}
// 5. 查询 MeshSeed
var meshSeed model.MeshSeed
if err := s.store.DB().Where("seed_id = ?", seedID).First(&meshSeed).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("MeshSeed 不存在")
}
return nil, fmt.Errorf("查询 MeshSeed 失败:%w", err)
}
// 6. 检查是否被吊销
if meshSeed.Revoked {
return nil, fmt.Errorf("MeshSeed 已被吊销")
}
// 7. 检查使用次数
if meshSeed.UsedCount >= meshSeed.MaxUses {
return nil, fmt.Errorf("MeshSeed 使用次数已用尽")
}
// 8. 检查过期时间
if time.Now().After(meshSeed.ExpiresAt) {
return nil, fmt.Errorf("MeshSeed 已过期")
}
return &meshSeed, nil
}
// IncrementUseCount 增加使用次数
func (s *MeshSeedService) IncrementUseCount(seedID string) error {
return s.store.DB().Transaction(func(tx *gorm.DB) error {
var meshSeed model.MeshSeed
if err := tx.Where("seed_id = ?", seedID).First(&meshSeed).Error; err != nil {
return err
}
return tx.Model(&meshSeed).UpdateColumn("used_count", meshSeed.UsedCount+1).Error
})
}
// RevokeMeshSeed 吊销 MeshSeed
func (s *MeshSeedService) RevokeMeshSeed(seedID string) error {
result := s.store.DB().Model(&model.MeshSeed{}).
Where("seed_id = ?", seedID).
Update("revoked", true)
if result.Error != nil {
return fmt.Errorf("吊销 MeshSeed 失败:%w", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("MeshSeed 不存在")
}
s.logger.Info("MeshSeed 已吊销", zap.String("seed_id", seedID))
return nil
}
// ListMeshSeeds 获取网络的 MeshSeed 列表
func (s *MeshSeedService) ListMeshSeeds(networkID uint) ([]model.MeshSeed, error) {
var seeds []model.MeshSeed
err := s.store.DB().Where("network_id = ? AND revoked = ?", networkID, false).
Order("created_at DESC").
Find(&seeds).Error
return seeds, err
}