[SG-386] iOS Update user state when coming from background (#1952)

* SG-386 Updated active user when coming from background to the iOS app and the extension had switched users

* Added iOSExtensionActiveUserIdKey to preference keys

* Reorder iOS preference keys
This commit is contained in:
Federico Maccaroni 2022-06-15 13:44:25 -03:00 committed by GitHub
parent c53a85cd50
commit 3aef86bd34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 79 additions and 27 deletions

View file

@ -130,7 +130,7 @@ namespace Bit.Droid
var secureStorageService = new SecureStorageService(); var secureStorageService = new SecureStorageService();
var cryptoPrimitiveService = new CryptoPrimitiveService(); var cryptoPrimitiveService = new CryptoPrimitiveService();
var mobileStorageService = new MobileStorageService(preferencesStorage, liteDbStorage); var mobileStorageService = new MobileStorageService(preferencesStorage, liteDbStorage);
var stateService = new StateService(mobileStorageService, secureStorageService); var stateService = new StateService(mobileStorageService, secureStorageService, messagingService);
var stateMigrationService = var stateMigrationService =
new StateMigrationService(liteDbStorage, preferencesStorage, secureStorageService); new StateMigrationService(liteDbStorage, preferencesStorage, secureStorageService);
var clipboardService = new ClipboardService(stateService); var clipboardService = new ClipboardService(stateService);

View file

@ -202,6 +202,7 @@ namespace Bit.App
private async Task ResumedAsync() private async Task ResumedAsync()
{ {
await _stateService.CheckExtensionActiveUserAndSwitchIfNeededAsync();
await _vaultTimeoutService.CheckVaultTimeoutAsync(); await _vaultTimeoutService.CheckVaultTimeoutAsync();
_messagingService.Send("startEventTimer"); _messagingService.Send("startEventTimer");
await UpdateThemeAsync(); await UpdateThemeAsync();

View file

@ -45,23 +45,28 @@ namespace Bit.App.Controls
public ICommand LongPressAccountCommand { get; } public ICommand LongPressAccountCommand { get; }
public bool FromIOSExtension { get; set; }
private async Task SelectAccountAsync(AccountViewCellViewModel item) private async Task SelectAccountAsync(AccountViewCellViewModel item)
{ {
if (item.AccountView.IsAccount) if (!item.AccountView.IsAccount)
{ {
if (!item.AccountView.IsActive) _messagingService.Send(AccountsManagerMessageCommands.ADD_ACCOUNT);
return;
}
if (!item.AccountView.IsActive)
{
await _stateService.SetActiveUserAsync(item.AccountView.UserId);
_messagingService.Send(AccountsManagerMessageCommands.SWITCHED_ACCOUNT);
if (FromIOSExtension)
{ {
await _stateService.SetActiveUserAsync(item.AccountView.UserId); await _stateService.SaveExtensionActiveUserIdToStorageAsync(item.AccountView.UserId);
_messagingService.Send("switchedAccount");
}
else if (AllowActiveAccountSelection)
{
_messagingService.Send("switchedAccount");
} }
} }
else else if (AllowActiveAccountSelection)
{ {
_messagingService.Send("addAccount"); _messagingService.Send(AccountsManagerMessageCommands.SWITCHED_ACCOUNT);
} }
} }

View file

@ -25,6 +25,7 @@ namespace Bit.App.Services
Constants.LastBuildKey, Constants.LastBuildKey,
Constants.ClearCiphersCacheKey, Constants.ClearCiphersCacheKey,
Constants.BiometricIntegrityKey, Constants.BiometricIntegrityKey,
Constants.iOSExtensionActiveUserIdKey,
Constants.iOSAutoFillClearCiphersCacheKey, Constants.iOSAutoFillClearCiphersCacheKey,
Constants.iOSAutoFillBiometricIntegrityKey, Constants.iOSAutoFillBiometricIntegrityKey,
Constants.iOSExtensionClearCiphersCacheKey, Constants.iOSExtensionClearCiphersCacheKey,
@ -32,7 +33,7 @@ namespace Bit.App.Services
Constants.iOSShareExtensionClearCiphersCacheKey, Constants.iOSShareExtensionClearCiphersCacheKey,
Constants.iOSShareExtensionBiometricIntegrityKey, Constants.iOSShareExtensionBiometricIntegrityKey,
Constants.RememberedEmailKey, Constants.RememberedEmailKey,
Constants.RememberedOrgIdentifierKey, Constants.RememberedOrgIdentifierKey
}; };
public MobileStorageService( public MobileStorageService(

View file

@ -6,21 +6,11 @@ using Bit.App.Resources;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Domain; using Bit.Core.Models.Domain;
using Bit.Core.Utilities;
using Xamarin.Forms; using Xamarin.Forms;
namespace Bit.App.Utilities.AccountManagement namespace Bit.App.Utilities.AccountManagement
{ {
public static class AccountsManagerMessageCommands
{
public const string LOCKED = "locked";
public const string LOCK_VAULT = "lockVault";
public const string LOGOUT = "logout";
public const string LOGGED_OUT = "loggedOut";
public const string ADD_ACCOUNT = "addAccount";
public const string ACCOUNT_ADDED = "accountAdded";
public const string SWITCHED_ACCOUNT = "switchedAccount";
}
public class AccountsManager : IAccountsManager public class AccountsManager : IAccountsManager
{ {
private readonly IBroadcasterService _broadcasterService; private readonly IBroadcasterService _broadcasterService;
@ -209,7 +199,7 @@ namespace Bit.App.Utilities.AccountManagement
private async Task SwitchedAccountAsync() private async Task SwitchedAccountAsync()
{ {
await AppHelpers.OnAccountSwitchAsync(); await AppHelpers.OnAccountSwitchAsync();
Device.BeginInvokeOnMainThread(async () => await Device.InvokeOnMainThreadAsync(async () =>
{ {
if (await _vaultTimeoutService.ShouldTimeoutAsync()) if (await _vaultTimeoutService.ShouldTimeoutAsync())
{ {

View file

@ -14,6 +14,7 @@ namespace Bit.Core.Abstractions
Task<string> GetActiveUserIdAsync(); Task<string> GetActiveUserIdAsync();
Task<bool> IsActiveAccountAsync(string userId = null); Task<bool> IsActiveAccountAsync(string userId = null);
Task SetActiveUserAsync(string userId); Task SetActiveUserAsync(string userId);
Task CheckExtensionActiveUserAndSwitchIfNeededAsync();
Task<bool> IsAuthenticatedAsync(string userId = null); Task<bool> IsAuthenticatedAsync(string userId = null);
Task<string> GetUserIdAsync(string email); Task<string> GetUserIdAsync(string email);
Task RefreshAccountViewsAsync(bool allowAddAccountRow); Task RefreshAccountViewsAsync(bool allowAddAccountRow);
@ -145,5 +146,6 @@ namespace Bit.Core.Abstractions
Task SetRefreshTokenAsync(string value, bool skipTokenStorage, string userId = null); Task SetRefreshTokenAsync(string value, bool skipTokenStorage, string userId = null);
Task<string> GetTwoFactorTokenAsync(string email = null); Task<string> GetTwoFactorTokenAsync(string email = null);
Task SetTwoFactorTokenAsync(string value, string email = null); Task SetTwoFactorTokenAsync(string value, string email = null);
Task SaveExtensionActiveUserIdToStorageAsync(string userId);
} }
} }

View file

@ -25,6 +25,7 @@
public static string iOSExtensionBiometricIntegrityKey = "iOSExtensionBiometricIntegrityState"; public static string iOSExtensionBiometricIntegrityKey = "iOSExtensionBiometricIntegrityState";
public static string iOSShareExtensionClearCiphersCacheKey = "iOSShareExtensionClearCiphersCache"; public static string iOSShareExtensionClearCiphersCacheKey = "iOSShareExtensionClearCiphersCache";
public static string iOSShareExtensionBiometricIntegrityKey = "iOSShareExtensionBiometricIntegrityState"; public static string iOSShareExtensionBiometricIntegrityKey = "iOSShareExtensionBiometricIntegrityState";
public static string iOSExtensionActiveUserIdKey = "iOSExtensionActiveUserId";
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";

View file

@ -15,16 +15,20 @@ namespace Bit.Core.Services
{ {
private readonly IStorageService _storageService; private readonly IStorageService _storageService;
private readonly IStorageService _secureStorageService; private readonly IStorageService _secureStorageService;
private readonly IMessagingService _messagingService;
private State _state; private State _state;
private bool _migrationChecked; private bool _migrationChecked;
public List<AccountView> AccountViews { get; set; } public List<AccountView> AccountViews { get; set; }
public StateService(IStorageService storageService, IStorageService secureStorageService) public StateService(IStorageService storageService,
IStorageService secureStorageService,
IMessagingService messagingService)
{ {
_storageService = storageService; _storageService = storageService;
_secureStorageService = secureStorageService; _secureStorageService = secureStorageService;
_messagingService = messagingService;
} }
public async Task<string> GetActiveUserIdAsync() public async Task<string> GetActiveUserIdAsync()
@ -67,6 +71,28 @@ namespace Bit.Core.Services
await SetPreAuthEnvironmentUrlsAsync(await GetEnvironmentUrlsAsync()); await SetPreAuthEnvironmentUrlsAsync(await GetEnvironmentUrlsAsync());
} }
public async Task CheckExtensionActiveUserAndSwitchIfNeededAsync()
{
var extensionUserId = await GetExtensionActiveUserIdFromStorageAsync();
if (string.IsNullOrEmpty(extensionUserId))
{
return;
}
if (_state?.ActiveUserId == extensionUserId)
{
// Clear the value in case the user changes the active user from the app
// so if that happens and the user sends the app to background and comes back
// the user is not changed again.
await SaveExtensionActiveUserIdToStorageAsync(null);
return;
}
await SetActiveUserAsync(extensionUserId);
await SaveExtensionActiveUserIdToStorageAsync(null);
_messagingService.Send(AccountsManagerMessageCommands.SWITCHED_ACCOUNT);
}
public async Task<bool> IsAuthenticatedAsync(string userId = null) public async Task<bool> IsAuthenticatedAsync(string userId = null)
{ {
return await GetAccessTokenAsync(userId) != null; return await GetAccessTokenAsync(userId) != null;
@ -1510,6 +1536,16 @@ namespace Bit.Core.Services
await _storageService.SaveAsync(Constants.StateKey, state); await _storageService.SaveAsync(Constants.StateKey, state);
} }
private async Task<string> GetExtensionActiveUserIdFromStorageAsync()
{
return await _storageService.GetAsync<string>(Constants.iOSExtensionActiveUserIdKey);
}
public async Task SaveExtensionActiveUserIdToStorageAsync(string userId)
{
await _storageService.SaveAsync(Constants.iOSExtensionActiveUserIdKey, userId);
}
private async Task CheckStateAsync() private async Task CheckStateAsync()
{ {
if (!_migrationChecked) if (!_migrationChecked)

View file

@ -0,0 +1,13 @@
namespace Bit.Core.Utilities
{
public static class AccountsManagerMessageCommands
{
public const string LOCKED = "locked";
public const string LOCK_VAULT = "lockVault";
public const string LOGOUT = "logout";
public const string LOGGED_OUT = "loggedOut";
public const string ADD_ACCOUNT = "addAccount";
public const string ACCOUNT_ADDED = "accountAdded";
public const string SWITCHED_ACCOUNT = "switchedAccount";
}
}

View file

@ -35,7 +35,10 @@ namespace Bit.iOS.Core.Utilities
LongPressAccountEnabled = false LongPressAccountEnabled = false
}; };
var vm = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger); var vm = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger)
{
FromIOSExtension = true
};
overlay.BindingContext = vm; overlay.BindingContext = vm;
var renderer = Platform.CreateRenderer(overlay.Content); var renderer = Platform.CreateRenderer(overlay.Content);

View file

@ -59,7 +59,7 @@ namespace Bit.iOS.Core.Utilities
() => ServiceContainer.Resolve<IAppIdService>("appIdService").GetAppIdAsync()); () => ServiceContainer.Resolve<IAppIdService>("appIdService").GetAppIdAsync());
var cryptoPrimitiveService = new CryptoPrimitiveService(); var cryptoPrimitiveService = new CryptoPrimitiveService();
var mobileStorageService = new MobileStorageService(preferencesStorage, liteDbStorage); var mobileStorageService = new MobileStorageService(preferencesStorage, liteDbStorage);
var stateService = new StateService(mobileStorageService, secureStorageService); var stateService = new StateService(mobileStorageService, secureStorageService, messagingService);
var stateMigrationService = var stateMigrationService =
new StateMigrationService(liteDbStorage, preferencesStorage, secureStorageService); new StateMigrationService(liteDbStorage, preferencesStorage, secureStorageService);
var deviceActionService = new DeviceActionService(stateService, messagingService); var deviceActionService = new DeviceActionService(stateService, messagingService);