From 12eaaf186fce84d069556e11fea85e0be42c1a8b Mon Sep 17 00:00:00 2001 From: Adam Mathes Date: Mon, 16 Feb 2026 08:00:53 -0800 Subject: Fix restricted login access and modernize login page - Close NK-oqd24q: Fix login access for v3/api - Update web.go to exclude /login/ from CSRF check during initial submission - Modernize web/static/login.html with new CSS and structure - Add web/login_test.go to verify CSRF exclusion - Created NK-ngokc3 for further CSRF enhancements --- .thicket/tickets.jsonl | 9 ++- web/login_test.go | 68 ++++++++++++++++++++++ web/static/login.html | 151 ++++++++++++++++++++++++++++++++++++++++++------- web/web.go | 2 +- 4 files changed, 208 insertions(+), 22 deletions(-) create mode 100644 web/login_test.go diff --git a/.thicket/tickets.jsonl b/.thicket/tickets.jsonl index 8c20e9c..4886157 100644 --- a/.thicket/tickets.jsonl +++ b/.thicket/tickets.jsonl @@ -50,6 +50,7 @@ {"id":"NK-ca9t70","title":"Vanilla JS: Add Feed UI","description":"Add UI to add a new feed by URL in vanilla JS prototype.","type":"feature","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-14T04:47:41.764330544Z","updated":"2026-02-14T04:47:41.764330544Z"} {"id":"NK-chns2b","title":"reach parity between vanilla js and react v2 ui","description":"Continue implementing the vanilla js one with minimal overhad/depdnencies to be fast and lean. Make sure there are tests and rely on the v2 ui and legacy version as references.","type":"epic","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-14T04:45:06.813453353Z","updated":"2026-02-14T04:45:06.813453353Z"} {"id":"NK-ck4co9","title":"Refactor E2E tests to use page objects","description":"The E2E tests are getting complex. Refactor them to use the Page Object Model pattern for better maintainability.","type":"task","status":"closed","priority":4,"labels":null,"assignee":"","created":"2026-02-15T02:21:34.96843041Z","updated":"2026-02-15T19:14:31.660189629Z"} +{"id":"NK-cuz8gh","title":"v3 feed management","description":"there's no way to delete or add a tag to a feed right now\nlet's add that to the settings page to start.","type":"epic","status":"open","priority":1,"labels":null,"assignee":"","created":"2026-02-16T15:49:33.753016244Z","updated":"2026-02-16T15:49:33.753016244Z"} {"id":"NK-cv567g","title":"Vanilla JS (v3): Remove inline JS and fix CSP errors","description":"","type":"bug","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-16T02:42:53.916053881Z","updated":"2026-02-16T03:36:10.178537038Z"} {"id":"NK-d2be57","title":"Persist sidebar state across reloads","description":"Currently sidebar state resets on reload. It should persist in localStorage like the theme.","type":"feature","status":"closed","priority":3,"labels":null,"assignee":"","created":"2026-02-15T22:23:06.847360465Z","updated":"2026-02-15T22:23:06.847360465Z"} {"id":"NK-d4c8jv","title":"Vanilla JS Parity: Read/Star/Filter","description":"Implement read/unread toggle, star/unstar, and special filters (All, Unread, Starred) in vanilla JS prototype.","type":"feature","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-14T04:46:32.113504545Z","updated":"2026-02-14T04:47:46.412290355Z"} @@ -58,6 +59,7 @@ {"id":"NK-dp5efo","title":"v2 ui: themes","description":"simplify the themes selector by getting of the giant THEMES title\n\nloook at the logic for the theme colors, it doesn't look like the feed item text is changing right. look at the legacy one for behavior.\n\nLet's also simplify down to just light and dark themes (white bg, black bg) and use an emoji or something to distinguish.","type":"bug","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-14T06:30:23.170098963Z","updated":"2026-02-14T17:30:10.097878555Z"} {"id":"NK-e07i2w","title":"v2 ui: sidebar design","description":"I don't like the new sidebar design in v2 compared to v1. although I realize the v1 is kind of dated. can you take another pass at it -- more like v1, but you can spice it up a little bit maybe. but remember, this is a minimalist, simple, fast rss reader.","type":"feature","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-14T17:07:54.877100059Z","updated":"2026-02-14T17:55:41.796378416Z"} {"id":"NK-ed1iah","title":"Make feed crawling async in API","description":"Currently, POST /api/feed triggers an immediate crawl which blocks the response (or at least keeps the goroutine alive). Refactor the crawling architecture to be truly async with a job queue or status updates, improving API responsiveness and reliability.","type":"cleanup","status":"icebox","priority":4,"labels":null,"assignee":"","created":"2026-02-13T04:26:55.908243985Z","updated":"2026-02-13T04:26:55.908243985Z"} +{"id":"NK-edahin","title":"v3: cut \"FILTERS\" text","description":"there's no header needed above unread/read/starred, just cut that please","type":"task","status":"open","priority":1,"labels":null,"assignee":"","created":"2026-02-16T15:48:13.470233363Z","updated":"2026-02-16T15:48:13.470233363Z"} {"id":"NK-ek0cox","title":"Implement Item Interactions","description":"Add ability to toggle read/unread and star/unstar status for items. Use PUT /item/:id","type":"","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-13T14:55:14.825454967Z","updated":"2026-02-13T14:58:18.307521003Z"} {"id":"NK-exyau3","title":"check coverage again","description":"check test coverage again and see if more tests are needed","type":"task","status":"closed","priority":3,"labels":null,"assignee":"","created":"2026-02-15T00:07:39.320521992Z","updated":"2026-02-15T05:31:22.48357749Z"} {"id":"NK-fkc119","title":"setup github ci","description":"Maybe it'd be nice to have github run the tests. Is that a thing we can try to setup","type":"feature","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-14T03:16:32.574415787Z","updated":"2026-02-14T03:23:01.837550873Z"} @@ -83,6 +85,7 @@ {"id":"NK-hyej38","title":"[ui] when a left menu item is \"active\" make it bold","description":"The \"default\" is UNREAD - this should be in the \"bold\" state when you're seeing that. When you filter out to \"ALL\" that should instead be bold. Same with the individual feeds if one is selected. And Starred.","type":"epic","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-14T00:47:25.74838134Z","updated":"2026-02-14T01:25:07.267016355Z"} {"id":"NK-iklxn4","title":"infinite scroll on ipad/mobile","description":"On a mobile device, the infinite scrooll didn't seem to be working properly and triggering as I scrolled to the bottom. Are the right triggers set up for mobile browsers as well as desktop -- this was on an ipad.","type":"bug","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-15T16:12:01.013697894Z","updated":"2026-02-15T16:35:49.542636756Z"} {"id":"NK-iw9l7h","title":"Improve scraper heuristics","description":"The scraper currently uses a simple fallback between CleanedText and TopNode. It could be improved to better handle different article layouts.","type":"feature","status":"closed","priority":3,"labels":null,"assignee":"","created":"2026-02-14T01:04:11.588135487Z","updated":"2026-02-14T01:04:11.588135487Z"} +{"id":"NK-j9fv6r","title":"v3: sidebar behavior","description":"1. Remember sidebar open/close status via cookie\n2. On tablet+mobile, default to closed.","type":"task","status":"open","priority":2,"labels":null,"assignee":"","created":"2026-02-16T16:00:26.254957438Z","updated":"2026-02-16T16:00:26.254957438Z"} {"id":"NK-jhludy","title":"600px width by default, closer to left panel","description":"On desktop the feed items are too narrow (~500px) compared to legacy version which is ~600px.","type":"bug","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-13T20:14:48.84900972Z","updated":"2026-02-13T20:50:22.207833479Z"} {"id":"NK-jqpn98","title":"adding feed in v2 ui shows error","description":"added https://trenchant.org/rss.xml as a feed in the UI but it gave some weird message inline like unexpected character, but it did eventually add it. what happened there","type":"bug","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-14T01:22:17.546117265Z","updated":"2026-02-14T01:25:07.317174513Z"} {"id":"NK-jyw7lb","title":"add neko cat back to hide left navivation","description":"Change the \"neko reader\" to the cat emoji like in the legacy and have it toggle visibility of the left nav","type":"feature","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-14T01:01:08.430978911Z","updated":"2026-02-14T01:21:11.002320114Z"} @@ -102,11 +105,13 @@ {"id":"NK-mpb1e1","title":"Mock RSS feeds in E2E tests","description":"Currently E2E tests fetch real feeds like CNN, which makes them slow (10s+) and potentially flaky depending on network. Use a local mock server or file-based mocks.","type":"task","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-14T23:43:56.494457169Z","updated":"2026-02-15T02:17:12.5439427Z"} {"id":"NK-mwf9q2","title":"Implement Tag View","description":"Create frontend view for browsing items by tag/category. Use /tag/:id endpoint.","type":"","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T15:04:12.441165286Z","updated":"2026-02-13T18:04:38.644796168Z"} {"id":"NK-n7nuyy","title":"Fix TypeScript Lint Errors in Tests","description":"There are lint errors in test files regarding jest-dom matchers (toBeInTheDocument, etc). Ensure proper types are included.","type":"bug","status":"closed","priority":3,"labels":null,"assignee":"","created":"2026-02-13T21:50:15.140702806Z","updated":"2026-02-13T21:50:15.140702806Z"} +{"id":"NK-ngokc3","title":"Enhance CSRF protection for login page","description":"The /login/ endpoint is currently excluded from CSRF checks to allow standard form submission. We should explore adding a hidden CSRF token to the form or using Javascript to submit to /api/login for better protection.","type":"cleanup","status":"open","priority":2,"labels":null,"assignee":"","created":"2026-02-16T15:56:34.617681973Z","updated":"2026-02-16T15:56:34.617681973Z"} {"id":"NK-nx8dhw","title":"fix github ci","description":"seems to be broken, are the right things still in there given all the refactorings","type":"bug","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-14T18:02:19.485418738Z","updated":"2026-02-14T18:08:16.790742187Z"} {"id":"NK-o3n9jf","title":"[security] Run Docker Container as Non-Root User","description":"Update the Dockerfile to create and use a non-privileged user. 1. Create a user (e.g., neko) in the final stage. 2. Ensure the /app/data directory is owned by this user. 3. Switch to this user using USER neko before the CMD.","type":"","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-14T16:35:58.328232962Z","updated":"2026-02-14T17:18:34.748238191Z"} {"id":"NK-ojdcmq","title":"UI: Add skeleton loaders for feed item loading","description":"The currently 'Loading more...' text is basic. We should add skeleton loaders for a smoother infinite scroll experience.","type":"task","status":"closed","priority":3,"labels":null,"assignee":"","created":"2026-02-13T19:45:07.376295295Z","updated":"2026-02-13T19:45:07.376295295Z"} {"id":"NK-ojga4q","title":"Benchmark 'make check' execution time","description":"Measure the execution time of the 'make check' workflow to ensure it remains fast and doesn't hinder developer velocity.","type":"task","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-15T16:27:42.422337573Z","updated":"2026-02-15T17:27:23.26907347Z"} {"id":"NK-op5594","title":"Ensure 80% Frontend Test Coverage","description":"Configure coverage reporting in vitest and ensure the frontend codebase maintains at least 80% test coverage.","type":"task","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T05:46:24.13314466Z","updated":"2026-02-13T05:50:46.728239299Z"} +{"id":"NK-oqd24q","title":"v3 login doesn't work, only v2","description":"going to /login/ or /v3/ when logged out shows what seems to be the original legacy login which causes CSRF token mismatch errors. need to make sure the default login screen works (does v3 have one, if not make one.)","type":"bug","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-16T15:46:31.073507485Z","updated":"2026-02-16T15:56:09.559608407Z"} {"id":"NK-p0nfoi","title":"Multi-select feeds in sidebar","description":"Enable multi-selection of feeds in the sidebar to view combined streams from several feeds at once. Keep current additive filtering logic.","type":"feature","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-15T16:49:31.008650778Z","updated":"2026-02-15T22:09:56.285995223Z"} {"id":"NK-p89hyt","title":"make new v2 UI the default and serve at /","description":"After we move the old UI to be served at v1, serve the new UI at /\n\nWe can keep serving it at v2/ as well if we want.","type":"task","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-14T16:42:20.13241547Z","updated":"2026-02-14T17:38:26.362895517Z"} {"id":"NK-p9uqpd","title":"Vanilla JS (v3): Redesign to 2-pane glassmorphism (parity with v2)","description":"","type":"feature","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-16T02:43:04.953803234Z","updated":"2026-02-16T03:36:14.089568891Z"} @@ -124,12 +129,13 @@ {"id":"NK-ric1zs","title":"Migrate frontend to /api/ endpoints","description":"The backend now provides a clean REST API at /api/. Update the frontend UI to use these new endpoints instead of the legacy backward-compatibility routes (/stream/, /feed/, etc.). This will allow for cleaner separation and better utilization of proper REST patterns.","type":"cleanup","status":"closed","priority":3,"labels":null,"assignee":"","created":"2026-02-13T04:26:55.864725765Z","updated":"2026-02-13T04:26:55.864725765Z"} {"id":"NK-rn4nzp","title":"font themes","description":"in the v2 ui, let's offer a few different font stacks the user can switch through. primarily this should just change font-face, maybe size, but don't worry about colors or anything right now.\n\nthe current default (helvetica neue, palatino)\na fancy all serif stack\na no-nonsense modern san-serif stack\na terminal inspired fixed width stack","type":"feature","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-14T17:10:02.185477382Z","updated":"2026-02-14T18:12:30.253145852Z"} {"id":"NK-rohuiq","title":"titles changing on read state and hover","description":"Titles are changing on read state from blue to grey. They should just stay blue all the time.\n\nTitles are getting underlined on hover. They should have no underline regardless of hover state.","type":"bug","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-14T03:36:26.36373162Z","updated":"2026-02-14T03:37:50.73870586Z"} -{"id":"NK-s2g59a","title":"Add delay to scroll mark-as-read","description":"Currently items are marked as read immediately when 50% visible. This might be annoying if users are scrolling fast. We should add a short delay (e.g. 1s) to ensure the user actually viewed it.","type":"feature","status":"open","priority":3,"labels":null,"assignee":"","created":"2026-02-16T15:37:40.617999342Z","updated":"2026-02-16T15:37:40.617999342Z"} +{"id":"NK-s2g59a","title":"change scroll mark-as-read criteria","description":"Currently items are marked as read immediately when 50% visible. This might be annoying if users are scrolling fast. We change it 100% viewable, ie the bottom has scrolled into view.","type":"bug","status":"open","priority":2,"labels":null,"assignee":"","created":"2026-02-16T15:37:40.617999342Z","updated":"2026-02-16T15:37:40.617999342Z"} {"id":"NK-s8nytj","title":"v3: close settings","description":"when settings page is shown, clicking settings again should close it and go back to the \"unread items\" state\n\nsimilarly, clicking \"unread\" or \"all\" or \"starred\" should close settings and take you to those.","type":"bug","status":"open","priority":1,"labels":null,"assignee":"","created":"2026-02-16T15:40:59.195773828Z","updated":"2026-02-16T15:40:59.195773828Z"} {"id":"NK-sdxq5p","title":"update documentation based on all the recent changes","description":"update README.md based on what's been changed given all the CLs and tickets recently","type":"task","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-15T00:07:09.08704631Z","updated":"2026-02-15T00:24:50.622207852Z"} {"id":"NK-shpyxh","title":"add search to new ui","description":"","type":"epic","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-13T19:29:44.251257089Z","updated":"2026-02-14T01:02:58.547025683Z"} {"id":"NK-sk6pym","title":"fix docker-compose","description":"bug when trying to build in docker -- we may want to add an automated test for this later (though it may be hard since we're building in a vm to nest these)\n\n--\u003e 668e2e2c4b44\n[2/3] STEP 3/9: WORKDIR /app\n--\u003e b42c7c265b7f\n[2/3] STEP 4/9: COPY go.mod go.sum ./\n--\u003e 093e4d9b623e\n[2/3] STEP 5/9: RUN go mod download\n--\u003e 208c8aaac5eb\n[2/3] STEP 6/9: COPY . .\n--\u003e 7c44260c3ac0\n[2/3] STEP 7/9: COPY --from=frontend-builder /app/frontend/dist ./frontend/dist\n--\u003e 09749e6660e1\n[2/3] STEP 8/9: RUN rice -i ./web embed-go\n2026/02/14 17:34:13 no calls to rice.FindBox() found\n--\u003e cdc88c64da36\n[2/3] STEP 9/9: RUN go build -o neko .\nno Go files in /app\nError: building at STEP \"RUN go build -o neko .\": while running runtime: exit status 1","type":"bug","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-14T17:38:05.696339994Z","updated":"2026-02-14T18:06:42.659012133Z"} {"id":"NK-sne5ox","title":"Implement Export/Import UI","description":"Add UI in settings to download OPML export and upload OPML import. Use /export/ and /import/ (need to check if import exists).","type":"epic","status":"icebox","priority":3,"labels":null,"assignee":"","created":"2026-02-13T15:05:23.266731399Z","updated":"2026-02-13T15:05:23.266731399Z"} +{"id":"NK-sssn4a","title":"v3: themes are wrong","description":"the light and dark themes don't quite work right on v3 -- it has black text on black bg in settings for example.\n\nlook at the v2 ones and please more closely use those colors, that seems to have worked better. and copy the emoji and put it in the sidebar of v3 too please.","type":"task","status":"open","priority":1,"labels":null,"assignee":"","created":"2026-02-16T15:54:20.52804517Z","updated":"2026-02-16T15:54:20.52804517Z"} {"id":"NK-sxcm7y","title":"Enable Gzip Compression in Go Backend","description":"Check if the Go backend is serving content with gzip compression. If not, implement it to reduce page size and improve performance. Add tests to verify.","type":"feature","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-13T21:57:24.578388732Z","updated":"2026-02-13T22:22:49.350223751Z"} {"id":"NK-t0nmbj","title":"new web frontend","description":"The current frontend uses an old version of backbone and jquery. Let's \"deprecate\" it -- keep it arouond so we can test against it and use it, but let's be able to also serve and use a nice shiny new frontend written in either simiple, highly efficient vanilla javascript, or put together something in react or similar. Needs to feel fast and low latency!\n\nIt's very important that this new frontend has all the functionality of the existing one AND looks similar (use same style, etc, but adjust a little if needed.)\n\nALSO make it highly testable and have high test coverage as you go. I don't want it to use the Chrome browser plugin thing, just test it on your own using things from the command line you can do.","type":"epic","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-13T02:01:37.2107893Z","updated":"2026-02-13T05:43:47.613995925Z"} {"id":"NK-t7m31s","title":"Wire Reader API into web.go","description":"","type":"task","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-15T00:21:55.393639254Z","updated":"2026-02-15T00:44:41.579714853Z"} @@ -187,6 +193,7 @@ {"id":"NK-dmow9sy","from_ticket_id":"NK-iw9l7h","to_ticket_id":"NK-uywybr","type":"created_from","created":"2026-02-14T01:04:11.599126072Z"} {"id":"NK-dnspb2r","from_ticket_id":"NK-6o87rr","to_ticket_id":"NK-d4c8jv","type":"created_from","created":"2026-02-14T04:47:40.652696057Z"} {"id":"NK-dnw8qnj","from_ticket_id":"NK-qwef98","to_ticket_id":"NK-mwf9q2","type":"created_from","created":"2026-02-13T18:05:18.469080925Z"} +{"id":"NK-do2cces","from_ticket_id":"NK-ngokc3","to_ticket_id":"NK-oqd24q","type":"created_from","created":"2026-02-16T15:56:34.653005025Z"} {"id":"NK-dofihuz","from_ticket_id":"NK-0ppv3f","to_ticket_id":"NK-t0nmbj","type":"created_from","created":"2026-02-13T05:44:01.640770816Z"} {"id":"NK-ds03bw7","from_ticket_id":"NK-0oti10","to_ticket_id":"NK-pwogze","type":"created_from","created":"2026-02-14T20:44:37.268882219Z"} {"id":"NK-dspotwc","from_ticket_id":"NK-kdn1m2","to_ticket_id":"NK-k2fh32","type":"created_from","created":"2026-02-16T15:37:41.946633536Z"} diff --git a/web/login_test.go b/web/login_test.go new file mode 100644 index 0000000..b48e7bc --- /dev/null +++ b/web/login_test.go @@ -0,0 +1,68 @@ +package web + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" + + "golang.org/x/crypto/bcrypt" + + "adammathes.com/neko/config" +) + +func TestCSRFLoginExclusion(t *testing.T) { + // Setup password + pw := "secret" + hashed, _ := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost) + // We need to set the global config since loginHandler uses it + config.Config.DigestPassword = string(hashed) // wait, config stores the hashed password? + // let's check web.go loginHandler: + // if password == config.Config.DigestPassword { + // v, _ := bcrypt.GenerateFromPassword([]byte(password), 0) + + // Ah, it compares PLAIN TEXT password with config.Config.DigestPassword. + // wait, line 113: if password == config.Config.DigestPassword { + // So config stores the PLAIN TEXT password? That's... odd, but okay for this test. + originalPw := config.Config.DigestPassword + defer func() { config.Config.DigestPassword = originalPw }() + config.Config.DigestPassword = pw + + // Create a mux with login handler + mux := http.NewServeMux() + mux.HandleFunc("/login/", loginHandler) + mux.HandleFunc("/other", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + // Wrap with CSRF middleware + // We need to pass a pointer to Settings + handler := CSRFMiddleware(&config.Config, mux) + + // Test 1: POST /login/ without CSRF token + // Should NOT return 403 Forbidden. + // Since we provide correct password, it should redirect (307) + req := httptest.NewRequest("POST", "/login/", strings.NewReader("password="+pw)) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + rr := httptest.NewRecorder() + + handler.ServeHTTP(rr, req) + + if rr.Code == http.StatusForbidden { + t.Errorf("Expected /login/ POST to be allowed without CSRF token, got 403 Forbidden") + } + if rr.Code != http.StatusTemporaryRedirect { + t.Errorf("Expected 307 Redirect on successful login, got %d", rr.Code) + } + + // Test 2: POST /other without CSRF token + // Should fail with 403 Forbidden + req2 := httptest.NewRequest("POST", "/other", nil) + rr2 := httptest.NewRecorder() + + handler.ServeHTTP(rr2, req2) + + if rr2.Code != http.StatusForbidden { + t.Errorf("Expected 403 Forbidden for POST /other, got %d", rr2.Code) + } +} diff --git a/web/static/login.html b/web/static/login.html index ab3e781..c7d0a03 100644 --- a/web/static/login.html +++ b/web/static/login.html @@ -1,23 +1,134 @@ - - - neko rss mode - - - - - - -
-

username

- - -

password

- - - -
- - + + + + + Neko Reader Login + + + +
+

Welcome Back

+
+
+ + +
+
+ + +
+ +
+ +
+ diff --git a/web/web.go b/web/web.go index a287bb9..d59d308 100644 --- a/web/web.go +++ b/web/web.go @@ -379,7 +379,7 @@ func CSRFMiddleware(cfg *config.Settings, next http.Handler) http.Handler { token = cookie.Value } - if (r.Method == http.MethodPost || r.Method == http.MethodPut || r.Method == http.MethodDelete) && r.URL.Path != "/api/login" { + if (r.Method == http.MethodPost || r.Method == http.MethodPut || r.Method == http.MethodDelete) && r.URL.Path != "/api/login" && r.URL.Path != "/login/" { headerToken := r.Header.Get("X-CSRF-Token") if headerToken == "" || headerToken != token { http.Error(w, "CSRF token mismatch", http.StatusForbidden) -- cgit v1.2.3