diff --git a/internal/api/issue138_cookie_test.go b/internal/api/issue138_cookie_test.go index d5e8ca2..93459be 100644 --- a/internal/api/issue138_cookie_test.go +++ b/internal/api/issue138_cookie_test.go @@ -29,7 +29,7 @@ func newTestServer138(t *testing.T) *httptest.ResponseRecorder { 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) + req := httptest.NewRequest("GET", "/public", nil) rec := httptest.NewRecorder() a.routes().ServeHTTP(rec, req) return rec diff --git a/internal/api/mine_test.go b/internal/api/mine_test.go index 233e5a5..c3adcfd 100644 --- a/internal/api/mine_test.go +++ b/internal/api/mine_test.go @@ -58,7 +58,7 @@ func TestMineCreateListDelete(t *testing.T) { a := &apiServer{store: st, cfg: cfg, ui: ui, settings: ss, adminKey: "test-admin-key"} h := a.routes() - alice := viewerCookieFor(t, h, "/history") + alice := viewerCookieFor(t, h, "/public") if alice == "" { t.Fatal("no viewer cookie issued") } @@ -89,7 +89,7 @@ func TestMineCreateListDelete(t *testing.T) { } // a different browser's cookie does NOT see it - bob := viewerCookieFor(t, h, "/history") + bob := viewerCookieFor(t, h, "/public") rec = doReq(t, h, "GET", "/api/mine", bob, "") json.Unmarshal(rec.Body.Bytes(), &list) if list.Total != 0 { diff --git a/internal/api/routes_rename_test.go b/internal/api/routes_rename_test.go new file mode 100644 index 0000000..6a02ec0 --- /dev/null +++ b/internal/api/routes_rename_test.go @@ -0,0 +1,52 @@ +package api + +// #256: renamed page routes; old URLs redirect. +import ( + "palette/internal/store" + "palette/internal/web" + + "net/http" + "net/http/httptest" + "testing" +) + +func TestRenamedPageRoutes(t *testing.T) { + globalLimiter = newLimiter() // fresh rate-limit buckets + 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"} + h := a.routes() + + // new routes render pages + for _, path := range []string{"/public", "/saved"} { + req := httptest.NewRequest("GET", path, nil) + rec := httptest.NewRecorder() + h.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("GET %s: %d, want 200", path, rec.Code) + } + } + + // old routes redirect + for _, tc := range [][2]string{{"/history", "/public"}, {"/mine", "/saved"}, {"/", "/public"}} { + req := httptest.NewRequest("GET", tc[0], nil) + rec := httptest.NewRecorder() + h.ServeHTTP(rec, req) + if rec.Code != http.StatusMovedPermanently && rec.Code != http.StatusFound { + t.Fatalf("GET %s: %d, want redirect", tc[0], rec.Code) + } + if loc := rec.Header().Get("Location"); loc != tc[1] { + t.Fatalf("GET %s redirects to %s, want %s", tc[0], loc, tc[1]) + } + } +} diff --git a/internal/api/server.go b/internal/api/server.go index aae5c96..b36a714 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -118,11 +118,14 @@ func (a *apiServer) routes() http.Handler { r.Get("/raw/{id}", a.handleRaw) // web pages - r.Get("/", http.RedirectHandler("/history", http.StatusFound).ServeHTTP) + r.Get("/", http.RedirectHandler("/public", http.StatusFound).ServeHTTP) r.Get("/new", a.ui.Handlers().HandleNewPage) - r.Get("/history", a.ui.Handlers().HandleHistoryPage) + r.Get("/public", a.ui.Handlers().HandleHistoryPage) + r.Get("/saved", a.ui.Handlers().HandleMinePage) r.Get("/settings", a.ui.Handlers().HandleSettingsPage) - r.Get("/mine", a.ui.Handlers().HandleMinePage) + // #256: old URLs redirect to the renamed pages + r.Get("/history", http.RedirectHandler("/public", http.StatusMovedPermanently).ServeHTTP) + r.Get("/mine", http.RedirectHandler("/saved", http.StatusMovedPermanently).ServeHTTP) r.Handle("/static/*", a.ui.StaticHandler()) r.Get("/unlock/{id}", a.handlePasteView) r.Post("/unlock/{id}", a.handlePasteView) diff --git a/internal/store/customslug.go b/internal/store/customslug.go index 65f0ae4..e39b378 100644 --- a/internal/store/customslug.go +++ b/internal/store/customslug.go @@ -13,7 +13,7 @@ var reservedSlugs = map[string]bool{ "api": true, "raw": true, "can": true, "cans": true, "public": true, "history": true, "static": true, "assets": true, "favicon.ico": true, "new": true, "login": true, "logout": true, "admin": true, "settings": true, - "mine": true, "unlock": true, "guess": true, "f": true, + "mine": true, "saved": true, "unlock": true, "guess": true, "f": true, } var ErrInvalidSlug = errors.New("custom slug must be 1-64 chars: letters, digits, dash, underscore; must start with letter or digit") diff --git a/internal/web/static/paste.js b/internal/web/static/paste.js index 0e88715..3b48dd4 100644 --- a/internal/web/static/paste.js +++ b/internal/web/static/paste.js @@ -42,7 +42,7 @@ function redeem() { try { tok = sessionStorage.getItem('deletion_token_' + PASTE_ID) || ''; } catch(e) {} if (!tok) { alert('deletion token not available in this browser'); return; } fetch('/api/pastes/' + PASTE_ID + '/redeem', {method: 'DELETE', headers: {'Authorization': 'Bearer ' + tok}}) - .then(r => { if (r.ok) location.href = '/history'; else alert('delete failed'); }); + .then(r => { if (r.ok) location.href = '/public'; else alert('delete failed'); }); } // wiring (moved from inline handlers for CSP #139) diff --git a/internal/web/templates/layout.html b/internal/web/templates/layout.html index b38e262..61eeca0 100644 --- a/internal/web/templates/layout.html +++ b/internal/web/templates/layout.html @@ -8,11 +8,11 @@ {{define "topbar"}}