-
Notifications
You must be signed in to change notification settings - Fork 0
/
nonces.go
78 lines (70 loc) · 1.69 KB
/
nonces.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
package kurma
import (
"bytes"
"crypto/rand"
"log"
"math/big"
"sync"
"time"
)
var (
nonceLen = 8
tokenLifetimeSeconds = 30 // TODO make this configurable (tune it in production)
)
func FakeNonce() string {
str, _ := generateRandomString(nonceLen)
return str
}
type NonceJar struct {
tokens []string
mu sync.Mutex
}
func (n *NonceJar) New() string {
n.mu.Lock()
defer n.mu.Unlock()
nonce, _ := generateRandomString(nonceLen)
log.Println("adding nonce", nonce)
n.tokens = append(n.tokens, nonce)
log.Printf("got %d tokens\n", len(n.tokens))
go n.expire(nonce)
return nonce
}
func (n *NonceJar) expire(token string) {
time.AfterFunc(time.Second*time.Duration(tokenLifetimeSeconds), func() {
n.mu.Lock()
defer n.mu.Unlock()
for i, nc := range n.tokens[:] {
if bytes.Equal([]byte(token), []byte(nc)) {
// we delete the expired token from the jar
n.tokens = append(n.tokens[:i], n.tokens[i+1:]...)
log.Printf("expired nonce %s\n", token)
return
}
}
})
}
func (n *NonceJar) IsValid(token string) bool {
n.mu.Lock()
defer n.mu.Unlock()
for i, nc := range n.tokens[:] {
if bytes.Equal([]byte(token), []byte(nc)) {
// we delete the used token from the jar
n.tokens = append(n.tokens[:i], n.tokens[i+1:]...)
log.Printf("consumed nonce %s\n", token)
return true
}
}
return false
}
func generateRandomString(n int) (string, error) {
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
ret := make([]byte, 0)
for i := 0; i < n; i++ {
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
if err != nil {
return "", err
}
ret = append(ret, letters[num.Int64()])
}
return string(ret), nil
}