Files
go-trustlog/api/model/crypto_config.go
ryan 4b72a37120 feat: 完善数据库持久化与存证功能
主要更新:

1. 数据库持久化功能
   - 支持三种策略:仅落库、既落库又存证、仅存证
   - 实现 Cursor Worker 异步扫描和存证机制
   - 实现 Retry Worker 失败重试机制
   - 支持 PostgreSQL、MySQL、SQLite 等多种数据库
   - 添加 ClientIP 和 ServerIP 字段(可空,仅落库)

2. 集群并发安全
   - 使用 SELECT FOR UPDATE SKIP LOCKED 防止重复处理
   - 实现 CAS (Compare-And-Set) 原子状态更新
   - 添加 updated_at 字段支持并发控制

3. Cursor 初始化优化
   - 自动基于历史数据初始化 cursor
   - 确保不遗漏任何历史记录
   - 修复 UPSERT 逻辑

4. 测试完善
   - 添加 E2E 集成测试(含 Pulsar 消费者验证)
   - 添加 PostgreSQL 集成测试
   - 添加 Pulsar 集成测试
   - 添加集群并发安全测试
   - 添加 Cursor 初始化验证测试
   - 补充大量单元测试,提升覆盖率

5. 工具脚本
   - 添加数据库迁移脚本
   - 添加 Cursor 状态检查工具
   - 添加 Cursor 初始化工具
   - 添加 Pulsar 消息验证工具

6. 文档清理
   - 删除冗余文档,只保留根目录 README

测试结果:
- 所有 E2E 测试通过(100%)
- 数据库持久化与异步存证流程验证通过
- 集群环境下的并发安全性验证通过
- Cursor 自动初始化和历史数据处理验证通过
2025-12-24 15:31:11 +08:00

