package main import ( "log" "net/http" ) func resetPassword(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" && !resetLimiter.Allow(remoteIP(r)) { http.Error(w, "Too many requests. Please try again later.", http.StatusTooManyRequests) return } if len(r.URL.Query().Get("l")) == 0 || len(r.URL.Query().Get("t")) == 0 { http.Redirect(w, r, "lost", http.StatusFound) return } base := map[string]any{ "login": r.URL.Query().Get("l"), "token": r.URL.Query().Get("t"), } if r.Method != "POST" { csrfToken, err := setCSRFToken(w) if err != nil { http.Error(w, "Internal server error", http.StatusInternalServerError) return } base["csrf_token"] = csrfToken displayTmpl(w, "reset.html", base) return } renderError := func(status int, msg string) { csrfToken, _ := setCSRFToken(w) base["error"] = msg base["csrf_token"] = csrfToken displayTmplError(w, status, "reset.html", base) } if !validateCSRF(r) { renderError(http.StatusForbidden, "Invalid or missing CSRF token. Please try again.") return } if !validateAltcha(r) { renderError(http.StatusForbidden, "Invalid or missing altcha response. Please try again.") return } // Check the two new passwords are identical if r.PostFormValue("newpassword") != r.PostFormValue("new2password") { renderError(http.StatusNotAcceptable, "New passwords are not identical. Please retry.") return } else if err := checkPasswdConstraint(r.PostFormValue("newpassword")); err != nil { renderError(http.StatusNotAcceptable, "The password you chose doesn't respect all constraints: "+err.Error()) return } // Validate and consume the token (single-use, server-side) token := r.PostFormValue("token") dn, ok := consumeResetToken(token) if !ok { renderError(http.StatusNotAcceptable, "Token invalid or expired, please retry the lost password procedure. Tokens expire after 1 hour.") return } // Connect to the LDAP server conn, err := myLDAP.Connect() if err != nil || conn == nil { log.Println(err) renderError(http.StatusInternalServerError, "Unable to process your request. Please try again later.") return } // Bind as service to perform the password change err = conn.ServiceBind() if err != nil { log.Println(err) renderError(http.StatusInternalServerError, "Unable to process your request. Please try again later.") return } // Replace the password by the new given if err := conn.ChangePassword(dn, r.PostFormValue("newpassword")); err != nil { log.Println(err) renderError(http.StatusInternalServerError, "Unable to process your request. Please try again later.") return } displayMsg(w, "Password successfully changed!", http.StatusOK) }