1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-05 23:53:33 +00:00
This commit is contained in:
Matt Portune
2022-01-17 21:58:04 -05:00
parent 120fb70039
commit 65739489a7
43 changed files with 893 additions and 1068 deletions

View File

@@ -80,11 +80,12 @@ namespace Bit.App
}
else if (message.Command == "logout")
{
var extras = message.Data as Tuple<bool?, string>;
var expired = extras?.Item1;
var userId = extras?.Item2;
var extras = message.Data as Tuple<string, bool, bool>;
var userId = extras?.Item1;
var userInitiated = extras?.Item2;
var expired = extras?.Item3;
Device.BeginInvokeOnMainThread(async () =>
await LogOutAsync(expired.GetValueOrDefault(), userId));
await LogOutAsync(userId, userInitiated, expired));
}
else if (message.Command == "loggedOut")
{
@@ -111,7 +112,7 @@ namespace Bit.App
}
else if (message.Command == "switchedAccount")
{
await SwitchedAccount();
await SwitchedAccountAsync();
}
else if (message.Command == "migrated")
{
@@ -241,13 +242,13 @@ namespace Bit.App
new System.Globalization.UmAlQuraCalendar();
}
private async Task LogOutAsync(bool expired, string userId)
private async Task LogOutAsync(string userId, bool? userInitiated, bool? expired)
{
await AppHelpers.LogOutAsync(userId);
await AppHelpers.LogOutAsync(userId, userInitiated.GetValueOrDefault(true));
await SetMainPageAsync();
_authService.LogOut(() =>
{
Current.MainPage = new NavigationPage(new HomePage(Options));
if (expired)
if (expired.GetValueOrDefault())
{
_platformUtilsService.ShowToast("warning", null, AppResources.LoginExpired);
}
@@ -258,14 +259,14 @@ namespace Bit.App
{
Device.BeginInvokeOnMainThread(async () =>
{
Options.ShowAccountSwitcher = true;
Current.MainPage = new NavigationPage(new HomePage(Options));
});
}
private async Task SwitchedAccount()
private async Task SwitchedAccountAsync()
{
await AppHelpers.ClearServiceCache();
await AppHelpers.OnAccountSwitchAsync();
UpdateTheme();
Device.BeginInvokeOnMainThread(async () =>
{
await SetMainPageAsync();
@@ -274,10 +275,7 @@ namespace Bit.App
private async Task SetMainPageAsync()
{
if (await _stateService.HasMultipleAccountsAsync())
{
Options.ShowAccountSwitcher = true;
}
await _stateService.RefreshAccountViews();
var authed = await _stateService.IsAuthenticatedAsync();
if (authed)
{

View File

@@ -45,13 +45,13 @@
<Label
Grid.Column="0"
Grid.Row="0"
Text="{Binding Account.Email}"
Text="{Binding AccountView.Email}"
StyleClass="list-title"
LineBreakMode="TailTruncation" />
<Label
Grid.Column="0"
Grid.Row="1"
Text="{Binding Account.Hostname}"
Text="{Binding AccountView.Hostname}"
StyleClass="list-sub"
LineBreakMode="TailTruncation" />
</Grid>

View File

@@ -5,27 +5,27 @@ namespace Bit.App.Controls
{
public class AccountViewCellViewModel : ExtendedViewModel
{
private AccountView _account;
private AccountView _accountView;
public AccountViewCellViewModel(AccountView accountView)
{
Account = accountView;
AccountView = accountView;
}
public AccountView Account
public AccountView AccountView
{
get => _account;
set => SetProperty(ref _account, value);
get => _accountView;
set => SetProperty(ref _accountView, value);
}
public bool IsAccount
{
get => Account.IsAccount;
get => AccountView.IsAccount;
}
public string AuthStatusText
{
get => Account.AuthStatus.ToString();
get => AccountView.AuthStatus.ToString();
}
}
}

View File

@@ -100,7 +100,8 @@ namespace Bit.App.Controls
for (var i = 0; i < 3; i++)
{
var value = (hash >> (i * 8)) & 0xff;
color += Convert.ToString(value, 16);
var base16 = "00" + Convert.ToString(value, 16);
color += base16.Substring(base16.Length - 2);
}
if (Device.RuntimePlatform == Device.iOS)
{

View File

@@ -21,7 +21,6 @@ namespace Bit.App.Models
public string SaveCardCode { get; set; }
public bool IosExtension { get; set; }
public Tuple<SendType, string, byte[], string> CreateSend { get; set; }
public bool ShowAccountSwitcher { get; set; }
public void SetAllFrom(AppOptions o)
{
@@ -45,7 +44,6 @@ namespace Bit.App.Models
SaveCardCode = o.SaveCardCode;
IosExtension = o.IosExtension;
CreateSend = o.CreateSend;
ShowAccountSwitcher = o.ShowAccountSwitcher;
}
}
}

View File

@@ -88,7 +88,7 @@
xct:ShadowEffect.Radius="10"
xct:ShadowEffect.OffsetY="3">
<ListView
ItemsSource="{Binding Accounts}"
ItemsSource="{Binding AccountViews}"
ItemSelected="AccountRow_Selected"
VerticalOptions="FillAndExpand"
RowHeight="60">

View File

@@ -14,6 +14,8 @@ namespace Bit.App.Pages
private readonly AppOptions _appOptions;
private IBroadcasterService _broadcasterService;
private bool _appeared;
public HomePage(AppOptions appOptions = null)
{
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
@@ -31,10 +33,6 @@ namespace Bit.App.Pages
{
ToolbarItems.Add(_closeItem);
}
if (_appOptions?.ShowAccountSwitcher ?? false)
{
ToolbarItems.Add(_accountAvatar);
}
}
public async Task DismissRegisterPageAndLogInAsync(string email)
@@ -46,12 +44,6 @@ namespace Bit.App.Pages
protected override async void OnAppearing()
{
base.OnAppearing();
_mainContent.Content = _mainLayout;
if (_appOptions?.ShowAccountSwitcher ?? false)
{
_appOptions.ShowAccountSwitcher = false;
_vm.AvatarImageSource = await GetAvatarImageSourceAsync();
}
_broadcasterService.Subscribe(nameof(HomePage), async (message) =>
{
if (message.Command == "updatedTheme")
@@ -62,6 +54,17 @@ namespace Bit.App.Pages
});
}
});
if (_appeared)
{
return;
}
_appeared = true;
_mainContent.Content = _mainLayout;
if (await HasMultipleAccountsAsync())
{
ToolbarItems.Add(_accountAvatar);
_vm.AvatarImageSource = await GetAvatarImageSourceAsync(false);
}
}
protected override void OnDisappearing()

View File

@@ -17,9 +17,9 @@ namespace Bit.App.Pages
PageTitle = AppResources.Bitwarden;
}
public ExtendedObservableCollection<AccountView> Accounts
public ExtendedObservableCollection<AccountView> AccountViews
{
get => _stateService.Accounts;
get => _stateService.AccountViews;
}
public Action StartLoginAction { get; set; }

View File

@@ -178,7 +178,7 @@
xct:ShadowEffect.Radius="10"
xct:ShadowEffect.OffsetY="3">
<ListView
ItemsSource="{Binding Accounts}"
ItemsSource="{Binding AccountViews}"
ItemSelected="AccountRow_Selected"
VerticalOptions="FillAndExpand"
RowHeight="60">

View File

@@ -27,10 +27,6 @@ namespace Bit.App.Pages
MasterPasswordEntry = _masterPassword;
PinEntry = _pin;
if (_appOptions?.ShowAccountSwitcher ?? false)
{
ToolbarItems.Add(_accountAvatar);
}
if (Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.Add(_moreItem);
@@ -66,9 +62,9 @@ namespace Bit.App.Pages
}
_appeared = true;
_mainContent.Content = _mainLayout;
if (_appOptions?.ShowAccountSwitcher ?? false)
if (await HasMultipleAccountsAsync())
{
_appOptions.ShowAccountSwitcher = false;
ToolbarItems.Add(_accountAvatar);
_vm.AvatarImageSource = await GetAvatarImageSourceAsync();
}
await _vm.InitAsync();

View File

@@ -113,9 +113,9 @@ namespace Bit.App.Pages
set => SetProperty(ref _lockedVerifyText, value);
}
public ExtendedObservableCollection<AccountView> Accounts
public ExtendedObservableCollection<AccountView> AccountViews
{
get => _stateService.Accounts;
get => _stateService.AccountViews;
}
public Command SubmitCommand { get; }

View File

@@ -130,7 +130,7 @@
xct:ShadowEffect.Radius="10"
xct:ShadowEffect.OffsetY="3">
<ListView
ItemsSource="{Binding Accounts}"
ItemsSource="{Binding AccountViews}"
ItemSelected="AccountRow_Selected"
VerticalOptions="FillAndExpand"
RowHeight="60">

View File

@@ -12,6 +12,7 @@ namespace Bit.App.Pages
private readonly LoginPageViewModel _vm;
private readonly AppOptions _appOptions;
private bool _appeared;
private bool _inputFocused;
public LoginPage(string email = null, AppOptions appOptions = null)
@@ -34,11 +35,6 @@ namespace Bit.App.Pages
{
ToolbarItems.RemoveAt(0);
}
if (_appOptions?.ShowAccountSwitcher ?? false)
{
ToolbarItems.Add(_accountAvatar);
ToolbarItems.Remove(_closeItem);
}
_email.ReturnType = ReturnType.Next;
_email.ReturnCommand = new Command(() => _masterPassword.Focus());
@@ -58,18 +54,24 @@ namespace Bit.App.Pages
protected override async void OnAppearing()
{
base.OnAppearing();
_mainContent.Content = _mainLayout;
if (_appOptions?.ShowAccountSwitcher ?? false)
{
_appOptions.ShowAccountSwitcher = false;
_vm.AvatarImageSource = await GetAvatarImageSourceAsync();
}
await _vm.InitAsync();
if (!_inputFocused)
{
RequestFocus(string.IsNullOrWhiteSpace(_vm.Email) ? _email : _masterPassword);
_inputFocused = true;
}
if (_appeared)
{
return;
}
_appeared = true;
_mainContent.Content = _mainLayout;
if (await HasMultipleAccountsAsync())
{
ToolbarItems.Add(_accountAvatar);
ToolbarItems.Remove(_closeItem);
_vm.AvatarImageSource = await GetAvatarImageSourceAsync();
}
}
private async void LogIn_Clicked(object sender, EventArgs e)

View File

@@ -62,9 +62,9 @@ namespace Bit.App.Pages
set => SetProperty(ref _masterPassword, value);
}
public ExtendedObservableCollection<AccountView> Accounts
public ExtendedObservableCollection<AccountView> AccountViews
{
get => _stateService.Accounts;
get => _stateService.AccountViews;
}
public Command LogInCommand { get; }

View File

@@ -38,6 +38,11 @@ namespace Bit.App.Pages
await SaveActivity();
}
public async Task<bool> HasMultipleAccountsAsync()
{
return await _stateService.HasMultipleAccountsAsync();
}
public bool DoOnce(Action action = null, int milliseconds = 1000)
{
if (LastPageAction.HasValue && (DateTime.UtcNow - LastPageAction.Value).TotalMilliseconds < milliseconds)
@@ -108,9 +113,9 @@ namespace Bit.App.Pages
});
}
protected async Task<AvatarImageSource> GetAvatarImageSourceAsync()
protected async Task<AvatarImageSource> GetAvatarImageSourceAsync(bool useCurrentActiveAccount = true)
{
return new AvatarImageSource(await _stateService.GetEmailAsync());
return new AvatarImageSource(useCurrentActiveAccount ? await _stateService.GetEmailAsync() : null);
}
protected async Task ShowAccountListAsync(bool isVisible, View listView, View overlay, View fab = null)
@@ -120,6 +125,9 @@ namespace Bit.App.Pages
// Not all animations are awaited. This is intentional to allow multiple simultaneous animations.
if (isVisible)
{
// Update account views to reflect current state
await _stateService.RefreshAccountViews();
// start listView in default (off-screen) position
await listView.TranslateTo(0, listView.Height * -1, 0);
@@ -173,13 +181,13 @@ namespace Bit.App.Pages
await Task.Delay(100);
await ShowAccountListAsync(false, listView, overlay, fab);
if (item.Account.IsAccount)
if (item.AccountView.IsAccount)
{
if (item.Account.AuthStatus != AuthenticationStatus.Active)
if (item.AccountView.AuthStatus != AuthenticationStatus.Active)
{
await _stateService.SetActiveUserAsync(item.Account.UserId);
_messagingService.Send("switchedAccount");
await _stateService.SetActiveUserAsync(item.AccountView.UserId);
}
_messagingService.Send("switchedAccount");
}
else
{

View File

@@ -180,7 +180,7 @@
xct:ShadowEffect.Radius="10"
xct:ShadowEffect.OffsetY="3">
<ListView
ItemsSource="{Binding Accounts}"
ItemsSource="{Binding AccountViews}"
ItemSelected="AccountRow_Selected"
VerticalOptions="FillAndExpand"
RowHeight="60">

View File

@@ -133,13 +133,13 @@ namespace Bit.App.Pages
get => _websiteIconsEnabled;
set => SetProperty(ref _websiteIconsEnabled, value);
}
public ExtendedObservableCollection<AccountView> Accounts
public ExtendedObservableCollection<AccountView> AccountViews
{
get
{
// create a separate collection that includes the "add new" row
var accounts = new ExtendedObservableCollection<AccountView>();
accounts.AddRange(_stateService.Accounts);
accounts.AddRange(_stateService.AccountViews);
accounts.Add(new AccountView());
return accounts;
}

View File

@@ -447,7 +447,7 @@ namespace Bit.App.Utilities
return Convert.ToBase64String(Encoding.UTF8.GetBytes(multiByteEscaped));
}
public static async Task LogOutAsync(string userId)
public static async Task LogOutAsync(string userId, bool userInitiated = false)
{
var syncService = ServiceContainer.Resolve<ISyncService>("syncService");
var tokenService = ServiceContainer.Resolve<ITokenService>("tokenService");
@@ -469,24 +469,30 @@ namespace Bit.App.Utilities
}
await Task.WhenAll(
syncService.SetLastSyncAsync(DateTime.MinValue),
tokenService.ClearTokenAsync(userId),
cryptoService.ClearKeysAsync(userId),
stateService.CleanAsync(userId),
settingsService.ClearAsync(userId),
cipherService.ClearAsync(userId),
folderService.ClearAsync(userId),
collectionService.ClearAsync(userId),
passwordGenerationService.ClearAsync(userId),
vaultTimeoutService.ClearAsync(userId),
deviceActionService.ClearCacheAsync());
if (userInitiated)
{
await Task.WhenAll(
syncService.SetLastSyncAsync(DateTime.MinValue),
tokenService.ClearTokenAsync(userId),
cryptoService.ClearKeysAsync(userId),
settingsService.ClearAsync(userId),
vaultTimeoutService.ClearAsync(userId),
stateService.ClearAsync(userId));
}
stateService.BiometricLocked = true;
searchService.ClearIndex();
}
public static async Task ClearServiceCache()
public static async Task OnAccountSwitchAsync()
{
var environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
var tokenService = ServiceContainer.Resolve<ITokenService>("tokenService");
var cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
var cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
var folderService = ServiceContainer.Resolve<IFolderService>("folderService");
var collectionService = ServiceContainer.Resolve<ICollectionService>("collectionService");
@@ -495,10 +501,13 @@ namespace Bit.App.Utilities
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
var searchService = ServiceContainer.Resolve<ISearchService>("searchService");
await environmentService.SetUrlsFromStorageAsync();
await Task.WhenAll(
cipherService.ClearCacheAsync(),
deviceActionService.ClearCacheAsync());
tokenService.ClearCache();
cryptoService.ClearCache();
folderService.ClearCache();
collectionService.ClearCache();
passwordGenerationService.ClearCache();

View File

@@ -16,6 +16,7 @@ namespace Bit.Core.Abstractions
Task ClearKeysAsync(string userId = null);
Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null);
Task ClearPinProtectedKeyAsync(string userId = null);
void ClearCache();
Task<byte[]> DecryptFromBytesAsync(byte[] encBytes, SymmetricCryptoKey key);
Task<byte[]> DecryptToBytesAsync(EncString encString, SymmetricCryptoKey key = null);
Task<string> DecryptToUtf8Async(EncString encString, SymmetricCryptoKey key = null);