311 lines
7.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"crypto/rand"
"errors"
"fmt"
"io"
"sync"
"github.com/crpt/go-crpt"
_ "github.com/crpt/go-crpt/ed25519" // Import Ed25519
_ "github.com/crpt/go-crpt/sm2" // Import SM2
"go.yandata.net/iod/iod/go-trustlog/api/logger"
)
// SignatureAlgorithm 定义支持的签名算法类型.
type SignatureAlgorithm string
const (
// SM2 国密SM2算法
SM2Algorithm SignatureAlgorithm = "sm2"
// Ed25519 Ed25519算法
Ed25519Algorithm SignatureAlgorithm = "ed25519"
)
// CryptoConfig 密码学配置
type CryptoConfig struct {
// SignatureAlgorithm 签名算法类型
// SM2 会自动使用 SM3 哈希Ed25519 会使用 SHA512 哈希
SignatureAlgorithm SignatureAlgorithm
}
var (
// 默认配置:使用 SM2内部自动使用 SM3
defaultConfig = &CryptoConfig{
SignatureAlgorithm: SM2Algorithm,
}
// 全局配置
globalConfig *CryptoConfig
globalConfigMutex sync.RWMutex
// ErrUnsupportedAlgorithm 不支持的算法错误
ErrUnsupportedAlgorithm = errors.New("unsupported signature algorithm")
)
func init() {
// 自动初始化全局配置为 SM2
globalConfig = defaultConfig
logger.GetGlobalLogger().Debug("Crypto config initialized with default SM2")
}
// SetGlobalCryptoConfig 设置全局密码学配置
func SetGlobalCryptoConfig(config *CryptoConfig) error {
if config == nil {
return errors.New("config cannot be nil")
}
// 验证配置
if err := config.Validate(); err != nil {
return fmt.Errorf("invalid config: %w", err)
}
globalConfigMutex.Lock()
defer globalConfigMutex.Unlock()
globalConfig = config
logger.GetGlobalLogger().Info("Global crypto config updated",
"signatureAlgorithm", config.SignatureAlgorithm,
)
return nil
}
// GetGlobalCryptoConfig 获取全局密码学配置
func GetGlobalCryptoConfig() *CryptoConfig {
globalConfigMutex.RLock()
defer globalConfigMutex.RUnlock()
if globalConfig == nil {
return defaultConfig
}
return globalConfig
}
// Validate 验证配置是否有效
func (c *CryptoConfig) Validate() error {
// 验证签名算法
switch c.SignatureAlgorithm {
case SM2Algorithm, Ed25519Algorithm:
// 支持的算法
default:
return fmt.Errorf("%w: %s", ErrUnsupportedAlgorithm, c.SignatureAlgorithm)
}
return nil
}
// toKeyType 将 SignatureAlgorithm 转换为 crpt.KeyType
func (a SignatureAlgorithm) toKeyType() (crpt.KeyType, error) {
switch a {
case SM2Algorithm:
return crpt.SM2, nil
case Ed25519Algorithm:
return crpt.Ed25519, nil
default:
return 0, fmt.Errorf("%w: %s", ErrUnsupportedAlgorithm, a)
}
}
// KeyPair 通用密钥对,支持多种算法
type KeyPair struct {
Public crpt.PublicKey `json:"publicKey"`
Private crpt.PrivateKey `json:"privateKey"`
Algorithm SignatureAlgorithm
}
// GenerateKeyPair 根据配置生成密钥对
func GenerateKeyPair(config *CryptoConfig) (*KeyPair, error) {
if config == nil {
config = GetGlobalCryptoConfig()
}
log := logger.GetGlobalLogger()
log.Debug("Generating key pair",
"algorithm", config.SignatureAlgorithm,
)
keyType, err := config.SignatureAlgorithm.toKeyType()
if err != nil {
return nil, err
}
pub, priv, err := crpt.GenerateKey(keyType, rand.Reader)
if err != nil {
log.Error("Failed to generate key pair",
"algorithm", config.SignatureAlgorithm,
"error", err,
)
return nil, fmt.Errorf("failed to generate %s key pair: %w", config.SignatureAlgorithm, err)
}
log.Debug("Key pair generated successfully",
"algorithm", config.SignatureAlgorithm,
)
return &KeyPair{
Public: pub,
Private: priv,
Algorithm: config.SignatureAlgorithm,
}, nil
}
// Sign 使用密钥对签名数据
func (kp *KeyPair) Sign(data []byte, rand io.Reader) ([]byte, error) {
if rand == nil {
rand = defaultRand()
}
log := logger.GetGlobalLogger()
log.Debug("Signing data",
"algorithm", kp.Algorithm,
"dataLength", len(data),
)
signature, err := crpt.SignMessage(kp.Private, data, rand, nil)
if err != nil {
log.Error("Failed to sign data",
"algorithm", kp.Algorithm,
"error", err,
)
return nil, fmt.Errorf("failed to sign with %s: %w", kp.Algorithm, err)
}
log.Debug("Data signed successfully",
"algorithm", kp.Algorithm,
"signatureLength", len(signature),
)
return signature, nil
}
// Verify 使用公钥验证签名
func (kp *KeyPair) Verify(data, signature []byte) (bool, error) {
log := logger.GetGlobalLogger()
log.Debug("Verifying signature",
"algorithm", kp.Algorithm,
"dataLength", len(data),
"signatureLength", len(signature),
)
ok, err := crpt.VerifyMessage(kp.Public, data, crpt.Signature(signature), nil)
if err != nil {
log.Error("Failed to verify signature",
"algorithm", kp.Algorithm,
"error", err,
)
return false, fmt.Errorf("failed to verify with %s: %w", kp.Algorithm, err)
}
if ok {
log.Debug("Signature verified successfully",
"algorithm", kp.Algorithm,
)
} else {
log.Warn("Signature verification failed",
"algorithm", kp.Algorithm,
)
}
return ok, nil
}
// MarshalPrivateKey 序列化私钥
func (kp *KeyPair) MarshalPrivateKey() ([]byte, error) {
if kp.Private == nil {
return nil, errors.New("private key is nil")
}
return kp.Private.Bytes(), nil
}
// MarshalPublicKey 序列化公钥
func (kp *KeyPair) MarshalPublicKey() ([]byte, error) {
if kp.Public == nil {
return nil, errors.New("public key is nil")
}
return kp.Public.Bytes(), nil
}
// ParsePrivateKey 解析私钥
func ParsePrivateKey(data []byte, algorithm SignatureAlgorithm) (crpt.PrivateKey, error) {
keyType, err := algorithm.toKeyType()
if err != nil {
return nil, err
}
return crpt.PrivateKeyFromBytes(keyType, data)
}
// ParsePublicKey 解析公钥
func ParsePublicKey(data []byte, algorithm SignatureAlgorithm) (crpt.PublicKey, error) {
keyType, err := algorithm.toKeyType()
if err != nil {
return nil, err
}
return crpt.PublicKeyFromBytes(keyType, data)
}
// defaultRand 返回默认的随机数生成器
func defaultRand() io.Reader {
return rand.Reader
}
// SignWithConfig 使用指定配置签名数据
func SignWithConfig(data, privateKeyDER []byte, config *CryptoConfig) ([]byte, error) {
if config == nil {
config = GetGlobalCryptoConfig()
}
log := logger.GetGlobalLogger()
log.Debug("Signing with config",
"algorithm", config.SignatureAlgorithm,
"dataLength", len(data),
)
privateKey, err := ParsePrivateKey(privateKeyDER, config.SignatureAlgorithm)
if err != nil {
return nil, fmt.Errorf("failed to parse private key: %w", err)
}
signature, err := crpt.SignMessage(privateKey, data, rand.Reader, nil)
if err != nil {
return nil, fmt.Errorf("failed to sign: %w", err)
}
log.Debug("Signed with config successfully",
"algorithm", config.SignatureAlgorithm,
"signatureLength", len(signature),
)
return signature, nil
}
// VerifyWithConfig 使用指定配置验证签名
func VerifyWithConfig(data, publicKeyDER, signature []byte, config *CryptoConfig) (bool, error) {
if config == nil {
config = GetGlobalCryptoConfig()
}
log := logger.GetGlobalLogger()
log.Debug("Verifying with config",
"algorithm", config.SignatureAlgorithm,
"dataLength", len(data),
)
publicKey, err := ParsePublicKey(publicKeyDER, config.SignatureAlgorithm)
if err != nil {
return false, fmt.Errorf("failed to parse public key: %w", err)
}
ok, err := crpt.VerifyMessage(publicKey, data, crpt.Signature(signature), nil)
if err != nil {
return false, fmt.Errorf("failed to verify: %w", err)
}
log.Debug("Verified with config",
"algorithm", config.SignatureAlgorithm,
"result", ok,
)
return ok, nil
}