Files
Moonlight/Moonlight/Shared/Views/Profile/Security.razor
2023-06-26 00:06:44 +02:00

233 lines
8.9 KiB
Plaintext

@page "/profile/security"
@using Moonlight.Shared.Components.Navigations
@using QRCoder
@using Moonlight.App.Services
@using Moonlight.App.Services.Interop
@using Moonlight.App.Database.Entities
@using Mappy.Net
@using Moonlight.App.Models.Forms
@using Moonlight.App.Repositories
@inject TotpService TotpService
@inject UserService UserService
@inject NavigationManager NavigationManager
@inject ModalService ModalService
@inject Repository<User> UserRepository
@inject SmartTranslateService SmartTranslateService
<ProfileNavigation Index="2"/>
<div class="row">
<div class="col-12 col-md-6 p-3">
<div class="card">
<div class="card-header">
<div class="card-title">
<TL>Two factor authentication</TL>
</div>
</div>
<div class="card-body fs-6">
<p>
<TL>2fa adds another layer of security to your account. You have to enter a 6 digit code in order to login.</TL>
</p>
<div class="d-flex justify-content-center">
@if (User.TotpEnabled)
{
<WButton Text="@(SmartTranslateService.Translate("Disable"))"
WorkingText=""
CssClasses="btn-danger"
OnClick="DisableTwoFactor">
</WButton>
}
else
{
<WButton Text="@(SmartTranslateService.Translate("Enable"))"
WorkingText=""
CssClasses="btn-primary"
OnClick="StartTwoFactorWizard">
</WButton>
}
</div>
</div>
</div>
</div>
<div class="col-12 col-md-6 p-3">
<div class="card">
<div class="card-header">
<div class="card-title">
<TL>Password</TL>
</div>
</div>
<div class="card-body fs-6">
<div class="d-flex justify-content-center">
<div class="input-group">
<input @bind="Password" class="form-control" type="password"/>
<WButton Text="@(SmartTranslateService.Translate("Enable"))"
WorkingText=""
CssClasses="btn-primary"
OnClick="ChangePassword">
</WButton>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-6 p-3">
<div class="card">
<div class="card-header">
<div class="card-title">
<TL>Preferences</TL>
</div>
</div>
<div class="card-body fs-6">
<div class="form-check form-switch">
<input @bind="UserModel.StreamerMode" class="form-check-input" type="checkbox" role="switch" id="streamerModeSwitch">
<label class="form-check-label" for="streamerModeSwitch">
<TL>Streamer mode</TL>
</label>
</div>
</div>
<div class="card-footer">
<div class="text-end">
<WButton Text="@(SmartTranslateService.Translate("Save"))"
WorkingText=""
CssClasses="btn-primary"
OnClick="SavePreferences">
</WButton>
</div>
</div>
</div>
</div>
</div>
@* Modals *@
<div class="modal fade" id="2fa" tabindex="-1" style="display: none" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">
<TL>Activate 2fa</TL>
</h2>
</div>
<div class="modal-body fs-6">
@if (!User.TotpEnabled)
{
if (string.IsNullOrEmpty(User.TotpSecret))
{
<p>
<TL>Make sure you have installed one of the following apps on your smartphone and press continue</TL>
</p>
<a href="https://support.google.com/accounts/answer/1066447?hl=en" target="_blank">Google Authenticator</a>
<br/>
<a href="https://www.microsoft.com/en-us/account/authenticator" target="_blank">Microsoft Authenticator</a>
<br/>
<a href="https://authy.com/download/" target="_blank">Authy</a>
<br/>
<a href="https://support.1password.com/one-time-passwords/" target="_blank">1Password</a>
<br/>
<div class="d-flex justify-content-center">
<WButton Text="@(SmartTranslateService.Translate("Continue"))"
WorkingText="@(SmartTranslateService.Translate("Preparing"))"
CssClasses="btn-primary"
OnClick="GenerateTwoFactorToken">
</WButton>
</div>
}
else
{
<p>
<TL>Scan the qr code and enter the code generated by the app you have scanned it in</TL>
</p>
<div class="mt-3 text-center">
@{
QRCodeGenerator qrGenerator = new QRCodeGenerator();
var qrCodeData = qrGenerator.CreateQrCode
(
$"otpauth://totp/{Uri.EscapeDataString(User.Email)}?secret={User.TotpSecret}&issuer={Uri.EscapeDataString("Moonlight")}",
QRCodeGenerator.ECCLevel.Q
);
PngByteQRCode qrCode = new PngByteQRCode(qrCodeData);
byte[] qrCodeAsPngByteArr = qrCode.GetGraphic(20);
var base64 = Convert.ToBase64String(qrCodeAsPngByteArr);
}
<img src="data:image/png;base64,@(base64)" alt="" class="mw-200px mt-2">
</div>
<div class="mt-3 d-flex justify-content-center">
<div class="input-group">
<input type="text"
@bind="TwoFactorCode"
placeholder="@(SmartTranslateService.Translate("Enter your 2fa code here"))"
class="form-control"/>
<WButton Text="@(SmartTranslateService.Translate("Enable"))"
WorkingText="@(SmartTranslateService.Translate("Processing"))"
CssClasses="btn-primary"
OnClick="EnableTwoFactor">
</WButton>
</div>
</div>
}
}
</div>
</div>
</div>
</div>
@code
{
[CascadingParameter]
public User User { get; set; }
private string TwoFactorCode = "";
private string Password = "";
private UserPreferencesDataModel UserModel;
protected override void OnParametersSet()
{
UserModel = Mapper.Map<UserPreferencesDataModel>(User);
}
private async Task StartTwoFactorWizard()
{
await ModalService.Show("2fa");
}
private async Task GenerateTwoFactorToken()
{
await TotpService.GenerateSecret();
await InvokeAsync(StateHasChanged);
}
private async Task EnableTwoFactor()
{
await ModalService.Hide("2fa");
await TotpService.Enable(TwoFactorCode);
await InvokeAsync(StateHasChanged);
NavigationManager.NavigateTo(NavigationManager.Uri, true);
}
private async Task DisableTwoFactor()
{
await TotpService.Disable();
await InvokeAsync(StateHasChanged);
}
private async Task ChangePassword()
{
await UserService.ChangePassword(User, Password);
NavigationManager.NavigateTo(NavigationManager.Uri, true);
}
private async Task SavePreferences()
{
User = Mapper.Map(User, UserModel);
UserRepository.Update(User);
await InvokeAsync(StateHasChanged);
NavigationManager.NavigateTo(NavigationManager.Uri, true);
}
}