View File

@@ -12,162 +12,152 @@ namespace Bit.Core.Abstractions
public interface IStateService
{
bool BiometricLocked { get; set; }
ExtendedObservableCollection<AccountView> Accounts { get; set; }
Task<string> GetActiveUserIdAsync(StorageOptions options = null);
ExtendedObservableCollection<AccountView> AccountViews { get; set; }
Task<List<string>> GetUserIdsAsync();
Task<string> GetActiveUserIdAsync();
Task SetActiveUserAsync(string userId);
Task<bool> IsAuthenticatedAsync(StorageOptions options = null);
Task<bool> IsAuthenticatedAsync(string userId = null);
Task<bool> HasMultipleAccountsAsync();
Task RefreshAccountViews();
Task AddAccountAsync(Account account);
// Task SetInformationAsync(string userId, string email, KdfType kdf, int? kdfIterations);
Task CleanAsync(string userId);
Task ClearAsync(string userId);
Task<EnvironmentUrlData> GetPreAuthEnvironmentUrlsAsync();
Task SetPreAuthEnvironmentUrlsAsync(EnvironmentUrlData value);
Task<EnvironmentUrlData> GetEnvironmentUrlsAsync(StorageOptions options = null);
Task SetEnvironmentUrlsAsync(EnvironmentUrlData value, StorageOptions options = null);
Task<bool?> GetBiometricUnlockAsync(StorageOptions options = null);
Task SetBiometricUnlockAsync(bool? value, StorageOptions options = null);
Task<bool> CanAccessPremiumAsync(StorageOptions options = null);
Task<string> GetProtectedPinAsync(StorageOptions options = null);
Task SetProtectedPinAsync(string value, StorageOptions options = null);
Task<string> GetPinProtectedAsync(StorageOptions options = null);
Task SetPinProtectedAsync(string value, StorageOptions options = null);
Task<EncString> GetPinProtectedCachedAsync(StorageOptions options = null);
Task SetPinProtectedCachedAsync(EncString value, StorageOptions options = null);
Task<KdfType?> GetKdfTypeAsync(StorageOptions options = null);
Task SetKdfTypeAsync(KdfType? value, StorageOptions options = null);
Task<int?> GetKdfIterationsAsync(StorageOptions options = null);
Task SetKdfIterationsAsync(int? value, StorageOptions options = null);
Task<string> GetKeyEncryptedAsync(StorageOptions options = null);
Task SetKeyEncryptedAsync(string value, StorageOptions options = null);
Task<SymmetricCryptoKey> GetKeyDecryptedAsync(StorageOptions options = null);
Task SetKeyDecryptedAsync(SymmetricCryptoKey value, StorageOptions options = null);
Task<string> GetKeyHashAsync(StorageOptions options = null);
Task SetKeyHashAsync(string value, StorageOptions options = null);
Task<string> GetKeyHashCachedAsync(StorageOptions options = null);
Task SetKeyHashCachedAsync(string value, StorageOptions options = null);
Task<string> GetEncKeyEncryptedAsync(StorageOptions options = null);
Task SetEncKeyEncryptedAsync(string value, StorageOptions options = null);
Task<SymmetricCryptoKey> GetEncKeyDecryptedAsync(StorageOptions options = null);
Task SetEncKeyDecryptedAsync(SymmetricCryptoKey value, StorageOptions options = null);
Task<Dictionary<string, string>> GetOrgKeysEncryptedAsync(StorageOptions options = null);
Task SetOrgKeysEncryptedAsync(Dictionary<string, string> value, StorageOptions options = null);
Task<Dictionary<string, SymmetricCryptoKey>> GetOrgKeysDecryptedAsync(StorageOptions options = null);
Task SetOrgKeysDecryptedAsync(Dictionary<string, SymmetricCryptoKey> value, StorageOptions options = null);
Task<byte[]> GetPublicKeyAsync(StorageOptions options = null);
Task SetPublicKeyAsync(byte[] value, StorageOptions options = null);
Task<string> GetPrivateKeyEncryptedAsync(StorageOptions options = null);
Task SetPrivateKeyEncryptedAsync(string value, StorageOptions options = null);
Task<byte[]> GetPrivateKeyDecryptedAsync(StorageOptions options = null);
Task SetPrivateKeyDecryptedAsync(byte[] value, StorageOptions options = null);
Task<List<string>> GetAutofillBlacklistedUrisAsync(StorageOptions options = null);
Task SetAutofillBlacklistedUrisAsync(List<string> value, StorageOptions options = null);
Task<bool?> GetAutofillTileAddedAsync(StorageOptions options = null);
Task SetAutofillTileAddedAsync(bool? value, StorageOptions options = null);
Task<string> GetEmailAsync(StorageOptions options = null);
// Task SetEmailAsync(string value, StorageOptions options = null);
Task<long?> GetLastActiveTimeAsync(StorageOptions options = null);
Task SetLastActiveTimeAsync(long? value, StorageOptions options = null);
Task<int?> GetVaultTimeoutAsync(StorageOptions options = null);
Task SetVaultTimeoutAsync(int? value, StorageOptions options = null);
Task<string> GetVaultTimeoutActionAsync(StorageOptions options = null);
Task SetVaultTimeoutActionAsync(string value, StorageOptions options = null);
Task<DateTime?> GetLastFileCacheClearAsync(StorageOptions options = null);
Task SetLastFileCacheClearAsync(DateTime? value, StorageOptions options = null);
Task<PreviousPageInfo> GetPreviousPageInfoAsync(StorageOptions options = null);
Task SetPreviousPageInfoAsync(PreviousPageInfo value, StorageOptions options = null);
Task<int> GetInvalidUnlockAttemptsAsync(StorageOptions options = null);
Task SetInvalidUnlockAttemptsAsync(int? value, StorageOptions options = null);
Task<string> GetLastBuildAsync(StorageOptions options = null);
Task SetLastBuildAsync(string value, StorageOptions options = null);
Task<bool?> GetDisableFaviconAsync(StorageOptions options = null);
Task SetDisableFaviconAsync(bool? value, StorageOptions options = null);
Task<bool?> GetDisableAutoTotpCopyAsync(StorageOptions options = null);
Task SetDisableAutoTotpCopyAsync(bool? value, StorageOptions options = null);
Task<bool?> GetInlineAutofillEnabledAsync(StorageOptions options = null);
Task SetInlineAutofillEnabledAsync(bool? value, StorageOptions options = null);
Task<bool?> GetAutofillDisableSavePromptAsync(StorageOptions options = null);
Task SetAutofillDisableSavePromptAsync(bool? value, StorageOptions options = null);
Task<Dictionary<string, Dictionary<string, object>>> GetLocalDataAsync(StorageOptions options = null);
Task SetLocalDataAsync(Dictionary<string, Dictionary<string, object>> value, StorageOptions options = null);
Task<Dictionary<string, CipherData>> GetEncryptedCiphersAsync(StorageOptions options = null);
Task SetEncryptedCiphersAsync(Dictionary<string, CipherData> value, StorageOptions options = null);
Task<int?> GetDefaultUriMatchAsync(StorageOptions options = null);
Task SetDefaultUriMatchAsync(int? value, StorageOptions options = null);
Task<HashSet<string>> GetNeverDomainsAsync(StorageOptions options = null);
Task SetNeverDomainsAsync(HashSet<string> value, StorageOptions options = null);
Task<int?> GetClearClipboardAsync(StorageOptions options = null);
Task SetClearClipboardAsync(int? value, StorageOptions options = null);
Task<Dictionary<string, CollectionData>> GetEncryptedCollectionsAsync(StorageOptions options = null);
Task SetEncryptedCollectionsAsync(Dictionary<string, CollectionData> value, StorageOptions options = null);
Task<bool> GetPasswordRepromptAutofillAsync(StorageOptions options = null);
Task SetPasswordRepromptAutofillAsync(bool? value, StorageOptions options = null);
Task<bool> GetPasswordVerifiedAutofillAsync(StorageOptions options = null);
Task SetPasswordVerifiedAutofillAsync(bool? value, StorageOptions options = null);
Task<DateTime?> GetLastSyncAsync(StorageOptions options = null);
Task SetLastSyncAsync(DateTime? value, StorageOptions options = null);
Task<string> GetSecurityStampAsync(StorageOptions options = null);
Task SetSecurityStampAsync(string value, StorageOptions options = null);
Task<bool> GetEmailVerifiedAsync(StorageOptions options = null);
Task SetEmailVerifiedAsync(bool? value, StorageOptions options = null);
Task<bool> GetForcePasswordReset(StorageOptions options = null);
Task SetForcePasswordResetAsync(bool? value, StorageOptions options = null);
Task<bool> GetSyncOnRefreshAsync(StorageOptions options = null);
Task SetSyncOnRefreshAsync(bool? value, StorageOptions options = null);
Task<string> GetRememberedEmailAsync(StorageOptions options = null);
Task SetRememberedEmailAsync(string value, StorageOptions options = null);
Task<bool?> GetRememberEmailAsync(StorageOptions options = null);
Task SetRememberEmailAsync(bool? value, StorageOptions options = null);
Task<string> GetRememberedOrgIdentifierAsync(StorageOptions options = null);
Task SetRememberedOrgIdentifierAsync(string value, StorageOptions options = null);
Task<bool?> GetRememberOrgIdentifierAsync(StorageOptions options = null);
Task SetRememberOrgIdentifierAsync(bool? value, StorageOptions options = null);
Task<string> GetThemeAsync(StorageOptions options = null);
Task SetThemeAsync(string value, StorageOptions options = null);
Task<bool?> GetAddSitePromptShownAsync(StorageOptions options = null);
Task SetAddSitePromptShownAsync(bool? value, StorageOptions options = null);
Task<bool?> GetMigratedFromV1Async(StorageOptions options = null);
Task SetMigratedFromV1Async(bool? value, StorageOptions options = null);
Task<bool?> GetMigratedFromV1AutofillPromptShownAsync(StorageOptions options = null);
Task SetMigratedFromV1AutofillPromptShownAsync(bool? value, StorageOptions options = null);
Task<bool?> GetTriedV1ResyncAsync(StorageOptions options = null);
Task SetTriedV1ResyncAsync(bool? value, StorageOptions options = null);
Task<bool?> GetPushInitialPromptShownAsync(StorageOptions options = null);
Task SetPushInitialPromptShownAsync(bool? value, StorageOptions options = null);
Task<DateTime?> GetPushLastRegistrationDateAsync(StorageOptions options = null);
Task SetPushLastRegistrationDateAsync(DateTime? value, StorageOptions options = null);
Task<string> GetPushCurrentTokenAsync(StorageOptions options = null);
Task SetPushCurrentTokenAsync(string value, StorageOptions options = null);
Task<List<EventData>> GetEventCollectionAsync(StorageOptions options = null);
Task SetEventCollectionAsync(List<EventData> value, StorageOptions options = null);
Task<Dictionary<string, FolderData>> GetEncryptedFoldersAsync(StorageOptions options = null);
Task SetEncryptedFoldersAsync(Dictionary<string, FolderData> value, StorageOptions options = null);
Task<Dictionary<string, PolicyData>> GetEncryptedPoliciesAsync(StorageOptions options = null);
Task SetEncryptedPoliciesAsync(Dictionary<string, PolicyData> value, StorageOptions options = null);
Task<string> GetPushRegisteredTokenAsync(StorageOptions options = null);
Task SetPushRegisteredTokenAsync(string value, StorageOptions options = null);
Task<bool?> GetAppExtensionStartedAsync(StorageOptions options = null);
Task SetAppExtensionStartedAsync(bool? value, StorageOptions options = null);
Task<bool?> GetAppExtensionActivatedAsync(StorageOptions options = null);
Task SetAppExtensionActivatedAsync(bool? value, StorageOptions options = null);
Task<string> GetAppIdAsync(StorageOptions options = null);
Task SetAppIdAsync(string value, StorageOptions options = null);
Task<bool> GetUsesKeyConnectorAsync(StorageOptions options = null);
Task SetUsesKeyConnectorAsync(bool? value, StorageOptions options = null);
Task<Dictionary<string, OrganizationData>> GetOrganizationsAsync(StorageOptions options = null);
Task SetOrganizationsAsync(Dictionary<string, OrganizationData> organizations, StorageOptions options = null);
Task<PasswordGenerationOptions> GetPasswordGenerationOptionsAsync(StorageOptions options = null);
Task SetPasswordGenerationOptionsAsync(PasswordGenerationOptions value, StorageOptions options = null);
Task<List<GeneratedPasswordHistory>> GetEncryptedPasswordGenerationHistory(StorageOptions options = null);
Task SetEncryptedPasswordGenerationHistoryAsync(List<GeneratedPasswordHistory> value, StorageOptions options = null);
Task<Dictionary<string, SendData>> GetEncryptedSendsAsync(StorageOptions options = null);
Task SetEncryptedSendsAsync(Dictionary<string, SendData> value, StorageOptions options = null);
Task<Dictionary<string, object>> GetSettingsAsync(StorageOptions options = null);
Task SetSettingsAsync(Dictionary<string, object> value, StorageOptions options = null);
Task<string> GetAccessTokenAsync(StorageOptions options = null);
Task SetAccessTokenAsync(string value, StorageOptions options = null);
Task<string> GetRefreshTokenAsync(StorageOptions options = null);
Task SetRefreshTokenAsync(string value, StorageOptions options = null);
Task<string> GetTwoFactorTokenAsync(StorageOptions options = null);
Task SetTwoFactorTokenAsync(string value, StorageOptions options = null);
Task<EnvironmentUrlData> GetEnvironmentUrlsAsync(string userId = null);
Task<bool?> GetBiometricUnlockAsync(string userId = null);
Task SetBiometricUnlockAsync(bool? value, string userId = null);
Task<bool> CanAccessPremiumAsync(string userId = null);
Task<string> GetProtectedPinAsync(string userId = null);
Task SetProtectedPinAsync(string value, string userId = null);
Task<string> GetPinProtectedAsync(string userId = null);
Task SetPinProtectedAsync(string value, string userId = null);
Task<EncString> GetPinProtectedCachedAsync(string userId = null);
Task SetPinProtectedCachedAsync(EncString value, string userId = null);
Task<KdfType?> GetKdfTypeAsync(string userId = null);
Task SetKdfTypeAsync(KdfType? value, string userId = null);
Task<int?> GetKdfIterationsAsync(string userId = null);
Task SetKdfIterationsAsync(int? value, string userId = null);
Task<string> GetKeyEncryptedAsync(string userId = null);
Task SetKeyEncryptedAsync(string value, string userId = null);
Task<SymmetricCryptoKey> GetKeyDecryptedAsync(string userId = null);
Task SetKeyDecryptedAsync(SymmetricCryptoKey value, string userId = null);
Task<string> GetKeyHashAsync(string userId = null);
Task SetKeyHashAsync(string value, string userId = null);
Task<string> GetEncKeyEncryptedAsync(string userId = null);
Task SetEncKeyEncryptedAsync(string value, string userId = null);
Task<Dictionary<string, string>> GetOrgKeysEncryptedAsync(string userId = null);
Task SetOrgKeysEncryptedAsync(Dictionary<string, string> value, string userId = null);
Task<string> GetPrivateKeyEncryptedAsync(string userId = null);
Task SetPrivateKeyEncryptedAsync(string value, string userId = null);
Task<List<string>> GetAutofillBlacklistedUrisAsync(string userId = null);
Task SetAutofillBlacklistedUrisAsync(List<string> value, string userId = null);
Task<bool?> GetAutofillTileAddedAsync(string userId = null);
Task SetAutofillTileAddedAsync(bool? value, string userId = null);
Task<string> GetEmailAsync(string userId = null);
// Task SetEmailAsync(string value, string userId = null);
Task<long?> GetLastActiveTimeAsync(string userId = null);
Task SetLastActiveTimeAsync(long? value, string userId = null);
Task<int?> GetVaultTimeoutAsync(string userId = null);
Task SetVaultTimeoutAsync(int? value, string userId = null);
Task<string> GetVaultTimeoutActionAsync(string userId = null);
Task SetVaultTimeoutActionAsync(string value, string userId = null);
Task<DateTime?> GetLastFileCacheClearAsync(string userId = null);
Task SetLastFileCacheClearAsync(DateTime? value, string userId = null);
Task<PreviousPageInfo> GetPreviousPageInfoAsync(string userId = null);
Task SetPreviousPageInfoAsync(PreviousPageInfo value, string userId = null);
Task<int> GetInvalidUnlockAttemptsAsync(string userId = null);
Task SetInvalidUnlockAttemptsAsync(int? value, string userId = null);
Task<string> GetLastBuildAsync(string userId = null);
Task SetLastBuildAsync(string value, string userId = null);
Task<bool?> GetDisableFaviconAsync(string userId = null);
Task SetDisableFaviconAsync(bool? value, string userId = null);
Task<bool?> GetDisableAutoTotpCopyAsync(string userId = null);
Task SetDisableAutoTotpCopyAsync(bool? value, string userId = null);
Task<bool?> GetInlineAutofillEnabledAsync(string userId = null);
Task SetInlineAutofillEnabledAsync(bool? value, string userId = null);
Task<bool?> GetAutofillDisableSavePromptAsync(string userId = null);
Task SetAutofillDisableSavePromptAsync(bool? value, string userId = null);
Task<Dictionary<string, Dictionary<string, object>>> GetLocalDataAsync(string userId = null);
Task SetLocalDataAsync(Dictionary<string, Dictionary<string, object>> value, string userId = null);
Task<Dictionary<string, CipherData>> GetEncryptedCiphersAsync(string userId = null);
Task SetEncryptedCiphersAsync(Dictionary<string, CipherData> value, string userId = null);
Task<int?> GetDefaultUriMatchAsync(string userId = null);
Task SetDefaultUriMatchAsync(int? value, string userId = null);
Task<HashSet<string>> GetNeverDomainsAsync(string userId = null);
Task SetNeverDomainsAsync(HashSet<string> value, string userId = null);
Task<int?> GetClearClipboardAsync(string userId = null);
Task SetClearClipboardAsync(int? value, string userId = null);
Task<Dictionary<string, CollectionData>> GetEncryptedCollectionsAsync(string userId = null);
Task SetEncryptedCollectionsAsync(Dictionary<string, CollectionData> value, string userId = null);
Task<bool> GetPasswordRepromptAutofillAsync(string userId = null);
Task SetPasswordRepromptAutofillAsync(bool? value, string userId = null);
Task<bool> GetPasswordVerifiedAutofillAsync(string userId = null);
Task SetPasswordVerifiedAutofillAsync(bool? value, string userId = null);
Task<DateTime?> GetLastSyncAsync(string userId = null);
Task SetLastSyncAsync(DateTime? value, string userId = null);
Task<string> GetSecurityStampAsync(string userId = null);
Task SetSecurityStampAsync(string value, string userId = null);
Task<bool> GetEmailVerifiedAsync(string userId = null);
Task SetEmailVerifiedAsync(bool? value, string userId = null);
Task<bool> GetForcePasswordReset(string userId = null);
Task SetForcePasswordResetAsync(bool? value, string userId = null);
Task<bool> GetSyncOnRefreshAsync(string userId = null);
Task SetSyncOnRefreshAsync(bool? value, string userId = null);
Task<string> GetRememberedEmailAsync(string userId = null);
Task SetRememberedEmailAsync(string value, string userId = null);
Task<bool?> GetRememberEmailAsync(string userId = null);
Task SetRememberEmailAsync(bool? value, string userId = null);
Task<string> GetRememberedOrgIdentifierAsync(string userId = null);
Task SetRememberedOrgIdentifierAsync(string value, string userId = null);
Task<bool?> GetRememberOrgIdentifierAsync(string userId = null);
Task SetRememberOrgIdentifierAsync(bool? value, string userId = null);
Task<string> GetThemeAsync(string userId = null);
Task SetThemeAsync(string value, string userId = null);
Task<bool?> GetAddSitePromptShownAsync(string userId = null);
Task SetAddSitePromptShownAsync(bool? value, string userId = null);
Task<bool?> GetMigratedFromV1Async(string userId = null);
Task SetMigratedFromV1Async(bool? value, string userId = null);
Task<bool?> GetMigratedFromV1AutofillPromptShownAsync(string userId = null);
Task SetMigratedFromV1AutofillPromptShownAsync(bool? value, string userId = null);
Task<bool?> GetTriedV1ResyncAsync(string userId = null);
Task SetTriedV1ResyncAsync(bool? value, string userId = null);
Task<bool?> GetPushInitialPromptShownAsync(string userId = null);
Task SetPushInitialPromptShownAsync(bool? value, string userId = null);
Task<DateTime?> GetPushLastRegistrationDateAsync(string userId = null);
Task SetPushLastRegistrationDateAsync(DateTime? value, string userId = null);
Task<string> GetPushCurrentTokenAsync(string userId = null);
Task SetPushCurrentTokenAsync(string value, string userId = null);
Task<List<EventData>> GetEventCollectionAsync(string userId = null);
Task SetEventCollectionAsync(List<EventData> value, string userId = null);
Task<Dictionary<string, FolderData>> GetEncryptedFoldersAsync(string userId = null);
Task SetEncryptedFoldersAsync(Dictionary<string, FolderData> value, string userId = null);
Task<Dictionary<string, PolicyData>> GetEncryptedPoliciesAsync(string userId = null);
Task SetEncryptedPoliciesAsync(Dictionary<string, PolicyData> value, string userId = null);
Task<string> GetPushRegisteredTokenAsync(string userId = null);
Task SetPushRegisteredTokenAsync(string value, string userId = null);
Task<bool?> GetAppExtensionStartedAsync(string userId = null);
Task SetAppExtensionStartedAsync(bool? value, string userId = null);
Task<bool?> GetAppExtensionActivatedAsync(string userId = null);
Task SetAppExtensionActivatedAsync(bool? value, string userId = null);
Task<string> GetAppIdAsync(string userId = null);
Task SetAppIdAsync(string value, string userId = null);
Task<bool> GetUsesKeyConnectorAsync(string userId = null);
Task SetUsesKeyConnectorAsync(bool? value, string userId = null);
Task<Dictionary<string, OrganizationData>> GetOrganizationsAsync(string userId = null);
Task SetOrganizationsAsync(Dictionary<string, OrganizationData> organizations, string userId = null);
Task<PasswordGenerationOptions> GetPasswordGenerationOptionsAsync(string userId = null);
Task SetPasswordGenerationOptionsAsync(PasswordGenerationOptions value, string userId = null);
Task<List<GeneratedPasswordHistory>> GetEncryptedPasswordGenerationHistory(string userId = null);
Task SetEncryptedPasswordGenerationHistoryAsync(List<GeneratedPasswordHistory> value, string userId = null);
Task<Dictionary<string, SendData>> GetEncryptedSendsAsync(string userId = null);
Task SetEncryptedSendsAsync(Dictionary<string, SendData> value, string userId = null);
Task<Dictionary<string, object>> GetSettingsAsync(string userId = null);
Task SetSettingsAsync(Dictionary<string, object> value, string userId = null);
Task<string> GetAccessTokenAsync(string userId = null);
Task SetAccessTokenAsync(string value, string userId = null);
Task<string> GetRefreshTokenAsync(string userId = null);
Task SetRefreshTokenAsync(string value, string userId = null);
Task<string> GetTwoFactorTokenAsync(string email = null);
Task SetTwoFactorTokenAsync(string value, string email = null);
}
}

