diff --git a/src/AliasVault.Admin/Auth/Pages/LoginWithRecoveryCode.razor b/src/AliasVault.Admin/Auth/Pages/LoginWithRecoveryCode.razor
index 60cd065ee..a47b33138 100644
--- a/src/AliasVault.Admin/Auth/Pages/LoginWithRecoveryCode.razor
+++ b/src/AliasVault.Admin/Auth/Pages/LoginWithRecoveryCode.razor
@@ -9,8 +9,8 @@
- You have requested to log in with a recovery code. This login will not be remembered until you provide - an authenticator app code at log in or disable 2FA and log in again. + You have requested to log in with a recovery code. A recovery code is a one-time code that can be used to log in to your account. + Note that if you don't manually disable 2FA after login, you will be asked for an authenticator code again at the next login.
Scan the QR Code or enter this key @sharedKey into your two factor authenticator app. Spaces and casing do not matter.
- +Scan the QR Code or enter this key @SharedKey into your two factor authenticator app. Spaces and casing do not matter.
+
@@ -67,9 +67,9 @@ else
@code {
private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
- private string? sharedKey;
- private string? authenticatorUri;
- private IEnumerable
Don't have access to your authenticator device? You can - log in with a recovery code. + . +
+} +else if (ShowLoginWithRecoveryCodeStep) +{ ++ You have requested to log in with a recovery code. A recovery code is a one-time code that can be used to log in to your account. + Note that if you don't manually disable 2FA after login, you will be asked for an authenticator code again at the next login. +
++ Regained access to your authenticator device? You can + instead.
} else @@ -85,9 +113,11 @@ else @code { private readonly LoginModel LoginModel = new(); private readonly LoginModel2Fa LoginModel2Fa = new(); + private readonly LoginModelRecoveryCode LoginModelRecoveryCode = new(); private FullScreenLoadingIndicator LoadingIndicator = new(); private ServerValidationErrors ServerValidationErrors = new(); - private bool ShowTwoFactorAuthStep = false; + private bool ShowTwoFactorAuthStep; + private bool ShowLoginWithRecoveryCodeStep; private SrpEphemeral ClientEphemeral = new(); private SrpSession ClientSession = new(); @@ -104,6 +134,20 @@ else } } + private void LoginWithAuthenticator() + { + ShowLoginWithRecoveryCodeStep = false; + ShowTwoFactorAuthStep = true; + StateHasChanged(); + } + + private void LoginWithRecoveryCode() + { + ShowLoginWithRecoveryCodeStep = true; + ShowTwoFactorAuthStep = false; + StateHasChanged(); + } + private async Task HandleLogin() { LoadingIndicator.Show(); @@ -136,6 +180,61 @@ else } } + private async Task HandleRecoveryCode() + { + LoadingIndicator.Show(); + ServerValidationErrors.Clear(); + + try + { + // Sanitize username + var username = LoginModel.Username.ToLowerInvariant().Trim(); + + // Validate 2-factor auth code auth and login + var result = await Http.PostAsJsonAsync("api/v1/Auth/validate-recovery-code", new ValidateLoginRequestRecoveryCode(username, ClientEphemeral.Public, ClientSession.Proof, LoginModelRecoveryCode.RecoveryCode)); + var responseContent = await result.Content.ReadAsStringAsync(); + + if (!result.IsSuccessStatusCode) + { + foreach (var error in ParseResponse(responseContent)) + { + ServerValidationErrors.AddError(error); + return; + } + } + + var validateLoginResponse = JsonSerializer.Deserialize+ Store these recovery codes in a safe place. +
++ If you lose your device and don't have the recovery codes you will lose access to your account. These + codes are only shown once! +
+@recoveryCode
+ Enable two-factor authentication to increase the security of your vaults.
+Enable two-factor authentication to increase the security of your vaults.
-