diff --git a/src/Android/MainApplication.cs b/src/Android/MainApplication.cs index 262e006c5..3cc9ea12a 100644 --- a/src/Android/MainApplication.cs +++ b/src/Android/MainApplication.cs @@ -41,7 +41,8 @@ namespace Bit.Droid { RegisterLocalServices(); var deviceActionService = ServiceContainer.Resolve("deviceActionService"); - ServiceContainer.Init(deviceActionService.DeviceUserAgent); + ServiceContainer.Init(deviceActionService.DeviceUserAgent, Constants.ClearCiphersCacheKey, + Constants.AndroidAllClearCipherCacheKeys); } #if !FDROID if (Build.VERSION.SdkInt <= BuildVersionCodes.Kitkat) diff --git a/src/App/App.xaml.cs b/src/App/App.xaml.cs index 6a98dae9d..a2e7fc191 100644 --- a/src/App/App.xaml.cs +++ b/src/App/App.xaml.cs @@ -163,7 +163,6 @@ namespace Bit.App { System.Diagnostics.Debug.WriteLine("XF App: OnStart"); await ClearCacheIfNeededAsync(); - await TryClearCiphersCacheAsync(); Prime(); if (string.IsNullOrWhiteSpace(Options.Uri)) { @@ -214,7 +213,6 @@ namespace Bit.App _messagingService.Send("cancelVaultTimeoutTimer"); _messagingService.Send("startEventTimer"); await ClearCacheIfNeededAsync(); - await TryClearCiphersCacheAsync(); Prime(); SyncIfNeeded(); if (Current.MainPage is NavigationPage navPage && navPage.CurrentPage is LockPage lockPage) @@ -390,20 +388,6 @@ namespace Bit.App }); } - private async Task TryClearCiphersCacheAsync() - { - if (Device.RuntimePlatform != Device.iOS) - { - return; - } - var clearCache = await _storageService.GetAsync(Constants.ClearCiphersCacheKey); - if (clearCache.GetValueOrDefault()) - { - _cipherService.ClearCache(); - await _storageService.RemoveAsync(Constants.ClearCiphersCacheKey); - } - } - private async Task LockedAsync(bool autoPromptBiometric) { await _stateService.PurgeAsync(); diff --git a/src/App/Services/MobileStorageService.cs b/src/App/Services/MobileStorageService.cs index 101eb9cc0..376222093 100644 --- a/src/App/Services/MobileStorageService.cs +++ b/src/App/Services/MobileStorageService.cs @@ -32,6 +32,8 @@ namespace Bit.App.Services Constants.MigratedFromV1AutofillPromptShown, Constants.TriedV1Resync, Constants.ClearCiphersCacheKey, + Constants.iOSAutoFillClearCiphersCacheKey, + Constants.iOSExtensionClearCiphersCacheKey, Constants.EnvironmentUrlsKey, }; diff --git a/src/Core/Abstractions/ICipherService.cs b/src/Core/Abstractions/ICipherService.cs index c3cac5583..6bee873f6 100644 --- a/src/Core/Abstractions/ICipherService.cs +++ b/src/Core/Abstractions/ICipherService.cs @@ -11,7 +11,7 @@ namespace Bit.Core.Abstractions public interface ICipherService { Task ClearAsync(string userId); - void ClearCache(); + Task ClearCacheAsync(); Task DeleteAsync(List ids); Task DeleteAsync(string id); Task DeleteAttachmentAsync(string id, string attachmentId); diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index b044b63ca..031bf042e 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -29,6 +29,8 @@ public static string OldUserIdKey = "userId"; public static string AddSitePromptShownKey = "addSitePromptShown"; public static string ClearCiphersCacheKey = "clearCiphersCache"; + public static string iOSAutoFillClearCiphersCacheKey = "iOSAutoFillClearCiphersCache"; + public static string iOSExtensionClearCiphersCacheKey = "iOSExtensionClearCiphersCache"; public static string MigratedFromV1 = "migratedFromV1"; public static string MigratedFromV1AutofillPromptShown = "migratedV1AutofillPromptShown"; public static string TriedV1Resync = "triedV1Resync"; @@ -37,5 +39,17 @@ public const int SelectFileRequestCode = 42; public const int SelectFilePermissionRequestCode = 43; public const int SaveFileRequestCode = 44; + + public static readonly string[] AndroidAllClearCipherCacheKeys = + { + ClearCiphersCacheKey + }; + + public static readonly string[] iOSAllClearCipherCacheKeys = + { + ClearCiphersCacheKey, + iOSAutoFillClearCiphersCacheKey, + iOSExtensionClearCiphersCacheKey + }; } } diff --git a/src/Core/Services/CipherService.cs b/src/Core/Services/CipherService.cs index 8af29ed96..6cad02b8d 100644 --- a/src/Core/Services/CipherService.cs +++ b/src/Core/Services/CipherService.cs @@ -33,6 +33,8 @@ namespace Bit.Core.Services private readonly IStorageService _storageService; private readonly II18nService _i18nService; private readonly Func _searchService; + private readonly string _clearCipherCacheKey; + private readonly string[] _allClearCipherCacheKeys; private Dictionary> _domainMatchBlacklist = new Dictionary> { ["google.com"] = new HashSet { "script.google.com" } @@ -47,7 +49,9 @@ namespace Bit.Core.Services IApiService apiService, IStorageService storageService, II18nService i18nService, - Func searchService) + Func searchService, + string clearCipherCacheKey, + string[] allClearCipherCacheKeys) { _cryptoService = cryptoService; _userService = userService; @@ -56,6 +60,8 @@ namespace Bit.Core.Services _storageService = storageService; _i18nService = i18nService; _searchService = searchService; + _clearCipherCacheKey = clearCipherCacheKey; + _allClearCipherCacheKeys = allClearCipherCacheKeys; } private List DecryptedCipherCache @@ -82,9 +88,16 @@ namespace Bit.Core.Services } } - public void ClearCache() + public async Task ClearCacheAsync() { DecryptedCipherCache = null; + if (_allClearCipherCacheKeys != null && _allClearCipherCacheKeys.Length > 0) + { + foreach (var key in _allClearCipherCacheKeys) + { + await _storageService.SaveAsync(key, true); + } + } } public async Task EncryptAsync(CipherView model, SymmetricCryptoKey key = null, @@ -218,15 +231,24 @@ namespace Bit.Core.Services return response?.ToList() ?? new List(); } - public Task> GetAllDecryptedAsync() + public async Task> GetAllDecryptedAsync() { + if (_clearCipherCacheKey != null) + { + var clearCache = await _storageService.GetAsync(_clearCipherCacheKey); + if (clearCache.GetValueOrDefault()) + { + DecryptedCipherCache = null; + await _storageService.RemoveAsync(_clearCipherCacheKey); + } + } if (DecryptedCipherCache != null) { - return Task.FromResult(DecryptedCipherCache); + return DecryptedCipherCache; } if (_getAllDecryptedTask != null && !_getAllDecryptedTask.IsCompleted && !_getAllDecryptedTask.IsFaulted) { - return _getAllDecryptedTask; + return await _getAllDecryptedTask; } async Task> doTask() { @@ -257,7 +279,7 @@ namespace Bit.Core.Services finally { } } _getAllDecryptedTask = doTask(); - return _getAllDecryptedTask; + return await _getAllDecryptedTask; } public async Task> GetAllDecryptedForGroupingAsync(string groupingId, bool folder = true) @@ -569,7 +591,7 @@ namespace Bit.Core.Services } ciphers[cipher.Id] = cipher; await _storageService.SaveAsync(storageKey, ciphers); - DecryptedCipherCache = null; + await ClearCacheAsync(); } public async Task UpsertAsync(List cipher) @@ -590,20 +612,20 @@ namespace Bit.Core.Services ciphers[c.Id] = c; } await _storageService.SaveAsync(storageKey, ciphers); - DecryptedCipherCache = null; + await ClearCacheAsync(); } public async Task ReplaceAsync(Dictionary ciphers) { var userId = await _userService.GetUserIdAsync(); await _storageService.SaveAsync(string.Format(Keys_CiphersFormat, userId), ciphers); - DecryptedCipherCache = null; + await ClearCacheAsync(); } public async Task ClearAsync(string userId) { await _storageService.RemoveAsync(string.Format(Keys_CiphersFormat, userId)); - ClearCache(); + await ClearCacheAsync(); } public async Task DeleteAsync(string id) @@ -621,7 +643,7 @@ namespace Bit.Core.Services } ciphers.Remove(id); await _storageService.SaveAsync(cipherKey, ciphers); - DecryptedCipherCache = null; + await ClearCacheAsync(); } public async Task DeleteAsync(List ids) @@ -642,7 +664,7 @@ namespace Bit.Core.Services ciphers.Remove(id); } await _storageService.SaveAsync(cipherKey, ciphers); - DecryptedCipherCache = null; + await ClearCacheAsync(); } public async Task DeleteWithServerAsync(string id) @@ -666,7 +688,7 @@ namespace Bit.Core.Services ciphers[id].Attachments.Remove(attachment); } await _storageService.SaveAsync(cipherKey, ciphers); - DecryptedCipherCache = null; + await ClearCacheAsync(); } public async Task DeleteAttachmentWithServerAsync(string id, string attachmentId) @@ -721,7 +743,7 @@ namespace Bit.Core.Services await _apiService.PutDeleteCipherAsync(id); ciphers[id].DeletedDate = DateTime.UtcNow; await _storageService.SaveAsync(cipherKey, ciphers); - DecryptedCipherCache = null; + await ClearCacheAsync(); } public async Task RestoreWithServerAsync(string id) @@ -740,7 +762,7 @@ namespace Bit.Core.Services await _apiService.PutRestoreCipherAsync(id); ciphers[id].DeletedDate = null; await _storageService.SaveAsync(cipherKey, ciphers); - DecryptedCipherCache = null; + await ClearCacheAsync(); } // Helpers diff --git a/src/Core/Services/VaultTimeoutService.cs b/src/Core/Services/VaultTimeoutService.cs index 9ae3bcceb..ce369210a 100644 --- a/src/Core/Services/VaultTimeoutService.cs +++ b/src/Core/Services/VaultTimeoutService.cs @@ -135,7 +135,7 @@ namespace Bit.Core.Services _cryptoService.ClearEncKeyAsync(true)); _folderService.ClearCache(); - _cipherService.ClearCache(); + await _cipherService.ClearCacheAsync(); _collectionService.ClearCache(); _searchService.ClearIndex(); _messagingService.Send("locked", userInitiated); diff --git a/src/Core/Utilities/ServiceContainer.cs b/src/Core/Utilities/ServiceContainer.cs index c9401c301..a6a0c194d 100644 --- a/src/Core/Utilities/ServiceContainer.cs +++ b/src/Core/Utilities/ServiceContainer.cs @@ -11,7 +11,8 @@ namespace Bit.Core.Utilities public static Dictionary RegisteredServices { get; set; } = new Dictionary(); public static bool Inited { get; set; } - public static void Init(string customUserAgent = null) + public static void Init(string customUserAgent = null, string clearCipherCacheKey = null, + string[] allClearCipherCacheKeys = null) { if (Inited) { @@ -40,7 +41,7 @@ namespace Bit.Core.Utilities var userService = new UserService(storageService, tokenService); var settingsService = new SettingsService(userService, storageService); var cipherService = new CipherService(cryptoService, userService, settingsService, apiService, - storageService, i18nService, () => searchService); + storageService, i18nService, () => searchService, clearCipherCacheKey, allClearCipherCacheKeys); var folderService = new FolderService(cryptoService, userService, apiService, storageService, i18nService, cipherService); var collectionService = new CollectionService(cryptoService, userService, storageService, i18nService); diff --git a/src/iOS.Autofill/CredentialProviderViewController.cs b/src/iOS.Autofill/CredentialProviderViewController.cs index 8f3e948ef..c52769ddb 100644 --- a/src/iOS.Autofill/CredentialProviderViewController.cs +++ b/src/iOS.Autofill/CredentialProviderViewController.cs @@ -273,7 +273,8 @@ namespace Bit.iOS.Autofill iOSCoreHelpers.RegisterLocalServices(); var deviceActionService = ServiceContainer.Resolve("deviceActionService"); var messagingService = ServiceContainer.Resolve("messagingService"); - ServiceContainer.Init(deviceActionService.DeviceUserAgent); + ServiceContainer.Init(deviceActionService.DeviceUserAgent, + Bit.Core.Constants.iOSAutoFillClearCiphersCacheKey, Bit.Core.Constants.iOSAllClearCipherCacheKeys); if (!_initedAppCenter) { iOSCoreHelpers.RegisterAppCenter(); diff --git a/src/iOS.Extension/LoadingViewController.cs b/src/iOS.Extension/LoadingViewController.cs index 45daeb1ea..8db33651e 100644 --- a/src/iOS.Extension/LoadingViewController.cs +++ b/src/iOS.Extension/LoadingViewController.cs @@ -395,7 +395,8 @@ namespace Bit.iOS.Extension iOSCoreHelpers.RegisterLocalServices(); var deviceActionService = ServiceContainer.Resolve("deviceActionService"); var messagingService = ServiceContainer.Resolve("messagingService"); - ServiceContainer.Init(deviceActionService.DeviceUserAgent); + ServiceContainer.Init(deviceActionService.DeviceUserAgent, + Bit.Core.Constants.iOSExtensionClearCiphersCacheKey, Bit.Core.Constants.iOSAllClearCipherCacheKeys); if (!_initedAppCenter) { iOSCoreHelpers.RegisterAppCenter(); diff --git a/src/iOS/AppDelegate.cs b/src/iOS/AppDelegate.cs index 0db17b027..ab3d39af4 100644 --- a/src/iOS/AppDelegate.cs +++ b/src/iOS/AppDelegate.cs @@ -301,7 +301,8 @@ namespace Bit.iOS iOSCoreHelpers.RegisterLocalServices(); RegisterPush(); var deviceActionService = ServiceContainer.Resolve("deviceActionService"); - ServiceContainer.Init(deviceActionService.DeviceUserAgent); + ServiceContainer.Init(deviceActionService.DeviceUserAgent, Constants.ClearCiphersCacheKey, + Constants.iOSAllClearCipherCacheKeys); iOSCoreHelpers.RegisterAppCenter(); _pushHandler = new iOSPushNotificationHandler( ServiceContainer.Resolve("pushNotificationListenerService"));