View File

@@ -1,31 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Models.Domain;
namespace Bit.Core.Abstractions
{
public interface IUserService
{
Task<bool> CanAccessPremiumAsync();
Task ClearAsync();
Task ClearOrganizationsAsync(string userId);
Task<List<Organization>> GetAllOrganizationAsync();
Task<string> GetEmailAsync();
Task<KdfType?> GetKdfAsync();
Task<int?> GetKdfIterationsAsync();
Task<Organization> GetOrganizationAsync(string id);
Task<Organization> GetOrganizationByIdentifierAsync(string identifier);
Task<string> GetSecurityStampAsync();
Task<bool> GetEmailVerifiedAsync();
Task<bool> GetForcePasswordReset();
Task<string> GetUserIdAsync();
Task<bool> IsAuthenticatedAsync();
Task ReplaceOrganizationsAsync(Dictionary<string, OrganizationData> organizations);
Task SetInformationAsync(string userId, string email, KdfType kdf, int? kdfIterations);
Task SetSecurityStampAsync(string stamp);
Task SetEmailVerifiedAsync(bool emailVerified);
Task SetForcePasswordReset(bool forcePasswordReset);
}
}

View File

@@ -11,7 +11,7 @@ namespace Bit.Core.Abstractions
Task<Tuple<bool, bool>> IsPinLockSetAsync();
Task<bool> IsBiometricLockSetAsync();
Task LockAsync(bool allowSoftLock = false, bool userInitiated = false, string userId = null);
Task LogOutAsync(string userId = null);
Task LogOutAsync(bool userInitiated = true, string userId = null);
Task SetVaultTimeoutOptionsAsync(int? timeout, string action);
Task<int?> GetVaultTimeout(string userId = null);
}

