From 71805cf65ccf8079a03d4473d7f76daf9b6d4e6e Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 12 Mar 2026 12:11:45 +0700 Subject: [PATCH] fix(reset): validate token on GET and surface errors on POST - Verify reset token before showing the form (GET), redirecting with an error immediately if the token is invalid or expired - Add peekResetToken to check token validity non-destructively - Fix POST form action to include query params so the URL check doesn't silently redirect to /lost before processing errors - Update page title and subtitle to reflect the reset step Co-Authored-By: Claude Sonnet 4.6 --- lost.go | 10 ++++++++++ reset.go | 6 ++++++ static/reset.html | 6 +++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lost.go b/lost.go index 7afe093..8fbef23 100644 --- a/lost.go +++ b/lost.go @@ -49,6 +49,16 @@ func storeResetToken(token string, dn string) { } } +func peekResetToken(token string) bool { + resetTokenStore.mu.Lock() + defer resetTokenStore.mu.Unlock() + entry, ok := resetTokenStore.tokens[token] + if !ok || time.Now().After(entry.expiresAt) { + return false + } + return true +} + func consumeResetToken(token string) (string, bool) { resetTokenStore.mu.Lock() defer resetTokenStore.mu.Unlock() diff --git a/reset.go b/reset.go index a65c27c..143976e 100644 --- a/reset.go +++ b/reset.go @@ -22,6 +22,12 @@ func resetPassword(w http.ResponseWriter, r *http.Request) { } if r.Method != "POST" { + if !peekResetToken(r.URL.Query().Get("t")) { + displayTmplError(w, http.StatusGone, "lost.html", map[string]any{ + "error": "Token invalid or expired, please retry the lost password procedure. Tokens expire after 1 hour.", + }) + return + } csrfToken, err := setCSRFToken(w) if err != nil { http.Error(w, "Internal server error", http.StatusInternalServerError) diff --git a/static/reset.html b/static/reset.html index 7cf48b1..379754c 100644 --- a/static/reset.html +++ b/static/reset.html @@ -1,8 +1,8 @@ {{template "header" .}} -

Forgot your password?

-

Define a new one!

+

Define your new password

+

Choose a strong password to secure your account.

-
+ {{if .error}}{{end}}