Files
build-web-application-with-…/de/code/src/apps/ch.4.5/nonce/main.go
2015-08-06 20:35:55 +02:00

71 lines
1.4 KiB
Go

// A nonce is a number or string used only once.
// This is useful for generating a unique token for login pages to prevent duplicate submissions.
package nonce
import (
"crypto/md5"
"errors"
"fmt"
"io"
"math/rand"
"strconv"
"time"
)
// Contains a unique token
type Nonce struct {
Token string
}
// Keeps track of marked/used tokens
type Nonces struct {
hashs map[string]bool
}
func New() Nonces {
return Nonces{make(map[string]bool)}
}
func (n *Nonces) NewNonce() Nonce {
return Nonce{n.NewToken()}
}
// Returns a new unique token
func (n *Nonces) NewToken() string {
t := createToken()
for n.HasToken(t) {
t = createToken()
}
return t
}
// Checks if token has been marked.
func (n *Nonces) HasToken(token string) bool {
return n.hashs[token] == true
}
func (n *Nonces) MarkToken(token string) {
n.hashs[token] = true
}
func (n *Nonces) CheckToken(token string) error {
if token == "" {
return errors.New("No token supplied")
}
if n.HasToken(token) {
return errors.New("Duplicate submission.")
}
return nil
}
func (n *Nonces) CheckThenMarkToken(token string) error {
defer n.MarkToken(token)
if err := n.CheckToken(token); err != nil {
return err
}
return nil
}
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))
}