internal/httpd/flash.go

650b235a4b9b5d89f728dfef9f388bb1904391ec
gitbay/internal/httpd/flash.go history · blame · raw

62 lines · 1923 bytes

 1package httpd
 2
 3import (
 4	"net/http"
 5	"net/url"
 6)
 7
 8// A form action that fails redirects back to the page it came from with
 9// the reason. The reason used to ride the URL as ?e=, so it survived a
10// reload and landed in history and bookmarks. It rides a one-shot cookie
11// now: set on the redirect, read and cleared by the page that renders it
12// (#119).
13const flashCookie = "gitbay_notice"
14
15// setFlash queues msg for the next page render. An empty msg sets
16// nothing.
17func (s *Server) setFlash(w http.ResponseWriter, msg string) {
18	if msg == "" {
19		return
20	}
21	if len(msg) > 300 {
22		msg = msg[:300]
23	}
24	http.SetCookie(w, &http.Cookie{
25		Name: flashCookie, Value: url.QueryEscape(msg), Path: "/",
26		HttpOnly: true, SameSite: http.SameSiteLaxMode,
27		Secure: s.cfg.HTTP.TLS != "off",
28		MaxAge: 60,
29	})
30}
31
32// takeFlash returns the queued message, if any, and clears it.
33func (s *Server) takeFlash(w http.ResponseWriter, r *http.Request) string {
34	c, err := r.Cookie(flashCookie)
35	if err != nil || c.Value == "" {
36		return ""
37	}
38	http.SetCookie(w, s.clearCookie(flashCookie, http.SameSiteLaxMode))
39	msg, err := url.QueryUnescape(c.Value)
40	if err != nil {
41		return ""
42	}
43	return msg
44}
45
46// clearCookie is the expiring twin of a Set-Cookie, carrying the same
47// attributes the setting call used.
48//
49// Deletion works without them — a cookie is identified by name, domain
50// and path, not by its flags — so this is consistency rather than a live
51// bug. It is worth having because a reviewer comparing the set and clear
52// paths should not have to work out whether the difference is deliberate,
53// and because a scanner will otherwise flag the bare form every time
54// (go:S2092, go:S3330, #153).
55func (s *Server) clearCookie(name string, sameSite http.SameSite) *http.Cookie {
56	return &http.Cookie{
57		Name: name, Value: "", Path: "/",
58		HttpOnly: true, SameSite: sameSite,
59		Secure: s.cfg.HTTP.TLS != "off",
60		MaxAge: -1,
61	}
62}