View File

@@ -64,8 +64,6 @@
public static string PassGenOptionsKey(string userId) => $"passwordGenerationOptions_{userId}";
public static string PassGenHistoryKey(string userId) => $"generatedPasswordHistory_{userId}";
public static string TwoFactorTokenKey(string email) => $"twoFactorToken_{email}";
public static string VaultTimeoutKey(string userId) => $"vaultTimeout_{userId}";
public static string VaultTimeoutActionKey(string userId) => $"vaultTimeoutAction_{userId}";
public static string LastActiveTimeKey(string userId) => $"lastActiveTime_{userId}";
public static string InvalidUnlockAttemptsKey(string userId) => $"invalidUnlockAttempts_{userId}";
public static string InlineAutofillEnabledKey(string userId) => $"inlineAutofillEnabled_{userId}";
@@ -83,8 +81,6 @@
public static string SettingsKey(string userId) => $"settings_{userId}";
public static string UsesKeyConnectorKey(string userId) => $"usesKeyConnector_{userId}";
public static string ProtectedPinKey(string userId) => $"protectedPin_{userId}";
public static string SecurityStampKey(string userId) => $"securityStamp_{userId}";
public static string EmailVerifiedKey(string userId) => $"emailVerified_{userId}";
public static string ForcePasswordResetKey(string userId) => $"forcePasswordReset_{userId}";
public static string LastSyncKey(string userId) => $"lastSync_{userId}";
public static string BiometricUnlockKey(string userId) => $"biometricUnlock_{userId}";

