65 lines
1.1 KiB
Go
65 lines
1.1 KiB
Go
package mockid
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
//var nonces map[string]int64
|
|
//var nonCh chan string
|
|
var nonces sync.Map
|
|
|
|
func issueNonce(w http.ResponseWriter, r *http.Request) {
|
|
b := make([]byte, 16)
|
|
_, _ = rand.Read(b)
|
|
nonce := base64.RawURLEncoding.EncodeToString(b)
|
|
//nonCh <- nonce
|
|
nonces.Store(nonce, time.Now())
|
|
|
|
w.Header().Set("Replay-Nonce", nonce)
|
|
}
|
|
|
|
func requireNonce(next http.HandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
nonce := r.Header.Get("Replay-Nonce")
|
|
// TODO expire nonces every so often
|
|
//t := nonces[nonce]
|
|
|
|
if !useNonce(nonce) {
|
|
http.Error(
|
|
w,
|
|
`{ "error": "invalid or expired nonce", "error_code": "ENONCE" }`,
|
|
http.StatusBadRequest,
|
|
)
|
|
return
|
|
}
|
|
|
|
issueNonce(w, r)
|
|
next(w, r)
|
|
}
|
|
}
|
|
|
|
func checkNonce(nonce string) bool {
|
|
var t time.Time
|
|
tmp, ok := nonces.Load(nonce)
|
|
if ok {
|
|
t = tmp.(time.Time)
|
|
}
|
|
if ok && time.Now().Sub(t) <= 15*time.Minute {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func useNonce(nonce string) bool {
|
|
if checkNonce(nonce) {
|
|
//delete(nonces, nonce)
|
|
nonces.Delete(nonce)
|
|
return true
|
|
}
|
|
return false
|
|
}
|