-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnonce.go
More file actions
109 lines (98 loc) · 2.13 KB
/
nonce.go
File metadata and controls
109 lines (98 loc) · 2.13 KB
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
// A nonce is a number or string used only once.
// This is useful for generating a unique token for login pages
// to prevent duplicate or unauthorized submissions.
// @url github.com/LarryBattle/nonce-golang
// @license MIT , 2013
// @author Larry Battle, github.com/LarryBattle
package nonce
import (
"crypto/md5"
"errors"
"fmt"
"io"
"math/rand"
"strconv"
"time"
)
const (
Version = "0.1.0"
Token_New = true
Token_Used = false
)
// The interface for saving and retrieving data
type IO interface {
Set(token string, val bool)
Get(token string) (val bool, has bool)
}
// global IO reader and writer
var db IO
// default IO object
type memory_db struct {
hash map[string]bool
}
func (m *memory_db) Get(token string) (val bool, has bool) {
val, has = m.hash[token]
return
}
func (m *memory_db) Set(token string, val bool) {
m.hash[token] = val
}
// Set the IO reader and writer
func SetIO(io IO) {
db = io
}
// Returns a new unique token
func NewToken() string {
t := createToken()
for {
if _, has := db.Get(t); !has {
break
}
t = createToken()
}
db.Set(t, Token_New)
return t
}
func createToken() string {
h := md5.New()
now := time.Now().Unix()
io.WriteString(h, strconv.FormatInt(now, 10))
io.WriteString(h, strconv.FormatInt(rand.Int63(), 10))
return fmt.Sprintf("%x", h.Sum(nil))
}
// Saves the token as used.
func MarkToken(token string) {
db.Set(token, Token_Used)
}
// Checks for three conditions.
// 1. If a token is supplied
// 2. If the passed token was created
// 3. If the passed token isn't used'
// An error will be returned if any of the conditions are false
func CheckToken(token string) error {
if token == "" {
return errors.New("No token supplied")
}
val, has := db.Get(token)
if !has {
return errors.New("Unknown token")
}
if val == Token_Used {
return errors.New("Duplicate submission.")
}
return nil
}
// Checks if the token is known and new.
// After the check, the token is marked as unused
func CheckThenMarkToken(token string) error {
if err := CheckToken(token); err != nil {
return err
}
MarkToken(token)
return nil
}
func init() {
db = &memory_db{
make(map[string]bool),
}
}