From e97a71e5b2e378d46ba4115ccade49f310390f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Atakan=20Do=C4=9Fan=20=C3=96zban?= Date: Fri, 17 Jul 2026 18:49:34 +0200 Subject: [PATCH] Add password hashing, user settings with 2FA, and project image lightbox. Hardens auth with PBKDF2, lockouts, local QR setup, and safer embeds while moving account security under the username menu. --- Controllers/adminController.cs | 202 ++++++++++++++++++- Controllers/loginController.cs | 183 ++++++++++++++++-- Models/classes/PasswordHasher.cs | 104 ++++++++++ Models/classes/SecretProtector.cs | 54 ++++++ Models/classes/TotpHelper.cs | 176 +++++++++++++++++ Models/classes/admin.cs | 26 ++- README.md | 16 +- Views/Shared/_AdminLayout.cshtml | 1 + Views/admin/security.cshtml | 5 + Views/admin/usersettings.cshtml | 116 +++++++++++ Views/login/index.cshtml | 31 +-- Views/login/verify.cshtml | 50 +++++ Views/myprojects/projectposts.cshtml | 278 ++++++++++++++++++++++++++- Web.config | 21 +- atakanozbancom.csproj | 8 +- database/add-2fa.sql | 8 + database/harden-auth.sql | 24 +++ database/schema.sql | 12 +- 18 files changed, 1253 insertions(+), 62 deletions(-) create mode 100644 Models/classes/PasswordHasher.cs create mode 100644 Models/classes/SecretProtector.cs create mode 100644 Models/classes/TotpHelper.cs create mode 100644 Views/admin/security.cshtml create mode 100644 Views/admin/usersettings.cshtml create mode 100644 Views/login/verify.cshtml create mode 100644 database/add-2fa.sql create mode 100644 database/harden-auth.sql diff --git a/Controllers/adminController.cs b/Controllers/adminController.cs index 45f0090..d175d7f 100644 --- a/Controllers/adminController.cs +++ b/Controllers/adminController.cs @@ -13,7 +13,7 @@ namespace atakanozbancom.Controllers private readonly Context db = new Context(); [Authorize] - public ActionResult Index() + public ActionResult Index() // admin dashboard landing page { ViewBag.MyProjectsCount = db.MyProjects.Count(); ViewBag.AffiliateLinksCount = db.AffiliateLinks.Count(); @@ -22,7 +22,7 @@ namespace atakanozbancom.Controllers } [Authorize] - public ActionResult MyProjects() + public ActionResult MyProjects() // shows what we have { var value = db.MyProjects.ToList(); return View(value); @@ -53,6 +53,7 @@ namespace atakanozbancom.Controllers DescTR = tr != null ? tr.description : "" }; + // NEW: vm.medias = db.projectmedia .Where(m => m.project_id == p.id) .OrderBy(m => m.sort_order) @@ -183,11 +184,19 @@ namespace atakanozbancom.Controllers return RedirectToAction("myprojectsget", new { id = projectId }); } + var trimmed = iframeUrl.Trim(); + if (!Uri.TryCreate(trimmed, UriKind.Absolute, out var embedUri) + || (embedUri.Scheme != Uri.UriSchemeHttps && embedUri.Scheme != Uri.UriSchemeHttp)) + { + TempData["ok"] = "Iframe URL must be a valid http(s) address."; + return RedirectToAction("myprojectsget", new { id = projectId }); + } + var row = new projectmedia { project_id = projectId, media_type = MediaType.Iframe, - url = iframeUrl.Trim(), + url = trimmed, sort_order = sortOrder }; @@ -295,6 +304,9 @@ namespace atakanozbancom.Controllers return RedirectToAction("myprojectsget", new { id = projectId }); } + // ================= AFFILIATE LINKS ================= + + // .svg intentionally excluded: SVGs can embed + + } + + + diff --git a/Views/login/index.cshtml b/Views/login/index.cshtml index 5a02e9f..f8518fd 100644 --- a/Views/login/index.cshtml +++ b/Views/login/index.cshtml @@ -1,19 +1,15 @@ - -@{ +@{ Layout = null; } - Sign-in - - -
@using (Html.BeginForm("index", "login", FormMethod.Post)) { + @Html.AntiForgeryToken()

Please sign in

+ if (ViewBag.Error != null) + { +
@ViewBag.Error
+ } +
- +
-
- +
+
}
- - diff --git a/Views/login/verify.cshtml b/Views/login/verify.cshtml new file mode 100644 index 0000000..0d0d67f --- /dev/null +++ b/Views/login/verify.cshtml @@ -0,0 +1,50 @@ +@{ + Layout = null; +} + + + + + + + Two-factor authentication + + + + +
+ @using (Html.BeginForm("Verify", "login", FormMethod.Post)) + { + @Html.AntiForgeryToken() +

Two-factor authentication

+

Enter the 6-digit code from your authenticator app.

+ + if (ViewBag.Error != null) + { +
@ViewBag.Error
+ } + +
+ +
+ + + Back to sign in + } +
+ + diff --git a/Views/myprojects/projectposts.cshtml b/Views/myprojects/projectposts.cshtml index 55b50fd..806829b 100644 --- a/Views/myprojects/projectposts.cshtml +++ b/Views/myprojects/projectposts.cshtml @@ -37,6 +37,7 @@ width: 100%; height: auto; object-fit: contain; + cursor: zoom-in; } .media-arrow { @@ -61,6 +62,91 @@ .carousel-indicators { z-index: 6; } + + #projectLightboxModal .modal-dialog { + width: auto; + max-width: calc(100vw - 2rem); + margin: 0.5rem auto; + } + + #projectLightboxModal .modal-content { + background: transparent; + width: fit-content; + max-width: 100%; + margin: 0 auto; + } + + #projectLightboxModal .modal-body { + padding: 0; + } + + #projectLightboxModal .lightbox-stage { + position: relative; + display: inline-block; + max-width: calc(100vw - 2rem); + line-height: 0; + background: #000; + border-radius: 0.35rem; + overflow: hidden; + } + + #projectLightboxModal .lightbox-stage img { + display: block; + width: auto; + height: auto; + max-width: calc(100vw - 2rem); + max-height: 85vh; + object-fit: contain; + } + + #projectLightboxModal .lightbox-arrow { + position: absolute; + top: 50%; + bottom: auto; + transform: translateY(-50%); + width: 3.5rem; + height: 3.5rem; + opacity: 0.9; + z-index: 2; + } + + #projectLightboxModal .lightbox-arrow.carousel-control-prev { + left: 0; + } + + #projectLightboxModal .lightbox-arrow.carousel-control-next { + right: 0; + } + + #projectLightboxModal .lightbox-indicators { + position: absolute; + left: 0; + right: 0; + bottom: 0.75rem; + margin: 0; + z-index: 2; + } + + #projectLightboxModal .lightbox-indicators button { + width: 10px; + height: 10px; + border-radius: 50%; + background-color: rgba(255, 255, 255, .5); + border: 0; + margin: 0 4px; + padding: 0; + } + + #projectLightboxModal .lightbox-indicators button.active { + background-color: #fff; + } + + #projectLightboxModal .lightbox-close { + position: absolute; + top: 0.6rem; + right: 0.6rem; + z-index: 3; + } @foreach (var p in Model) @@ -104,7 +190,9 @@