chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
117
internal/store/memory/passkey.go
Normal file
117
internal/store/memory/passkey.go
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
package memory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
// PasskeyStore 是 store.PasskeyStore 的内存实现。
|
||||
type PasskeyStore struct {
|
||||
mu sync.RWMutex
|
||||
byID map[string]domain.PasskeyCredential // key = string(credentialID)
|
||||
}
|
||||
|
||||
// NewPasskeyStore 创建内存 passkey 凭据 store。
|
||||
func NewPasskeyStore() *PasskeyStore {
|
||||
return &PasskeyStore{byID: make(map[string]domain.PasskeyCredential)}
|
||||
}
|
||||
|
||||
func (s *PasskeyStore) InsertPasskey(_ context.Context, cred domain.PasskeyCredential) error {
|
||||
if len(cred.CredentialID) == 0 || cred.UserID == 0 {
|
||||
return domain.ErrPasskeyInvalid
|
||||
}
|
||||
s.mu.Lock()
|
||||
s.byID[string(cred.CredentialID)] = cred.Clone()
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PasskeyStore) GetPasskeyByCredentialID(_ context.Context, credentialID []byte) (domain.PasskeyCredential, bool, error) {
|
||||
s.mu.RLock()
|
||||
cred, ok := s.byID[string(credentialID)]
|
||||
s.mu.RUnlock()
|
||||
if !ok {
|
||||
return domain.PasskeyCredential{}, false, nil
|
||||
}
|
||||
return cred.Clone(), true, nil
|
||||
}
|
||||
|
||||
func (s *PasskeyStore) ListPasskeysByUser(_ context.Context, userID int64) ([]domain.PasskeyCredential, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
out := make([]domain.PasskeyCredential, 0)
|
||||
for _, cred := range s.byID {
|
||||
if cred.UserID == userID {
|
||||
out = append(out, cred.Clone())
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *PasskeyStore) UpdatePasskeyUsage(_ context.Context, credentialID []byte, signCount uint32, lastUsedAt int64) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
cred, ok := s.byID[string(credentialID)]
|
||||
if !ok {
|
||||
return domain.ErrPasskeyNotFound
|
||||
}
|
||||
cred.SignCount = signCount
|
||||
cred.LastUsedAt = lastUsedAt
|
||||
s.byID[string(credentialID)] = cred
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PasskeyStore) DeletePasskey(_ context.Context, userID int64, credentialID []byte) (bool, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
cred, ok := s.byID[string(credentialID)]
|
||||
if !ok || cred.UserID != userID {
|
||||
return false, nil
|
||||
}
|
||||
delete(s.byID, string(credentialID))
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// PasskeyChallengeStore 是 store.PasskeyChallengeStore 的内存实现(进程内、短 TTL)。
|
||||
// 与 QR 登录 token 同属进程内一次性凭据,不跨实例。
|
||||
type PasskeyChallengeStore struct {
|
||||
mu sync.Mutex
|
||||
m map[string]challengeEntry // key = string(challenge)
|
||||
}
|
||||
|
||||
type challengeEntry struct {
|
||||
c domain.PasskeyChallenge
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
// NewPasskeyChallengeStore 创建内存挑战 store。
|
||||
func NewPasskeyChallengeStore() *PasskeyChallengeStore {
|
||||
return &PasskeyChallengeStore{m: make(map[string]challengeEntry)}
|
||||
}
|
||||
|
||||
func (s *PasskeyChallengeStore) SavePasskeyChallenge(_ context.Context, challenge []byte, c domain.PasskeyChallenge, ttl time.Duration) error {
|
||||
if len(challenge) == 0 {
|
||||
return domain.ErrPasskeyChallengeInvalid
|
||||
}
|
||||
s.mu.Lock()
|
||||
s.m[string(challenge)] = challengeEntry{c: c, expiresAt: time.Now().Add(ttl)}
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PasskeyChallengeStore) ConsumePasskeyChallenge(_ context.Context, challenge []byte) (domain.PasskeyChallenge, bool, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
entry, ok := s.m[string(challenge)]
|
||||
if !ok {
|
||||
return domain.PasskeyChallenge{}, false, nil
|
||||
}
|
||||
delete(s.m, string(challenge)) // 一次性:无论是否过期都删除
|
||||
if time.Now().After(entry.expiresAt) {
|
||||
return domain.PasskeyChallenge{}, false, nil
|
||||
}
|
||||
return entry.c, true, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue