go-examples/webcounter/main.go
2017-07-28 20:47:26 +02:00

84 lines
1.5 KiB
Go

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)
}