Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1cd2e4e97c |
@@ -1,67 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
// #138: the vwr viewer cookie must carry the Secure attribute. Tests inspect
|
|
||||||
// the Set-Cookie header directly rather than relying on cookie round-tripping,
|
|
||||||
// because Go's HTTP client (and browsers) drop Secure cookies over plain HTTP,
|
|
||||||
// which is how tests and local dev run.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http/httptest"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"palette/internal/store"
|
|
||||||
"palette/internal/web"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newTestServer138(t *testing.T) *httptest.ResponseRecorder {
|
|
||||||
t.Helper()
|
|
||||||
st, err := store.OpenStore(":memory:")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
ui, err := web.New()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
cfg := Config{MaxTextBytes: 5 * 1024 * 1024}
|
|
||||||
ss := NewTestSettingsStore(t, cfg)
|
|
||||||
globalSettingsFn = ss.get
|
|
||||||
t.Cleanup(func() { globalSettingsFn = nil })
|
|
||||||
a := &apiServer{store: st, cfg: cfg, ui: ui, settings: ss, adminKey: "test-admin-key"}
|
|
||||||
req := httptest.NewRequest("GET", "/history", nil)
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
a.routes().ServeHTTP(rec, req)
|
|
||||||
return rec
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestViewerCookieAttributes(t *testing.T) {
|
|
||||||
rec := newTestServer138(t)
|
|
||||||
var vwr *string
|
|
||||||
for _, c := range rec.Result().Cookies() {
|
|
||||||
if c.Name == "vwr" {
|
|
||||||
cc := c
|
|
||||||
vwr = &cc.Value
|
|
||||||
if !c.Secure {
|
|
||||||
t.Error("vwr cookie missing Secure attribute (#138)")
|
|
||||||
}
|
|
||||||
if !c.HttpOnly {
|
|
||||||
t.Error("vwr cookie missing HttpOnly attribute")
|
|
||||||
}
|
|
||||||
if c.Path != "/" {
|
|
||||||
t.Errorf("vwr cookie Path = %q, want /", c.Path)
|
|
||||||
}
|
|
||||||
if c.SameSite != 2 { // http.SameSiteLaxMode
|
|
||||||
t.Errorf("vwr cookie SameSite = %v, want Lax", c.SameSite)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if vwr == nil {
|
|
||||||
t.Fatal("no vwr cookie set")
|
|
||||||
}
|
|
||||||
// also confirm the raw header form spells out Secure
|
|
||||||
sc := rec.Header().Get("Set-Cookie")
|
|
||||||
if !strings.Contains(sc, "Secure") {
|
|
||||||
t.Errorf("Set-Cookie header %q lacks Secure", sc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -141,12 +141,9 @@ func viewerCookieMiddleware(next http.Handler) http.Handler {
|
|||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if c, err := r.Cookie("vwr"); err != nil || c.Value == "" {
|
if c, err := r.Cookie("vwr"); err != nil || c.Value == "" {
|
||||||
id := store.GenSlug(16)
|
id := store.GenSlug(16)
|
||||||
// #138: Secure keeps the viewer id off plain-HTTP requests
|
|
||||||
// (all deployments are HTTPS-only behind traefik).
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: "vwr", Value: id, Path: "/",
|
Name: "vwr", Value: id, Path: "/",
|
||||||
MaxAge: 31536000, HttpOnly: true, Secure: true,
|
MaxAge: 31536000, HttpOnly: true, SameSite: http.SameSiteLaxMode,
|
||||||
SameSite: http.SameSiteLaxMode,
|
|
||||||
})
|
})
|
||||||
r.AddCookie(&http.Cookie{Name: "vwr", Value: id})
|
r.AddCookie(&http.Cookie{Name: "vwr", Value: id})
|
||||||
// remember that this cookie was minted here, not sent by the client
|
// remember that this cookie was minted here, not sent by the client
|
||||||
|
|||||||
Reference in New Issue
Block a user