mirror of
https://github.com/bitwarden/mobile
synced 2025-12-20 10:13:42 +00:00
1602 lines
69 KiB
C#
1602 lines
69 KiB
C#
using System;
|
|
using Bit.Core.Abstractions;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Bit.Core.Enums;
|
|
using Bit.Core.Models.Data;
|
|
using Bit.Core.Models.Domain;
|
|
using Bit.Core.Models.View;
|
|
using Bit.Core.Utilities;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace Bit.Core.Services
|
|
{
|
|
public class StateService : IStateService
|
|
{
|
|
private readonly IStorageService _storageService;
|
|
private readonly IStorageService _secureStorageService;
|
|
|
|
private State _state;
|
|
|
|
public bool BiometricLocked { get; set; }
|
|
|
|
public ExtendedObservableCollection<AccountView> AccountViews { get; set; }
|
|
|
|
public StateService(IStorageService storageService, IStorageService secureStorageService)
|
|
{
|
|
_storageService = storageService;
|
|
_secureStorageService = secureStorageService;
|
|
}
|
|
|
|
public async Task<List<string>> GetUserIdsAsync()
|
|
{
|
|
await CheckStateAsync();
|
|
return _state?.Accounts?.Keys.ToList();
|
|
}
|
|
|
|
public async Task<string> GetActiveUserIdAsync()
|
|
{
|
|
await CheckStateAsync();
|
|
|
|
var activeUserId = _state?.ActiveUserId;
|
|
if (activeUserId == null)
|
|
{
|
|
var state = await GetStateFromStorageAsync();
|
|
activeUserId = state?.ActiveUserId;
|
|
}
|
|
return activeUserId;
|
|
}
|
|
|
|
public async Task SetActiveUserAsync(string userId)
|
|
{
|
|
if (userId != null)
|
|
{
|
|
await ValidateUserAsync(userId);
|
|
}
|
|
await CheckStateAsync();
|
|
var state = await GetStateFromStorageAsync();
|
|
state.ActiveUserId = userId;
|
|
await SaveStateToStorageAsync(state);
|
|
_state.ActiveUserId = userId;
|
|
|
|
// Update pre-auth settings based on now-active user
|
|
var rememberEmail = await GetRememberEmailAsync();
|
|
if (rememberEmail.GetValueOrDefault(true))
|
|
{
|
|
await SetRememberedEmailAsync(await GetEmailAsync());
|
|
}
|
|
await SetPreAuthEnvironmentUrlsAsync(await GetEnvironmentUrlsAsync());
|
|
}
|
|
|
|
public async Task<bool> IsAuthenticatedAsync(string userId = null)
|
|
{
|
|
return await GetAccessTokenAsync(userId) != null;
|
|
}
|
|
|
|
public async Task<bool> HasMultipleAccountsAsync()
|
|
{
|
|
await CheckStateAsync();
|
|
return _state.Accounts?.Count > 1;
|
|
}
|
|
|
|
public async Task RefreshAccountViewsAsync(bool allowAddAccountRow)
|
|
{
|
|
await CheckStateAsync();
|
|
|
|
if (AccountViews == null)
|
|
{
|
|
AccountViews = new ExtendedObservableCollection<AccountView>();
|
|
}
|
|
AccountViews.Clear();
|
|
var accountList = _state?.Accounts?.Values.ToList();
|
|
if (accountList == null)
|
|
{
|
|
return;
|
|
}
|
|
var vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
|
foreach (var account in accountList)
|
|
{
|
|
var accountView = new AccountView(account);
|
|
if (accountView.UserId == _state.ActiveUserId)
|
|
{
|
|
accountView.AuthStatus = AuthenticationStatus.Active;
|
|
}
|
|
else
|
|
{
|
|
var isLocked = await vaultTimeoutService.IsLockedAsync(accountView.UserId);
|
|
var shouldTimeout = await vaultTimeoutService.ShouldTimeoutAsync(accountView.UserId);
|
|
if (isLocked || shouldTimeout)
|
|
{
|
|
var action = account.Settings.VaultTimeoutAction;
|
|
accountView.AuthStatus = action == "logOut" ? AuthenticationStatus.LoggedOut
|
|
: AuthenticationStatus.Locked;
|
|
}
|
|
else
|
|
{
|
|
accountView.AuthStatus = AuthenticationStatus.Unlocked;
|
|
}
|
|
}
|
|
AccountViews.Add(accountView);
|
|
}
|
|
if (allowAddAccountRow && AccountViews.Count < Constants.MaxAccounts)
|
|
{
|
|
AccountViews.Add(new AccountView());
|
|
}
|
|
}
|
|
|
|
public async Task AddAccountAsync(Account account)
|
|
{
|
|
await ScaffoldNewAccountAsync(account);
|
|
await SetActiveUserAsync(account.Profile.UserId);
|
|
await RefreshAccountViewsAsync(true);
|
|
}
|
|
|
|
public async Task ClearAsync(string userId)
|
|
{
|
|
if (userId == null)
|
|
{
|
|
throw new Exception("userId cannot be null");
|
|
}
|
|
|
|
await RemoveAccountAsync(userId);
|
|
|
|
// Find the next user to make active, if any
|
|
if (_state?.Accounts != null)
|
|
{
|
|
foreach (var account in _state.Accounts)
|
|
{
|
|
var uid = account.Value?.Profile?.UserId;
|
|
if (uid == null)
|
|
{
|
|
continue;
|
|
}
|
|
if (await IsAuthenticatedAsync(uid))
|
|
{
|
|
await SetActiveUserAsync(uid);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public async Task<EnvironmentUrlData> GetPreAuthEnvironmentUrlsAsync()
|
|
{
|
|
return await GetValueAsync<EnvironmentUrlData>(
|
|
Constants.PreAuthEnvironmentUrlsKey, await GetDefaultStorageOptionsAsync());
|
|
}
|
|
|
|
public async Task SetPreAuthEnvironmentUrlsAsync(EnvironmentUrlData value)
|
|
{
|
|
await SetValueAsync(
|
|
Constants.PreAuthEnvironmentUrlsKey, value, await GetDefaultStorageOptionsAsync());
|
|
}
|
|
|
|
public async Task<EnvironmentUrlData> GetEnvironmentUrlsAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Settings?.EnvironmentUrls;
|
|
}
|
|
|
|
public async Task<bool?> GetBiometricUnlockAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.BiometricUnlockKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetBiometricUnlockAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.BiometricUnlockKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool> CanAccessPremiumAsync(string userId = null)
|
|
{
|
|
if (userId == null)
|
|
{
|
|
userId = await GetActiveUserIdAsync();
|
|
}
|
|
if (!await IsAuthenticatedAsync(userId))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var account = await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync()));
|
|
if (account?.Profile?.HasPremiumPersonally.GetValueOrDefault() ?? false)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
var organizationService = ServiceContainer.Resolve<IOrganizationService>("organizationService");
|
|
var organizations = await organizationService.GetAllAsync(userId);
|
|
return organizations?.Any(o => o.UsersGetPremium && o.Enabled) ?? false;
|
|
}
|
|
|
|
public async Task<string> GetProtectedPinAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultSecureStorageOptionsAsync());
|
|
var key = Constants.ProtectedPinKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetProtectedPinAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultSecureStorageOptionsAsync());
|
|
var key = Constants.ProtectedPinKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetPinProtectedAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PinProtectedKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetPinProtectedAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PinProtectedKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<EncString> GetPinProtectedCachedAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Settings?.PinProtected;
|
|
}
|
|
|
|
public async Task SetPinProtectedCachedAsync(EncString value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var account = await GetAccountAsync(reconciledOptions);
|
|
account.Settings.PinProtected = value;
|
|
await SaveAccountAsync(account, reconciledOptions);
|
|
}
|
|
|
|
public async Task<KdfType?> GetKdfTypeAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Profile?.KdfType;
|
|
}
|
|
|
|
public async Task SetKdfTypeAsync(KdfType? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var account = await GetAccountAsync(reconciledOptions);
|
|
account.Profile.KdfType = value;
|
|
await SaveAccountAsync(account, reconciledOptions);
|
|
}
|
|
|
|
public async Task<int?> GetKdfIterationsAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Profile?.KdfIterations;
|
|
}
|
|
|
|
public async Task SetKdfIterationsAsync(int? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var account = await GetAccountAsync(reconciledOptions);
|
|
account.Profile.KdfIterations = value;
|
|
await SaveAccountAsync(account, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetKeyEncryptedAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultSecureStorageOptionsAsync());
|
|
var key = Constants.KeyKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetKeyEncryptedAsync(string value, string userId)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultSecureStorageOptionsAsync());
|
|
var key = Constants.KeyKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<SymmetricCryptoKey> GetKeyDecryptedAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync())
|
|
))?.Keys?.Key;
|
|
}
|
|
|
|
public async Task SetKeyDecryptedAsync(SymmetricCryptoKey value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultInMemoryOptionsAsync());
|
|
var account = await GetAccountAsync(reconciledOptions);
|
|
account.Keys.Key = value;
|
|
await SaveAccountAsync(account, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetKeyHashAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.KeyHashKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetKeyHashAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.KeyHashKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetEncKeyEncryptedAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.EncKeyKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetEncKeyEncryptedAsync(string value, string userId)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.EncKeyKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<Dictionary<string, string>> GetOrgKeysEncryptedAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.EncOrgKeysKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<Dictionary<string, string>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetOrgKeysEncryptedAsync(Dictionary<string, string> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.EncOrgKeysKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetPrivateKeyEncryptedAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.EncPrivateKeyKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetPrivateKeyEncryptedAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.EncPrivateKeyKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<List<string>> GetAutofillBlacklistedUrisAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AutofillBlacklistedUrisKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<List<string>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetAutofillBlacklistedUrisAsync(List<string> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AutofillBlacklistedUrisKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetAutofillTileAddedAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AutofillTileAdded;
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetAutofillTileAddedAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AutofillTileAdded;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetEmailAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Profile?.Email;
|
|
}
|
|
|
|
public async Task<long?> GetLastActiveTimeAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.LastActiveTimeKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<long?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetLastActiveTimeAsync(long? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.LastActiveTimeKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<int?> GetVaultTimeoutAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Settings?.VaultTimeout;
|
|
}
|
|
|
|
public async Task SetVaultTimeoutAsync(int? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var account = await GetAccountAsync(reconciledOptions);
|
|
account.Settings.VaultTimeout = value;
|
|
await SaveAccountAsync(account, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetVaultTimeoutActionAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Settings?.VaultTimeoutAction;
|
|
}
|
|
|
|
public async Task SetVaultTimeoutActionAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var account = await GetAccountAsync(reconciledOptions);
|
|
account.Settings.VaultTimeoutAction = value;
|
|
await SaveAccountAsync(account, reconciledOptions);
|
|
}
|
|
|
|
public async Task<DateTime?> GetLastFileCacheClearAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.LastFileCacheClearKey;
|
|
return await GetValueAsync<DateTime?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetLastFileCacheClearAsync(DateTime? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.LastFileCacheClearKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<PreviousPageInfo> GetPreviousPageInfoAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PreviousPageKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<PreviousPageInfo>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetPreviousPageInfoAsync(PreviousPageInfo value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PreviousPageKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<int> GetInvalidUnlockAttemptsAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.InvalidUnlockAttemptsKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<int>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetInvalidUnlockAttemptsAsync(int? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.InvalidUnlockAttemptsKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetLastBuildAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.LastBuildKey;
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetLastBuildAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.LastBuildKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetDisableFaviconAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.DisableFaviconKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetDisableFaviconAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.DisableFaviconKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetDisableAutoTotpCopyAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.DisableAutoTotpCopyKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetDisableAutoTotpCopyAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.DisableAutoTotpCopyKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetInlineAutofillEnabledAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.InlineAutofillEnabledKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetInlineAutofillEnabledAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.InlineAutofillEnabledKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetAutofillDisableSavePromptAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AutofillDisableSavePromptKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetAutofillDisableSavePromptAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AutofillDisableSavePromptKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<Dictionary<string, Dictionary<string, object>>> GetLocalDataAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.LocalDataKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<Dictionary<string, Dictionary<string, object>>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetLocalDataAsync(Dictionary<string, Dictionary<string, object>> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.LocalDataKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<Dictionary<string, CipherData>> GetEncryptedCiphersAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.CiphersKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<Dictionary<string, CipherData>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetEncryptedCiphersAsync(Dictionary<string, CipherData> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.CiphersKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<int?> GetDefaultUriMatchAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.DefaultUriMatchKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<int?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetDefaultUriMatchAsync(int? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.DefaultUriMatchKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<HashSet<string>> GetNeverDomainsAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.NeverDomainsKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<HashSet<string>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetNeverDomainsAsync(HashSet<string> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.NeverDomainsKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<int?> GetClearClipboardAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.ClearClipboardKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<int?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetClearClipboardAsync(int? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.ClearClipboardKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<Dictionary<string, CollectionData>> GetEncryptedCollectionsAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.CollectionsKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<Dictionary<string, CollectionData>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetEncryptedCollectionsAsync(Dictionary<string, CollectionData> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.CollectionsKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool> GetPasswordRepromptAutofillAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PasswordRepromptAutofillKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<bool?>(key, reconciledOptions) ?? false;
|
|
}
|
|
|
|
public async Task SetPasswordRepromptAutofillAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PasswordRepromptAutofillKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool> GetPasswordVerifiedAutofillAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PasswordVerifiedAutofillKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<bool?>(key, reconciledOptions) ?? false;
|
|
}
|
|
|
|
public async Task SetPasswordVerifiedAutofillAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PasswordVerifiedAutofillKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<DateTime?> GetLastSyncAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.LastSyncKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<DateTime?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetLastSyncAsync(DateTime? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.LastSyncKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetSecurityStampAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Profile?.Stamp;
|
|
}
|
|
|
|
public async Task SetSecurityStampAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var account = await GetAccountAsync(reconciledOptions);
|
|
account.Profile.Stamp = value;
|
|
await SaveAccountAsync(account, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool> GetEmailVerifiedAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Profile?.EmailVerified ?? false;
|
|
}
|
|
|
|
public async Task SetEmailVerifiedAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var account = await GetAccountAsync(reconciledOptions);
|
|
account.Profile.EmailVerified = value;
|
|
await SaveAccountAsync(account, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool> GetForcePasswordReset(string userId)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.ForcePasswordResetKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<bool?>(key, reconciledOptions) ?? false;
|
|
}
|
|
|
|
public async Task SetForcePasswordResetAsync(bool? value, string userId)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.ForcePasswordResetKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool> GetSyncOnRefreshAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.SyncOnRefreshKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<bool?>(key, reconciledOptions) ?? false;
|
|
}
|
|
|
|
public async Task SetSyncOnRefreshAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.SyncOnRefreshKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetRememberedEmailAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.RememberedEmailKey;
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetRememberedEmailAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.RememberedEmailKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetRememberEmailAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.RememberEmailKey;
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetRememberEmailAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.RememberEmailKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetRememberedOrgIdentifierAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.RememberedOrgIdentifierKey;
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetRememberedOrgIdentifierAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.RememberedOrgIdentifierKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetRememberOrgIdentifierAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.RememberOrgIdentifierKey;
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetRememberOrgIdentifierAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.RememberOrgIdentifierKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetThemeAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.ThemeKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetThemeAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.ThemeKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetAddSitePromptShownAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AddSitePromptShownKey;
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetAddSitePromptShownAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AddSitePromptShownKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetMigratedFromV1Async(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.MigratedFromV1;
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetMigratedFromV1Async(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.MigratedFromV1;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetMigratedFromV1AutofillPromptShownAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.MigratedFromV1AutofillPromptShown;
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetMigratedFromV1AutofillPromptShownAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.MigratedFromV1AutofillPromptShown;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetTriedV1ResyncAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.TriedV1Resync;
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetTriedV1ResyncAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.TriedV1Resync;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetPushInitialPromptShownAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PushInitialPromptShownKey;
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetPushInitialPromptShownAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PushInitialPromptShownKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<DateTime?> GetPushLastRegistrationDateAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PushLastRegistrationDateKey;
|
|
return await GetValueAsync<DateTime?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetPushLastRegistrationDateAsync(DateTime? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PushLastRegistrationDateKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetPushCurrentTokenAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PushCurrentTokenKey;
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetPushCurrentTokenAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PushCurrentTokenKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<List<EventData>> GetEventCollectionAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.EventCollectionKey;
|
|
return await GetValueAsync<List<EventData>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetEventCollectionAsync(List<EventData> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.EventCollectionKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<Dictionary<string, FolderData>> GetEncryptedFoldersAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.FoldersKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<Dictionary<string, FolderData>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetEncryptedFoldersAsync(Dictionary<string, FolderData> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.FoldersKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<Dictionary<string, PolicyData>> GetEncryptedPoliciesAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PoliciesKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<Dictionary<string, PolicyData>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetEncryptedPoliciesAsync(Dictionary<string, PolicyData> value, string userId)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PoliciesKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetPushRegisteredTokenAsync()
|
|
{
|
|
var options = await GetDefaultStorageOptionsAsync();
|
|
var key = Constants.PushRegisteredTokenKey;
|
|
return await GetValueAsync<string>(key, options);
|
|
}
|
|
|
|
public async Task SetPushRegisteredTokenAsync(string value)
|
|
{
|
|
var options = await GetDefaultStorageOptionsAsync();
|
|
var key = Constants.PushRegisteredTokenKey;
|
|
await SetValueAsync(key, value, options);
|
|
}
|
|
|
|
public async Task<bool?> GetAppExtensionStartedAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AppExtensionStartedKey;
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetAppExtensionStartedAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AppExtensionStartedKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool?> GetAppExtensionActivatedAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AppExtensionActivatedKey;
|
|
return await GetValueAsync<bool?>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetAppExtensionActivatedAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AppExtensionActivatedKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetAppIdAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AppIdKey;
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetAppIdAsync(string value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.AppIdKey;
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<bool> GetUsesKeyConnectorAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.UsesKeyConnectorKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<bool?>(key, reconciledOptions) ?? false;
|
|
}
|
|
|
|
public async Task SetUsesKeyConnectorAsync(bool? value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.UsesKeyConnectorKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<Dictionary<string, OrganizationData>> GetOrganizationsAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.OrganizationsKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<Dictionary<string, OrganizationData>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetOrganizationsAsync(Dictionary<string, OrganizationData> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.OrganizationsKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<PasswordGenerationOptions> GetPasswordGenerationOptionsAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PassGenOptionsKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<PasswordGenerationOptions>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetPasswordGenerationOptionsAsync(PasswordGenerationOptions value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PassGenOptionsKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<List<GeneratedPasswordHistory>> GetEncryptedPasswordGenerationHistory(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PassGenHistoryKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<List<GeneratedPasswordHistory>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetEncryptedPasswordGenerationHistoryAsync(List<GeneratedPasswordHistory> value,
|
|
string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.PassGenHistoryKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<Dictionary<string, SendData>> GetEncryptedSendsAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.SendsKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<Dictionary<string, SendData>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetEncryptedSendsAsync(Dictionary<string, SendData> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.SendsKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<Dictionary<string, object>> GetSettingsAsync(string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.SettingsKey(reconciledOptions.UserId);
|
|
return await GetValueAsync<Dictionary<string, object>>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetSettingsAsync(Dictionary<string, object> value, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.SettingsKey(reconciledOptions.UserId);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetAccessTokenAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Tokens?.AccessToken;
|
|
}
|
|
|
|
public async Task SetAccessTokenAsync(string value, bool skipTokenStorage, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(
|
|
new StorageOptions { UserId = userId, SkipTokenStorage = skipTokenStorage },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var account = await GetAccountAsync(reconciledOptions);
|
|
account.Tokens.AccessToken = value;
|
|
await SaveAccountAsync(account, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetRefreshTokenAsync(string userId = null)
|
|
{
|
|
return (await GetAccountAsync(
|
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
|
))?.Tokens?.RefreshToken;
|
|
}
|
|
|
|
public async Task SetRefreshTokenAsync(string value, bool skipTokenStorage, string userId = null)
|
|
{
|
|
var reconciledOptions = ReconcileOptions(
|
|
new StorageOptions { UserId = userId, SkipTokenStorage = skipTokenStorage },
|
|
await GetDefaultStorageOptionsAsync());
|
|
var account = await GetAccountAsync(reconciledOptions);
|
|
account.Tokens.RefreshToken = value;
|
|
await SaveAccountAsync(account, reconciledOptions);
|
|
}
|
|
|
|
public async Task<string> GetTwoFactorTokenAsync(string email = null)
|
|
{
|
|
var reconciledOptions =
|
|
ReconcileOptions(new StorageOptions { Email = email }, await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.TwoFactorTokenKey(reconciledOptions.Email);
|
|
return await GetValueAsync<string>(key, reconciledOptions);
|
|
}
|
|
|
|
public async Task SetTwoFactorTokenAsync(string value, string email = null)
|
|
{
|
|
var reconciledOptions =
|
|
ReconcileOptions(new StorageOptions { Email = email }, await GetDefaultStorageOptionsAsync());
|
|
var key = Constants.TwoFactorTokenKey(reconciledOptions.Email);
|
|
await SetValueAsync(key, value, reconciledOptions);
|
|
}
|
|
|
|
// Helpers
|
|
|
|
private async Task<T> GetValueAsync<T>(string key, StorageOptions options)
|
|
{
|
|
var value = await GetStorageService(options).GetAsync<T>(key);
|
|
Log("GET", options, key, JsonConvert.SerializeObject(value));
|
|
return value;
|
|
}
|
|
|
|
private async Task SetValueAsync<T>(string key, T value, StorageOptions options)
|
|
{
|
|
if (value == null)
|
|
{
|
|
Log("REMOVE", options, key, null);
|
|
await GetStorageService(options).RemoveAsync(key);
|
|
return;
|
|
}
|
|
Log("SET", options, key, JsonConvert.SerializeObject(value));
|
|
await GetStorageService(options).SaveAsync(key, value);
|
|
}
|
|
|
|
private IStorageService GetStorageService(StorageOptions options)
|
|
{
|
|
return options.UseSecureStorage.GetValueOrDefault(false) ? _secureStorageService : _storageService;
|
|
}
|
|
|
|
private async Task<Account> GetAccountAsync(StorageOptions options)
|
|
{
|
|
await CheckStateAsync();
|
|
|
|
if (options?.UserId == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// Memory
|
|
if (_state?.Accounts?.ContainsKey(options.UserId) ?? false)
|
|
{
|
|
if (_state.Accounts[options.UserId].Keys == null)
|
|
{
|
|
_state.Accounts[options.UserId].Keys = new Account.AccountKeys();
|
|
}
|
|
return _state.Accounts[options.UserId];
|
|
}
|
|
|
|
// Storage
|
|
_state = await GetStateFromStorageAsync();
|
|
if (_state?.Accounts?.ContainsKey(options.UserId) ?? false)
|
|
{
|
|
if (_state.Accounts[options.UserId].Keys == null)
|
|
{
|
|
_state.Accounts[options.UserId].Keys = new Account.AccountKeys();
|
|
}
|
|
return _state.Accounts[options.UserId];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async Task SaveAccountAsync(Account account, StorageOptions options = null)
|
|
{
|
|
if (account?.Profile?.UserId == null)
|
|
{
|
|
throw new Exception("account?.Profile?.UserId cannot be null");
|
|
}
|
|
|
|
await CheckStateAsync();
|
|
|
|
// Memory
|
|
if (UseMemory(options))
|
|
{
|
|
if (_state.Accounts == null)
|
|
{
|
|
_state.Accounts = new Dictionary<string, Account>();
|
|
}
|
|
_state.Accounts[account.Profile.UserId] = account;
|
|
}
|
|
|
|
// Storage
|
|
if (UseDisk(options))
|
|
{
|
|
var state = await GetStateFromStorageAsync() ?? new State();
|
|
if (state.Accounts == null)
|
|
{
|
|
state.Accounts = new Dictionary<string, Account>();
|
|
}
|
|
|
|
// Use Account copy constructor to clone with keys excluded (for storage)
|
|
state.Accounts[account.Profile.UserId] = new Account(account);
|
|
|
|
// If we have a vault timeout and the action is log out, don't store token
|
|
if (options?.SkipTokenStorage.GetValueOrDefault() ?? false)
|
|
{
|
|
state.Accounts[account.Profile.UserId].Tokens.AccessToken = null;
|
|
state.Accounts[account.Profile.UserId].Tokens.RefreshToken = null;
|
|
}
|
|
|
|
await SaveStateToStorageAsync(state);
|
|
}
|
|
}
|
|
|
|
private async Task RemoveAccountAsync(string userId)
|
|
{
|
|
if (userId == null)
|
|
{
|
|
throw new Exception("userId cannot be null");
|
|
}
|
|
|
|
await CheckStateAsync();
|
|
|
|
// Memory
|
|
if (_state?.Accounts?.ContainsKey(userId) ?? false)
|
|
{
|
|
_state?.Accounts?.Remove(userId);
|
|
}
|
|
if (_state?.ActiveUserId == userId)
|
|
{
|
|
_state.ActiveUserId = null;
|
|
}
|
|
|
|
// Storage
|
|
var stateModified = false;
|
|
var state = await GetStateFromStorageAsync();
|
|
if (state?.Accounts?.ContainsKey(userId) ?? false)
|
|
{
|
|
state.Accounts.Remove(userId);
|
|
stateModified = true;
|
|
}
|
|
if (state?.ActiveUserId == userId)
|
|
{
|
|
state.ActiveUserId = null;
|
|
stateModified = true;
|
|
}
|
|
if (stateModified)
|
|
{
|
|
await SaveStateToStorageAsync(state);
|
|
}
|
|
|
|
// Secure Storage
|
|
await SetProtectedPinAsync(null, userId);
|
|
await SetKeyEncryptedAsync(null, userId);
|
|
}
|
|
|
|
private async Task ScaffoldNewAccountAsync(Account account)
|
|
{
|
|
await CheckStateAsync();
|
|
|
|
account.Settings.EnvironmentUrls = await GetPreAuthEnvironmentUrlsAsync();
|
|
|
|
// Storage
|
|
var state = await GetStateFromStorageAsync() ?? new State();
|
|
if (state.Accounts == null)
|
|
{
|
|
state.Accounts = new Dictionary<string, Account>();
|
|
}
|
|
if (state.Accounts.ContainsKey(account.Profile.UserId))
|
|
{
|
|
// Account data already exists, restore appropriate data
|
|
account.Settings.VaultTimeout = state.Accounts[account.Profile.UserId].Settings?.VaultTimeout;
|
|
account.Settings.VaultTimeoutAction =
|
|
state.Accounts[account.Profile.UserId].Settings?.VaultTimeoutAction;
|
|
}
|
|
else
|
|
{
|
|
// New account, set defaults
|
|
account.Settings.VaultTimeout = 15;
|
|
account.Settings.VaultTimeoutAction = "lock";
|
|
}
|
|
state.Accounts[account.Profile.UserId] = account;
|
|
await SaveStateToStorageAsync(state);
|
|
|
|
// Memory
|
|
if (_state == null)
|
|
{
|
|
_state = state;
|
|
}
|
|
else
|
|
{
|
|
if (_state.Accounts == null)
|
|
{
|
|
_state.Accounts = new Dictionary<string, Account>();
|
|
}
|
|
_state.Accounts[account.Profile.UserId] = account;
|
|
}
|
|
}
|
|
|
|
private StorageOptions ReconcileOptions(StorageOptions requestedOptions, StorageOptions defaultOptions)
|
|
{
|
|
if (requestedOptions == null)
|
|
{
|
|
return defaultOptions;
|
|
}
|
|
requestedOptions.StorageLocation = requestedOptions.StorageLocation ?? defaultOptions.StorageLocation;
|
|
requestedOptions.UseSecureStorage = requestedOptions.UseSecureStorage ?? defaultOptions.UseSecureStorage;
|
|
requestedOptions.UserId = requestedOptions.UserId ?? defaultOptions.UserId;
|
|
requestedOptions.Email = requestedOptions.Email ?? defaultOptions.Email;
|
|
requestedOptions.SkipTokenStorage = requestedOptions.SkipTokenStorage ?? defaultOptions.SkipTokenStorage;
|
|
return requestedOptions;
|
|
}
|
|
|
|
private async Task<StorageOptions> GetDefaultStorageOptionsAsync()
|
|
{
|
|
return new StorageOptions()
|
|
{
|
|
StorageLocation = StorageLocation.Both,
|
|
UserId = await GetActiveUserIdAsync(),
|
|
};
|
|
}
|
|
|
|
private async Task<StorageOptions> GetDefaultSecureStorageOptionsAsync()
|
|
{
|
|
return new StorageOptions()
|
|
{
|
|
StorageLocation = StorageLocation.Disk,
|
|
UseSecureStorage = true,
|
|
UserId = await GetActiveUserIdAsync(),
|
|
};
|
|
}
|
|
|
|
private async Task<StorageOptions> GetDefaultInMemoryOptionsAsync()
|
|
{
|
|
return new StorageOptions()
|
|
{
|
|
StorageLocation = StorageLocation.Memory,
|
|
UserId = await GetActiveUserIdAsync(),
|
|
};
|
|
}
|
|
|
|
private bool UseMemory(StorageOptions options)
|
|
{
|
|
return options?.StorageLocation == StorageLocation.Memory ||
|
|
options?.StorageLocation == StorageLocation.Both;
|
|
}
|
|
|
|
private bool UseDisk(StorageOptions options)
|
|
{
|
|
return options?.StorageLocation == StorageLocation.Disk ||
|
|
options?.StorageLocation == StorageLocation.Both;
|
|
}
|
|
|
|
private async Task<State> GetStateFromStorageAsync()
|
|
{
|
|
var state = await _storageService.GetAsync<State>(Constants.StateKey);
|
|
// TODO Remove logging once all bugs are squished
|
|
Debug.WriteLine(JsonConvert.SerializeObject(state, Formatting.Indented),
|
|
">>> GetStateFromStorageAsync()");
|
|
return state;
|
|
}
|
|
|
|
private async Task SaveStateToStorageAsync(State state)
|
|
{
|
|
await _storageService.SaveAsync(Constants.StateKey, state);
|
|
// TODO Remove logging once all bugs are squished
|
|
Debug.WriteLine(JsonConvert.SerializeObject(state, Formatting.Indented),
|
|
">>> SaveStateToStorageAsync()");
|
|
}
|
|
|
|
private async Task CheckStateAsync()
|
|
{
|
|
// TODO perform migration if necessary
|
|
|
|
if (_state == null)
|
|
{
|
|
_state = await GetStateFromStorageAsync() ?? new State();
|
|
}
|
|
}
|
|
|
|
private async Task<bool> IsLockedAsync(string userId)
|
|
{
|
|
if (userId == null)
|
|
{
|
|
userId = await GetActiveUserIdAsync();
|
|
}
|
|
bool hasKey;
|
|
var inMemoryKey = await GetKeyDecryptedAsync(userId);
|
|
if (inMemoryKey != null)
|
|
{
|
|
hasKey = true;
|
|
}
|
|
else
|
|
{
|
|
var storedKey = await GetKeyEncryptedAsync(userId);
|
|
hasKey = storedKey != null;
|
|
}
|
|
if (hasKey)
|
|
{
|
|
var biometricLock = await GetBiometricUnlockAsync(userId);
|
|
var biometricSet = biometricLock.GetValueOrDefault();
|
|
if (biometricSet && BiometricLocked)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return !hasKey;
|
|
}
|
|
|
|
private async Task ValidateUserAsync(string userId)
|
|
{
|
|
if (string.IsNullOrEmpty(userId))
|
|
{
|
|
throw new Exception("userId cannot be null or empty");
|
|
}
|
|
await CheckStateAsync();
|
|
var accounts = _state?.Accounts;
|
|
if (accounts == null || !accounts.Any())
|
|
{
|
|
throw new Exception("At least one account required to validate user");
|
|
}
|
|
foreach (var account in accounts)
|
|
{
|
|
if (account.Key == userId)
|
|
{
|
|
// found match, user is valid
|
|
return;
|
|
}
|
|
}
|
|
throw new Exception("User does not exist in account list");
|
|
}
|
|
|
|
private void Log(string tag, StorageOptions options, string key, string value)
|
|
{
|
|
// TODO Remove this once all bugs are squished
|
|
var text = options?.UseSecureStorage ?? false ? "SECURE / " : "";
|
|
text += "Key: " + key + " / ";
|
|
if (value != null)
|
|
{
|
|
text += "Value: " + value;
|
|
}
|
|
Debug.WriteLine(text, ">>> " + tag);
|
|
}
|
|
}
|
|
}
|