Files

38 lines
891 B
Go

package handler
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"time"
)
// csrfToken returns an HMAC token valid for the current and previous hour.
// Reuses the session secret so no additional secret is required.
func csrfToken() string {
return csrfTokenForTime(time.Now().UTC())
}
func csrfTokenForTime(t time.Time) string {
bucket := t.Truncate(time.Hour).Unix()
mac := hmac.New(sha256.New, sessionSecret())
mac.Write([]byte(fmt.Sprintf("csrf:%d", bucket)))
return hex.EncodeToString(mac.Sum(nil))
}
// csrfValid returns true if token matches the current or previous hour's token.
func csrfValid(token string) bool {
if token == "" {
return false
}
now := time.Now().UTC()
for _, t := range []time.Time{now, now.Add(-time.Hour)} {
expected := csrfTokenForTime(t)
if hmac.Equal([]byte(token), []byte(expected)) {
return true
}
}
return false
}