Add project files.

This commit is contained in:
Khwezi Mngoma
2026-06-05 22:07:25 +02:00
parent 59ea7de742
commit 437e8c5c08
978 changed files with 151911 additions and 0 deletions
@@ -0,0 +1,55 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@model LiteCharmsSecurity.STS.Identity.ViewModels.Manage.ChangePasswordViewModel
@{
ViewData["Title"] = Localizer["Title"];
}
<section class="space-y-6">
<div class="card">
<div class="card-header">
<h2 class="card-title">@ViewData["Title"]</h2>
</div>
<div class="card-content space-y-6">
@await Html.PartialAsync("_ValidationSummary")
@await Html.PartialAsync("_StatusMessage", Model.StatusMessage)
<form method="post" class="space-y-4">
<div class="form-item">
<label asp-for="OldPassword" class="form-label">
<lucideicon name="lock" class="inline-block h-4 w-4 mr-1" />
@Localizer["OldPassword"]
</label>
<input asp-for="OldPassword" type="password" class="input" tw-validation />
<span asp-validation-for="OldPassword" class="form-message"></span>
</div>
<div class="form-item">
<label asp-for="NewPassword" class="form-label">
<lucideicon name="key-round" class="inline-block h-4 w-4 mr-1" />
@Localizer["NewPassword"]
</label>
<input asp-for="NewPassword" type="password" class="input" tw-validation />
<span asp-validation-for="NewPassword" class="form-message"></span>
</div>
<div class="form-item">
<label asp-for="ConfirmPassword" class="form-label">
<lucideicon name="lock-keyhole" class="inline-block h-4 w-4 mr-1" />
@Localizer["ConfirmPassword"]
</label>
<input asp-for="ConfirmPassword" type="password" class="input" tw-validation />
<span asp-validation-for="ConfirmPassword" class="form-message"></span>
</div>
<div>
<button type="submit" class="btn-default">
<lucideicon name="save" class="inline-block h-4 w-4 mr-2" />
@Localizer["Update"]
</button>
</div>
</form>
</div>
</div>
</section>
@@ -0,0 +1,43 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@model LiteCharmsSecurity.STS.Identity.ViewModels.Manage.DeletePersonalDataViewModel
@{
ViewData["Title"] = Localizer["Title"];
}
<section class="space-y-6 max-w-2xl">
<div class="card">
<div class="card-header">
<h2 class="card-title">@ViewData["Title"]</h2>
</div>
<div class="card-content space-y-6">
<div class="alert-destructive">
<lucideicon name="alert-circle" class="h-4 w-4" />
<div>
<div class="alert-title">@Localizer["Alert"]</div>
</div>
</div>
<form id="delete-user" method="post" class="space-y-4">
@await Html.PartialAsync("_ValidationSummary")
@if (Model.RequirePassword)
{
<div class="form-item">
<label asp-for="Password" class="form-label">
<lucideicon name="lock" class="inline-block h-4 w-4 mr-1" />
@Localizer["Password"]
</label>
<input asp-for="Password" type="password" class="input" tw-validation />
<span asp-validation-for="Password" class="form-message"></span>
</div>
}
<button class="btn-destructive" type="submit">
<lucideicon name="trash-2" class="inline-block h-4 w-4 mr-2" />
@Localizer["Delete"]
</button>
</form>
</div>
</div>
</section>
@@ -0,0 +1,30 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@{
ViewData["Title"] = Localizer["Title"];
}
<section class="space-y-6 max-w-2xl">
<div class="card">
<div class="card-header">
<h2 class="card-title">@ViewData["Title"]</h2>
</div>
<div class="card-content space-y-6">
<div class="alert-destructive">
<lucideicon name="alert-circle" class="h-4 w-4" />
<div>
<div class="alert-title">@Localizer["SubTitle"]</div>
<div class="alert-description">@Localizer["Info"] <a asp-action="ResetAuthenticatorWarning" class="underline underline-offset-4">@Localizer["ResetAuthenticator"]</a></div>
</div>
</div>
<form asp-action="Disable2fa" method="post">
<button class="btn-destructive" type="submit">
<lucideicon name="shield-off" class="inline-block h-4 w-4 mr-2" />
@Localizer["Disable2FA"]
</button>
</form>
</div>
</div>
</section>
@@ -0,0 +1,10 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@{
ViewData["Title"] = Localizer["Title"];
}
<div class="py-8">
<h1 class="text-4xl font-bold">@ViewData["Title"]</h1>
</div>
@@ -0,0 +1,59 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@model LiteCharmsSecurity.STS.Identity.ViewModels.Manage.EnableAuthenticatorViewModel
@{
ViewData["Title"] = Localizer["Title"];
}
<section class="space-y-6">
<div class="card">
<div class="card-header">
<h2 class="card-title">@ViewData["Title"]</h2>
<p class="card-description">@Localizer["SubTitle"]</p>
</div>
<div class="card-content space-y-6">
<ol class="space-y-6 list-decimal pl-5 text-sm text-muted-foreground">
<li class="space-y-2">
<p class="text-foreground">
@Localizer["DownloadTitle"]
<a href="https://go.microsoft.com/fwlink/?Linkid=825071" class="text-primary hover:underline">Windows Phone</a>,
<a href="https://go.microsoft.com/fwlink/?Linkid=825072" class="text-primary hover:underline">Android</a>,
<a href="https://go.microsoft.com/fwlink/?Linkid=825073" class="text-primary hover:underline">iOS</a>.
@Localizer["GoogleAuthenticatorTitle"]
<a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&amp;hl=en" class="text-primary hover:underline">Android</a>,
<a href="https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8" class="text-primary hover:underline">iOS</a>.
</p>
</li>
<li class="space-y-3">
<p class="text-foreground">@Localizer["ScanQR"] <kbd class="rounded bg-muted px-1 py-0.5 text-xs">@Model.SharedKey</kbd> @Localizer["ScanQRSubTitle"]</p>
<div id="qrCode" class="rounded-md border p-4 inline-block"></div>
<div id="qrCodeData" data-url="@Model.AuthenticatorUri"></div>
</li>
<li class="space-y-3">
<p class="text-foreground">@Localizer["Info"]</p>
<form method="post" class="space-y-4 max-w-md">
@await Html.PartialAsync("_ValidationSummary")
<div class="form-item">
<label asp-for="Code" class="form-label">
<lucideicon name="shield-check" class="inline-block h-4 w-4 mr-1" />
@Localizer["Code"]
</label>
<input asp-for="Code" class="input" autocomplete="off" tw-validation />
<span asp-validation-for="Code" class="form-message"></span>
</div>
<button type="submit" class="btn-default">
<lucideicon name="check" class="inline-block h-4 w-4 mr-2" />
@Localizer["Verify"]
</button>
</form>
</li>
</ol>
</div>
</div>
</section>
<script src="~/js/qrcode.min.js"></script>
<script src="~/js/enable-authenticator.js" asp-append-version="true"></script>
@@ -0,0 +1,69 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@model LiteCharmsSecurity.STS.Identity.ViewModels.Manage.ExternalLoginsViewModel
@{
ViewData["Title"] = Localizer["Title"];
}
<section class="space-y-6">
@await Html.PartialAsync("_StatusMessage", Model.StatusMessage)
<div class="card">
<div class="card-header">
<h2 class="card-title">@Localizer["SubTitle"]</h2>
</div>
<div class="card-content space-y-6">
@if (Model.CurrentLogins?.Count > 0)
{
<div class="table-wrapper">
<table class="table">
<tbody class="table-body">
@foreach (var login in Model.CurrentLogins)
{
<tr class="table-row">
<td class="table-cell font-medium">@login.LoginProvider</td>
<td class="table-cell text-right">
@if (Model.ShowRemoveButton)
{
<form asp-action="RemoveLogin" method="post" class="inline">
<input asp-for="@login.LoginProvider" name="LoginProvider" type="hidden" />
<input asp-for="@login.ProviderKey" name="ProviderKey" type="hidden" />
<button type="submit" class="btn-destructive btn-sm" title="Remove this @login.LoginProvider login from your account">
<lucideicon name="unlink" class="inline-block h-3 w-3 mr-1" />
@Localizer["Remove"]
</button>
</form>
}
</td>
</tr>
}
</tbody>
</table>
</div>
}
else
{
<div class="alert-default">
<lucideicon name="info" class="h-4 w-4" />
<div>
<div class="alert-description">@Localizer["Title"]</div>
</div>
</div>
}
@if (Model.OtherLogins?.Count > 0)
{
<div class="space-y-3">
<h4 class="text-sm font-semibold uppercase tracking-wide text-muted-foreground">@Localizer["TitleAddAnotherService"]</h4>
<form asp-action="LinkLogin" method="post" class="flex flex-wrap gap-3">
@foreach (var provider in Model.OtherLogins)
{
<button type="submit" class="btn-outline" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</form>
</div>
}
</div>
</div>
</section>
@@ -0,0 +1,33 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@{
ViewData["Title"] = Localizer["Title"];
}
<section class="space-y-6 max-w-2xl">
<div class="card">
<div class="card-header">
<h2 class="card-title">@ViewData["Title"]</h2>
</div>
<div class="card-content space-y-6">
<div class="alert-default">
<lucideicon name="info" class="h-4 w-4" />
<div>
<div class="alert-title">@Localizer["SubTitle"]</div>
<div class="alert-description space-y-2">
<p>@Localizer["LostInfo"]</p>
<p>@Localizer["GenerateRecoveryCodeInfo"] <a asp-action="ResetAuthenticatorWarning" class="underline underline-offset-4">@Localizer["ResetKeys"]</a></p>
</div>
</div>
</div>
<form asp-action="GenerateRecoveryCodes" method="post">
<button class="btn-destructive" type="submit">
<lucideicon name="refresh-cw" class="inline-block h-4 w-4 mr-2" />
@Localizer["GenerateCodes"]
</button>
</form>
</div>
</div>
</section>
@@ -0,0 +1,145 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@model LiteCharmsSecurity.STS.Identity.ViewModels.Manage.IndexViewModel
<section class="space-y-6">
<div class="card">
<div class="card-header">
<h2 class="card-title">@Localizer["Title"]</h2>
<p class="card-description">@Localizer["Manage your profile and contact information."]</p>
</div>
<div class="card-content space-y-6">
@await Html.PartialAsync("_ValidationSummary")
@await Html.PartialAsync("_StatusMessage", Model.StatusMessage)
<div class="grid gap-6 md:grid-cols-[180px,1fr]">
<div class="flex items-start">
<img-gravatar email="@Model.Email" class="rounded-full border shadow-sm" size="150" />
</div>
<form method="post" class="space-y-6">
<!-- Username (read-only) -->
<div class="form-item">
<label asp-for="Username" class="form-label" tw-validation>
<lucideicon name="user" class="inline-block h-4 w-4 mr-1" />
@Localizer["Username"]
</label>
<input asp-for="Username" class="input" disabled tw-validation />
<span asp-validation-for="Username" class="form-message"></span>
</div>
<!-- Email + verification -->
<div class="form-item">
<label asp-for="Email" class="form-label" tw-validation>
<lucideicon name="mail" class="inline-block h-4 w-4 mr-1" />
@Localizer["Email"]
</label>
<input type="hidden" asp-for="IsEmailConfirmed" />
<div class="flex flex-col gap-2 sm:flex-row sm:items-center">
<input asp-for="Email" class="input sm:flex-1" tw-validation />
@if (!Model.IsEmailConfirmed)
{
<button asp-action="SendVerificationEmail" class="btn-link">@Localizer["SendVerificationEmail"]</button>
}
</div>
<span asp-validation-for="Email" class="form-message"></span>
</div>
<!-- Contact -->
<div class="grid gap-6 md:grid-cols-2">
<div class="form-item">
<label asp-for="PhoneNumber" class="form-label" tw-validation>
<lucideicon name="phone" class="inline-block h-4 w-4 mr-1" />
@Localizer["Phone number"]
</label>
<input asp-for="PhoneNumber" class="input" tw-validation />
<span asp-validation-for="PhoneNumber" class="form-message"></span>
</div>
<div class="form-item">
<label asp-for="Name" class="form-label" tw-validation>
<lucideicon name="user-circle" class="inline-block h-4 w-4 mr-1" />
@Localizer["Full name"]
</label>
<input asp-for="Name" class="input" tw-validation />
<span asp-validation-for="Name" class="form-message"></span>
</div>
</div>
<div class="form-item">
<label asp-for="Website" class="form-label" tw-validation>
<lucideicon name="globe" class="inline-block h-4 w-4 mr-1" />
@Localizer["Website"]
</label>
<input asp-for="Website" class="input" tw-validation />
<span asp-validation-for="Website" class="form-message"></span>
</div>
<div class="form-item">
<label asp-for="Profile" class="form-label" tw-validation>
<lucideicon name="link" class="inline-block h-4 w-4 mr-1" />
@Localizer["Profile"]
</label>
<input asp-for="Profile" class="input" tw-validation />
<span asp-validation-for="Profile" class="form-message"></span>
</div>
<!-- Address -->
<div class="form-item">
<label asp-for="StreetAddress" class="form-label" tw-validation>
<lucideicon name="map-pin" class="inline-block h-4 w-4 mr-1" />
@Localizer["Street address"]
</label>
<input asp-for="StreetAddress" class="input" tw-validation />
<span asp-validation-for="StreetAddress" class="form-message"></span>
</div>
<div class="grid gap-6 md:grid-cols-2">
<div class="form-item">
<label asp-for="Locality" class="form-label" tw-validation>
<lucideicon name="building" class="inline-block h-4 w-4 mr-1" />
@Localizer["City"]
</label>
<input asp-for="Locality" class="input" tw-validation />
<span asp-validation-for="Locality" class="form-message"></span>
</div>
<div class="form-item">
<label asp-for="Region" class="form-label" tw-validation>
<lucideicon name="map" class="inline-block h-4 w-4 mr-1" />
@Localizer["State/Province"]
</label>
<input asp-for="Region" class="input" tw-validation />
<span asp-validation-for="Region" class="form-message"></span>
</div>
</div>
<div class="grid gap-6 md:grid-cols-2">
<div class="form-item">
<label asp-for="PostalCode" class="form-label" tw-validation>
<lucideicon name="hash" class="inline-block h-4 w-4 mr-1" />
@Localizer["Postal code"]
</label>
<input asp-for="PostalCode" class="input" tw-validation />
<span asp-validation-for="PostalCode" class="form-message"></span>
</div>
<div class="form-item">
<label asp-for="Country" class="form-label" tw-validation>
<lucideicon name="flag" class="inline-block h-4 w-4 mr-1" />
@Localizer["Country"]
</label>
<input asp-for="Country" class="input" tw-validation />
<span asp-validation-for="Country" class="form-message"></span>
</div>
</div>
<div class="flex gap-3">
<button type="submit" class="btn-default">
<lucideicon name="save" class="inline-block h-4 w-4 mr-2" />
@Localizer["Save"]
</button>
</div>
</form>
</div>
</div>
</div>
</section>
@@ -0,0 +1,17 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@{
ViewData["Title"] = Localizer["Title"];
}
<div class="py-8">
@await Html.PartialAsync("_ValidationSummary")
<h1 class="text-4xl font-bold mb-2">@ViewData["Title"]</h1>
<div class="alert-destructive">
<lucideicon name="alert-circle" class="h-4 w-4" />
<div>
<div class="alert-description">@Localizer["Error"]</div>
</div>
</div>
</div>
@@ -0,0 +1,70 @@
@using System.Buffers.Text
@using LiteCharmsSecurity.STS.Identity.Passkeys
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
@model LiteCharmsSecurity.STS.Identity.ViewModels.Manage.PasskeysViewModel
@{
ViewData["Title"] = Localizer["Title"];
}
<partial name="_StatusMessage" model="@Model.StatusMessage" />
<h3 class="text-2xl font-bold mb-6">@ViewData["Title"]</h3>
<div class="card mb-6">
<div class="card-content py-6">
@if (Model.CurrentPasskeys?.Count > 0)
{
<div class="space-y-4">
@foreach (var passkey in Model.CurrentPasskeys)
{
var credentialId = Base64Url.EncodeToString(passkey.CredentialId);
<div class="flex items-center justify-between py-3 border-b border-border last:border-0">
<div class="flex items-center gap-3">
<lucideicon name="fingerprint" class="h-5 w-5 text-muted-foreground" />
<span>@(passkey.Name ?? Localizer["UnnamedPasskey"].Value)</span>
</div>
<form asp-action="UpdatePasskey" method="post" class="flex items-center gap-2">
<input type="hidden" name="CredentialId" value="@credentialId" />
<button type="submit" name="Action" value="rename" class="btn-outline btn-sm">
<lucideicon name="pencil" class="h-4 w-4 mr-1" />
@Localizer["Rename"]
</button>
<button type="submit" name="Action" value="delete" class="btn-destructive btn-sm"
onclick="return confirm('@Localizer["ConfirmDelete"]');">
<lucideicon name="trash-2" class="h-4 w-4 mr-1" />
@Localizer["Delete"]
</button>
</form>
</div>
}
</div>
}
else
{
<div class="text-center py-8 text-muted-foreground">
<lucideicon name="fingerprint" class="h-12 w-12 mx-auto mb-4 opacity-50" />
<p>@Localizer["NoPasskeys"]</p>
</div>
}
</div>
</div>
<div class="card">
<div class="card-header">
<h4 class="card-title">@Localizer["AddPasskey"]</h4>
<p class="card-description">@Localizer["AddPasskeyDescription"]</p>
</div>
<div class="card-content">
<form asp-action="AddPasskey" method="post">
<passkey-submit operation="@PasskeyOperation.Create" name="Passkey" class="btn-default" formnovalidate>
<lucideicon name="plus" class="inline-block h-4 w-4 mr-2" />
@Localizer["AddPasskeyButton"]
</passkey-submit>
</form>
</div>
</div>
@section scripts {
<script src="~/js/passkey-submit.js" asp-append-version="true"></script>
}
@@ -0,0 +1,40 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@{
ViewData["Title"] = Localizer["Title"];
}
<div class="py-8">
<h1 class="text-4xl font-bold mb-6">@ViewData["Title"]</h1>
<div class="max-w-2xl space-y-6">
<div class="alert-default">
<lucideicon name="info" class="h-4 w-4" />
<div>
<div class="alert-description">@Localizer["Info"]</div>
</div>
</div>
<form asp-action="DownloadPersonalData" method="post">
<button class="btn-default" type="submit">
<lucideicon name="download" class="inline-block h-4 w-4 mr-2" />
@Localizer["Download"]
</button>
</form>
<div class="alert-destructive">
<lucideicon name="alert-circle" class="h-4 w-4" />
<div>
<div class="alert-description">@Localizer["Warning"]</div>
</div>
</div>
<div>
<a asp-action="DeletePersonalData" class="btn-destructive">
<lucideicon name="trash-2" class="inline-block h-4 w-4 mr-2" />
@Localizer["Delete"]
</a>
</div>
</div>
</div>
@@ -0,0 +1,47 @@
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
@model LiteCharmsSecurity.STS.Identity.ViewModels.Manage.RenamePasskeyViewModel
@{
ViewData["Title"] = Localizer["Title"];
}
<partial name="_StatusMessage" model="@Model.StatusMessage" />
<h3 class="text-2xl font-bold mb-6">@ViewData["Title"]</h3>
<div class="card">
<div class="card-content py-6">
@if (!string.IsNullOrEmpty(Model.Name))
{
<p class="text-muted-foreground mb-4">@Localizer["RenameDescription", Model.Name]</p>
}
else
{
<p class="text-muted-foreground mb-4">@Localizer["NameDescription"]</p>
}
<form asp-action="RenamePasskey" method="post" class="space-y-4">
<input type="hidden" asp-for="CredentialId" />
<div class="form-item">
<label class="form-label" for="Name">
<lucideicon name="tag" class="inline-block h-4 w-4 mr-1" />
@Localizer["Name"]
</label>
<input id="Name" class="input" asp-for="Name" autofocus autocomplete="off" />
<span asp-validation-for="Name" class="text-destructive text-sm"></span>
</div>
<div class="flex gap-2">
<button type="submit" class="btn-default">
<lucideicon name="check" class="inline-block h-4 w-4 mr-2" />
@Localizer["Save"]
</button>
<a asp-action="Passkeys" class="btn-outline">
<lucideicon name="x" class="inline-block h-4 w-4 mr-2" />
@Localizer["Cancel"]
</a>
</div>
</form>
</div>
</div>
@@ -0,0 +1,30 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@{
ViewData["Title"] = Localizer["Title"];
}
<section class="space-y-6 max-w-2xl">
<div class="card">
<div class="card-header">
<h2 class="card-title">@ViewData["Title"]</h2>
</div>
<div class="card-content space-y-6">
<div class="alert-destructive">
<lucideicon name="alert-circle" class="h-4 w-4" />
<div>
<div class="alert-title">@Localizer["SubTitle"]</div>
<div class="alert-description">@Localizer["Info"]</div>
</div>
</div>
<form asp-action="ResetAuthenticator" method="post">
<button class="btn-destructive" type="submit">
<lucideicon name="rotate-ccw" class="inline-block h-4 w-4 mr-2" />
@Localizer["Reset"]
</button>
</form>
</div>
</div>
</section>
@@ -0,0 +1,49 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@model LiteCharmsSecurity.STS.Identity.ViewModels.Manage.SetPasswordViewModel
@{
ViewData["Title"] = Localizer["Title"];
}
<section class="space-y-6">
<div class="card max-w-2xl">
<div class="card-header">
<h2 class="card-title">@Localizer["SubTitle"]</h2>
</div>
<div class="card-content space-y-6">
@await Html.PartialAsync("_StatusMessage", Model.StatusMessage)
<div class="alert-default">
<lucideicon name="info" class="h-4 w-4" />
<div>
<div class="alert-description">@Localizer["Info"]</div>
</div>
</div>
<form method="post" class="space-y-4">
<div class="form-item">
<label asp-for="NewPassword" class="form-label">
<lucideicon name="key-round" class="inline-block h-4 w-4 mr-1" />
@Localizer["NewPassword"]
</label>
<input asp-for="NewPassword" type="password" class="input" tw-validation />
<span asp-validation-for="NewPassword" class="form-message"></span>
</div>
<div class="form-item">
<label asp-for="ConfirmPassword" class="form-label">
<lucideicon name="lock-keyhole" class="inline-block h-4 w-4 mr-1" />
@Localizer["ConfirmPassword"]
</label>
<input asp-for="ConfirmPassword" type="password" class="input" tw-validation />
<span asp-validation-for="ConfirmPassword" class="form-message"></span>
</div>
<div>
<button type="submit" class="btn-default">
<lucideicon name="save" class="inline-block h-4 w-4 mr-2" />
@Localizer["SetPassword"]
</button>
</div>
</form>
</div>
</div>
</section>
@@ -0,0 +1,34 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@model LiteCharmsSecurity.STS.Identity.ViewModels.Manage.ShowRecoveryCodesViewModel
@{
ViewData["Title"] = Localizer["Title"];
}
<section class="space-y-6 max-w-2xl">
<div class="card">
<div class="card-header">
<h2 class="card-title">@ViewData["Title"]</h2>
</div>
<div class="card-content space-y-6">
<div class="alert-default">
<lucideicon name="info" class="h-4 w-4" />
<div>
<div class="alert-title">@Localizer["SubTitle"]</div>
<div class="alert-description">@Localizer["Info"]</div>
</div>
</div>
<div class="grid gap-3 sm:grid-cols-2 font-mono text-sm">
@for (var row = 0; row < Model.RecoveryCodes.Length; row += 2)
{
<div class="flex items-center justify-between rounded-md border bg-muted/40 px-3 py-2">
<span>@Model.RecoveryCodes[row]</span>
<span>@Model.RecoveryCodes[row + 1]</span>
</div>
}
</div>
</div>
</div>
</section>
@@ -0,0 +1,95 @@
@inject IViewLocalizer Localizer
@using Microsoft.AspNetCore.Mvc.Localization
@model LiteCharmsSecurity.STS.Identity.ViewModels.Manage.TwoFactorAuthenticationViewModel
@{
ViewData["Title"] = Localizer["Title"];
}
<section class="space-y-6">
@if (Model.Is2faEnabled)
{
<div class="card">
<div class="card-header">
<h2 class="card-title">@ViewData["Title"]</h2>
</div>
<div class="card-content space-y-4">
@if (Model.RecoveryCodesLeft == 0)
{
<div class="alert-destructive">
<lucideicon name="alert-circle" class="h-4 w-4" />
<div>
<div class="alert-title">@Localizer["NoCodes"]</div>
<div class="alert-description">@Localizer["YouMust"] <a asp-action="GenerateRecoveryCodes" class="underline underline-offset-4">@Localizer["GenerateNewCodes"]</a> @Localizer["BeforeLogin"]</div>
</div>
</div>
}
else if (Model.RecoveryCodesLeft == 1)
{
<div class="alert-destructive">
<lucideicon name="alert-circle" class="h-4 w-4" />
<div>
<div class="alert-title">@Localizer["OneCode"]</div>
<div class="alert-description">@Localizer["YouCanGenerateCodes"] <a asp-action="GenerateRecoveryCodes" class="underline underline-offset-4">@Localizer["GenerateNewCodes"]</a></div>
</div>
</div>
}
else if (Model.RecoveryCodesLeft <= 3)
{
<div class="alert-default">
<lucideicon name="info" class="h-4 w-4" />
<div>
<div class="alert-title">@Localizer["YouHave"] @Model.RecoveryCodesLeft.ToString() @Localizer["RecoveryCodeLeft"]</div>
<div class="alert-description">@Localizer["YouShould"] <a asp-action="GenerateRecoveryCodes" class="underline underline-offset-4">@Localizer["GenerateNewCodes"]</a></div>
</div>
</div>
}
@if (Model.IsMachineRemembered)
{
<form method="post" asp-controller="Manage" asp-action="ForgetTwoFactorClient">
<button type="submit" class="btn-outline">@Localizer["ForgetBrowser"]</button>
</form>
}
<div class="flex flex-wrap gap-3">
<a asp-action="Disable2faWarning" class="btn-outline">
<lucideicon name="shield-off" class="inline-block h-4 w-4 mr-2" />
@Localizer["Disable2FA"]
</a>
<a asp-action="GenerateRecoveryCodesWarning" class="btn-destructive">
<lucideicon name="refresh-cw" class="inline-block h-4 w-4 mr-2" />
@Localizer["ResetCodes"]
</a>
</div>
</div>
</div>
}
<div class="card">
<div class="card-header">
<h3 class="card-title">@Localizer["AuthenticatorApp"]</h3>
</div>
<div class="card-content">
@if (!Model.HasAuthenticator)
{
<a id="enable-authenticator" asp-action="EnableAuthenticator" class="btn-default">
<lucideicon name="smartphone" class="inline-block h-4 w-4 mr-2" />
@Localizer["AddAuthenticator"]
</a>
}
else
{
<div class="flex flex-wrap gap-3">
<a id="enable-authenticator" asp-action="EnableAuthenticator" class="btn-default">
<lucideicon name="settings" class="inline-block h-4 w-4 mr-2" />
@Localizer["SetupAuthenticator"]
</a>
<a id="reset-authenticator" asp-action="ResetAuthenticatorWarning" class="btn-destructive">
<lucideicon name="rotate-ccw" class="inline-block h-4 w-4 mr-2" />
@Localizer["ResetAuthenticator"]
</a>
</div>
}
</div>
</div>
</section>
@@ -0,0 +1,13 @@
@model string
@if (!String.IsNullOrEmpty(Model))
{
var statusMessageClass = Model.StartsWith("Error") ? "alert-destructive" : "alert-default";
var iconName = Model.StartsWith("Error") ? "alert-circle" : "check";
<div class="@statusMessageClass mb-4">
<lucideicon name="@iconName" class="h-4 w-4" />
<div>
<div class="alert-description">@Model</div>
</div>
</div>
}