1
0
mirror of https://github.com/bitwarden/mobile.git synced 2024-12-27 17:08:00 +01:00

[SG-705] Popup when a request for authentication comes in on a logged-in account that is not active (#2135)

* [SG-705] Added pop up to perform account switching if the user receives a login request from another account.

* [SG-705] missing resource designer

* [SG-705] Fixed wrong key for state service variable.

* [SG-705] Fix formatting of account switch alert.

* [SG-705] dotnet format run

* [SG-705] Removed async

* [SG-705] Refactor on App
This commit is contained in:
André Bispo 2022-10-18 17:21:45 +01:00 committed by GitHub
parent d18efdea73
commit eefc9bd239
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 242 additions and 207 deletions

View File

@ -11,6 +11,7 @@ using Bit.Core;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Models.Response;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Xamarin.Forms; using Xamarin.Forms;
@ -168,13 +169,17 @@ namespace Bit.App
return; return;
} }
var notification = await _stateService.GetPasswordlessLoginNotificationAsync(); var notification = await _stateService.GetPasswordlessLoginNotificationAsync();
if (notification == null) if (notification == null)
{ {
return; return;
} }
if (await CheckShouldSwitchActiveUserAsync(notification))
{
return;
}
// Delay to wait for the vault page to appear // Delay to wait for the vault page to appear
await Task.Delay(2000); await Task.Delay(2000);
var loginRequestData = await _authService.GetPasswordlessLoginRequestByIdAsync(notification.Id); var loginRequestData = await _authService.GetPasswordlessLoginRequestByIdAsync(notification.Id);
@ -197,6 +202,27 @@ namespace Bit.App
} }
} }
private async Task<bool> CheckShouldSwitchActiveUserAsync(PasswordlessRequestNotification notification)
{
var activeUserId = await _stateService.GetActiveUserIdAsync();
if (notification.UserId == activeUserId)
{
return false;
}
var notificationUserEmail = await _stateService.GetEmailAsync(notification.UserId);
await Device.InvokeOnMainThreadAsync(async () =>
{
var result = await _deviceActionService.DisplayAlertAsync(AppResources.LogInRequested, string.Format(AppResources.LoginAttemptFromXDoYouWantToSwitchToThisAccount, notificationUserEmail), AppResources.Cancel, AppResources.Ok);
if (result == AppResources.Ok)
{
await _stateService.SetActiveUserAsync(notification.UserId);
_messagingService.Send(AccountsManagerMessageCommands.SWITCHED_ACCOUNT);
}
});
return true;
}
public AppOptions Options { get; private set; } public AppOptions Options { get; private set; }
protected async override void OnStart() protected async override void OnStart()

File diff suppressed because it is too large Load Diff

View File

@ -2464,4 +2464,9 @@ select Add TOTP to store the key safely</value>
<data name="LoginRequestHasAlreadyExpired" xml:space="preserve"> <data name="LoginRequestHasAlreadyExpired" xml:space="preserve">
<value>Login request has already expired.</value> <value>Login request has already expired.</value>
</data> </data>
<data name="LoginAttemptFromXDoYouWantToSwitchToThisAccount" xml:space="preserve">
<value>Login attempt from:
{0}
Do you want to switch to this account?</value>
</data>
</root> </root>

View File

@ -146,7 +146,7 @@ namespace Bit.App.Services
return; return;
} }
await _stateService.Value.SetPasswordlessLoginNotificationAsync(passwordlessLoginMessage, passwordlessLoginMessage?.UserId); await _stateService.Value.SetPasswordlessLoginNotificationAsync(passwordlessLoginMessage);
var userEmail = await _stateService.Value.GetEmailAsync(passwordlessLoginMessage?.UserId); var userEmail = await _stateService.Value.GetEmailAsync(passwordlessLoginMessage?.UserId);
var notificationData = new PasswordlessNotificationData() var notificationData = new PasswordlessNotificationData()
@ -247,14 +247,10 @@ namespace Bit.App.Services
{ {
if (data is PasswordlessNotificationData passwordlessNotificationData) if (data is PasswordlessNotificationData passwordlessNotificationData)
{ {
var notificationUserId = await _stateService.Value.GetUserIdAsync(passwordlessNotificationData.UserEmail); var savedNotification = await _stateService.Value.GetPasswordlessLoginNotificationAsync();
if (notificationUserId != null) if (savedNotification != null)
{ {
var savedNotification = await _stateService.Value.GetPasswordlessLoginNotificationAsync(notificationUserId); await _stateService.Value.SetPasswordlessLoginNotificationAsync(null);
if (savedNotification != null)
{
await _stateService.Value.SetPasswordlessLoginNotificationAsync(null, notificationUserId);
}
} }
} }
} }

