using System; using System.Linq; using System.Web.Mvc; using System.Web.Security; using atakanozbancom.Models.classes; namespace atakanozbancom.Controllers { public class loginController : Controller { private readonly Context c = new Context(); private const int MaxPasswordFailures = 8; private const int MaxTotpFailures = 5; private const int LockMinutes = 15; public ActionResult Index() { return View(); } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Index(admin ad) { if (ad == null || string.IsNullOrWhiteSpace(ad.username) || string.IsNullOrWhiteSpace(ad.password)) { ViewBag.Error = "Username and password are required."; return View(); } var user = c.admins.FirstOrDefault(x => x.username == ad.username); if (user == null) { ViewBag.Error = "Invalid username or password."; return View(); } if (user.login_lock_until.HasValue && user.login_lock_until.Value > DateTime.UtcNow) { ViewBag.Error = "Account temporarily locked. Try again later."; return View(); } if (!PasswordHasher.Verify(ad.password, user.password)) { user.login_failed_count++; if (user.login_failed_count >= MaxPasswordFailures) { user.login_lock_until = DateTime.UtcNow.AddMinutes(LockMinutes); user.login_failed_count = 0; } c.SaveChanges(); ViewBag.Error = "Invalid username or password."; return View(); } user.login_failed_count = 0; user.login_lock_until = null; if (!PasswordHasher.IsHashed(user.password)) { user.password = PasswordHasher.Hash(ad.password); } c.SaveChanges(); ClearPending2Fa(); if (user.two_factor_enabled && !string.IsNullOrWhiteSpace(user.two_factor_secret)) { if (user.totp_lock_until.HasValue && user.totp_lock_until.Value > DateTime.UtcNow) { ViewBag.Error = "Too many failed 2FA attempts. Try again later."; return View(); } Session["Pending2FaUserId"] = user.id; Session["Pending2FaUsername"] = user.username; Session["Pending2FaExpiresUtc"] = DateTime.UtcNow.AddMinutes(10); return RedirectToAction("Verify"); } CompleteLogin(user.username); return RedirectToAction("Index", "admin"); } public ActionResult Verify() { if (!HasValidPending2Fa()) { ClearPending2Fa(); return RedirectToAction("Index"); } return View(); } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Verify(string code) { if (!HasValidPending2Fa()) { ClearPending2Fa(); return RedirectToAction("Index"); } var pendingId = Convert.ToInt32(Session["Pending2FaUserId"]); var pendingUsername = Session["Pending2FaUsername"].ToString(); var user = c.admins.FirstOrDefault(x => x.id == pendingId && x.username == pendingUsername); if (user == null || !user.two_factor_enabled || string.IsNullOrWhiteSpace(user.two_factor_secret)) { ClearPending2Fa(); return RedirectToAction("Index"); } if (user.totp_lock_until.HasValue && user.totp_lock_until.Value > DateTime.UtcNow) { ViewBag.Error = "Too many failed attempts. Try again later."; return View(); } var secret = ResolveTotpSecret(user); if (string.IsNullOrWhiteSpace(secret) || !TotpHelper.VerifyCode(secret, code)) { user.totp_failed_count++; if (user.totp_failed_count >= MaxTotpFailures) { user.totp_lock_until = DateTime.UtcNow.AddMinutes(LockMinutes); user.totp_failed_count = 0; ViewBag.Error = "Too many failed attempts. Try again later."; } else { ViewBag.Error = "Invalid authentication code."; } c.SaveChanges(); return View(); } user.totp_failed_count = 0; user.totp_lock_until = null; c.SaveChanges(); ClearPending2Fa(); CompleteLogin(user.username); return RedirectToAction("Index", "admin"); } public ActionResult logout() { ClearPending2Fa(); Session.Remove("username"); Session.Abandon(); FormsAuthentication.SignOut(); return RedirectToAction("index", "login"); } private void CompleteLogin(string username) { FormsAuthentication.SetAuthCookie(username, false); Session["username"] = username; } private bool HasValidPending2Fa() { if (Session["Pending2FaUserId"] == null || Session["Pending2FaUsername"] == null) return false; var expires = Session["Pending2FaExpiresUtc"] as DateTime?; if (expires == null || expires.Value < DateTime.UtcNow) return false; return true; } private static string ResolveTotpSecret(admin user) { if (string.IsNullOrWhiteSpace(user.two_factor_secret)) return null; var unprotected = SecretProtector.Unprotect(user.two_factor_secret); if (!string.IsNullOrWhiteSpace(unprotected)) return unprotected; return user.two_factor_secret; } private void ClearPending2Fa() { Session.Remove("Pending2FaUserId"); Session.Remove("Pending2FaUsername"); Session.Remove("Pending2FaSetupSecret"); Session.Remove("Pending2FaExpiresUtc"); } } }