Files
backend/internal/service/yggdrasil_certificate_service.go
lan 0bcd9336c4 refactor: Update service and repository methods to use context
- Refactored multiple service and repository methods to accept context as a parameter, enhancing consistency and enabling better control over request lifecycles.
- Updated handlers to utilize context in method calls, improving error handling and performance.
- Cleaned up Dockerfile by removing unnecessary whitespace.
2025-12-03 15:27:12 +08:00

113 lines
3.0 KiB
Go

package service
import (
apperrors "carrotskin/internal/errors"
"carrotskin/internal/repository"
"context"
"fmt"
"time"
"go.uber.org/zap"
)
// CertificateService 证书服务接口
type CertificateService interface {
// GeneratePlayerCertificate 生成玩家证书
GeneratePlayerCertificate(ctx context.Context, uuid string) (map[string]interface{}, error)
// GetPublicKey 获取公钥
GetPublicKey(ctx context.Context) (string, error)
}
// yggdrasilCertificateService 证书服务实现
type yggdrasilCertificateService struct {
profileRepo repository.ProfileRepository
signatureService *SignatureService
logger *zap.Logger
}
// NewCertificateService 创建证书服务实例
func NewCertificateService(
profileRepo repository.ProfileRepository,
signatureService *SignatureService,
logger *zap.Logger,
) CertificateService {
return &yggdrasilCertificateService{
profileRepo: profileRepo,
signatureService: signatureService,
logger: logger,
}
}
// GeneratePlayerCertificate 生成玩家证书
func (s *yggdrasilCertificateService) GeneratePlayerCertificate(ctx context.Context, uuid string) (map[string]interface{}, error) {
if uuid == "" {
return nil, apperrors.ErrUUIDRequired
}
s.logger.Info("开始生成玩家证书",
zap.String("uuid", uuid),
)
// 获取密钥对
keyPair, err := s.profileRepo.GetKeyPair(ctx, uuid)
if err != nil {
s.logger.Info("获取用户密钥对失败,将创建新密钥对",
zap.Error(err),
zap.String("uuid", uuid),
)
keyPair = nil
}
// 如果没有找到密钥对或密钥对已过期,创建一个新的
now := time.Now().UTC()
if keyPair == nil || keyPair.Refresh.Before(now) || keyPair.PrivateKey == "" || keyPair.PublicKey == "" {
s.logger.Info("为用户创建新的密钥对",
zap.String("uuid", uuid),
)
keyPair, err = s.signatureService.NewKeyPair()
if err != nil {
s.logger.Error("生成玩家证书密钥对失败",
zap.Error(err),
zap.String("uuid", uuid),
)
return nil, fmt.Errorf("生成玩家证书密钥对失败: %w", err)
}
// 保存密钥对到数据库
err = s.profileRepo.UpdateKeyPair(ctx, uuid, keyPair)
if err != nil {
s.logger.Warn("更新用户密钥对失败",
zap.Error(err),
zap.String("uuid", uuid),
)
// 继续执行,即使保存失败
}
}
// 计算expiresAt的毫秒时间戳
expiresAtMillis := keyPair.Expiration.UnixMilli()
// 返回玩家证书
certificate := map[string]interface{}{
"keyPair": map[string]interface{}{
"privateKey": keyPair.PrivateKey,
"publicKey": keyPair.PublicKey,
},
"publicKeySignature": keyPair.PublicKeySignature,
"publicKeySignatureV2": keyPair.PublicKeySignatureV2,
"expiresAt": expiresAtMillis,
"refreshedAfter": keyPair.Refresh.UnixMilli(),
}
s.logger.Info("成功生成玩家证书",
zap.String("uuid", uuid),
)
return certificate, nil
}
// GetPublicKey 获取公钥
func (s *yggdrasilCertificateService) GetPublicKey(ctx context.Context) (string, error) {
return s.signatureService.GetPublicKeyFromRedis()
}