72a8336087
Backend: - DB: add UpdateAdminPasswordHash(id, hash) in queries_users.go - Auth: add ChangePassword(username, old, new) method that verifies old password, validates length >= 8, and stores bcrypt hash - Handlers: add handleChangePassword on PUT /api/auth/password (auth required) - Router: register route inside protected group Frontend: - api.ts: add changePassword(oldPassword, newPassword) - Settings.tsx: new page with form (current + new + confirm), client-side validation, success/error feedback - App.tsx: add /settings route - Layout.tsx: add 'Ajustes' nav item
82 lines
2.2 KiB
Go
82 lines
2.2 KiB
Go
package web
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
)
|
|
|
|
type loginRequest struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
type changePasswordRequest struct {
|
|
OldPassword string `json:"old_password"`
|
|
NewPassword string `json:"new_password"`
|
|
}
|
|
|
|
func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
|
|
if s.Auth == nil {
|
|
writeError(w, http.StatusServiceUnavailable, "auth not configured")
|
|
return
|
|
}
|
|
defer r.Body.Close()
|
|
var req loginRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid request body")
|
|
return
|
|
}
|
|
if !s.Auth.Authenticate(req.Username, req.Password) {
|
|
writeError(w, http.StatusUnauthorized, "invalid credentials")
|
|
return
|
|
}
|
|
s.Auth.setSessionCookie(w, req.Username)
|
|
writeJSON(w, http.StatusOK, map[string]any{"username": req.Username})
|
|
}
|
|
|
|
func (s *Server) handleLogout(w http.ResponseWriter, r *http.Request) {
|
|
if s.Auth != nil {
|
|
s.Auth.clearSessionCookie(w)
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"ok": true})
|
|
}
|
|
|
|
func (s *Server) handleAuthStatus(w http.ResponseWriter, r *http.Request) {
|
|
if s.Auth == nil {
|
|
writeJSON(w, http.StatusOK, map[string]any{"authenticated": true, "username": ""})
|
|
return
|
|
}
|
|
username, ok := s.Auth.currentUser(r)
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"authenticated": ok,
|
|
"username": username,
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleChangePassword(w http.ResponseWriter, r *http.Request) {
|
|
if s.Auth == nil {
|
|
writeError(w, http.StatusServiceUnavailable, "auth not configured")
|
|
return
|
|
}
|
|
username, ok := s.Auth.currentUser(r)
|
|
if !ok {
|
|
writeError(w, http.StatusUnauthorized, "authentication required")
|
|
return
|
|
}
|
|
defer r.Body.Close()
|
|
var req changePasswordRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid request body")
|
|
return
|
|
}
|
|
if req.OldPassword == "" || req.NewPassword == "" {
|
|
writeError(w, http.StatusBadRequest, "old_password and new_password are required")
|
|
return
|
|
}
|
|
if err := s.Auth.ChangePassword(username, req.OldPassword, req.NewPassword); err != nil {
|
|
writeError(w, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"ok": true})
|
|
}
|