View File

@@ -1,11 +1,11 @@
using System.Collections.Generic;
using Bit.Core.Enums;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
namespace Bit.Core.Models.Domain
{
public class Account : Domain
{
public AuthenticationStatus? AuthStatus;
public AccountProfile Profile;
public AccountTokens Tokens;
public AccountSettings Settings;
@@ -24,6 +24,7 @@ namespace Bit.Core.Models.Domain
public Account(Account account)
{
// Copy constructor excludes Keys (for storage)
AuthStatus = account.AuthStatus;
Profile = new AccountProfile(account.Profile);
Tokens = new AccountTokens(account.Tokens);
Settings = new AccountSettings(account.Settings);
@@ -42,18 +43,20 @@ namespace Bit.Core.Models.Domain
UserId = copy.UserId;
Email = copy.Email;
AuthStatus = copy.AuthStatus;
HasPremiumPersonally = copy.HasPremiumPersonally;
Stamp = copy.Stamp;
KdfType = copy.KdfType;
KdfIterations = copy.KdfIterations;
EmailVerified = copy.EmailVerified;
HasPremiumPersonally = copy.HasPremiumPersonally;
}
public string UserId;
public string Email;
public AuthenticationStatus? AuthStatus;
public bool? HasPremiumPersonally;
public string Stamp;
public KdfType? KdfType;
public int? KdfIterations;
public bool? EmailVerified;
public bool? HasPremiumPersonally;
}
public class AccountTokens
@@ -88,21 +91,19 @@ namespace Bit.Core.Models.Domain
EnvironmentUrls = copy.EnvironmentUrls;
PinProtected = copy.PinProtected;
VaultTimeout = copy.VaultTimeout;
VaultTimeoutAction = copy.VaultTimeoutAction;
}
public EnvironmentUrlData EnvironmentUrls;
public EncString PinProtected;
public int? VaultTimeout;
public string VaultTimeoutAction;
}
public class AccountKeys
{
public SymmetricCryptoKey Key;
public string KeyHash;
public SymmetricCryptoKey EncKey;
public Dictionary<string, SymmetricCryptoKey>
OrganizationKeys = new Dictionary<string, SymmetricCryptoKey>();
public byte[] PrivateKey;
public byte[] PublicKey;
}
}
}