View File

@ -154,8 +154,8 @@ namespace Bit.Core.Abstractions
Task SaveExtensionActiveUserIdToStorageAsync(string userId); Task SaveExtensionActiveUserIdToStorageAsync(string userId);
Task<bool> GetApprovePasswordlessLoginsAsync(string userId = null); Task<bool> GetApprovePasswordlessLoginsAsync(string userId = null);
Task SetApprovePasswordlessLoginsAsync(bool? value, string userId = null); Task SetApprovePasswordlessLoginsAsync(bool? value, string userId = null);
Task<PasswordlessRequestNotification> GetPasswordlessLoginNotificationAsync(string userId = null); Task<PasswordlessRequestNotification> GetPasswordlessLoginNotificationAsync();
Task SetPasswordlessLoginNotificationAsync(PasswordlessRequestNotification value, string userId = null); Task SetPasswordlessLoginNotificationAsync(PasswordlessRequestNotification value);
Task<UsernameGenerationOptions> GetUsernameGenerationOptionsAsync(string userId = null); Task<UsernameGenerationOptions> GetUsernameGenerationOptionsAsync(string userId = null);
Task SetUsernameGenerationOptionsAsync(UsernameGenerationOptions value, string userId = null); Task SetUsernameGenerationOptionsAsync(UsernameGenerationOptions value, string userId = null);
} }

View File

@ -30,6 +30,7 @@
public static string EventCollectionKey = "eventCollection"; public static string EventCollectionKey = "eventCollection";
public static string RememberedEmailKey = "rememberedEmail"; public static string RememberedEmailKey = "rememberedEmail";
public static string RememberedOrgIdentifierKey = "rememberedOrgIdentifier"; public static string RememberedOrgIdentifierKey = "rememberedOrgIdentifier";
public static string PasswordlessLoginNotificationKey = "passwordlessLoginNotificationKey";
public const string PasswordlessNotificationId = "26072022"; public const string PasswordlessNotificationId = "26072022";
public const string AndroidNotificationChannelId = "general_notification_channel"; public const string AndroidNotificationChannelId = "general_notification_channel";
public const string iOSNotificationCategoryId = "dismissableCategory"; public const string iOSNotificationCategoryId = "dismissableCategory";
@ -93,7 +94,6 @@
public static string LastSyncKey(string userId) => $"lastSync_{userId}"; public static string LastSyncKey(string userId) => $"lastSync_{userId}";
public static string BiometricUnlockKey(string userId) => $"biometricUnlock_{userId}"; public static string BiometricUnlockKey(string userId) => $"biometricUnlock_{userId}";
public static string ApprovePasswordlessLoginsKey(string userId) => $"approvePasswordlessLogins_{userId}"; public static string ApprovePasswordlessLoginsKey(string userId) => $"approvePasswordlessLogins_{userId}";
public static string PasswordlessLoginNofiticationKey(string userId) => $"passwordlessLoginNofitication_{userId}";
public static string UsernameGenOptionsKey(string userId) => $"usernameGenerationOptions_{userId}"; public static string UsernameGenOptionsKey(string userId) => $"usernameGenerationOptions_{userId}";
} }
} }

View File

@ -1277,20 +1277,18 @@ namespace Bit.Core.Services
await SetValueAsync(key, value, reconciledOptions); await SetValueAsync(key, value, reconciledOptions);
} }
public async Task<PasswordlessRequestNotification> GetPasswordlessLoginNotificationAsync(string userId = null) public async Task<PasswordlessRequestNotification> GetPasswordlessLoginNotificationAsync()
{ {
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, var options = await GetDefaultStorageOptionsAsync();
await GetDefaultStorageOptionsAsync()); var key = Constants.PasswordlessLoginNotificationKey;
var key = Constants.PasswordlessLoginNofiticationKey(reconciledOptions.UserId); return await GetValueAsync<PasswordlessRequestNotification>(key, options);
return await GetValueAsync<PasswordlessRequestNotification>(key, reconciledOptions);
} }
public async Task SetPasswordlessLoginNotificationAsync(PasswordlessRequestNotification value, string userId = null) public async Task SetPasswordlessLoginNotificationAsync(PasswordlessRequestNotification value)
{ {
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, var options = await GetDefaultStorageOptionsAsync();
await GetDefaultStorageOptionsAsync()); var key = Constants.PasswordlessLoginNotificationKey;
var key = Constants.PasswordlessLoginNofiticationKey(reconciledOptions.UserId); await SetValueAsync(key, value, options);
await SetValueAsync(key, value, reconciledOptions);
} }
// Helpers // Helpers