From dbadf8c56f724f53a1a19dbbec573189988813af Mon Sep 17 00:00:00 2001 From: mpbw2 <59324545+mpbw2@users.noreply.github.com> Date: Wed, 30 Aug 2023 10:55:20 -0400 Subject: [PATCH] [PM-3222] Migration of data from LiteDB to shared pref storage (#2724) * Migration of data from LiteDB to shared pref storage * tweaks --- src/App/Pages/BaseContentPage.cs | 6 + src/App/Services/MobileStorageService.cs | 69 +++-- src/Core/Abstractions/IAppIdService.cs | 1 - src/Core/Abstractions/ICipherService.cs | 1 - src/Core/Abstractions/IStateService.cs | 6 +- src/Core/Constants.cs | 6 +- src/Core/Services/AppIdService.cs | 7 +- src/Core/Services/CipherService.cs | 23 +- src/Core/Services/StateMigrationService.cs | 312 ++++++++++++++++++++- src/Core/Services/StateService.cs | 29 +- 10 files changed, 373 insertions(+), 87 deletions(-) diff --git a/src/App/Pages/BaseContentPage.cs b/src/App/Pages/BaseContentPage.cs index fc4e502ac..659c4b2bd 100644 --- a/src/App/Pages/BaseContentPage.cs +++ b/src/App/Pages/BaseContentPage.cs @@ -150,6 +150,12 @@ namespace Bit.App.Pages private async Task SaveActivityAsync() { SetServices(); + if (await _stateService.GetActiveUserIdAsync() == null) + { + // Fresh install and/or all users logged out won't have an active user, skip saving last active time + return; + } + await _stateService.SetLastActiveTimeAsync(_deviceActionService.GetActiveTime()); } } diff --git a/src/App/Services/MobileStorageService.cs b/src/App/Services/MobileStorageService.cs index 78f2fcde8..bb2827bc8 100644 --- a/src/App/Services/MobileStorageService.cs +++ b/src/App/Services/MobileStorageService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Bit.Core; using Bit.Core.Abstractions; @@ -11,27 +12,16 @@ namespace Bit.App.Services private readonly IStorageService _preferencesStorageService; private readonly IStorageService _liteDbStorageService; - private readonly HashSet _preferenceStorageKeys = new HashSet + private readonly HashSet _liteDbStorageKeys = new HashSet { - Constants.StateVersionKey, - Constants.PreAuthEnvironmentUrlsKey, - Constants.AutofillTileAdded, - Constants.AddSitePromptShownKey, - Constants.PushInitialPromptShownKey, - Constants.LastFileCacheClearKey, - Constants.PushRegisteredTokenKey, - Constants.LastBuildKey, - Constants.ClearCiphersCacheKey, - Constants.BiometricIntegritySourceKey, - Constants.iOSExtensionActiveUserIdKey, - Constants.iOSAutoFillClearCiphersCacheKey, - Constants.iOSAutoFillBiometricIntegritySourceKey, - Constants.iOSExtensionClearCiphersCacheKey, - Constants.iOSExtensionBiometricIntegritySourceKey, - Constants.iOSShareExtensionClearCiphersCacheKey, - Constants.iOSShareExtensionBiometricIntegritySourceKey, - Constants.RememberedEmailKey, - Constants.RememberedOrgIdentifierKey + Constants.EventCollectionKey, + Constants.CiphersKey(""), + Constants.FoldersKey(""), + Constants.CollectionsKey(""), + Constants.CiphersLocalDataKey(""), + Constants.SendsKey(""), + Constants.PassGenHistoryKey(""), + Constants.SettingsKey(""), }; public MobileStorageService( @@ -44,29 +34,30 @@ namespace Bit.App.Services public async Task GetAsync(string key) { - if (_preferenceStorageKeys.Contains(key)) + if (IsLiteDbKey(key)) { - return await _preferencesStorageService.GetAsync(key); + return await _liteDbStorageService.GetAsync(key); } - return await _liteDbStorageService.GetAsync(key); + + return await _preferencesStorageService.GetAsync(key) ?? await TryMigrateLiteDbToPrefsAsync(key); } public Task SaveAsync(string key, T obj) { - if (_preferenceStorageKeys.Contains(key)) + if (IsLiteDbKey(key)) { - return _preferencesStorageService.SaveAsync(key, obj); + return _liteDbStorageService.SaveAsync(key, obj); } - return _liteDbStorageService.SaveAsync(key, obj); + return _preferencesStorageService.SaveAsync(key, obj); } public Task RemoveAsync(string key) { - if (_preferenceStorageKeys.Contains(key)) + if (IsLiteDbKey(key)) { - return _preferencesStorageService.RemoveAsync(key); + return _liteDbStorageService.RemoveAsync(key); } - return _liteDbStorageService.RemoveAsync(key); + return _preferencesStorageService.RemoveAsync(key); } public void Dispose() @@ -80,5 +71,25 @@ namespace Bit.App.Services disposablePrefService.Dispose(); } } + + // Helpers + + private bool IsLiteDbKey(string key) + { + return _liteDbStorageKeys.Any(key.StartsWith) || + _liteDbStorageKeys.Contains(key); + } + + private async Task TryMigrateLiteDbToPrefsAsync(string key) + { + var currentValue = await _liteDbStorageService.GetAsync(key); + if (currentValue != null) + { + await _preferencesStorageService.SaveAsync(key, currentValue); + await _liteDbStorageService.RemoveAsync(key); + } + + return currentValue; + } } } diff --git a/src/Core/Abstractions/IAppIdService.cs b/src/Core/Abstractions/IAppIdService.cs index 6c3bd6d30..c5f7c0909 100644 --- a/src/Core/Abstractions/IAppIdService.cs +++ b/src/Core/Abstractions/IAppIdService.cs @@ -5,6 +5,5 @@ namespace Bit.Core.Abstractions public interface IAppIdService { Task GetAppIdAsync(); - Task GetAnonymousAppIdAsync(); } } diff --git a/src/Core/Abstractions/ICipherService.cs b/src/Core/Abstractions/ICipherService.cs index d68b0dc93..527ce0087 100644 --- a/src/Core/Abstractions/ICipherService.cs +++ b/src/Core/Abstractions/ICipherService.cs @@ -35,7 +35,6 @@ namespace Bit.Core.Abstractions Task ReplaceAsync(Dictionary ciphers); Task SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data); Task SaveCollectionsWithServerAsync(Cipher cipher); - Task SaveNeverDomainAsync(string domain); Task SaveWithServerAsync(Cipher cipher); Task ShareWithServerAsync(CipherView cipher, string organizationId, HashSet collectionIds); Task UpdateLastUsedDateAsync(string id); diff --git a/src/Core/Abstractions/IStateService.cs b/src/Core/Abstractions/IStateService.cs index 5b40b60d6..07ce65461 100644 --- a/src/Core/Abstractions/IStateService.cs +++ b/src/Core/Abstractions/IStateService.cs @@ -92,14 +92,12 @@ namespace Bit.Core.Abstractions Task SetInlineAutofillEnabledAsync(bool? value, string userId = null); Task GetAutofillDisableSavePromptAsync(string userId = null); Task SetAutofillDisableSavePromptAsync(bool? value, string userId = null); - Task>> GetLocalDataAsync(string userId = null); - Task SetLocalDataAsync(Dictionary> value, string userId = null); + Task>> GetCiphersLocalDataAsync(string userId = null); + Task SetCiphersLocalDataAsync(Dictionary> value, string userId = null); Task> GetEncryptedCiphersAsync(string userId = null); Task SetEncryptedCiphersAsync(Dictionary value, string userId = null); Task GetDefaultUriMatchAsync(string userId = null); Task SetDefaultUriMatchAsync(int? value, string userId = null); - Task> GetNeverDomainsAsync(string userId = null); - Task SetNeverDomainsAsync(HashSet value, string userId = null); Task GetClearClipboardAsync(string userId = null); Task SetClearClipboardAsync(int? value, string userId = null); Task> GetEncryptedCollectionsAsync(string userId = null); diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index c3e2add96..74b415aa7 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -9,11 +9,12 @@ namespace Bit.Core public const string AndroidAppProtocol = "androidapp://"; public const string iOSAppProtocol = "iosapp://"; public const string DefaultUsernameGenerated = "-"; + public const string AppIdKey = "appId"; public const string StateVersionKey = "stateVersion"; public const string StateKey = "state"; public const string PreAuthEnvironmentUrlsKey = "preAuthEnvironmentUrls"; public const string LastFileCacheClearKey = "lastFileCacheClear"; - public const string AutofillTileAdded = "autofillTileAdded"; + public const string AutofillTileAddedKey = "autofillTileAdded"; public const string PushRegisteredTokenKey = "pushRegisteredToken"; public const string PushInitialPromptShownKey = "pushInitialPromptShown"; public const string PushInstallationRegistrationErrorKey = "pushInstallationRegistrationError"; @@ -92,8 +93,7 @@ namespace Bit.Core public static string FoldersKey(string userId) => $"folders_{userId}"; public static string CollectionsKey(string userId) => $"collections_{userId}"; public static string OrganizationsKey(string userId) => $"organizations_{userId}"; - public static string LocalDataKey(string userId) => $"ciphersLocalData_{userId}"; - public static string NeverDomainsKey(string userId) => $"neverDomains_{userId}"; + public static string CiphersLocalDataKey(string userId) => $"ciphersLocalData_{userId}"; public static string SendsKey(string userId) => $"sends_{userId}"; public static string PoliciesKey(string userId) => $"policies_{userId}"; public static string EncOrgKeysKey(string userId) => $"encOrgKeys_{userId}"; diff --git a/src/Core/Services/AppIdService.cs b/src/Core/Services/AppIdService.cs index b95fd432f..e1641e9ae 100644 --- a/src/Core/Services/AppIdService.cs +++ b/src/Core/Services/AppIdService.cs @@ -15,12 +15,7 @@ namespace Bit.Core.Services public Task GetAppIdAsync() { - return MakeAndGetAppIdAsync("appId"); - } - - public Task GetAnonymousAppIdAsync() - { - return MakeAndGetAppIdAsync("anonymousAppId"); + return MakeAndGetAppIdAsync(Constants.AppIdKey); } private async Task MakeAndGetAppIdAsync(string key) diff --git a/src/Core/Services/CipherService.cs b/src/Core/Services/CipherService.cs index d2192810b..7f6364763 100644 --- a/src/Core/Services/CipherService.cs +++ b/src/Core/Services/CipherService.cs @@ -208,7 +208,7 @@ namespace Bit.Core.Services public async Task GetAsync(string id) { - var localData = await _stateService.GetLocalDataAsync(); + var localData = await _stateService.GetCiphersLocalDataAsync(); var ciphers = await _stateService.GetEncryptedCiphersAsync(); if (!ciphers?.ContainsKey(id) ?? true) { @@ -220,7 +220,7 @@ namespace Bit.Core.Services public async Task> GetAllAsync() { - var localData = await _stateService.GetLocalDataAsync(); + var localData = await _stateService.GetCiphersLocalDataAsync(); var ciphers = await _stateService.GetEncryptedCiphersAsync(); var response = ciphers?.Select(c => new Cipher(c.Value, false, localData?.ContainsKey(c.Key) ?? false ? localData[c.Key] : null)); @@ -458,7 +458,7 @@ namespace Bit.Core.Services public async Task UpdateLastUsedDateAsync(string id) { - var ciphersLocalData = await _stateService.GetLocalDataAsync(); + var ciphersLocalData = await _stateService.GetCiphersLocalDataAsync(); if (ciphersLocalData == null) { ciphersLocalData = new Dictionary>(); @@ -476,7 +476,7 @@ namespace Bit.Core.Services ciphersLocalData[id].Add("lastUsedDate", DateTime.UtcNow); } - await _stateService.SetLocalDataAsync(ciphersLocalData); + await _stateService.SetCiphersLocalDataAsync(ciphersLocalData); // Update cache if (DecryptedCipherCache == null) { @@ -489,21 +489,6 @@ namespace Bit.Core.Services } } - public async Task SaveNeverDomainAsync(string domain) - { - if (string.IsNullOrWhiteSpace(domain)) - { - return; - } - var domains = await _stateService.GetNeverDomainsAsync(); - if (domains == null) - { - domains = new HashSet(); - } - domains.Add(domain); - await _stateService.SetNeverDomainsAsync(domains); - } - public async Task SaveWithServerAsync(Cipher cipher) { CipherResponse response; diff --git a/src/Core/Services/StateMigrationService.cs b/src/Core/Services/StateMigrationService.cs index caf693bd4..068299455 100644 --- a/src/Core/Services/StateMigrationService.cs +++ b/src/Core/Services/StateMigrationService.cs @@ -13,7 +13,7 @@ namespace Bit.Core.Services { public class StateMigrationService : IStateMigrationService { - private const int StateVersion = 5; + private const int StateVersion = 6; private readonly DeviceType _deviceType; private readonly IStorageService _preferencesStorageService; @@ -80,9 +80,12 @@ namespace Bit.Core.Services goto case 3; case 3: await MigrateFrom3To4Async(); - break; + goto case 4; case 4: await MigrateFrom4To5Async(); + goto case 5; + case 5: + await MigrateFrom5To6Async(); break; } } @@ -544,6 +547,296 @@ namespace Bit.Core.Services #endregion + #region v5 to v6 Migration + + private async Task MigrateFrom5To6Async() + { + // global data + await MoveToPrefsAsync(V6Keys.AppIdKey); + await MoveToPrefsAsync(V6Keys.DisableFaviconKey); + await MoveToPrefsAsync(V6Keys.ThemeKey); + await MoveToPrefsAsync(V6Keys.AutoDarkThemeKey); + await MoveToPrefsAsync(V6Keys.PasswordlessLoginNotificationKey); + await MoveToPrefsAsync(V6Keys.PreLoginEmailKey); + await MoveToPrefsAsync(V6Keys.LastUserShouldConnectToWatchKey); + await MoveToPrefsAsync(V6Keys.PushInstallationRegistrationErrorKey); + await MoveToPrefsAsync(V6Keys.AutofillNeedsIdentityReplacementKey); + + // account data + var state = await GetValueAsync(Storage.LiteDb, Constants.StateKey); + if (state?.Accounts != null) + { + await SetValueAsync(Storage.Prefs, Constants.StateKey, state); + + foreach (var account in state.Accounts.Where(a => a.Value?.Profile?.UserId != null)) + { + var userId = account.Value.Profile.UserId; + + await MoveToPrefsAsync(V6Keys.BiometricUnlockKey(userId)); + await MoveToPrefsAsync(V6Keys.ProtectedPinKey(userId)); + await MoveToPrefsAsync(V6Keys.PinKeyEncryptedUserKeyKey(userId)); + await MoveToPrefsAsync(V6Keys.KeyHashKey(userId)); + await MoveToPrefsAsync(V6Keys.MasterKeyEncryptedUserKeyKey(userId)); + await MoveToPrefsAsync>(V6Keys.EncOrgKeysKey(userId)); + await MoveToPrefsAsync(V6Keys.EncPrivateKeyKey(userId)); + await MoveToPrefsAsync>(V6Keys.AutofillBlacklistedUrisKey(userId)); + await MoveToPrefsAsync(V6Keys.LastActiveTimeKey(userId)); + await MoveToPrefsAsync(V6Keys.VaultTimeoutKey(userId)); + await MoveToPrefsAsync(V6Keys.VaultTimeoutActionKey(userId)); + await MoveToPrefsAsync(V6Keys.ScreenCaptureAllowedKey(userId)); + await MoveToPrefsAsync(V6Keys.PreviousPageKey(userId)); + await MoveToPrefsAsync(V6Keys.InvalidUnlockAttemptsKey(userId)); + await MoveToPrefsAsync(V6Keys.DisableAutoTotpCopyKey(userId)); + await MoveToPrefsAsync(V6Keys.InlineAutofillEnabledKey(userId)); + await MoveToPrefsAsync(V6Keys.AutofillDisableSavePromptKey(userId)); + await MoveToPrefsAsync(V6Keys.DefaultUriMatchKey(userId)); + await MoveToPrefsAsync(V6Keys.ClearClipboardKey(userId)); + await MoveToPrefsAsync(V6Keys.PasswordRepromptAutofillKey(userId)); + await MoveToPrefsAsync(V6Keys.PasswordVerifiedAutofillKey(userId)); + await MoveToPrefsAsync(V6Keys.LastSyncKey(userId)); + await MoveToPrefsAsync(V6Keys.SyncOnRefreshKey(userId)); + await MoveToPrefsAsync(V6Keys.PushLastRegistrationDateKey(userId)); + await MoveToPrefsAsync(V6Keys.PushCurrentTokenKey(userId)); + await MoveToPrefsAsync>(V6Keys.PoliciesKey(userId)); + await MoveToPrefsAsync(V6Keys.UsesKeyConnectorKey(userId)); + await MoveToPrefsAsync>( + V6Keys.OrganizationsKey(userId)); + await MoveToPrefsAsync(V6Keys.PassGenOptionsKey(userId)); + await MoveToPrefsAsync(V6Keys.UsernameGenOptionsKey(userId)); + await MoveToPrefsAsync(V6Keys.TwoFactorTokenKey(userId)); + await MoveToPrefsAsync(V6Keys.ApprovePasswordlessLoginsKey(userId)); + await MoveToPrefsAsync(V6Keys.ShouldConnectToWatchKey(userId)); + await MoveToPrefsAsync(V6Keys.DeviceKeyKey(userId)); + } + } + + await RemoveValueAsync(Storage.LiteDb, Constants.StateKey); + await RemoveValueAsync(Storage.LiteDb, V6Keys.LastActiveTimeKey("")); + + // Update stored version + await SetLastStateVersionAsync(6); + } + + private class V6Keys + { + // global keys + + internal const string AppIdKey = "appId"; + internal const string DisableFaviconKey = "disableFavicon"; + internal const string ThemeKey = "theme"; + internal const string AutoDarkThemeKey = "autoDarkTheme"; + internal const string PasswordlessLoginNotificationKey = "passwordlessLoginNotificationKey"; + internal const string PreLoginEmailKey = "preLoginEmailKey"; + internal const string LastUserShouldConnectToWatchKey = "lastUserShouldConnectToWatch"; + internal const string PushInstallationRegistrationErrorKey = "pushInstallationRegistrationError"; + internal const string AutofillNeedsIdentityReplacementKey = "autofillNeedsIdentityReplacement"; + + // account keys + + internal static string BiometricUnlockKey(string userId) => $"biometricUnlock_{userId}"; + internal static string ProtectedPinKey(string userId) => $"protectedPin_{userId}"; + internal static string PinKeyEncryptedUserKeyKey(string userId) => $"pinKeyEncryptedUserKey_{userId}"; + internal static string KeyHashKey(string userId) => $"keyHash_{userId}"; + internal static string MasterKeyEncryptedUserKeyKey(string userId) => $"masterKeyEncryptedUserKey_{userId}"; + internal static string EncOrgKeysKey(string userId) => $"encOrgKeys_{userId}"; + internal static string EncPrivateKeyKey(string userId) => $"encPrivateKey_{userId}"; + internal static string AutofillBlacklistedUrisKey(string userId) => $"autofillBlacklistedUris_{userId}"; + internal static string LastActiveTimeKey(string userId) => $"lastActiveTime_{userId}"; + internal static string VaultTimeoutKey(string userId) => $"vaultTimeout_{userId}"; + internal static string VaultTimeoutActionKey(string userId) => $"vaultTimeoutAction_{userId}"; + internal static string ScreenCaptureAllowedKey(string userId) => $"screenCaptureAllowed_{userId}"; + internal static string PreviousPageKey(string userId) => $"previousPage_{userId}"; + internal static string InvalidUnlockAttemptsKey(string userId) => $"invalidUnlockAttempts_{userId}"; + internal static string DisableAutoTotpCopyKey(string userId) => $"disableAutoTotpCopy_{userId}"; + internal static string InlineAutofillEnabledKey(string userId) => $"inlineAutofillEnabled_{userId}"; + internal static string AutofillDisableSavePromptKey(string userId) => $"autofillDisableSavePrompt_{userId}"; + internal static string DefaultUriMatchKey(string userId) => $"defaultUriMatch_{userId}"; + internal static string ClearClipboardKey(string userId) => $"clearClipboard_{userId}"; + internal static string PasswordRepromptAutofillKey(string userId) => $"passwordRepromptAutofillKey_{userId}"; + internal static string PasswordVerifiedAutofillKey(string userId) => $"passwordVerifiedAutofillKey_{userId}"; + internal static string LastSyncKey(string userId) => $"lastSync_{userId}"; + internal static string SyncOnRefreshKey(string userId) => $"syncOnRefresh_{userId}"; + internal static string PushLastRegistrationDateKey(string userId) => $"pushLastRegistrationDate_{userId}"; + internal static string PushCurrentTokenKey(string userId) => $"pushCurrentToken_{userId}"; + internal static string PoliciesKey(string userId) => $"policies_{userId}"; + internal static string UsesKeyConnectorKey(string userId) => $"usesKeyConnector_{userId}"; + internal static string OrganizationsKey(string userId) => $"organizations_{userId}"; + internal static string PassGenOptionsKey(string userId) => $"passwordGenerationOptions_{userId}"; + internal static string UsernameGenOptionsKey(string userId) => $"usernameGenerationOptions_{userId}"; + internal static string TwoFactorTokenKey(string email) => $"twoFactorToken_{email}"; + internal static string ApprovePasswordlessLoginsKey(string userId) => $"approvePasswordlessLogins_{userId}"; + internal static string ShouldConnectToWatchKey(string userId) => $"shouldConnectToWatch_{userId}"; + internal static string DeviceKeyKey(string userId) => $"deviceKey_{userId}"; + + // objects + + internal class PasswordlessRequestNotification + { + public string UserId { get; set; } + public string Id { get; set; } + } + + internal enum VaultTimeoutAction + { + Lock = 0, + Logout = 1, + } + + internal class PreviousPageInfo + { + public string Page { get; set; } + public string CipherId { get; set; } + public string SendId { get; set; } + public string SearchText { get; set; } + } + + internal class PolicyData + { + public string Id { get; set; } + public string OrganizationId { get; set; } + public V6Keys.PolicyType Type { get; set; } + public Dictionary Data { get; set; } + public bool Enabled { get; set; } + } + + internal enum PolicyType : byte + { + TwoFactorAuthentication = 0, + MasterPassword = 1, + PasswordGenerator = 2, + OnlyOrg = 3, + RequireSso = 4, + PersonalOwnership = 5, + DisableSend = 6, + SendOptions = 7, + ResetPassword = 8, + MaximumVaultTimeout = 9, + DisablePersonalVaultExport = 10, + } + + internal class OrganizationData + { + public string Id { get; set; } + public string Name { get; set; } + public V6Keys.OrganizationUserStatusType Status { get; set; } + public V6Keys.OrganizationUserType Type { get; set; } + public bool Enabled { get; set; } + public bool UseGroups { get; set; } + public bool UseDirectory { get; set; } + public bool UseEvents { get; set; } + public bool UseTotp { get; set; } + public bool Use2fa { get; set; } + public bool UseApi { get; set; } + public bool UsePolicies { get; set; } + public bool SelfHost { get; set; } + public bool UsersGetPremium { get; set; } + public int? Seats { get; set; } + public short? MaxCollections { get; set; } + public short? MaxStorageGb { get; set; } + public V6Keys.Permissions Permissions { get; set; } = new Permissions(); + public string Identifier { get; set; } + public bool UsesKeyConnector { get; set; } + public string KeyConnectorUrl { get; set; } + } + + internal enum OrganizationUserStatusType : byte + { + Invited = 0, + Accepted = 1, + Confirmed = 2 + } + + internal enum OrganizationUserType : byte + { + Owner = 0, + Admin = 1, + User = 2, + Manager = 3, + Custom = 4, + } + + internal class Permissions + { + public bool AccessBusinessPortal { get; set; } + public bool AccessEventLogs { get; set; } + public bool AccessImportExport { get; set; } + public bool AccessReports { get; set; } + public bool EditAssignedCollections { get; set; } + public bool DeleteAssignedCollections { get; set; } + public bool CreateNewCollections { get; set; } + public bool EditAnyCollection { get; set; } + public bool DeleteAnyCollection { get; set; } + public bool ManageGroups { get; set; } + public bool ManagePolicies { get; set; } + public bool ManageSso { get; set; } + public bool ManageUsers { get; set; } + } + + internal class PasswordGenerationOptions + { + public int? Length { get; set; } + public bool? AllowAmbiguousChar { get; set; } + public bool? Number { get; set; } + public int? MinNumber { get; set; } + public bool? Uppercase { get; set; } + public int? MinUppercase { get; set; } + public bool? Lowercase { get; set; } + public int? MinLowercase { get; set; } + public bool? Special { get; set; } + public int? MinSpecial { get; set; } + public string Type { get; set; } + public int? NumWords { get; set; } + public string WordSeparator { get; set; } + public bool? Capitalize { get; set; } + public bool? IncludeNumber { get; set; } + } + + internal class UsernameGenerationOptions + { + public V6Keys.UsernameType Type { get; set; } + public V6Keys.ForwardedEmailServiceType ServiceType { get; set; } + public V6Keys.UsernameEmailType PlusAddressedEmailType { get; set; } + public V6Keys.UsernameEmailType CatchAllEmailType { get; set; } + public bool CapitalizeRandomWordUsername { get; set; } + public bool IncludeNumberRandomWordUsername { get; set; } + public string PlusAddressedEmail { get; set; } + public string CatchAllEmailDomain { get; set; } + public string FirefoxRelayApiAccessToken { get; set; } + public string SimpleLoginApiKey { get; set; } + public string DuckDuckGoApiKey { get; set; } + public string FastMailApiKey { get; set; } + public string AnonAddyApiAccessToken { get; set; } + public string AnonAddyDomainName { get; set; } + public string EmailWebsite { get; set; } + } + + internal enum UsernameType + { + PlusAddressedEmail = 0, + CatchAllEmail = 1, + ForwardedEmailAlias = 2, + RandomWord = 3, + } + + internal enum ForwardedEmailServiceType + { + None = -1, + AnonAddy = 0, + FirefoxRelay = 1, + SimpleLogin = 2, + DuckDuckGo = 3, + Fastmail = 4, + } + + internal enum UsernameEmailType + { + Random = 0, + Website = 1, + } + } + + #endregion + // Helpers private async Task GetLastStateVersionAsync() @@ -612,5 +905,20 @@ namespace Bit.Core.Services return _liteDbStorageService; } } + + private async Task MoveToPrefsAsync(string key) + { + var value = await GetValueAsync(Storage.LiteDb, key); + if (value == null) + { + return; + } + + if (await GetValueAsync(Storage.Prefs, key) == null) + { + await SetValueAsync(Storage.Prefs, key, value); + } + await RemoveValueAsync(Storage.LiteDb, key); + } } } diff --git a/src/Core/Services/StateService.cs b/src/Core/Services/StateService.cs index 4f6446261..5920870c9 100644 --- a/src/Core/Services/StateService.cs +++ b/src/Core/Services/StateService.cs @@ -548,12 +548,12 @@ namespace Bit.Core.Services public async Task GetAutofillTileAddedAsync() { - return await GetValueAsync(Constants.AutofillTileAdded, await GetDefaultStorageOptionsAsync()); + return await GetValueAsync(Constants.AutofillTileAddedKey, await GetDefaultStorageOptionsAsync()); } public async Task SetAutofillTileAddedAsync(bool? value) { - await SetValueAsync(Constants.AutofillTileAdded, value, await GetDefaultStorageOptionsAsync()); + await SetValueAsync(Constants.AutofillTileAddedKey, value, await GetDefaultStorageOptionsAsync()); } public async Task GetEmailAsync(string userId = null) @@ -751,19 +751,19 @@ namespace Bit.Core.Services reconciledOptions); } - public async Task>> GetLocalDataAsync(string userId = null) + public async Task>> GetCiphersLocalDataAsync(string userId = null) { var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync()); return await GetValueAsync>>( - Constants.LocalDataKey(reconciledOptions.UserId), reconciledOptions); + Constants.CiphersLocalDataKey(reconciledOptions.UserId), reconciledOptions); } - public async Task SetLocalDataAsync(Dictionary> value, string userId = null) + public async Task SetCiphersLocalDataAsync(Dictionary> value, string userId = null) { var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync()); - await SetValueAsync(Constants.LocalDataKey(reconciledOptions.UserId), value, reconciledOptions); + await SetValueAsync(Constants.CiphersLocalDataKey(reconciledOptions.UserId), value, reconciledOptions); } public async Task> GetEncryptedCiphersAsync(string userId = null) @@ -795,21 +795,6 @@ namespace Bit.Core.Services await SetValueAsync(Constants.DefaultUriMatchKey(reconciledOptions.UserId), value, reconciledOptions); } - public async Task> GetNeverDomainsAsync(string userId = null) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultStorageOptionsAsync()); - return await GetValueAsync>(Constants.NeverDomainsKey(reconciledOptions.UserId), - reconciledOptions); - } - - public async Task SetNeverDomainsAsync(HashSet value, string userId = null) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultStorageOptionsAsync()); - await SetValueAsync(Constants.NeverDomainsKey(reconciledOptions.UserId), value, reconciledOptions); - } - public async Task GetClearClipboardAsync(string userId = null) { var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, @@ -1542,7 +1527,7 @@ namespace Bit.Core.Services SetLastActiveTimeAsync(null, userId), SetPreviousPageInfoAsync(null, userId), SetInvalidUnlockAttemptsAsync(null, userId), - SetLocalDataAsync(null, userId), + SetCiphersLocalDataAsync(null, userId), SetEncryptedCiphersAsync(null, userId), SetEncryptedCollectionsAsync(null, userId), SetLastSyncAsync(null, userId),