// Package sdb implements dstore.Documents backed by leveldb using data at rest // encryption. package sdb import ( "bytes" "github.com/minio/sio" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/iterator" ldbutil "github.com/syndtr/goleveldb/leveldb/util" ) type sdb struct { db *leveldb.DB key SecretKey cfg sio.Config } type siter struct { iterator.Iterator db *sdb } func (i *siter) Value() []byte { b := i.Iterator.Value() if b == nil { return nil } decrypted, err := i.db.decrypt(b) if err != nil { return nil } return decrypted } func newSDB(db *leveldb.DB, key SecretKey) *sdb { cfg := sio.Config{ Key: key[:], MinVersion: sio.Version20, MaxVersion: sio.Version20, } return &sdb{db: db, key: key, cfg: cfg} } func (d *sdb) Close() error { return d.db.Close() } func (d *sdb) Has(path string) (bool, error) { return d.db.Has([]byte(path), nil) } func (d *sdb) Delete(path string) error { return d.db.Delete([]byte(path), nil) } func (d *sdb) NewIterator(prefix string) iterator.Iterator { iter := d.db.NewIterator(ldbutil.BytesPrefix([]byte(prefix)), nil) return &siter{iter, d} } func (d *sdb) Put(path string, b []byte) error { encrypted, err := d.encrypt(b) if err != nil { return err } if err := d.db.Put([]byte(path), encrypted, nil); err != nil { return err } return nil } func (d *sdb) Get(path string) ([]byte, error) { b, err := d.db.Get([]byte(path), nil) if err != nil { if err == leveldb.ErrNotFound { return nil, nil } return nil, err } decrypted, err := d.decrypt(b) if err != nil { return nil, err } return decrypted, nil } func (d *sdb) encrypt(b []byte) ([]byte, error) { var buf bytes.Buffer _, err := sio.Encrypt(&buf, bytes.NewReader(b), d.cfg) if err != nil { return nil, err } return buf.Bytes(), nil } func (d *sdb) decrypt(b []byte) ([]byte, error) { if len(b) == 0 { return b, nil } var buf bytes.Buffer _, err := sio.Decrypt(&buf, bytes.NewReader(b), d.cfg) if err != nil { return nil, err } return buf.Bytes(), nil } // func (d *DB) encrypt(b []byte) ([]byte, error) { // return keys.SecretBoxSeal(b, d.key), nil // } // func (d *DB) decrypt(b []byte) ([]byte, error) { // return keys.SecretBoxOpen(b, d.key) // }