308 lines
7.1 KiB
Go
308 lines
7.1 KiB
Go
package memory
|
||
|
||
import (
|
||
"context"
|
||
"encoding/binary"
|
||
"sync"
|
||
"telesrv/internal/domain"
|
||
"telesrv/internal/store"
|
||
"time"
|
||
)
|
||
|
||
// AuthKeyStore 是 store.AuthKeyStore 的内存实现。
|
||
type AuthKeyStore struct {
|
||
mu sync.RWMutex
|
||
keys map[[8]byte]store.AuthKeyData
|
||
}
|
||
|
||
// NewAuthKeyStore 创建内存 AuthKeyStore。
|
||
func NewAuthKeyStore() *AuthKeyStore {
|
||
return &AuthKeyStore{keys: make(map[[8]byte]store.AuthKeyData)}
|
||
}
|
||
|
||
func (s *AuthKeyStore) Save(_ context.Context, k store.AuthKeyData) error {
|
||
s.mu.Lock()
|
||
s.keys[k.ID] = k
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
func (s *AuthKeyStore) Get(_ context.Context, id [8]byte) (store.AuthKeyData, bool, error) {
|
||
s.mu.RLock()
|
||
k, ok := s.keys[id]
|
||
s.mu.RUnlock()
|
||
return k, ok, nil
|
||
}
|
||
|
||
func (s *AuthKeyStore) UpdateClientInfo(_ context.Context, id [8]byte, info store.AuthKeyClientInfo) error {
|
||
s.mu.Lock()
|
||
k, ok := s.keys[id]
|
||
if ok {
|
||
mergeAuthKeyClientInfo(&k, info)
|
||
s.keys[id] = k
|
||
}
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
func mergeAuthKeyClientInfo(k *store.AuthKeyData, info store.AuthKeyClientInfo) {
|
||
if info.Layer > 0 {
|
||
k.Layer = info.Layer
|
||
}
|
||
if info.DeviceModel != "" {
|
||
k.DeviceModel = info.DeviceModel
|
||
}
|
||
if info.Platform != "" {
|
||
k.Platform = info.Platform
|
||
}
|
||
if info.SystemVersion != "" {
|
||
k.SystemVersion = info.SystemVersion
|
||
}
|
||
if info.APIID != 0 {
|
||
k.APIID = info.APIID
|
||
}
|
||
if info.AppVersion != "" {
|
||
k.AppVersion = info.AppVersion
|
||
}
|
||
}
|
||
|
||
func (s *AuthKeyStore) Delete(_ context.Context, id [8]byte) error {
|
||
s.mu.Lock()
|
||
delete(s.keys, id)
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
// SessionStore 是 store.SessionStore 的内存实现。
|
||
type SessionStore struct {
|
||
mu sync.RWMutex
|
||
sessions map[int64]store.SessionData
|
||
}
|
||
|
||
// NewSessionStore 创建内存 SessionStore。
|
||
func NewSessionStore() *SessionStore {
|
||
return &SessionStore{sessions: make(map[int64]store.SessionData)}
|
||
}
|
||
|
||
func (s *SessionStore) Save(_ context.Context, d store.SessionData) error {
|
||
s.mu.Lock()
|
||
s.sessions[d.ID] = d
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
func (s *SessionStore) Get(_ context.Context, id int64) (store.SessionData, bool, error) {
|
||
s.mu.RLock()
|
||
d, ok := s.sessions[id]
|
||
s.mu.RUnlock()
|
||
return d, ok, nil
|
||
}
|
||
|
||
func (s *SessionStore) Delete(_ context.Context, id int64) error {
|
||
s.mu.Lock()
|
||
delete(s.sessions, id)
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
// TempAuthKeyBindingStore 是 store.TempAuthKeyBindingStore 的内存实现。
|
||
type TempAuthKeyBindingStore struct {
|
||
mu sync.RWMutex
|
||
m map[[8]byte]domain.TempAuthKeyBinding
|
||
}
|
||
|
||
// NewTempAuthKeyBindingStore 创建内存 TempAuthKeyBindingStore。
|
||
func NewTempAuthKeyBindingStore() *TempAuthKeyBindingStore {
|
||
return &TempAuthKeyBindingStore{m: make(map[[8]byte]domain.TempAuthKeyBinding)}
|
||
}
|
||
|
||
func (s *TempAuthKeyBindingStore) Save(_ context.Context, b domain.TempAuthKeyBinding) error {
|
||
b.EncryptedMessage = append([]byte(nil), b.EncryptedMessage...)
|
||
s.mu.Lock()
|
||
s.m[b.TempAuthKeyID] = b
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
func (s *TempAuthKeyBindingStore) GetByTemp(_ context.Context, tempAuthKeyID [8]byte) (domain.TempAuthKeyBinding, bool, error) {
|
||
s.mu.RLock()
|
||
b, ok := s.m[tempAuthKeyID]
|
||
s.mu.RUnlock()
|
||
if !ok {
|
||
return domain.TempAuthKeyBinding{}, false, nil
|
||
}
|
||
b.EncryptedMessage = append([]byte(nil), b.EncryptedMessage...)
|
||
return b, true, nil
|
||
}
|
||
|
||
func (s *TempAuthKeyBindingStore) DeleteExpired(_ context.Context, expiredBefore int64, limit int) (int, error) {
|
||
if limit <= 0 {
|
||
return 0, nil
|
||
}
|
||
s.mu.Lock()
|
||
defer s.mu.Unlock()
|
||
deleted := 0
|
||
for id, b := range s.m {
|
||
if deleted >= limit {
|
||
break
|
||
}
|
||
if int64(b.ExpiresAt) < expiredBefore {
|
||
delete(s.m, id)
|
||
deleted++
|
||
}
|
||
}
|
||
return deleted, nil
|
||
}
|
||
|
||
// AuthorizationStore 是 store.AuthorizationStore 的内存实现。
|
||
type AuthorizationStore struct {
|
||
mu sync.RWMutex
|
||
m map[[8]byte]domain.Authorization
|
||
}
|
||
|
||
// NewAuthorizationStore 创建内存 AuthorizationStore。
|
||
func NewAuthorizationStore() *AuthorizationStore {
|
||
return &AuthorizationStore{m: make(map[[8]byte]domain.Authorization)}
|
||
}
|
||
|
||
func (s *AuthorizationStore) Bind(_ context.Context, a domain.Authorization) error {
|
||
now := time.Now()
|
||
if a.Hash == 0 {
|
||
a.Hash = int64(binary.LittleEndian.Uint64(a.AuthKeyID[:]))
|
||
}
|
||
if a.CreatedAt.IsZero() {
|
||
a.CreatedAt = now
|
||
}
|
||
a.ActiveAt = now
|
||
s.mu.Lock()
|
||
if existing, ok := s.m[a.AuthKeyID]; ok && !existing.CreatedAt.IsZero() {
|
||
a.CreatedAt = existing.CreatedAt
|
||
}
|
||
s.m[a.AuthKeyID] = a
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
func (s *AuthorizationStore) ByAuthKey(_ context.Context, id [8]byte) (domain.Authorization, bool, error) {
|
||
s.mu.RLock()
|
||
a, ok := s.m[id]
|
||
s.mu.RUnlock()
|
||
return a, ok, nil
|
||
}
|
||
|
||
func (s *AuthorizationStore) UpdateLayer(_ context.Context, id [8]byte, layer int) error {
|
||
if layer <= 0 {
|
||
return nil
|
||
}
|
||
s.mu.Lock()
|
||
if a, ok := s.m[id]; ok {
|
||
a.Layer = layer
|
||
a.ActiveAt = time.Now()
|
||
s.m[id] = a
|
||
}
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
func (s *AuthorizationStore) MarkPasswordPassed(_ context.Context, id [8]byte) error {
|
||
s.mu.Lock()
|
||
if a, ok := s.m[id]; ok {
|
||
a.PasswordPending = false
|
||
a.ActiveAt = time.Now()
|
||
s.m[id] = a
|
||
}
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
func (s *AuthorizationStore) ListByUser(_ context.Context, userID int64) ([]domain.Authorization, error) {
|
||
s.mu.RLock()
|
||
defer s.mu.RUnlock()
|
||
out := make([]domain.Authorization, 0)
|
||
for _, a := range s.m {
|
||
if a.UserID == userID {
|
||
out = append(out, a)
|
||
}
|
||
}
|
||
return out, nil
|
||
}
|
||
|
||
func (s *AuthorizationStore) Delete(_ context.Context, id [8]byte) error {
|
||
s.mu.Lock()
|
||
delete(s.m, id)
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
func (s *AuthorizationStore) DeleteByHash(_ context.Context, userID, hash int64) (domain.Authorization, bool, error) {
|
||
s.mu.Lock()
|
||
defer s.mu.Unlock()
|
||
for id, a := range s.m {
|
||
if a.UserID == userID && a.Hash == hash {
|
||
delete(s.m, id)
|
||
return a, true, nil
|
||
}
|
||
}
|
||
return domain.Authorization{}, false, nil
|
||
}
|
||
|
||
func (s *AuthorizationStore) DeleteByUserExcept(_ context.Context, userID int64, keepAuthKeyID [8]byte) ([]domain.Authorization, error) {
|
||
s.mu.Lock()
|
||
defer s.mu.Unlock()
|
||
out := make([]domain.Authorization, 0)
|
||
for id, a := range s.m {
|
||
if a.UserID != userID || id == keepAuthKeyID {
|
||
continue
|
||
}
|
||
delete(s.m, id)
|
||
out = append(out, a)
|
||
}
|
||
return out, nil
|
||
}
|
||
|
||
// CodeStore 是 store.CodeStore 的内存实现(带 TTL)。
|
||
type CodeStore struct {
|
||
mu sync.Mutex
|
||
m map[string]codeEntry
|
||
}
|
||
|
||
// NewCodeStore 创建内存 CodeStore。
|
||
func NewCodeStore() *CodeStore {
|
||
return &CodeStore{m: make(map[string]codeEntry)}
|
||
}
|
||
|
||
func (s *CodeStore) Set(_ context.Context, hash string, code store.PhoneCode, ttl time.Duration) error {
|
||
s.mu.Lock()
|
||
s.m[hash] = codeEntry{code: code, expires: time.Now().Add(ttl)}
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
func (s *CodeStore) Get(_ context.Context, hash string) (store.PhoneCode, bool, error) {
|
||
s.mu.Lock()
|
||
defer s.mu.Unlock()
|
||
e, ok := s.m[hash]
|
||
if !ok || time.Now().After(e.expires) {
|
||
return store.PhoneCode{}, false, nil
|
||
}
|
||
return e.code, true, nil
|
||
}
|
||
|
||
func (s *CodeStore) Update(_ context.Context, hash string, code store.PhoneCode) error {
|
||
s.mu.Lock()
|
||
defer s.mu.Unlock()
|
||
e, ok := s.m[hash]
|
||
if !ok || time.Now().After(e.expires) {
|
||
return nil
|
||
}
|
||
e.code = code
|
||
s.m[hash] = e
|
||
return nil
|
||
}
|
||
|
||
func (s *CodeStore) Del(_ context.Context, hash string) error {
|
||
s.mu.Lock()
|
||
delete(s.m, hash)
|
||
s.mu.Unlock()
|
||
return nil
|
||
}
|