117 lines
2.8 KiB
Go
117 lines
2.8 KiB
Go
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,
|
||
})
|
||
}
|