@@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.App.Models.Misc;
|
namespace Moonlight.App.Models.Forms;
|
||||||
|
|
||||||
public class LoginDataModel
|
public class LoginDataModel
|
||||||
{
|
{
|
||||||
9
Moonlight/App/Models/Forms/LoginTotpDataModel.cs
Normal file
9
Moonlight/App/Models/Forms/LoginTotpDataModel.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms;
|
||||||
|
|
||||||
|
public class LoginTotpDataModel
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "You need to enter a 2fa code")]
|
||||||
|
public string Code { get; set; } = "";
|
||||||
|
}
|
||||||
@@ -13,6 +13,8 @@
|
|||||||
@using Moonlight.App.Models.Misc
|
@using Moonlight.App.Models.Misc
|
||||||
@using Moonlight.App.Services.OAuth2
|
@using Moonlight.App.Services.OAuth2
|
||||||
@using Moonlight.App.Services.Sessions
|
@using Moonlight.App.Services.Sessions
|
||||||
|
@using System.ComponentModel.DataAnnotations
|
||||||
|
@using Moonlight.App.Models.Forms
|
||||||
|
|
||||||
@inject AlertService AlertService
|
@inject AlertService AlertService
|
||||||
@inject UserService UserService
|
@inject UserService UserService
|
||||||
@@ -26,9 +28,9 @@
|
|||||||
<div class="card rounded-3 w-md-550px">
|
<div class="card rounded-3 w-md-550px">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex flex-center flex-column-fluid pb-15 pb-lg-20">
|
<div class="d-flex flex-center flex-column-fluid pb-15 pb-lg-20">
|
||||||
<SmartForm Model="User" OnValidSubmit="DoLogin">
|
@if (!TotpRequired)
|
||||||
@if (!TotpRequired)
|
{
|
||||||
{
|
<SmartForm Model="LoginData" OnValidSubmit="DoLogin">
|
||||||
<div class="text-center mt-3 mb-11">
|
<div class="text-center mt-3 mb-11">
|
||||||
<h1 class="text-dark fw-bolder mb-3">
|
<h1 class="text-dark fw-bolder mb-3">
|
||||||
<TL>Sign In</TL>
|
<TL>Sign In</TL>
|
||||||
@@ -64,11 +66,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3 mb-3">
|
<div class="mt-3 mb-3">
|
||||||
<InputText @bind-Value="User.Email" type="email" placeholder="@(SmartTranslateService.Translate("Email"))" class="form-control bg-transparent"/>
|
<InputText @bind-Value="LoginData.Email" type="email" placeholder="@(SmartTranslateService.Translate("Email"))" class="form-control bg-transparent"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<InputText @bind-Value="User.Password" type="password" placeholder="@(SmartTranslateService.Translate("Password"))" class="form-control bg-transparent"/>
|
<InputText @bind-Value="LoginData.Password" type="password" placeholder="@(SmartTranslateService.Translate("Password"))" class="form-control bg-transparent"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex flex-stack flex-wrap gap-3 fs-base fw-semibold mb-8">
|
<div class="d-flex flex-stack flex-wrap gap-3 fs-base fw-semibold mb-8">
|
||||||
@@ -84,29 +86,29 @@
|
|||||||
<TL>Sign-in</TL>
|
<TL>Sign-in</TL>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
else
|
<div class="text-gray-500 text-center fw-semibold fs-6">
|
||||||
{
|
<TL>Not registered yet?</TL>
|
||||||
|
|
||||||
|
<a href="/register" class="link-primary">
|
||||||
|
<TL>Sign up</TL>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</SmartForm>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<SmartForm Model="TotpData" OnValidSubmit="DoLogin">
|
||||||
<div class="fv-row mb-8 fv-plugins-icon-container">
|
<div class="fv-row mb-8 fv-plugins-icon-container">
|
||||||
<input type="number" class="form-control bg-transparent">
|
<InputText @bind-Value="TotpData.Code" type="number" class="form-control bg-transparent"></InputText>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-grid mb-10">
|
<div class="d-grid mb-10">
|
||||||
<WButton Text="@(SmartTranslateService.Translate("Sign-in"))"
|
<button type="submit" class="btn btn-primary">
|
||||||
WorkingText="@(SmartTranslateService.Translate("Working"))"
|
<TL>Sign-in</TL>
|
||||||
CssClasses="btn-primary"
|
</button>
|
||||||
OnClick="DoLogin">
|
|
||||||
</WButton>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
</SmartForm>
|
||||||
|
}
|
||||||
<div class="text-gray-500 text-center fw-semibold fs-6">
|
|
||||||
<TL>Not registered yet?</TL>
|
|
||||||
|
|
||||||
<a href="/register" class="link-primary">
|
|
||||||
<TL>Sign up</TL>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</SmartForm>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -114,22 +116,39 @@
|
|||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private LoginDataModel User = new();
|
private LoginDataModel LoginData = new();
|
||||||
|
private LoginTotpDataModel TotpData = new();
|
||||||
|
|
||||||
private bool TotpRequired = false;
|
private bool TotpRequired = false;
|
||||||
private string TotpCode = "";
|
|
||||||
|
|
||||||
private async Task DoLogin()
|
private async Task DoLogin()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
User.Email = User.Email.ToLower().Trim();
|
LoginData.Email = LoginData.Email.ToLower().Trim();
|
||||||
|
|
||||||
TotpRequired = await UserService.CheckTotp(User.Email, User.Password);
|
if (string.IsNullOrEmpty(TotpData.Code))
|
||||||
|
|
||||||
if (!TotpRequired)
|
|
||||||
{
|
{
|
||||||
var token = await UserService.Login(User.Email, User.Password);
|
TotpRequired = await UserService.CheckTotp(LoginData.Email, LoginData.Password);
|
||||||
|
|
||||||
|
if (!TotpRequired)
|
||||||
|
{
|
||||||
|
var token = await UserService.Login(LoginData.Email, LoginData.Password);
|
||||||
|
await CookieService.SetValue("token", token, 10);
|
||||||
|
|
||||||
|
if (NavigationManager.Uri.EndsWith("login"))
|
||||||
|
NavigationManager.NavigateTo("/", true);
|
||||||
|
else
|
||||||
|
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var token = await UserService.Login(LoginData.Email, LoginData.Password, TotpData.Code);
|
||||||
await CookieService.SetValue("token", token, 10);
|
await CookieService.SetValue("token", token, 10);
|
||||||
|
|
||||||
if (NavigationManager.Uri.EndsWith("login"))
|
if (NavigationManager.Uri.EndsWith("login"))
|
||||||
@@ -137,13 +156,14 @@
|
|||||||
else
|
else
|
||||||
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
await InvokeAsync(StateHasChanged);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (DisplayException e)
|
catch (DisplayException e)
|
||||||
{
|
{
|
||||||
|
// Reset state
|
||||||
|
LoginData = new();
|
||||||
|
TotpData = new();
|
||||||
|
TotpRequired = false;
|
||||||
|
|
||||||
await AlertService.Error(
|
await AlertService.Error(
|
||||||
SmartTranslateService.Translate("Error"),
|
SmartTranslateService.Translate("Error"),
|
||||||
SmartTranslateService.Translate(e.Message)
|
SmartTranslateService.Translate(e.Message)
|
||||||
@@ -151,6 +171,11 @@
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
// Reset state
|
||||||
|
LoginData = new();
|
||||||
|
TotpData = new();
|
||||||
|
TotpRequired = false;
|
||||||
|
|
||||||
await AlertService.Error(
|
await AlertService.Error(
|
||||||
SmartTranslateService.Translate("Error"),
|
SmartTranslateService.Translate("Error"),
|
||||||
SmartTranslateService.Translate("An error occured while logging you in")
|
SmartTranslateService.Translate("An error occured while logging you in")
|
||||||
|
|||||||
@@ -176,12 +176,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-body scroll-y pt-10 pb-15 px-lg-17">
|
<div class="modal-body scroll-y pt-10 pb-15 px-lg-17">
|
||||||
<div class="text-gray-500 fw-semibold fs-6 mb-10">
|
<div class="text-gray-500 fw-semibold fs-6 mb-10">
|
||||||
To finish activating, enter the current TOTP code <br/>
|
<div class="alert alert-primary d-flex align-items-center p-5 mb-10">
|
||||||
<input type="text" class="form-control form-control-lg form-control-solid" @bind="currentTotp"/>
|
<i class="bx bx-info-circle fs-2hx text-primary me-4">
|
||||||
|
<span class="path1"></span><span class="path2"></span>
|
||||||
|
</i>
|
||||||
|
<div class="d-flex flex-column">
|
||||||
|
<h4 class="mb-1 text-primary">
|
||||||
|
<TL>2fa Code requiered</TL>
|
||||||
|
</h4>
|
||||||
|
<span>In order to finish the activation of 2fa, you need to enter the code your 2fa app shows you.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-control form-control-lg form-control-solid" placeholder="@SmartTranslateService.Translate("2fa Code")" @bind="currentTotp"/>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<WButton CssClasses="btn btn-primary px-6 align-self-center text-nowrap float end" WorkingText="@SmartTranslateService.Translate("Saving")" Text="@SmartTranslateService.Translate("Save")" OnClick="CheckAndSaveTotp">
|
<WButton CssClasses="btn btn-primary px-6 align-self-center text-nowrap float-end" WorkingText="@SmartTranslateService.Translate("Saving")" Text="@SmartTranslateService.Translate("Finish")" OnClick="CheckAndSaveTotp">
|
||||||
</WButton>
|
</WButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -239,9 +249,10 @@
|
|||||||
if (await TotpService.Verify(TotpSecret, currentTotp))
|
if (await TotpService.Verify(TotpSecret, currentTotp))
|
||||||
{
|
{
|
||||||
await TotpService.EnforceTotpLogin();
|
await TotpService.EnforceTotpLogin();
|
||||||
TotpEnabled = await TotpService.GetEnabled();
|
TotpEnabled = true;
|
||||||
TotpSecret = await TotpService.GetSecret();
|
TotpSecret = await TotpService.GetSecret();
|
||||||
await ToastService.Success("Successfully enabled 2fa!");
|
await ToastService.Success("Successfully enabled 2fa!");
|
||||||
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user