package routes import ( "bssapp-backend/internal/auditlog" "bssapp-backend/internal/mailer" "bssapp-backend/internal/security" "database/sql" "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func ForgotPasswordHandler( db *sql.DB, mailer *mailer.GraphMailer, ) http.HandlerFunc { type request struct { Email string `json:"email"` } return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") // ------------------------------------------------------- // 1️⃣ Request parse (enumeration yok) // ------------------------------------------------------- var req request if err := json.NewDecoder(r.Body).Decode(&req); err != nil { respondOK(w) return } email := strings.TrimSpace(strings.ToLower(req.Email)) if email == "" { respondOK(w) return } // ------------------------------------------------------- // 2️⃣ Aktif kullanıcıyı bul // ------------------------------------------------------- var userID int64 err := db.QueryRow(` SELECT id FROM mk_dfusr WHERE email = $1 AND is_active = true `, email).Scan(&userID) if err != nil { // ❗ kullanıcı yok → bilgi sızdırma yok respondOK(w) return } // ------------------------------------------------------- // 3️⃣ Reset token üret // ------------------------------------------------------- plain, hash, err := security.GenerateResetToken() if err != nil { respondOK(w) return } expires := time.Now().Add(30 * time.Minute) // ------------------------------------------------------- // 4️⃣ DB’ye SADECE HASH kaydet // ------------------------------------------------------- _, _ = db.Exec(` INSERT INTO dfusr_password_reset ( dfusr_id, token, expires_at ) VALUES ($1, $2, $3) `, userID, hash, expires) // ------------------------------------------------------- // 5️⃣ Reset URL (PLAIN token) // ------------------------------------------------------- resetURL := fmt.Sprintf( "%s/password-reset/%s", os.Getenv("FRONTEND_URL"), plain, ) // ------------------------------------------------------- // 6️⃣ Mail gönder (fail olsa bile enumeration yok) // ------------------------------------------------------- _ = mailer.SendPasswordResetMail(email, resetURL) // ------------------------------------------------------- // 7️⃣ AUDIT LOG // ------------------------------------------------------- auditlog.Write(auditlog.ActivityLog{ ActionType: "PASSWORD_FORGOT_REQUEST", ActionCategory: "security", ActionTarget: email, IsSuccess: true, }) respondOK(w) } } func respondOK(w http.ResponseWriter) { _ = json.NewEncoder(w).Encode(map[string]bool{ "success": true, }) }