172 lines
4.8 KiB
Go
172 lines
4.8 KiB
Go
package memory
|
|
|
|
import (
|
|
"context"
|
|
"encoding/binary"
|
|
"math"
|
|
"time"
|
|
|
|
"telesrv/internal/store"
|
|
)
|
|
|
|
type authKeySessionLayerKey struct {
|
|
rawAuthKeyID [8]byte
|
|
sessionID int64
|
|
}
|
|
|
|
func (s *AuthKeyStore) GetSessionLayer(
|
|
_ context.Context,
|
|
rawAuthKeyID [8]byte,
|
|
sessionID int64,
|
|
) (store.AuthKeySessionLayer, bool, error) {
|
|
now := time.Now()
|
|
key := authKeySessionLayerKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID}
|
|
s.state.mu.Lock()
|
|
value, found := s.state.sessionLayers[key]
|
|
if found && !now.Before(value.ExpiresAt) {
|
|
delete(s.state.sessionLayers, key)
|
|
found = false
|
|
value = store.AuthKeySessionLayer{}
|
|
} else if found {
|
|
value.SharedDefault = s.state.sessionLayerIsSharedDefaultLocked(rawAuthKeyID, value)
|
|
}
|
|
s.state.mu.Unlock()
|
|
return value, found, nil
|
|
}
|
|
|
|
func (s *AuthKeyStore) AdvanceSessionLayer(
|
|
_ context.Context,
|
|
rawAuthKeyID [8]byte,
|
|
sessionID int64,
|
|
layer int,
|
|
msgID int64,
|
|
) (store.AuthKeySessionLayer, bool, error) {
|
|
now := time.Now()
|
|
expiresAt, freshEvidence := store.AuthKeySessionLayerEvidenceFresh(now, msgID)
|
|
if layer <= 0 || !freshEvidence {
|
|
return store.AuthKeySessionLayer{}, false, store.ErrAuthKeySessionLayerInvalid
|
|
}
|
|
key := authKeySessionLayerKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID}
|
|
s.state.mu.Lock()
|
|
defer s.state.mu.Unlock()
|
|
if _, found := s.state.keys[rawAuthKeyID]; !found {
|
|
return store.AuthKeySessionLayer{}, false, store.ErrAuthKeyNotFound
|
|
}
|
|
current, found := s.state.sessionLayers[key]
|
|
if found && now.Before(current.ExpiresAt) {
|
|
switch {
|
|
case msgID < current.MessageID:
|
|
current.SharedDefault = s.state.sessionLayerIsSharedDefaultLocked(rawAuthKeyID, current)
|
|
return current, false, nil
|
|
case msgID == current.MessageID:
|
|
if layer != current.Layer {
|
|
return current, false, store.ErrAuthKeySessionLayerConflict
|
|
}
|
|
current.SharedDefault = s.state.sessionLayerIsSharedDefaultLocked(rawAuthKeyID, current)
|
|
return current, false, nil
|
|
}
|
|
}
|
|
var (
|
|
permID [8]byte
|
|
perm store.AuthKeyData
|
|
bound bool
|
|
)
|
|
if binding, ok := s.state.bindings[rawAuthKeyID]; ok {
|
|
bound = true
|
|
binary.LittleEndian.PutUint64(permID[:], uint64(binding.PermAuthKeyID))
|
|
var permFound bool
|
|
perm, permFound = s.state.keys[permID]
|
|
if !permFound {
|
|
return store.AuthKeySessionLayer{}, false, store.ErrAuthKeyBindingInvalid
|
|
}
|
|
}
|
|
if found && now.Before(current.ExpiresAt) && layer == current.Layer {
|
|
current.MessageID = msgID
|
|
current.ExpiresAt = expiresAt
|
|
stored := current
|
|
stored.SharedDefault = false
|
|
s.state.sessionLayers[key] = stored
|
|
current.SharedDefault = s.state.sessionLayerIsSharedDefaultLocked(rawAuthKeyID, current)
|
|
return current, true, nil
|
|
}
|
|
if s.state.nextLayerObservation == math.MaxInt64 {
|
|
return store.AuthKeySessionLayer{}, false, store.ErrAuthKeySessionLayerInvalid
|
|
}
|
|
s.state.nextLayerObservation++
|
|
current = store.AuthKeySessionLayer{
|
|
Layer: layer,
|
|
MessageID: msgID,
|
|
ObservationID: s.state.nextLayerObservation,
|
|
ExpiresAt: expiresAt,
|
|
}
|
|
stored := current
|
|
stored.SharedDefault = false
|
|
s.state.sessionLayers[key] = stored
|
|
raw := s.state.keys[rawAuthKeyID]
|
|
raw.Layer = layer
|
|
raw.LayerObservationID = current.ObservationID
|
|
s.state.keys[rawAuthKeyID] = raw
|
|
if bound {
|
|
perm.Layer = layer
|
|
perm.LayerObservationID = current.ObservationID
|
|
s.state.keys[permID] = perm
|
|
s.state.mirrorAuthorizationLayersLocked([][8]byte{rawAuthKeyID, permID}, layer)
|
|
} else {
|
|
s.state.mirrorAuthorizationLayersLocked([][8]byte{rawAuthKeyID}, layer)
|
|
}
|
|
current.SharedDefault = true
|
|
return current, true, nil
|
|
}
|
|
|
|
func (s *AuthKeyStore) DeleteSessionLayer(
|
|
_ context.Context,
|
|
rawAuthKeyID [8]byte,
|
|
sessionID int64,
|
|
) (bool, error) {
|
|
key := authKeySessionLayerKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID}
|
|
s.state.mu.Lock()
|
|
_, deleted := s.state.sessionLayers[key]
|
|
delete(s.state.sessionLayers, key)
|
|
s.state.mu.Unlock()
|
|
return deleted, nil
|
|
}
|
|
|
|
func (s *AuthKeyStore) DeleteExpiredSessionLayers(_ context.Context, limit int) (int, error) {
|
|
if limit <= 0 {
|
|
return 0, nil
|
|
}
|
|
now := time.Now()
|
|
s.state.mu.Lock()
|
|
deleted := 0
|
|
for key, value := range s.state.sessionLayers {
|
|
if deleted >= limit {
|
|
break
|
|
}
|
|
if now.Before(value.ExpiresAt) {
|
|
continue
|
|
}
|
|
delete(s.state.sessionLayers, key)
|
|
deleted++
|
|
}
|
|
s.state.mu.Unlock()
|
|
return deleted, nil
|
|
}
|
|
|
|
func (s *authKeyState) deleteSessionLayersLocked(rawAuthKeyID [8]byte) {
|
|
for key := range s.sessionLayers {
|
|
if key.rawAuthKeyID == rawAuthKeyID {
|
|
delete(s.sessionLayers, key)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *authKeyState) sessionLayerIsSharedDefaultLocked(rawAuthKeyID [8]byte, value store.AuthKeySessionLayer) bool {
|
|
defaultKeyID := rawAuthKeyID
|
|
if binding, ok := s.bindings[rawAuthKeyID]; ok {
|
|
binary.LittleEndian.PutUint64(defaultKeyID[:], uint64(binding.PermAuthKeyID))
|
|
}
|
|
key, found := s.keys[defaultKeyID]
|
|
return found &&
|
|
key.Layer == value.Layer &&
|
|
key.LayerObservationID == value.ObservationID
|
|
}
|