package main import ( "fmt" "os" "strconv" "strings" "github.com/gofrs/uuid/v3" log "github.com/sirupsen/logrus" "github.com/xuyu/goredis" ) type storageRedis struct { conn *goredis.Redis } func newStorageRedis() (storage, error) { if os.Getenv("REDIS_URL") == "" { return nil, fmt.Errorf("REDIS_URL environment variable not set") } c, err := goredis.DialURL(os.Getenv("REDIS_URL")) if err != nil { return nil, err } s := &storageRedis{ conn: c, } if err := s.migrate(); err != nil { // Move from the old to the new storage format return nil, err } return s, nil } func (s storageRedis) migrate() error { t, err := s.conn.Type(s.redisKey()) if err != nil { return err } log.Printf("Key %q type: %s", s.redisKey(), t) if t == "hash" { hashs, err := s.conn.HGetAll(s.redisKey()) if err != nil { return err } for k, v := range hashs { if err := s.writeKey(k, v); err != nil { return err } } if _, err = s.conn.Del(s.redisKey()); err != nil { return err } } return nil } func (s storageRedis) redisExpiry() int { exp := os.Getenv("REDIS_EXPIRY") if exp == "" { return 0 } e, err := strconv.ParseInt(exp, 10, 64) if err != nil { return 0 } return int(e) } func (s storageRedis) redisKey() string { key := os.Getenv("REDIS_KEY") if key == "" { key = "io.luzifer.ots" } return key } func (s storageRedis) Create(secret string) (string, error) { id := uuid.Must(uuid.NewV4()).String() err := s.writeKey(id, secret) return id, err } func (s storageRedis) ReadAndDestroy(id string) (string, error) { secret, err := s.conn.Get(strings.Join([]string{s.redisKey(), id}, ":")) if err != nil { return "", err } if secret == nil { return "", errSecretNotFound } _, err = s.conn.Del(strings.Join([]string{s.redisKey(), id}, ":")) return string(secret), err } func (s storageRedis) writeKey(id, value string) error { return s.conn.Set( strings.Join([]string{s.redisKey(), id}, ":"), // Key value, // Secret s.redisExpiry(), // Expiry in seconds 0, // Expiry milliseconds false, // MustExist true, // MustNotExist ) }