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 }