119 lines
2.4 KiB
Go
119 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/golang/groupcache/lru"
|
|
"github.com/go-redis/redis/v8"
|
|
"github.com/pborman/uuid"
|
|
)
|
|
|
|
var bgCtx = context.Background()
|
|
|
|
type CacheStore interface {
|
|
AddNonce(nonce string, val string) error
|
|
GetAndDeleteNonce(nonce string) (string, error)
|
|
Clear() error // used in tests only
|
|
}
|
|
|
|
type MemoryStore struct {
|
|
Mutex *sync.Mutex
|
|
Cache *lru.Cache
|
|
}
|
|
|
|
func (store *MemoryStore) AddNonce(nonce string, val string) error {
|
|
store.Mutex.Lock()
|
|
store.Cache.Add(nonce, val)
|
|
store.Mutex.Unlock()
|
|
return nil
|
|
}
|
|
|
|
func (store *MemoryStore) GetAndDeleteNonce(nonce string) (val string, err error) {
|
|
store.Mutex.Lock()
|
|
_val, ok := store.Cache.Get(nonce)
|
|
store.Mutex.Unlock()
|
|
if !ok {
|
|
err = fmt.Errorf("[%T] nonce not found: %s", store, nonce)
|
|
return "", err
|
|
}
|
|
val = _val.(string)
|
|
store.Mutex.Lock()
|
|
store.Cache.Remove(nonce)
|
|
store.Mutex.Unlock()
|
|
return val, nil
|
|
}
|
|
|
|
// used in tests only
|
|
func (store *MemoryStore) Clear() error {
|
|
store.Mutex.Lock()
|
|
store.Cache.Clear()
|
|
store.Mutex.Unlock()
|
|
return nil
|
|
}
|
|
|
|
type RedisStore struct {
|
|
Redis *redis.Client
|
|
Namespace string
|
|
}
|
|
|
|
func (store *RedisStore) AddNonce(nonce string, val string) error {
|
|
err := store.Redis.SetEX(bgCtx, store.Prefix(nonce), val, 600 * time.Second).Err()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (store *RedisStore) GetAndDeleteNonce(nonce string) (val string, err error) {
|
|
prefixedKey := store.Prefix(nonce)
|
|
val, err = store.Redis.Get(bgCtx, prefixedKey).Result()
|
|
if err != nil {
|
|
return "", fmt.Errorf("[%T] nonce not found: %s", store, nonce)
|
|
}
|
|
err = store.Redis.Del(bgCtx, prefixedKey).Err()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return val, nil
|
|
}
|
|
|
|
// used in tests only
|
|
func (store *RedisStore) Clear() error {
|
|
keys, err := store.Redis.Keys(bgCtx, store.Namespace + "*").Result()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, key := range keys {
|
|
err := store.Redis.Del(bgCtx, key).Err()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (store *RedisStore) Prefix(in string) string {
|
|
return store.Namespace + in
|
|
}
|
|
|
|
func (store *RedisStore) GetSetNXCookieSecret() (string, error) {
|
|
prefixedKey := store.Prefix("cookie-secret-uuid")
|
|
secret := uuid.New()
|
|
ourSecretSet, err := store.Redis.SetNX(bgCtx, prefixedKey, secret, 0).Result()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if ourSecretSet {
|
|
return secret, nil
|
|
}
|
|
|
|
secret, err = store.Redis.Get(bgCtx, prefixedKey).Result()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return secret, nil
|
|
}
|