1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-30 15:13:24 +00:00

Account Switching (#1807)

* Account Switching (#1720)

* Account switching

* WIP

* wip

* wip

* updates to send test logic

* fixed Send tests

* fixes for theme handling on account switching and re-adding existing account

* switch fixes

* fixes

* fixes

* cleanup

* vault timeout fixes

* account list status enhancements

* logout fixes and token handling improvements

* merge latest (#1727)

* remove duplicate dependency

* fix for initial login token storage paradox (#1730)

* Fix avatar color update toolbar item issue on iOS for account switching (#1735)

* Updated account switching menu UI (#1733)

* updated account switching menu UI

* additional changes

* add key suffix to constant

* GetFirstLetters method tweaks

* Fix crash on account switching when logging out when having more than user at a time (#1740)

* single account migration to multi-account on app update (#1741)

* Account Switching Tap to dismiss (#1743)

* Added tap to dismiss on the Account switching overlay and improved a bit the code

* Fix account switching overlay background transparent on the proper place

* Fixed transparent background and the shadow on the account switching overlay

* Fix iOS top space on Account switching list overlay after modal (#1746)

* Fix top space added to Account switching list overlay after closing modal

* Fix top space added to Account switching list overlay after closing modal on lock, login and home views just in case we add modals in the future there as well

* Usability: dismiss account list on certain events (#1748)

* dismiss account list on certain events

* use new FireAndForget method for back button logic

* Create and use Account Switching overlay control (#1753)

* Added Account switching overlay control and its own ViewModel and refactored accordingly

* Fix account switching Accounts list binding update

* Implemented dismiss account switching overlay when changing tabs and when selecting the same tab. Also updated the deprecated listener on CustomTabbedRenderer on Android (#1755)

* Overriden Equals on AvatarImageSource so it doesn't get set multiple times when it's the same image thus producing blinking on tab chaged (#1756)

* Usability improvements for logout on vault timeout (#1781)

* accountswitching fixes (#1784)

* Fix for invalid PIN lock state when switching accounts (#1792)

* fix for pin lock flow

* named tuple values and updated async

* clear send service cache on account switch (#1796)

* Global theme and account removal (#1793)

* Global theme and account removal

* remove redundant call to hide account list overlay

* cleanup and additional tweaks

* add try/catch to remove account dialog flow

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
This commit is contained in:
Matt Portune
2022-02-23 12:40:17 -05:00
committed by GitHub
parent ded3f07fa6
commit 2e8824ce05
144 changed files with 5064 additions and 1761 deletions

View File

@@ -2,7 +2,6 @@
using Bit.App.Abstractions;
using Bit.App.Pages;
using Bit.App.Resources;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
@@ -14,6 +13,7 @@ using System.Threading.Tasks;
using Bit.App.Models;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Data;
using Newtonsoft.Json;
using Xamarin.Essentials;
using Xamarin.Forms;
@@ -46,8 +46,8 @@ namespace Bit.App.Utilities
}
if (!string.IsNullOrWhiteSpace(cipher.Login.Totp))
{
var userService = ServiceContainer.Resolve<IUserService>("userService");
var canAccessPremium = await userService.CanAccessPremiumAsync();
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
var canAccessPremium = await stateService.CanAccessPremiumAsync();
if (canAccessPremium || cipher.OrganizationUseTotp)
{
options.Add(AppResources.CopyTotp);
@@ -330,33 +330,15 @@ namespace Bit.App.Utilities
}
public static async Task<bool> PerformUpdateTasksAsync(ISyncService syncService,
IDeviceActionService deviceActionService, IStorageService storageService)
IDeviceActionService deviceActionService, IStateService stateService)
{
var currentBuild = deviceActionService.GetBuildNumber();
var lastBuild = await storageService.GetAsync<string>(Constants.LastBuildKey);
if (lastBuild == null)
{
// Installed
var currentTimeout = await storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
if (currentTimeout == null)
{
await storageService.SaveAsync(Constants.VaultTimeoutKey, 15);
}
var currentAction = await storageService.GetAsync<string>(Constants.VaultTimeoutActionKey);
if (currentAction == null)
{
await storageService.SaveAsync(Constants.VaultTimeoutActionKey, "lock");
}
}
else if (lastBuild != currentBuild)
var lastBuild = await stateService.GetLastBuildAsync();
if (lastBuild == null || lastBuild != currentBuild)
{
// Updated
var tasks = Task.Run(() => syncService.FullSyncAsync(true));
}
if (lastBuild != currentBuild)
{
await storageService.SaveAsync(Constants.LastBuildKey, currentBuild);
await stateService.SetLastBuildAsync(currentBuild);
return true;
}
return false;
@@ -418,35 +400,34 @@ namespace Bit.App.Utilities
public static async Task<PreviousPageInfo> ClearPreviousPage()
{
var storageService = ServiceContainer.Resolve<IStorageService>("storageService");
var previousPage = await storageService.GetAsync<PreviousPageInfo>(Constants.PreviousPageKey);
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
var previousPage = await stateService.GetPreviousPageInfoAsync();
if (previousPage != null)
{
await storageService.RemoveAsync(Constants.PreviousPageKey);
await stateService.SetPreviousPageInfoAsync(null);
}
return previousPage;
}
public static async Task<int> IncrementInvalidUnlockAttemptsAsync()
{
var storageService = ServiceContainer.Resolve<IStorageService>("storageService");
var invalidUnlockAttempts = await storageService.GetAsync<int>(Constants.InvalidUnlockAttempts);
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
var invalidUnlockAttempts = await stateService.GetInvalidUnlockAttemptsAsync();
invalidUnlockAttempts++;
await storageService.SaveAsync(Constants.InvalidUnlockAttempts, invalidUnlockAttempts);
await stateService.SetInvalidUnlockAttemptsAsync(invalidUnlockAttempts);
return invalidUnlockAttempts;
}
public static async Task ResetInvalidUnlockAttemptsAsync()
{
var storageService = ServiceContainer.Resolve<IStorageService>("storageService");
await storageService.RemoveAsync(Constants.InvalidUnlockAttempts);
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
await stateService.SetInvalidUnlockAttemptsAsync(null);
}
public static async Task<bool> IsVaultTimeoutImmediateAsync()
{
var storageService = ServiceContainer.Resolve<IStorageService>("storageService");
var vaultTimeoutMinutes = await storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
var vaultTimeoutMinutes = await stateService.GetVaultTimeoutAsync();
if (vaultTimeoutMinutes.GetValueOrDefault(-1) == 0)
{
return true;
@@ -466,10 +447,8 @@ namespace Bit.App.Utilities
return Convert.ToBase64String(Encoding.UTF8.GetBytes(multiByteEscaped));
}
public static async Task LogOutAsync()
public static async Task LogOutAsync(string userId, bool userInitiated = false)
{
var userService = ServiceContainer.Resolve<IUserService>("userService");
var syncService = ServiceContainer.Resolve<ISyncService>("syncService");
var tokenService = ServiceContainer.Resolve<ITokenService>("tokenService");
var cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
var settingsService = ServiceContainer.Resolve<ISettingsService>("settingsService");
@@ -481,23 +460,70 @@ namespace Bit.App.Utilities
var vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
var policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
var searchService = ServiceContainer.Resolve<ISearchService>("searchService");
var userId = await userService.GetUserIdAsync();
if (userId == null)
{
userId = await stateService.GetActiveUserIdAsync();
}
await Task.WhenAll(
syncService.SetLastSyncAsync(DateTime.MinValue),
tokenService.ClearTokenAsync(),
cryptoService.ClearKeysAsync(),
userService.ClearAsync(),
settingsService.ClearAsync(userId),
cipherService.ClearAsync(userId),
folderService.ClearAsync(userId),
collectionService.ClearAsync(userId),
passwordGenerationService.ClearAsync(),
vaultTimeoutService.ClearAsync(),
stateService.PurgeAsync(),
passwordGenerationService.ClearAsync(userId),
deviceActionService.ClearCacheAsync(),
tokenService.ClearTokenAsync(userId),
cryptoService.ClearKeysAsync(userId),
settingsService.ClearAsync(userId),
vaultTimeoutService.ClearAsync(userId),
policyService.ClearAsync(userId),
stateService.LogoutAccountAsync(userId, userInitiated));
stateService.BiometricLocked = true;
searchService.ClearIndex();
// check if we switched accounts automatically
if (userInitiated && await stateService.GetActiveUserIdAsync() != null)
{
var messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
messagingService.Send("switchedAccount");
var platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
platformUtilsService.ShowToast("info", null, AppResources.AccountSwitchedAutomatically);
}
}
public static async Task OnAccountSwitchAsync()
{
var environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
var tokenService = ServiceContainer.Resolve<ITokenService>("tokenService");
var cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
var settingsService = ServiceContainer.Resolve<ISettingsService>("settingsService");
var cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
var folderService = ServiceContainer.Resolve<IFolderService>("folderService");
var collectionService = ServiceContainer.Resolve<ICollectionService>("collectionService");
var sendService = ServiceContainer.Resolve<ISendService>("sendService");
var passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>(
"passwordGenerationService");
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
var policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
var searchService = ServiceContainer.Resolve<ISearchService>("searchService");
await environmentService.SetUrlsFromStorageAsync();
await Task.WhenAll(
cipherService.ClearCacheAsync(),
deviceActionService.ClearCacheAsync());
vaultTimeoutService.BiometricLocked = true;
tokenService.ClearCache();
cryptoService.ClearCache();
settingsService.ClearCache();
folderService.ClearCache();
collectionService.ClearCache();
sendService.ClearCache();
passwordGenerationService.ClearCache();
policyService.ClearCache();
searchService.ClearIndex();
}
}