summaryrefslogtreecommitdiff
path: root/internal/storer/storer.go
blob: 99da8b86964ecc76c111bc217bee66fc98db0715 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package storer

import (
	"bytes"
	"encoding/gob"
	"time"

	"github.com/dgraph-io/badger"
	"github.com/neonxp/sendsafe/internal/encryption"
	"github.com/rs/xid"
)

type Store struct {
	db *badger.DB
}

func New(dbFile string) (*Store, error) {
	db, err := badger.Open(badger.DefaultOptions(dbFile))
	if err != nil {
		return nil, err
	}

	return &Store{
		db: db,
	}, nil
}

func (s *Store) Save(text string, pin string, ttl int) (string, error) {
	var err error

	encrypted := false

	if pin != "" {
		text, err = encryption.Encrypt([]byte(pin), text)
		if err != nil {
			return "", err
		}

		encrypted = true
	}

	record := memo{
		Text:      text,
		Encrypted: encrypted,
	}

	buf := bytes.NewBuffer([]byte{})
	if err := gob.NewEncoder(buf).Encode(record); err != nil {
		return "", err
	}

	id := xid.New()
	err = s.db.Update(func(txn *badger.Txn) error {
		return txn.SetEntry(&badger.Entry{
			Key:       id.Bytes(),
			Value:     buf.Bytes(),
			ExpiresAt: uint64(time.Now().Add(time.Duration(ttl) * time.Minute).Unix()),
		})
	})

	return id.String(), err
}

func (s *Store) IsEncrypted(id string) (bool, error) {
	var encrypted bool

	return encrypted, s.db.View(func(txn *badger.Txn) error {
		uid, err := xid.FromString(id)
		if err != nil {
			return err
		}
		value, err := txn.Get(uid.Bytes())
		if err != nil {
			return err
		}
		record := new(memo)
		return value.Value(func(val []byte) error {
			if err := gob.NewDecoder(bytes.NewBuffer(val)).Decode(record); err != nil {
				return err
			}
			encrypted = record.Encrypted
			return nil
		})
	})
}

func (s *Store) Get(id string, pin string) (string, error) {
	var text string

	return text, s.db.Update(func(txn *badger.Txn) error {
		uid, err := xid.FromString(id)
		if err != nil {
			return err
		}
		value, err := txn.Get(uid.Bytes())
		if err != nil {
			return err
		}
		record := new(memo)
		err = value.Value(func(val []byte) error {
			if err := gob.NewDecoder(bytes.NewBuffer(val)).Decode(record); err != nil {
				return err
			}
			return nil
		})
		if err != nil {
			return err
		}

		text = record.Text
		if record.Encrypted {
			text, err = encryption.Decrypt([]byte(pin), text)
			if err != nil {
				return err
			}
		}
		return txn.Delete(uid.Bytes())
	})
}

func init() {
	gob.Register(memo{})
}

type memo struct {
	Text      string
	Encrypted bool
}