View File

@@ -15,17 +15,16 @@ namespace Bit.Core.Models.View
return;
}
IsAccount = true;
UserId = a.Profile.UserId;
Email = a.Profile.Email;
Hostname = a.Settings.EnvironmentUrls.Base;
AuthStatus = a.Profile.AuthStatus;
AuthStatus = a.AuthStatus;
UserId = a.Profile?.UserId;
Email = a.Profile?.Email;
Hostname = a.Settings?.EnvironmentUrls?.Base;
}
public bool IsAccount { get; set; }
public AuthenticationStatus? AuthStatus { get; set; }
public string UserId { get; set; }
public string Email { get; set; }
public string Hostname { get; set; }
public AuthenticationStatus? AuthStatus { get; set; }
}
}

View File

@@ -24,12 +24,12 @@ namespace Bit.Core.Services
private readonly HttpClient _httpClient = new HttpClient();
private readonly ITokenService _tokenService;
private readonly IPlatformUtilsService _platformUtilsService;
private readonly Func<bool, Task> _logoutCallbackAsync;
private readonly Func<Tuple<string, bool, bool>, Task> _logoutCallbackAsync;
public ApiService(
ITokenService tokenService,
IPlatformUtilsService platformUtilsService,
Func<bool, Task> logoutCallbackAsync,
Func<Tuple<string, bool, bool>, Task> logoutCallbackAsync,
string customUserAgent = null)
{
_tokenService = tokenService;
@@ -698,7 +698,7 @@ namespace Bit.Core.Services
if (authed && ((tokenError && response.StatusCode == HttpStatusCode.BadRequest) ||
response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden))
{
await _logoutCallbackAsync(true);
await _logoutCallbackAsync(new Tuple<string, bool, bool>(null, false, true));
return null;
}
try

View File

@@ -359,9 +359,9 @@ namespace Bit.Core.Services
{
UserId = _tokenService.GetUserId(),
Email = _tokenService.GetEmail(),
HasPremiumPersonally = _tokenService.GetPremium(),
KdfType = tokenResponse.Kdf,
KdfIterations = tokenResponse.KdfIterations,
HasPremiumPersonally = _tokenService.GetPremium(),
},
new Account.AccountTokens()
{

View File

@@ -639,7 +639,7 @@ namespace Bit.Core.Services
public async Task ClearAsync(string userId)
{
await _stateService.SetEncryptedCiphersAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetEncryptedCiphersAsync(null, userId);
await ClearCacheAsync();
}

View File

@@ -181,7 +181,7 @@ namespace Bit.Core.Services
public async Task ClearAsync(string userId)
{
await _stateService.SetEncryptedCollectionsAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetEncryptedCollectionsAsync(null, userId);
_decryptedCollectionCache = null;
}

View File

@@ -17,7 +17,12 @@ namespace Bit.Core.Services
private readonly IStateService _stateService;
private readonly ICryptoFunctionService _cryptoFunctionService;
private SymmetricCryptoKey _encKey;
private SymmetricCryptoKey _legacyEtmKey;
private string _keyHash;
private byte[] _publicKey;
private byte[] _privateKey;
private Dictionary<string, SymmetricCryptoKey> _orgKeys;
private Task<SymmetricCryptoKey> _getEncKeysTask;
private Task<Dictionary<string, SymmetricCryptoKey>> _getOrgKeysTask;
@@ -44,7 +49,7 @@ namespace Bit.Core.Services
public async Task SetKeyHashAsync(string keyHash)
{
await _stateService.SetKeyHashCachedAsync(keyHash);
_keyHash = keyHash;
await _stateService.SetKeyHashAsync(keyHash);
}
@@ -55,7 +60,7 @@ namespace Bit.Core.Services
return;
}
await _stateService.SetEncKeyEncryptedAsync(encKey);
await _stateService.SetEncKeyDecryptedAsync(null);
_encKey = null;
}
public async Task SetEncPrivateKeyAsync(string encPrivateKey)
@@ -65,13 +70,13 @@ namespace Bit.Core.Services
return;
}
await _stateService.SetPrivateKeyEncryptedAsync(encPrivateKey);
await _stateService.SetPrivateKeyDecryptedAsync(null);
_privateKey = null;
}
public async Task SetOrgKeysAsync(IEnumerable<ProfileOrganizationResponse> orgs)
{
var orgKeys = orgs.ToDictionary(org => org.Id, org => org.Key);
await _stateService.SetOrgKeysDecryptedAsync(null);
_orgKeys = null;
await _stateService.SetOrgKeysEncryptedAsync(orgKeys);
}
@@ -93,25 +98,23 @@ namespace Bit.Core.Services
public async Task<string> GetKeyHashAsync()
{
var inMemoryKeyHash = await _stateService.GetKeyHashCachedAsync();
if (inMemoryKeyHash != null)
if (_keyHash != null)
{
return inMemoryKeyHash;
return _keyHash;
}
var keyHash = await _stateService.GetKeyHashAsync();
if (keyHash != null)
{
await _stateService.SetKeyHashCachedAsync(keyHash);
_keyHash = keyHash;
}
return keyHash;
return _keyHash;
}
public Task<SymmetricCryptoKey> GetEncKeyAsync(SymmetricCryptoKey key = null)
{
var inMemoryKey = _stateService.GetEncKeyDecryptedAsync().GetAwaiter().GetResult();
if (inMemoryKey != null)
if (_encKey != null)
{
return Task.FromResult(inMemoryKey);
return Task.FromResult(_encKey);
}
if (_getEncKeysTask != null && !_getEncKeysTask.IsCompleted && !_getEncKeysTask.IsFaulted)
{
@@ -156,9 +159,8 @@ namespace Bit.Core.Services
{
return null;
}
var newEncKey = new SymmetricCryptoKey(decEncKey);
await _stateService.SetEncKeyDecryptedAsync(newEncKey);
return newEncKey;
_encKey = new SymmetricCryptoKey(decEncKey);
return _encKey;
}
finally
{
@@ -171,36 +173,32 @@ namespace Bit.Core.Services
public async Task<byte[]> GetPublicKeyAsync()
{
var inMemoryKey = await _stateService.GetPublicKeyAsync();
if (inMemoryKey != null)
if (_publicKey != null)
{
return inMemoryKey;
return _publicKey;
}
var privateKey = await GetPrivateKeyAsync();
if (privateKey == null)
{
return null;
}
inMemoryKey = await _cryptoFunctionService.RsaExtractPublicKeyAsync(privateKey);
await _stateService.SetPublicKeyAsync(inMemoryKey);
return inMemoryKey;
_publicKey = await _cryptoFunctionService.RsaExtractPublicKeyAsync(privateKey);
return _publicKey;
}
public async Task<byte[]> GetPrivateKeyAsync()
{
var inMemoryKey = await _stateService.GetPrivateKeyDecryptedAsync();
if (inMemoryKey != null)
if (_privateKey != null)
{
return inMemoryKey;
return _privateKey;
}
var encPrivateKey = await _stateService.GetPrivateKeyEncryptedAsync();
if (encPrivateKey == null)
{
return null;
}
inMemoryKey = await DecryptToBytesAsync(new EncString(encPrivateKey), null);
await _stateService.SetPrivateKeyDecryptedAsync(inMemoryKey);
return inMemoryKey;
_privateKey = await DecryptToBytesAsync(new EncString(encPrivateKey), null);
return _privateKey;
}
public async Task<List<string>> GetFingerprintAsync(string userId, byte[] publicKey = null)
@@ -220,10 +218,9 @@ namespace Bit.Core.Services
public Task<Dictionary<string, SymmetricCryptoKey>> GetOrgKeysAsync()
{
var inMemoryKeys = _stateService.GetOrgKeysDecryptedAsync();
if (inMemoryKeys != null && inMemoryKeys.Result.Count > 0)
if (_orgKeys != null && _orgKeys.Count > 0)
{
return inMemoryKeys;
return Task.FromResult(_orgKeys);
}
if (_getOrgKeysTask != null && !_getOrgKeysTask.IsCompleted && !_getOrgKeysTask.IsFaulted)
{
@@ -249,9 +246,9 @@ namespace Bit.Core.Services
if (setKey)
{
await _stateService.SetOrgKeysDecryptedAsync(orgKeys);
_orgKeys = orgKeys;
}
return orgKeys;
return _orgKeys;
}
finally
{
@@ -312,48 +309,57 @@ namespace Bit.Core.Services
public async Task ClearKeyAsync(string userId = null)
{
await _stateService.SetKeyDecryptedAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetKeyDecryptedAsync(null, userId);
_legacyEtmKey = null;
await _stateService.SetKeyEncryptedAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetKeyEncryptedAsync(null, userId);
}
public async Task ClearKeyHashAsync(string userId = null)
{
await _stateService.SetKeyHashCachedAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetKeyHashAsync(null, new StorageOptions { UserId = userId });
_keyHash = null;
await _stateService.SetKeyHashAsync(null, userId);
}
public async Task ClearEncKeyAsync(bool memoryOnly = false, string userId = null)
{
await _stateService.SetEncKeyDecryptedAsync(null, new StorageOptions { UserId = userId });
_encKey = null;
if (!memoryOnly)
{
await _stateService.SetEncKeyEncryptedAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetEncKeyEncryptedAsync(null, userId);
}
}
public async Task ClearKeyPairAsync(bool memoryOnly = false, string userId = null)
{
await _stateService.SetPublicKeyAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetPrivateKeyDecryptedAsync(null, new StorageOptions { UserId = userId });
_publicKey = _privateKey = null;
if (!memoryOnly)
{
await _stateService.SetPrivateKeyEncryptedAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetPrivateKeyEncryptedAsync(null, userId);
}
}
public async Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null)
{
await _stateService.SetOrgKeysDecryptedAsync(null, new StorageOptions { UserId = userId });
_orgKeys = null;
if (!memoryOnly)
{
await _stateService.SetOrgKeysEncryptedAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetOrgKeysEncryptedAsync(null, userId);
}
}
public async Task ClearPinProtectedKeyAsync(string userId = null)
{
await _stateService.SetPinProtectedAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetPinProtectedAsync(null, userId);
}
public void ClearCache()
{
_encKey = null;
_legacyEtmKey = null;
_keyHash = null;
_publicKey = null;
_privateKey = null;
_orgKeys = null;
}
public async Task ClearKeysAsync(string userId = null)

View File

@@ -192,7 +192,7 @@ namespace Bit.Core.Services
public async Task ClearAsync(string userId)
{
await _stateService.SetEncryptedFoldersAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetEncryptedFoldersAsync(null, userId);
_decryptedFolderCache = null;
}

View File

@@ -38,7 +38,7 @@ namespace Bit.Core.Services
public async Task<List<Organization>> GetAllAsync(string userId = null)
{
var organizations = await _stateService.GetOrganizationsAsync(new StorageOptions { UserId = userId });
var organizations = await _stateService.GetOrganizationsAsync(userId);
return organizations?.Select(o => new Organization(o.Value)).ToList() ?? new List<Organization>();
}
@@ -49,7 +49,7 @@ namespace Bit.Core.Services
public async Task ClearAllAsync(string userId)
{
await _stateService.SetOrganizationsAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetOrganizationsAsync(null, userId);
}
}
}

View File

@@ -483,8 +483,7 @@ namespace Bit.Core.Services
public async Task ClearAsync(string userId = null)
{
_history = new List<GeneratedPasswordHistory>();
await _stateService.SetEncryptedPasswordGenerationHistoryAsync(null,
new StorageOptions { UserId = userId });
await _stateService.SetEncryptedPasswordGenerationHistoryAsync(null, userId);
}
public Result PasswordStrength(string password, List<string> userInputs = null)

View File

@@ -60,7 +60,7 @@ namespace Bit.Core.Services
public async Task Clear(string userId)
{
await _stateService.SetEncryptedPoliciesAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetEncryptedPoliciesAsync(null, userId);
_policyCache = null;
}

View File

@@ -45,7 +45,7 @@ namespace Bit.Core.Services
public async Task ClearAsync(string userId)
{
await _stateService.SetEncryptedSendsAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetEncryptedSendsAsync(null, userId);
ClearCache();
}

View File

@@ -2,7 +2,6 @@
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Models.Domain;
namespace Bit.Core.Services
{
@@ -44,7 +43,7 @@ namespace Bit.Core.Services
public async Task ClearAsync(string userId)
{
await _stateService.SetSettingsAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetSettingsAsync(null, userId);
ClearCache();
}

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@ namespace Bit.Core.Services
private readonly IPolicyService _policyService;
private readonly ISendService _sendService;
private readonly IKeyConnectorService _keyConnectorService;
private readonly Func<bool, Task> _logoutCallbackAsync;
private readonly Func<Tuple<string, bool, bool>, Task> _logoutCallbackAsync;
public SyncService(
IStateService stateService,
@@ -39,7 +39,7 @@ namespace Bit.Core.Services
IPolicyService policyService,
ISendService sendService,
IKeyConnectorService keyConnectorService,
Func<bool, Task> logoutCallbackAsync)
Func<Tuple<string, bool, bool>, Task> logoutCallbackAsync)
{
_stateService = stateService;
_apiService = apiService;
@@ -316,7 +316,7 @@ namespace Bit.Core.Services
{
if (_logoutCallbackAsync != null)
{
await _logoutCallbackAsync(true);
await _logoutCallbackAsync(new Tuple<string, bool, bool>(response.Id, false, true));
}
return;
}

View File

@@ -5,7 +5,6 @@ using System;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Bit.Core.Models.Domain;
namespace Bit.Core.Services
{
@@ -94,25 +93,25 @@ namespace Bit.Core.Services
public async Task SetTwoFactorTokenAsync(string token, string email)
{
await _stateService.SetTwoFactorTokenAsync(token, new StorageOptions { Email = email });
await _stateService.SetTwoFactorTokenAsync(token, email);
}
public async Task<string> GetTwoFactorTokenAsync(string email)
{
return await _stateService.GetTwoFactorTokenAsync(new StorageOptions { Email = email });
return await _stateService.GetTwoFactorTokenAsync(email);
}
public async Task ClearTwoFactorTokenAsync(string email)
{
await _stateService.SetTwoFactorTokenAsync(null, new StorageOptions { Email = email });
await _stateService.SetTwoFactorTokenAsync(null, email);
}
public async Task ClearTokenAsync(string userId = null)
{
ClearCache();
await Task.WhenAll(
_stateService.SetAccessTokenAsync(null, new StorageOptions { UserId = userId }),
_stateService.SetRefreshTokenAsync(null, new StorageOptions { UserId = userId }));
_stateService.SetAccessTokenAsync(null, userId),
_stateService.SetRefreshTokenAsync(null, userId));
}
public void ClearCache()

View File

@@ -1,221 +0,0 @@
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Models.Domain;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Bit.Core.Services
{
public class UserService : IUserService
{
private string _userId;
private string _email;
private string _stamp;
private KdfType? _kdf;
private int? _kdfIterations;
private bool? _emailVerified;
private bool? _forcePasswordReset;
private const string Keys_UserId = "userId";
private const string Keys_UserEmail = "userEmail";
private const string Keys_Stamp = "securityStamp";
private const string Keys_Kdf = "kdf";
private const string Keys_KdfIterations = "kdfIterations";
private const string Keys_OrganizationsFormat = "organizations_{0}";
private const string Keys_EmailVerified = "emailVerified";
private const string Keys_ForcePasswordReset = "forcePasswordReset";
private readonly IStorageService _storageService;
private readonly ITokenService _tokenService;
public UserService(IStorageService storageService, ITokenService tokenService)
{
_storageService = storageService;
_tokenService = tokenService;
}
public async Task SetInformationAsync(string userId, string email, KdfType kdf, int? kdfIterations)
{
_email = email;
_userId = userId;
_kdf = kdf;
_kdfIterations = kdfIterations;
await Task.WhenAll(
_storageService.SaveAsync(Keys_UserEmail, email),
_storageService.SaveAsync(Keys_UserId, userId),
_storageService.SaveAsync(Keys_Kdf, (int)kdf),
_storageService.SaveAsync(Keys_KdfIterations, kdfIterations));
}
public async Task SetSecurityStampAsync(string stamp)
{
_stamp = stamp;
await _storageService.SaveAsync(Keys_Stamp, stamp);
}
public async Task SetEmailVerifiedAsync(bool emailVerified)
{
_emailVerified = emailVerified;
await _storageService.SaveAsync(Keys_EmailVerified, emailVerified);
}
public async Task SetForcePasswordReset(bool forcePasswordReset)
{
_forcePasswordReset = forcePasswordReset;
await _storageService.SaveAsync(Keys_ForcePasswordReset, forcePasswordReset);
}
public async Task<string> GetUserIdAsync()
{
if (_userId == null)
{
_userId = await _storageService.GetAsync<string>(Keys_UserId);
}
return _userId;
}
public async Task<string> GetEmailAsync()
{
if (_email == null)
{
_email = await _storageService.GetAsync<string>(Keys_UserEmail);
}
return _email;
}
public async Task<string> GetSecurityStampAsync()
{
if (_stamp == null)
{
_stamp = await _storageService.GetAsync<string>(Keys_Stamp);
}
return _stamp;
}
public async Task<bool> GetEmailVerifiedAsync()
{
if (_emailVerified == null)
{
_emailVerified = await _storageService.GetAsync<bool>(Keys_EmailVerified);
}
return _emailVerified.GetValueOrDefault();
}
public async Task<KdfType?> GetKdfAsync()
{
if (_kdf == null)
{
_kdf = (KdfType?)(await _storageService.GetAsync<int?>(Keys_Kdf));
}
return _kdf;
}
public async Task<int?> GetKdfIterationsAsync()
{
if (_kdfIterations == null)
{
_kdfIterations = await _storageService.GetAsync<int?>(Keys_KdfIterations);
}
return _kdfIterations;
}
public async Task<bool> GetForcePasswordReset()
{
if (_forcePasswordReset == null)
{
_forcePasswordReset = await _storageService.GetAsync<bool>(Keys_ForcePasswordReset);
}
return _forcePasswordReset.GetValueOrDefault();
}
public async Task ClearAsync()
{
var userId = await GetUserIdAsync();
await Task.WhenAll(
_storageService.RemoveAsync(Keys_UserId),
_storageService.RemoveAsync(Keys_UserEmail),
_storageService.RemoveAsync(Keys_Stamp),
_storageService.RemoveAsync(Keys_Kdf),
_storageService.RemoveAsync(Keys_KdfIterations),
_storageService.RemoveAsync(Keys_ForcePasswordReset),
ClearOrganizationsAsync(userId));
_userId = _email = _stamp = null;
_kdf = null;
_kdfIterations = null;
}
public async Task<bool> IsAuthenticatedAsync()
{
var token = await _tokenService.GetTokenAsync();
if (token == null)
{
return false;
}
var userId = await GetUserIdAsync();
return userId != null;
}
public async Task<bool> CanAccessPremiumAsync()
{
var authed = await IsAuthenticatedAsync();
if (!authed)
{
return false;
}
var tokenPremium = _tokenService.GetPremium();
if (tokenPremium)
{
return true;
}
var orgs = await GetAllOrganizationAsync();
return orgs?.Any(o => o.UsersGetPremium && o.Enabled) ?? false;
}
public async Task<Organization> GetOrganizationAsync(string id)
{
var userId = await GetUserIdAsync();
var organizations = await _storageService.GetAsync<Dictionary<string, OrganizationData>>(
string.Format(Keys_OrganizationsFormat, userId));
if (organizations == null || !organizations.ContainsKey(id))
{
return null;
}
return new Organization(organizations[id]);
}
public async Task<Organization> GetOrganizationByIdentifierAsync(string identifier)
{
var userId = await GetUserIdAsync();
var organizations = await GetAllOrganizationAsync();
if (organizations == null || organizations.Count == 0)
{
return null;
}
return organizations.FirstOrDefault(o => o.Identifier == identifier);
}
public async Task<List<Organization>> GetAllOrganizationAsync()
{
var userId = await GetUserIdAsync();
var organizations = await _storageService.GetAsync<Dictionary<string, OrganizationData>>(
string.Format(Keys_OrganizationsFormat, userId));
return organizations?.Select(o => new Organization(o.Value)).ToList() ?? new List<Organization>();
}
public async Task ReplaceOrganizationsAsync(Dictionary<string, OrganizationData> organizations)
{
var userId = await GetUserIdAsync();
await _storageService.SaveAsync(string.Format(Keys_OrganizationsFormat, userId), organizations);
}
public async Task ClearOrganizationsAsync(string userId)
{
await _storageService.RemoveAsync(string.Format(Keys_OrganizationsFormat, userId));
}
}
}

View File

@@ -1,5 +1,4 @@
using Bit.Core.Abstractions;
using Bit.Core.Models.Domain;
using System;
using System.Linq;
using System.Threading.Tasks;
@@ -21,7 +20,7 @@ namespace Bit.Core.Services
private readonly IPolicyService _policyService;
private readonly IKeyConnectorService _keyConnectorService;
private readonly Action<bool> _lockedCallback;
private readonly Func<Tuple<bool, string>, Task> _loggedOutCallback;
private readonly Func<Tuple<string, bool, bool>, Task> _loggedOutCallback;
public VaultTimeoutService(
ICryptoService cryptoService,
@@ -36,7 +35,7 @@ namespace Bit.Core.Services
IPolicyService policyService,
IKeyConnectorService keyConnectorService,
Action<bool> lockedCallback,
Func<Tuple<bool, string>, Task> loggedOutCallback)
Func<Tuple<string, bool, bool>, Task> loggedOutCallback)
{
_cryptoService = cryptoService;
_stateService = stateService;
@@ -74,18 +73,18 @@ namespace Bit.Core.Services
return;
}
foreach (var account in _stateService.Accounts)
foreach (var userId in await _stateService.GetUserIdsAsync())
{
if (account.UserId != null && await ShouldLockAsync(account.UserId))
if (userId != null && await ShouldLockAsync(userId))
{
await ExecuteTimeoutActionAsync(account.UserId);
await ExecuteTimeoutActionAsync(userId);
}
}
}
private async Task<bool> ShouldLockAsync(string userId)
{
var authed = await _stateService.IsAuthenticatedAsync(new StorageOptions { UserId = userId });
var authed = await _stateService.IsAuthenticatedAsync(userId);
if (!authed)
{
return false;
@@ -99,7 +98,7 @@ namespace Bit.Core.Services
{
return false;
}
var lastActiveTime = await _stateService.GetLastActiveTimeAsync(new StorageOptions { UserId = userId });
var lastActiveTime = await _stateService.GetLastActiveTimeAsync(userId);
if (lastActiveTime == null)
{
return false;
@@ -111,10 +110,10 @@ namespace Bit.Core.Services
private async Task ExecuteTimeoutActionAsync(string userId)
{
var action = await _stateService.GetVaultTimeoutActionAsync(new StorageOptions { UserId = userId });
var action = await _stateService.GetVaultTimeoutActionAsync(userId);
if (action == "logOut")
{
await LogOutAsync(userId);
await LogOutAsync(false, userId);
}
else
{
@@ -124,7 +123,7 @@ namespace Bit.Core.Services
public async Task LockAsync(bool allowSoftLock = false, bool userInitiated = false, string userId = null)
{
var authed = await _stateService.IsAuthenticatedAsync(new StorageOptions { UserId = userId });
var authed = await _stateService.IsAuthenticatedAsync(userId);
if (!authed)
{
return;
@@ -136,7 +135,7 @@ namespace Bit.Core.Services
if (!pinLock && !await IsBiometricLockSetAsync())
{
await LogOutAsync();
await LogOutAsync(userInitiated, userId);
return;
}
}
@@ -172,11 +171,11 @@ namespace Bit.Core.Services
_lockedCallback?.Invoke(userInitiated);
}
public async Task LogOutAsync(string userId = null)
public async Task LogOutAsync(bool userInitiated = true, string userId = null)
{
if(_loggedOutCallback != null)
{
await _loggedOutCallback.Invoke(new Tuple<bool, string>(false, userId));
await _loggedOutCallback.Invoke(new Tuple<string, bool, bool>(userId, userInitiated, false));
}
}
@@ -203,8 +202,8 @@ namespace Bit.Core.Services
public async Task ClearAsync(string userId = null)
{
await _stateService.SetPinProtectedAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetProtectedPinAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetPinProtectedAsync(null, userId);
await _stateService.SetProtectedPinAsync(null, userId);
}
public async Task<int?> GetVaultTimeout(string userId = null) {

View File

@@ -30,9 +30,9 @@ namespace Bit.Core.Utilities
SearchService searchService = null;
var tokenService = new TokenService(stateService);
var apiService = new ApiService(tokenService, platformUtilsService, (bool expired) =>
var apiService = new ApiService(tokenService, platformUtilsService, (extras) =>
{
messagingService.Send("logout", expired);
messagingService.Send("logout", extras);
return Task.FromResult(0);
}, customUserAgent);
var appIdService = new AppIdService(stateService);
@@ -59,9 +59,9 @@ namespace Bit.Core.Utilities
});
var syncService = new SyncService(stateService, apiService, settingsService, folderService, cipherService,
cryptoService, collectionService, organizationService, messagingService, policyService, sendService,
keyConnectorService, (bool expired) =>
keyConnectorService, (extras) =>
{
messagingService.Send("logout", expired);
messagingService.Send("logout", extras);
return Task.FromResult(0);
});
var passwordGenerationService = new PasswordGenerationService(cryptoService, stateService,

View File

@@ -145,7 +145,8 @@ namespace Bit.iOS
{
if (_deviceActionService.SystemMajorVersion() >= 12)
{
await ASCredentialIdentityStore.SharedStore?.RemoveAllCredentialIdentitiesAsync();
// TODO make account-specific
// await ASCredentialIdentityStore.SharedStore?.RemoveAllCredentialIdentitiesAsync();
}
}
else if ((message.Command == "softDeletedCipher" || message.Command == "restoredCipher")