Hardens auth with PBKDF2, lockouts, local QR setup, and safer embeds while moving account security under the username menu.
117 lines
5.2 KiB
Plaintext
117 lines
5.2 KiB
Plaintext
@{
|
|
ViewBag.Title = "User Settings";
|
|
Layout = "~/Views/Shared/_AdminLayout.cshtml";
|
|
var enabled = ViewBag.TwoFactorEnabled == true;
|
|
}
|
|
|
|
<h2 class="text-white mt-3 mb-3">User Settings</h2>
|
|
<p class="text-white-50">Account: <strong class="text-white">@ViewBag.Username</strong></p>
|
|
|
|
<div class="row">
|
|
<div class="col-lg-6 mb-4">
|
|
<div class="bg-dark border border-secondary rounded p-4 text-white h-100">
|
|
<h4 class="mb-3">Change password</h4>
|
|
|
|
@if (TempData["pwdOk"] != null)
|
|
{
|
|
<div class="alert alert-success py-2">@TempData["pwdOk"]</div>
|
|
}
|
|
@if (TempData["pwdError"] != null)
|
|
{
|
|
<div class="alert alert-danger py-2">@TempData["pwdError"]</div>
|
|
}
|
|
|
|
@using (Html.BeginForm("ChangePassword", "admin", FormMethod.Post))
|
|
{
|
|
@Html.AntiForgeryToken()
|
|
<div class="mb-3">
|
|
<label class="form-label">Current password</label>
|
|
<input type="password" name="currentPassword" class="form-control bg-dark text-white" autocomplete="current-password" required />
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">New password</label>
|
|
<input type="password" name="newPassword" class="form-control bg-dark text-white" autocomplete="new-password" minlength="8" required />
|
|
<small class="text-muted">At least 8 characters.</small>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Confirm new password</label>
|
|
<input type="password" name="confirmPassword" class="form-control bg-dark text-white" autocomplete="new-password" minlength="8" required />
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">Update password</button>
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-6 mb-4">
|
|
<div class="bg-dark border border-secondary rounded p-4 text-white h-100">
|
|
<h4 class="mb-3">
|
|
Two-factor authentication
|
|
@if (enabled)
|
|
{
|
|
<span class="badge text-bg-success ms-2">Enabled</span>
|
|
}
|
|
else
|
|
{
|
|
<span class="badge text-bg-secondary ms-2">Disabled</span>
|
|
}
|
|
</h4>
|
|
|
|
@if (TempData["tfaOk"] != null)
|
|
{
|
|
<div class="alert alert-success py-2">@TempData["tfaOk"]</div>
|
|
}
|
|
@if (TempData["tfaError"] != null)
|
|
{
|
|
<div class="alert alert-danger py-2">@TempData["tfaError"]</div>
|
|
}
|
|
|
|
@if (enabled)
|
|
{
|
|
<p class="text-white-50">2FA is active. Enter a current authenticator code to disable it.</p>
|
|
using (Html.BeginForm("DisableTwoFactor", "admin", FormMethod.Post))
|
|
{
|
|
@Html.AntiForgeryToken()
|
|
<div class="mb-3">
|
|
<label class="form-label">Authenticator code</label>
|
|
<input type="text" name="code" class="form-control bg-dark text-white" maxlength="6" inputmode="numeric" pattern="[0-9]*" autocomplete="one-time-code" required />
|
|
</div>
|
|
<button type="submit" class="btn btn-danger" onclick="return confirm('Disable two-factor authentication?');">Disable 2FA</button>
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<ol class="text-white-50">
|
|
<li>Open your authenticator app and scan the QR code below.</li>
|
|
<li>Or enter this secret manually: <code class="text-white">@ViewBag.SetupSecret</code></li>
|
|
<li>Enter the 6-digit code to confirm and enable 2FA.</li>
|
|
</ol>
|
|
|
|
<div class="text-center my-3">
|
|
<div id="totpQr" class="d-inline-block bg-white p-2 rounded"></div>
|
|
</div>
|
|
|
|
using (Html.BeginForm("EnableTwoFactor", "admin", FormMethod.Post))
|
|
{
|
|
@Html.AntiForgeryToken()
|
|
<div class="mb-3">
|
|
<label class="form-label">Authenticator code</label>
|
|
<input type="text" name="code" class="form-control bg-dark text-white" maxlength="6" inputmode="numeric" pattern="[0-9]*" autocomplete="one-time-code" required />
|
|
</div>
|
|
<button type="submit" class="btn btn-success">Enable 2FA</button>
|
|
}
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
|
<script>
|
|
(function () {
|
|
var uri = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject((string)ViewBag.OtpAuthUri));
|
|
var el = document.getElementById('totpQr');
|
|
if (el && uri && typeof QRCode !== 'undefined') {
|
|
new QRCode(el, { text: uri, width: 200, height: 200 });
|
|
}
|
|
})();
|
|
</script>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|