Skip to content

Commit

Permalink
Introduce data expiry in Redis
Browse files Browse the repository at this point in the history
Signed-off-by: Knut Ahlers <[email protected]>
  • Loading branch information
Luzifer committed May 5, 2018
1 parent 1dcc254 commit 0aba898
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 6 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ For a better setup you can choose the backend which is used to store the secrets
- `mem` - In memory storage (wiped on restart of the daemon)
- `redis` - Storing the secrets in a hash under one key
- `REDIS_URL` - Redis connection string `tcp://auth:PWD@HOST:PORT/DB`
- `REDIS_KEY` - Key to store the hash in (Default `io.luzifer.ots`)
- `REDIS_EXPIRY` - Expiry of the keys in seconds (Default `0` = no expiry)
- `REDIS_KEY` - Key prefix to store the keys under (Default `io.luzifer.ots`)

**Hint:** Starting in `v0.7.0` the secrets in Redis are no longer stored in a hash but in own keys. This allows for individual expiry. At the first start of `v0.7.0` the old data will be migrated automatically and afterwards be subject of expiry if you set `REDIS_EXPIRY`. My hosted instance uses an expiry of 90d (= 7776000s).

## Localize to your own language

Expand Down
72 changes: 67 additions & 5 deletions storage_redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package main
import (
"fmt"
"os"
"strconv"
"strings"

"github.com/satori/uuid"
log "github.com/sirupsen/logrus"
"github.com/xuyu/goredis"
)

Expand All @@ -22,9 +25,57 @@ func newStorageRedis() (storage, error) {
return nil, err
}

return &storageRedis{
s := &storageRedis{
conn: c,
}, nil
}

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 {
Expand All @@ -38,13 +89,13 @@ func (s storageRedis) redisKey() string {

func (s storageRedis) Create(secret string) (string, error) {
id := uuid.NewV4().String()
_, err := s.conn.HSet(s.redisKey(), id, secret)
err := s.writeKey(id, secret)

return id, err
}

func (s storageRedis) ReadAndDestroy(id string) (string, error) {
secret, err := s.conn.HGet(s.redisKey(), id)
secret, err := s.conn.Get(strings.Join([]string{s.redisKey(), id}, ":"))
if err != nil {
return "", err
}
Expand All @@ -53,6 +104,17 @@ func (s storageRedis) ReadAndDestroy(id string) (string, error) {
return "", errSecretNotFound
}

_, err = s.conn.HDel(s.redisKey(), id)
_, 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
)
}

0 comments on commit 0aba898

Please sign in to comment.