feat(session): scope main site cookies with the __Host- prefix
4 files changed, +21 −16
- forge/account.go modified +3 −3
- forge/flow_test.go modified +5 −5
- forge/limit.go modified +1 −1
- forge/web.go modified +12 −7
forge/account.go modified
| @@ -102,7 +102,7 @@ func (s *Server) resetPassword(w http.ResponseWriter, r *http.Request) { | ||
| 102 | 102 | } |
| 103 | 103 | |
| 104 | 104 | func (s *Server) pendingUser(r *http.Request) (User, bool) { |
| 105 | - c, err := r.Cookie("pending") | |
| 105 | + c, err := r.Cookie(pendingCookie) | |
| 106 | 106 | if err != nil { |
| 107 | 107 | return User{}, false |
| 108 | 108 | } |
| @@ -148,10 +148,10 @@ func (s *Server) totpLogin(w http.ResponseWriter, r *http.Request) { | ||
| 148 | 148 | return |
| 149 | 149 | } |
| 150 | 150 | } |
| 151 | - if c, err := r.Cookie("pending"); err == nil { | |
| 151 | + if c, err := r.Cookie(pendingCookie); err == nil { | |
| 152 | 152 | s.store.db.Exec(`delete from mailtokens where token = ?`, c.Value) |
| 153 | 153 | } |
| 154 | - http.SetCookie(w, &http.Cookie{Name: "pending", Value: "", Path: "/", MaxAge: -1}) | |
| 154 | + http.SetCookie(w, &http.Cookie{Name: pendingCookie, Value: "", Path: "/", HttpOnly: true, Secure: true, MaxAge: -1}) | |
| 155 | 155 | s.startSession(w, u) |
| 156 | 156 | http.Redirect(w, r, "/", http.StatusSeeOther) |
| 157 | 157 | } |
forge/flow_test.go modified
| @@ -34,7 +34,7 @@ func post(h http.Handler, path string, form url.Values, cookie string) *httptest | ||
| 34 | 34 | r.Header.Set("Sec-Fetch-Site", "same-origin") |
| 35 | 35 | r.RemoteAddr = "192.0.2.1:1000" |
| 36 | 36 | if cookie != "" { |
| 37 | - r.Header.Set("Cookie", "session="+cookie) | |
| 37 | + r.Header.Set("Cookie", sessionCookie+"="+cookie) | |
| 38 | 38 | } |
| 39 | 39 | w := httptest.NewRecorder() |
| 40 | 40 | h.ServeHTTP(w, r) |
| @@ -45,7 +45,7 @@ func get(h http.Handler, path, cookie string) *httptest.ResponseRecorder { | ||
| 45 | 45 | r := httptest.NewRequest("GET", path, nil) |
| 46 | 46 | r.RemoteAddr = "192.0.2.1:1000" |
| 47 | 47 | if cookie != "" { |
| 48 | - r.Header.Set("Cookie", "session="+cookie) | |
| 48 | + r.Header.Set("Cookie", sessionCookie+"="+cookie) | |
| 49 | 49 | } |
| 50 | 50 | w := httptest.NewRecorder() |
| 51 | 51 | h.ServeHTTP(w, r) |
| @@ -54,7 +54,7 @@ func get(h http.Handler, path, cookie string) *httptest.ResponseRecorder { | ||
| 54 | 54 | |
| 55 | 55 | func session(w *httptest.ResponseRecorder) string { |
| 56 | 56 | for _, c := range w.Result().Cookies() { |
| 57 | - if c.Name == "session" { | |
| 57 | + if c.Name == sessionCookie { | |
| 58 | 58 | return c.Value |
| 59 | 59 | } |
| 60 | 60 | } |
| @@ -107,7 +107,7 @@ func TestCrossOriginPostRefused(t *testing.T) { | ||
| 107 | 107 | r := httptest.NewRequest("POST", "/settings/profile", strings.NewReader("display=pwned")) |
| 108 | 108 | r.Header.Set("Content-Type", "application/x-www-form-urlencoded") |
| 109 | 109 | r.Header.Set("Sec-Fetch-Site", "cross-site") |
| 110 | - r.Header.Set("Cookie", "session="+id) | |
| 110 | + r.Header.Set("Cookie", sessionCookie+"="+id) | |
| 111 | 111 | w := httptest.NewRecorder() |
| 112 | 112 | h.ServeHTTP(w, r) |
| 113 | 113 | if w.Code != 403 || s.store.Profile(u.ID).Display == "pwned" { |
| @@ -411,7 +411,7 @@ func TestAttachments(t *testing.T) { | ||
| 411 | 411 | r.Header.Set("Sec-Fetch-Site", "same-origin") |
| 412 | 412 | r.RemoteAddr = "192.0.2.1:1000" |
| 413 | 413 | if cookie != "" { |
| 414 | - r.Header.Set("Cookie", "session="+cookie) | |
| 414 | + r.Header.Set("Cookie", sessionCookie+"="+cookie) | |
| 415 | 415 | } |
| 416 | 416 | w := httptest.NewRecorder() |
| 417 | 417 | h.ServeHTTP(w, r) |
forge/limit.go modified
| @@ -140,7 +140,7 @@ func (s *Server) allowPost(r *http.Request) bool { | ||
| 140 | 140 | if r.Method != "POST" { |
| 141 | 141 | return true |
| 142 | 142 | } |
| 143 | - if _, err := r.Cookie("session"); err != nil { | |
| 143 | + if _, err := r.Cookie(sessionCookie); err != nil { | |
| 144 | 144 | return true |
| 145 | 145 | } |
| 146 | 146 | u := s.current(r) |
forge/web.go modified
| @@ -214,7 +214,7 @@ func (s *Server) fail(w http.ResponseWriter, r *http.Request, code int, msg stri | ||
| 214 | 214 | } |
| 215 | 215 | |
| 216 | 216 | func (s *Server) current(r *http.Request) *User { |
| 217 | - c, err := r.Cookie("session") | |
| 217 | + c, err := r.Cookie(sessionCookie) | |
| 218 | 218 | if err != nil { |
| 219 | 219 | return nil |
| 220 | 220 | } |
| @@ -344,7 +344,7 @@ func (s *Server) login(w http.ResponseWriter, r *http.Request) { | ||
| 344 | 344 | } |
| 345 | 345 | if s.store.Account(u.ID).TOTP != "" { |
| 346 | 346 | token, _ := s.store.CreateMailToken(u.ID, "totp", "") |
| 347 | - http.SetCookie(w, &http.Cookie{Name: "pending", Value: token, Path: "/", HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode, MaxAge: 600}) | |
| 347 | + http.SetCookie(w, &http.Cookie{Name: pendingCookie, Value: token, Path: "/", HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode, MaxAge: 600}) | |
| 348 | 348 | http.Redirect(w, r, "/login/totp", http.StatusSeeOther) |
| 349 | 349 | return |
| 350 | 350 | } |
| @@ -357,14 +357,14 @@ func (s *Server) startSession(w http.ResponseWriter, u User) { | ||
| 357 | 357 | if err != nil { |
| 358 | 358 | return |
| 359 | 359 | } |
| 360 | - http.SetCookie(w, &http.Cookie{Name: "session", Value: id, Path: "/", HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode, MaxAge: 90 * 86400}) | |
| 360 | + http.SetCookie(w, &http.Cookie{Name: sessionCookie, Value: id, Path: "/", HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode, MaxAge: 90 * 86400}) | |
| 361 | 361 | } |
| 362 | 362 | |
| 363 | 363 | func (s *Server) logout(w http.ResponseWriter, r *http.Request) { |
| 364 | - if c, err := r.Cookie("session"); err == nil { | |
| 364 | + if c, err := r.Cookie(sessionCookie); err == nil { | |
| 365 | 365 | s.store.DeleteSession(c.Value) |
| 366 | 366 | } |
| 367 | - http.SetCookie(w, &http.Cookie{Name: "session", Value: "", Path: "/", MaxAge: -1}) | |
| 367 | + http.SetCookie(w, &http.Cookie{Name: sessionCookie, Value: "", Path: "/", HttpOnly: true, Secure: true, MaxAge: -1}) | |
| 368 | 368 | http.Redirect(w, r, "/", http.StatusSeeOther) |
| 369 | 369 | } |
| 370 | 370 | |
| @@ -699,7 +699,7 @@ func (s *Server) endSessions(w http.ResponseWriter, r *http.Request) { | ||
| 699 | 699 | return |
| 700 | 700 | } |
| 701 | 701 | s.store.DeleteSessions(u.ID) |
| 702 | - http.SetCookie(w, &http.Cookie{Name: "session", Value: "", Path: "/", MaxAge: -1}) | |
| 702 | + http.SetCookie(w, &http.Cookie{Name: sessionCookie, Value: "", Path: "/", HttpOnly: true, Secure: true, MaxAge: -1}) | |
| 703 | 703 | http.Redirect(w, r, "/login", http.StatusSeeOther) |
| 704 | 704 | } |
| 705 | 705 | |
| @@ -870,7 +870,7 @@ func (s *Server) password(w http.ResponseWriter, r *http.Request) { | ||
| 870 | 870 | http.Redirect(w, r, "/settings/security?error="+template.URLQueryEscaper(err.Error()), http.StatusSeeOther) |
| 871 | 871 | return |
| 872 | 872 | } |
| 873 | - if c, err := r.Cookie("session"); err == nil { | |
| 873 | + if c, err := r.Cookie(sessionCookie); err == nil { | |
| 874 | 874 | s.store.KeepOnlySession(u.ID, c.Value) |
| 875 | 875 | } |
| 876 | 876 | http.Redirect(w, r, "/settings/security", http.StatusSeeOther) |
| @@ -1183,6 +1183,11 @@ func (s *Server) summary(w http.ResponseWriter, r *http.Request, repo Repo) { | ||
| 1183 | 1183 | |
| 1184 | 1184 | var displayMath = regexp.MustCompile(`(?m)^( {0,3})\$\$([^$\n]+)\$\$[ \t]*$`) |
| 1185 | 1185 | |
| 1186 | +const ( | |
| 1187 | + sessionCookie = "__Host-session" | |
| 1188 | + pendingCookie = "__Host-pending" | |
| 1189 | +) | |
| 1190 | + | |
| 1186 | 1191 | const maxRender = 4 << 20 |
| 1187 | 1192 | |
| 1188 | 1193 | const maxHighlight = 512 << 10 |