Files
yml 8fef037be3 AES 字段加密迁配置并兼容旧密文
移除字段加密硬编码主密钥,改为 FIELD_ENCRYPTION_KEY 注入。

保留 FIELD_ENCRYPTION_LEGACY_KEY 透明回退旧密文,新写入统一使用主密钥;生产环境校验主密钥和 legacy 密钥长度、占位符及相等关系,并统一生产环境判断口径。

补充配置与旧密文兼容回归测试。
2026-06-14 17:53:24 +08:00

106 lines
2.2 KiB
Go

package realname
import (
"context"
"crypto/rand"
"encoding/hex"
"errors"
"strings"
"time"
"hfb_sys/backend/pkg/crypto"
)
type Provider interface {
Name() string
Start(ctx context.Context, req StartRequest) (ProviderResult, error)
}
type StartRequest struct {
UserID uint64
Name string
IDNo string
}
type ProviderResult struct {
ProviderOrderNo string
Status string
MaskedName string
EncryptedName string // 加密的完整姓名
MaskedIDNo string
EncryptedIDNo string // 加密的完整身份证号
VerifiedAt *time.Time
FailReason string
}
type MockProvider struct {
encryptor crypto.Encryptor
}
func NewMockProvider(encryptor crypto.Encryptor) *MockProvider {
if encryptor == nil {
encryptor = &crypto.MockEncryptor{}
}
return &MockProvider{encryptor: encryptor}
}
func (p *MockProvider) Name() string {
return "mock"
}
func (p *MockProvider) Start(_ context.Context, req StartRequest) (ProviderResult, error) {
if strings.TrimSpace(req.Name) == "" || strings.TrimSpace(req.IDNo) == "" {
return ProviderResult{}, errors.New("name and id no are required")
}
orderNo, err := randomOrderNo()
if err != nil {
return ProviderResult{}, err
}
// 加密完整信息
encryptedName, err := p.encryptor.Encrypt(req.Name)
if err != nil {
return ProviderResult{}, err
}
encryptedIDNo, err := p.encryptor.Encrypt(req.IDNo)
if err != nil {
return ProviderResult{}, err
}
now := time.Now()
return ProviderResult{
ProviderOrderNo: orderNo,
Status: StatusVerified,
MaskedName: maskName(req.Name),
EncryptedName: encryptedName,
MaskedIDNo: maskIDNo(req.IDNo),
EncryptedIDNo: encryptedIDNo,
VerifiedAt: &now,
}, nil
}
func randomOrderNo() (string, error) {
buf := make([]byte, 8)
if _, err := rand.Read(buf); err != nil {
return "", err
}
return "mock_rn_" + hex.EncodeToString(buf), nil
}
func maskName(name string) string {
name = strings.TrimSpace(name)
if len([]rune(name)) <= 1 {
return name
}
runes := []rune(name)
return string(runes[0]) + strings.Repeat("*", len(runes)-1)
}
func maskIDNo(idNo string) string {
idNo = strings.TrimSpace(idNo)
if len(idNo) <= 8 {
return idNo
}
return idNo[:4] + strings.Repeat("*", len(idNo)-8) + idNo[len(idNo)-4:]
}