package handlers import ( "context" "crypto/hmac" "crypto/sha256" "encoding/base64" "errors" "net/http" ) func (h *Handlers) GetSession(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { cookieName := "session_token" sessionCookie, err := r.Cookie(cookieName) if err != nil { msg := "auth failed; failed to get session token from cookies" h.log.Debug(msg, "error", err) next.ServeHTTP(w, r) return } cookieValueB, err := base64.URLEncoding. DecodeString(sessionCookie.Value) if err != nil { msg := "auth failed; failed to decode b64 cookie" h.log.Debug(msg, "error", err) next.ServeHTTP(w, r) return } cookieValue := string(cookieValueB) if len(cookieValue) < sha256.Size { h.log.Warn("small cookie", "size", len(cookieValue)) next.ServeHTTP(w, r) return } // Split apart the signature and original cookie value. signature := cookieValue[:sha256.Size] sessionToken := cookieValue[sha256.Size:] //verify signature mac := hmac.New(sha256.New, []byte(h.cfg.CookieSecret)) mac.Write([]byte(cookieName)) mac.Write([]byte(sessionToken)) expectedSignature := mac.Sum(nil) if !hmac.Equal([]byte(signature), expectedSignature) { h.log.Debug("cookie with an invalid sign") next.ServeHTTP(w, r) return } userSession, err := h.cacheGetSession(sessionToken) if err != nil { msg := "auth failed; session does not exists" err = errors.New(msg) h.log.Debug(msg, "error", err) next.ServeHTTP(w, r) return } if userSession.IsExpired() { h.mc.RemoveKey(sessionToken) msg := "session is expired" h.log.Debug(msg, "error", err, "token", sessionToken) next.ServeHTTP(w, r) return } ctx := context.WithValue(r.Context(), "username", userSession.Username) if err := h.cacheSetSession(sessionToken, userSession); err != nil { msg := "failed to marshal user session" h.log.Warn(msg, "error", err) next.ServeHTTP(w, r) return } next.ServeHTTP(w, r.WithContext(ctx)) }) }