This repository has been archived by the owner on Apr 12, 2023. It is now read-only.
/
fakedb.go
132 lines (115 loc) · 2.47 KB
/
fakedb.go
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
129
130
131
132
package storage
import (
"crypto/rand"
"encoding/base64"
"errors"
"sync"
"golang.org/x/crypto/scrypt"
)
type Note struct {
Title, Text string
}
type DB struct {
mu sync.Mutex
// user -> note title -> notes
notes map[string]map[string]Note
// user -> token
sessionTokens map[string]string
// token -> user
userSessions map[string]string
// user -> pw hash
credentials map[string]string
}
func NewDB() *DB {
return &DB{
notes: map[string]map[string]Note{},
sessionTokens: map[string]string{},
userSessions: map[string]string{},
credentials: map[string]string{},
}
}
// Notes
func (s *DB) AddOrEditNote(user string, n Note) {
s.mu.Lock()
defer s.mu.Unlock()
if s.notes[user] == nil {
s.notes[user] = map[string]Note{}
}
s.notes[user][n.Title] = n
}
func (s *DB) GetNotes(user string) []Note {
s.mu.Lock()
defer s.mu.Unlock()
var ns []Note
for _, n := range s.notes[user] {
ns = append(ns, n)
}
return ns
}
// Sessions
func (s *DB) GetUser(token string) (user string, valid bool) {
s.mu.Lock()
defer s.mu.Unlock()
user, valid = s.sessionTokens[token]
return user, valid
}
func (s *DB) GetToken(user string) (token string) {
s.mu.Lock()
defer s.mu.Unlock()
token, has := s.userSessions[user]
if has {
return token
}
token = genToken()
s.userSessions[user] = token
s.sessionTokens[token] = user
return token
}
func (s *DB) DelSession(user string) {
s.mu.Lock()
defer s.mu.Unlock()
token, has := s.userSessions[user]
if !has {
return
}
delete(s.userSessions, user)
delete(s.sessionTokens, token)
}
func genToken() string {
b := make([]byte, 20)
rand.Read(b)
tok := base64.RawStdEncoding.EncodeToString(b)
return tok
}
// Credentials
// HasUser checks if the user exists.
func (s *DB) HasUser(name string) bool {
s.mu.Lock()
defer s.mu.Unlock()
_, has := s.credentials[name]
return has
}
// AddUser adds a user to the storage if it is not already there.
func (s *DB) AddOrAuthUser(name, password string) error {
s.mu.Lock()
defer s.mu.Unlock()
if password == "" {
return errors.New("password cannot be empty")
}
if storedHash, has := s.credentials[name]; has {
if storedHash != hash(password) {
return errors.New("wrong password")
}
return nil
}
s.credentials[name] = hash(password)
return nil
}
func hash(pw string) string {
salt := []byte("please use a proper salt in production")
hash, err := scrypt.Key([]byte(pw), salt, 32768, 8, 1, 32)
if err != nil {
panic("this should not happen")
}
return string(hash)
}