This commit is contained in:
2026-02-11 17:46:22 +03:00
commit eacfacb13b
266 changed files with 51337 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
package routes
import (
"bssapp-backend/auth"
"bssapp-backend/internal/auditlog"
"bssapp-backend/internal/security"
"database/sql"
"encoding/json"
"net/http"
"golang.org/x/crypto/bcrypt"
)
func ChangeOwnPasswordHandler(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
// --------------------------------------------------
// 1⃣ JWT CLAIMS
// --------------------------------------------------
claims, ok := auth.GetClaimsFromContext(r.Context())
if !ok || claims == nil {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
// --------------------------------------------------
// 2⃣ PAYLOAD
// --------------------------------------------------
var req struct {
CurrentPassword string `json:"current_password"`
NewPassword string `json:"new_password"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "invalid payload", http.StatusBadRequest)
return
}
if req.CurrentPassword == "" || req.NewPassword == "" {
http.Error(w, "current_password and new_password required", http.StatusBadRequest)
return
}
// --------------------------------------------------
// 3⃣ PASSWORD POLICY
// --------------------------------------------------
if err := security.ValidatePassword(req.NewPassword); err != nil {
http.Error(w, err.Error(), http.StatusUnprocessableEntity)
return
}
// --------------------------------------------------
// 4⃣ MEVCUT HASH ÇEK
// --------------------------------------------------
var currentHash string
err := db.QueryRow(`
SELECT password_hash
FROM mk_dfusr
WHERE id = $1
AND is_active = true
`, claims.ID).Scan(&currentHash)
if err != nil {
http.Error(w, "user not found", http.StatusUnauthorized)
return
}
// --------------------------------------------------
// 5⃣ CURRENT PASSWORD CHECK
// --------------------------------------------------
if bcrypt.CompareHashAndPassword(
[]byte(currentHash),
[]byte(req.CurrentPassword),
) != nil {
http.Error(w, "current password incorrect", http.StatusUnauthorized)
return
}
// --------------------------------------------------
// 6⃣ NEW HASH
// --------------------------------------------------
newHash, err := bcrypt.GenerateFromPassword(
[]byte(req.NewPassword),
bcrypt.DefaultCost,
)
if err != nil {
http.Error(w, "hash error", http.StatusInternalServerError)
return
}
// --------------------------------------------------
// 7⃣ UPDATE (⚠️ force_password_change DEĞİŞMEZ)
// --------------------------------------------------
_, err = db.Exec(`
UPDATE mk_dfusr
SET
password_hash = $1,
password_updated_at = now(),
updated_at = now()
WHERE id = $2
`, string(newHash), claims.ID)
if err != nil {
http.Error(w, "password update failed", http.StatusInternalServerError)
return
}
// --------------------------------------------------
// 8⃣ AUDIT
// --------------------------------------------------
auditlog.Write(auditlog.ActivityLog{
ActionType: "PASSWORD_CHANGED",
ActionCategory: "security",
ActionTarget: claims.Username,
IsSuccess: true,
})
// --------------------------------------------------
// 9⃣ RESPONSE
// --------------------------------------------------
_ = json.NewEncoder(w).Encode(map[string]any{
"success": true,
})
}
}