Replace map[string]interface{} with map[string]any, ioutil.ReadAll with
io.ReadAll, and simplify redundant fmt.Sprintf/w.Write calls.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
93 lines
2.6 KiB
Go
93 lines
2.6 KiB
Go
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)
|
|
}
|