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  }