github.com/database64128/shadowsocks-go@v1.7.0/ss2022/saltpool.go (about) 1 package ss2022 2 3 import "time" 4 5 // SaltPool stores salts for [retention, 2*retention) to protect against replay attacks 6 // during the replay window. 7 // 8 // SaltPool is not safe for concurrent use. 9 type SaltPool[T comparable] struct { 10 pool map[T]time.Time 11 retention time.Duration 12 lastClean time.Time 13 } 14 15 // clean removes expired salts from the pool. 16 func (p *SaltPool[T]) clean() { 17 if now := time.Now(); now.Sub(p.lastClean) > p.retention { 18 for salt, added := range p.pool { 19 if now.Sub(added) > p.retention { 20 delete(p.pool, salt) 21 } 22 } 23 p.lastClean = now 24 } 25 } 26 27 // Check returns whether the given salt is valid (not in the pool). 28 func (p *SaltPool[T]) Check(salt T) bool { 29 p.clean() 30 _, ok := p.pool[salt] 31 return !ok 32 } 33 34 // Add adds the given salt to the pool. 35 func (p *SaltPool[T]) Add(salt T) { 36 p.pool[salt] = time.Now() 37 } 38 39 // NewSaltPool returns a new SaltPool with the given retention. 40 func NewSaltPool[T comparable](retention time.Duration) *SaltPool[T] { 41 return &SaltPool[T]{ 42 pool: make(map[T]time.Time), 43 retention: retention, 44 lastClean: time.Now(), 45 } 46 }