package main import ( "crypto/hmac" "crypto/sha256" "fmt" "hash" "html/template" "log" "net/http" "strconv" "strings" ) var TPL *template.Template const ( SECRET = "QDFuO2FyRHhGKEg5QlI4XDMlM2sK" COUNTER_COOKIE string = "counter" ) func displayPage(res http.ResponseWriter, req *http.Request) { count, cookie := updateCounter(req) http.SetCookie(res, cookie) TPL.Execute(res, count) } func updateCounter(req *http.Request) (uint64, *http.Cookie) { count := fromCookie(req) count++ val := toCookieVal(count) cookie := &http.Cookie{ Name: COUNTER_COOKIE, Value: val, } return count, cookie } func fromCookie(req *http.Request) uint64 { cookie, err := req.Cookie(COUNTER_COOKIE) if err != nil { return 0 } sp := strings.Split(cookie.Value, "|") if len(sp) != 2 { return 0 } c, err := strconv.Atoi(sp[0]) if err != nil { return 0 } if !checkMac(sp[0], sp[1]) { return 0 } return uint64(c) } func checkMac(val string, macStr string) bool { var mac []byte fmt.Sscanf(macStr, "%x", &mac) return hmac.Equal(mac, cookieHash(val).Sum(nil)) } func cookieHash(val string) hash.Hash { mac := hmac.New(sha256.New, []byte(SECRET)) mac.Write([]byte(val)) return mac } func toCookieVal(count uint64) string { val := strconv.FormatUint(count, 10) return val + "|" + fmt.Sprintf("%x", cookieHash(val).Sum(nil)) } func main() { var err error TPL, err = template.ParseFiles("tpl.html") if err != nil { log.Fatalln(err) } http.HandleFunc("/", displayPage) http.ListenAndServe(":9000", nil) }