/
secret_svc.go
146 lines (135 loc) · 4.61 KB
/
secret_svc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package service
import (
"context"
"encoding/base32"
"errors"
"fmt"
"github.com/lidenger/otpserver/cmd"
"github.com/lidenger/otpserver/internal/model"
"github.com/lidenger/otpserver/internal/param"
"github.com/lidenger/otpserver/internal/store"
"github.com/lidenger/otpserver/pkg/crypt"
"github.com/lidenger/otpserver/pkg/otperr"
"github.com/lidenger/otpserver/pkg/util"
)
type SecretSvc struct {
Store store.SecretStore // 主存储
StoreBackup store.SecretStore // 备存储
StoreMemory store.SecretStore // 内存存储
storeDetectionEventChan chan<- struct{}
}
// Add 添加账号密钥
func (s *SecretSvc) Add(ctx context.Context, account string, isEnable uint8) error {
exists, err := s.IsExists(ctx, account)
if err != nil {
return err
}
if exists {
msg := fmt.Sprintf("账号%s已存在不能重复添加", account)
return otperr.ErrRepeatAdd(errors.New(msg))
}
// 创建一个新的model
m, err := s.NewSecretModel(account, isEnable)
if err != nil {
return err
}
err = MultiStoreInsert[*model.AccountSecretModel](ctx, s.storeDetectionEventChan, m, s.Store, s.StoreBackup, s.StoreMemory)
return err
}
// NewSecretModel 创建一个新的账号密钥model
func (s *SecretSvc) NewSecretModel(account string, isEnable uint8) (*model.AccountSecretModel, error) {
m := &model.AccountSecretModel{}
m.Account = account
m.IsEnable = isEnable
// 密钥加密存储
var err error
m.SecretSeed, err = genSecret(cmd.P.RootKey192, cmd.P.IV)
if err != nil {
return nil, err
}
// 计算数据摘要
m.DataCheck = s.CalcDataCheckSum(m.IsEnable, m.Account, m.SecretSeed)
return m, nil
}
// 生成密钥
func genSecret(rootKey, iv []byte) (string, error) {
secret := util.GenerateStr()
secretEncode := base32.StdEncoding.EncodeToString([]byte(secret))
secretCipher, err := crypt.Encrypt(rootKey, iv, []byte(secretEncode))
if err != nil {
return "", otperr.ErrEncrypt(err)
}
return secretCipher, nil
}
// IsExists 账号密钥是否存在
func (s *SecretSvc) IsExists(ctx context.Context, account string) (bool, error) {
secretData, err := s.GetByAccount(ctx, account, false)
if err != nil {
return false, err
}
return secretData != nil, nil
}
// GetByAccount 通过账号获取密钥信息,密钥已解密
// isDecrypt 是否解密账号密钥
func (s *SecretSvc) GetByAccount(ctx context.Context, account string, isDecrypt bool) (*model.AccountSecretModel, error) {
var err error
p := ¶m.SecretParam{Account: account}
data, err := MultiStoreSelectByCondition[*param.SecretParam, *model.AccountSecretModel](ctx, s.storeDetectionEventChan, p, s.StoreMemory, s.Store, s.StoreBackup)
if err != nil {
return nil, err
}
secretModel := util.GetArrFirstItem(data)
if secretModel == nil {
return nil, nil
}
err = s.CheckModel(secretModel, isDecrypt)
if err != nil {
return nil, err
}
return secretModel, err
}
// CheckModel 校验数据,解密账号密钥密文
func (s *SecretSvc) CheckModel(m *model.AccountSecretModel, isDecrypt bool) error {
check := s.CalcDataCheckSum(m.IsEnable, m.Account, m.SecretSeed)
if m.DataCheck != check {
msg := fmt.Sprintf("账号密钥数据校验不通过,疑似被篡改,请关注(ID:%d,账号:%s)", m.ID, m.Account)
return otperr.ErrAccountSecretDataCheck(errors.New(msg))
}
if isDecrypt {
secret, err := crypt.Decrypt(cmd.P.RootKey192, cmd.P.IV, m.SecretSeed)
if err != nil {
return otperr.ErrDecrypt(err)
}
m.SecretSeed = string(secret)
}
return nil
}
// CalcDataCheckSum 计算数据校验和
func (s *SecretSvc) CalcDataCheckSum(isEnable uint8, account, secretSeedCipher string) string {
data := fmt.Sprintf("%d,%s,%s", isEnable, account, secretSeedCipher)
return crypt.HmacDigest(cmd.P.RootKey192, data)
}
// Paging 分页
func (s *SecretSvc) Paging(ctx context.Context, p *param.SecretPagingParam) (result []*model.AccountSecretModel, count int64, err error) {
result, count, err = MultiStorePaging[*param.SecretPagingParam, *model.AccountSecretModel](ctx, s.storeDetectionEventChan, p, s.Store, s.StoreBackup)
return
}
func (s *SecretSvc) SetEnable(ctx context.Context, account string, isEnable uint8) error {
m, err := s.GetByAccount(ctx, account, false)
if err != nil {
return err
}
if m == nil {
return otperr.ErrParamIllegal("账号不存在:" + account)
}
// 数据一致无需更新
if m.IsEnable == isEnable {
return nil
}
checkSum := s.CalcDataCheckSum(isEnable, account, m.SecretSeed)
params := make(map[string]any)
params["is_enable"] = isEnable
params["data_check"] = checkSum
err = MultiStoreUpdate(ctx, s.storeDetectionEventChan, m.ID, params, s.Store, s.StoreBackup, s.StoreMemory)
return err
}