1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-09 03:53:15 +00:00

Account switching

This commit is contained in:
Matt Portune
2022-01-16 22:43:37 -05:00
parent 86397a6f1e
commit ebae2585f6
129 changed files with 3883 additions and 1265 deletions

View File

@@ -5,6 +5,5 @@ namespace Bit.Core.Abstractions
public interface IAppIdService
{
Task<string> GetAppIdAsync();
Task<string> GetAnonymousAppIdAsync();
}
}

View File

@@ -22,4 +22,4 @@ namespace Bit.Core.Abstractions
Task UpsertAsync(CollectionData collection);
Task UpsertAsync(List<CollectionData> collection);
}
}
}

View File

@@ -9,13 +9,13 @@ namespace Bit.Core.Abstractions
{
public interface ICryptoService
{
Task ClearEncKeyAsync(bool memoryOnly = false);
Task ClearKeyAsync();
Task ClearKeyHashAsync();
Task ClearKeyPairAsync(bool memoryOnly = false);
Task ClearKeysAsync();
Task ClearOrgKeysAsync(bool memoryOnly = false);
Task ClearPinProtectedKeyAsync();
Task ClearEncKeyAsync(bool memoryOnly = false, string userId = null);
Task ClearKeyAsync(string userId = null);
Task ClearKeyHashAsync(string userId = null);
Task ClearKeyPairAsync(bool memoryOnly = false, string userId = null);
Task ClearKeysAsync(string userId = null);
Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null);
Task ClearPinProtectedKeyAsync(string userId = null);
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

@@ -9,4 +9,4 @@ namespace Bit.Core.Abstractions
Task CollectAsync(EventType eventType, string cipherId = null, bool uploadImmediately = false);
Task UploadEventsAsync();
}
}
}

View File

@@ -23,4 +23,4 @@ namespace Bit.Core.Abstractions
Task UpsertAsync(FolderData folder);
Task UpsertAsync(List<FolderData> folder);
}
}
}

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Models.Data;
using Bit.Core.Models.Domain;
namespace Bit.Core.Abstractions
{
public interface IOrganizationService
{
Task<Organization> GetAsync(string id);
Task<Organization> GetByIdentifierAsync(string identifier);
Task<List<Organization>> GetAllAsync(string userId = null);
Task ReplaceAsync(Dictionary<string, OrganizationData> organizations);
Task ClearAllAsync(string userId);
}
}

View File

@@ -8,7 +8,8 @@ namespace Bit.Core.Abstractions
public interface IPasswordGenerationService
{
Task AddHistoryAsync(string password, CancellationToken token = default(CancellationToken));
Task ClearAsync();
Task ClearAsync(string userId = null);
void ClearCache();
Task<string> GeneratePassphraseAsync(PasswordGenerationOptions options);
Task<string> GeneratePasswordAsync(PasswordGenerationOptions options);
Task<List<GeneratedPasswordHistory>> GetHistoryAsync();

View File

@@ -10,4 +10,4 @@ namespace Bit.Core.Abstractions
Task<List<List<string>>> GetEquivalentDomainsAsync();
Task SetEquivalentDomainsAsync(List<List<string>> equivalentDomains);
}
}
}

View File

@@ -1,12 +1,173 @@
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
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;
namespace Bit.Core.Abstractions
{
public interface IStateService
{
Task<T> GetAsync<T>(string key);
Task RemoveAsync(string key);
Task SaveAsync<T>(string key, T obj);
Task PurgeAsync();
bool BiometricLocked { get; set; }
ExtendedObservableCollection<AccountView> Accounts { get; set; }
Task<string> GetActiveUserIdAsync(StorageOptions options = null);
Task SetActiveUserAsync(string userId);
Task<bool> IsAuthenticatedAsync(StorageOptions options = null);
Task<bool> HasMultipleAccountsAsync();
Task AddAccountAsync(Account account);
// Task SetInformationAsync(string userId, string email, KdfType kdf, int? kdfIterations);
Task CleanAsync(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);
}
}
}

View File

@@ -6,15 +6,16 @@ namespace Bit.Core.Abstractions
{
public interface ITokenService
{
Task ClearTokenAsync();
Task ClearTokenAsync(string userId = null);
Task ClearTwoFactorTokenAsync(string email);
void ClearCache();
JObject DecodeToken();
string GetEmail();
bool GetEmailVerified();
string GetIssuer();
string GetName();
bool GetPremium();
bool GetIsExternal();
Task<bool> GetIsExternal();
Task<string> GetRefreshTokenAsync();
Task<string> GetTokenAsync();
Task ToggleTokensAsync();

View File

@@ -1,22 +1,18 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Models.Domain;
namespace Bit.Core.Abstractions
{
public interface IVaultTimeoutService
{
EncString PinProtectedKey { get; set; }
bool BiometricLocked { get; set; }
Task CheckVaultTimeoutAsync();
Task ClearAsync();
Task<bool> IsLockedAsync();
Task ClearAsync(string userId = null);
Task<bool> IsLockedAsync(string userId = null);
Task<Tuple<bool, bool>> IsPinLockSetAsync();
Task<bool> IsBiometricLockSetAsync();
Task LockAsync(bool allowSoftLock = false, bool userInitiated = false);
Task LogOutAsync();
Task LockAsync(bool allowSoftLock = false, bool userInitiated = false, string userId = null);
Task LogOutAsync(string userId = null);
Task SetVaultTimeoutOptionsAsync(int? timeout, string action);
Task<int?> GetVaultTimeout();
Task<int?> GetVaultTimeout(string userId = null);
}
}

View File

@@ -4,29 +4,16 @@
{
public const string AndroidAppProtocol = "androidapp://";
public const string iOSAppProtocol = "iosapp://";
public static string SyncOnRefreshKey = "syncOnRefresh";
public static string VaultTimeoutKey = "lockOption";
public static string VaultTimeoutActionKey = "vaultTimeoutAction";
public static string LastActiveTimeKey = "lastActiveTime";
public static string BiometricUnlockKey = "fingerprintUnlock";
public static string ProtectedPin = "protectedPin";
public static string PinProtectedKey = "pinProtectedKey";
public static string DefaultUriMatch = "defaultUriMatch";
public static string DisableAutoTotpCopyKey = "disableAutoTotpCopy";
public static string EnvironmentUrlsKey = "environmentUrls";
public static string StateKey = "state";
public static string AppIdKey = "appId";
public static string PreAuthEnvironmentUrlsKey = "preAuthEnvironmentUrls";
public static string LastFileCacheClearKey = "lastFileCacheClear";
public static string AutofillDisableSavePromptKey = "autofillDisableSavePrompt";
public static string AutofillBlacklistedUrisKey = "autofillBlacklistedUris";
public static string AutofillTileAdded = "autofillTileAdded";
public static string DisableFaviconKey = "disableFavicon";
public static string PushRegisteredTokenKey = "pushRegisteredToken";
public static string PushCurrentTokenKey = "pushCurrentToken";
public static string PushLastRegistrationDateKey = "pushLastRegistrationDate";
public static string PushInitialPromptShownKey = "pushInitialPromptShown";
public static string ThemeKey = "theme";
public static string ClearClipboardKey = "clearClipboard";
public static string LastBuildKey = "lastBuild";
public static string OldUserIdKey = "userId";
public static string AddSitePromptShownKey = "addSitePromptShown";
public static string ClearCiphersCacheKey = "clearCiphersCache";
public static string BiometricIntegrityKey = "biometricIntegrityState";
@@ -38,11 +25,12 @@
public static string MigratedFromV1AutofillPromptShown = "migratedV1AutofillPromptShown";
public static string TriedV1Resync = "triedV1Resync";
public static string EventCollectionKey = "eventCollection";
public static string PreviousPageKey = "previousPage";
public static string InlineAutofillEnabledKey = "inlineAutofillEnabled";
public static string InvalidUnlockAttempts = "invalidUnlockAttempts";
public static string PasswordRepromptAutofillKey = "passwordRepromptAutofillKey";
public static string PasswordVerifiedAutofillKey = "passwordVerifiedAutofillKey";
public static string RememberEmailKey = "rememberEmail";
public static string RememberedEmailKey = "rememberedEmail";
public static string RememberOrgIdentifierKey = "rememberOrgIdentifier";
public static string RememberedOrgIdentifierKey = "rememberedOrgIdentifier";
public static string AppExtensionStartedKey = "appExtensionStarted";
public static string AppExtensionActivatedKey = "appExtensionActivated";
public const int SelectFileRequestCode = 42;
public const int SelectFilePermissionRequestCode = 43;
public const int SaveFileRequestCode = 44;
@@ -58,5 +46,47 @@
iOSAutoFillClearCiphersCacheKey,
iOSExtensionClearCiphersCacheKey
};
public static string CiphersKey(string userId) => $"ciphers_{userId}";
public static string FoldersKey(string userId) => $"folders_{userId}";
public static string CollectionsKey(string userId) => $"collections_{userId}";
public static string OrganizationsKey(string userId) => $"organizations_{userId}";
public static string LocalDataKey(string userId) => $"ciphersLocalData_{userId}";
public static string NeverDomainsKey(string userId) => $"neverDomains_{userId}";
public static string SendsKey(string userId) => $"sends_{userId}";
public static string PoliciesKey(string userId) => $"policies_{userId}";
public static string KeyKey(string userId) => $"key_{userId}";
public static string EncOrgKeysKey(string userId) => $"encOrgKeys_{userId}";
public static string EncPrivateKeyKey(string userId) => $"encPrivateKey_{userId}";
public static string EncKeyKey(string userId) => $"encKey_{userId}";
public static string KeyHashKey(string userId) => $"keyHash_{userId}";
public static string PinProtectedKey(string userId) => $"pinProtectedKey_{userId}";
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}";
public static string AutofillDisableSavePromptKey(string userId) => $"autofillDisableSavePrompt_{userId}";
public static string AutofillBlacklistedUrisKey(string userId) => $"autofillBlacklistedUris_{userId}";
public static string ClearClipboardKey(string userId) => $"clearClipboard_{userId}";
public static string SyncOnRefreshKey(string userId) => $"syncOnRefresh_{userId}";
public static string DisableFaviconKey(string userId) => $"disableFavicon_{userId}";
public static string DefaultUriMatchKey(string userId) => $"defaultUriMatch_{userId}";
public static string ThemeKey(string userId) => $"theme_{userId}";
public static string DisableAutoTotpCopyKey(string userId) => $"disableAutoTotpCopy_{userId}";
public static string PreviousPageKey(string userId) => $"previousPage_{userId}";
public static string PasswordRepromptAutofillKey(string userId) => $"passwordRepromptAutofillKey_{userId}";
public static string PasswordVerifiedAutofillKey(string userId) => $"passwordVerifiedAutofillKey_{userId}";
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

@@ -0,0 +1,10 @@
namespace Bit.Core.Enums
{
public enum AuthenticationStatus : byte
{
LoggedOut = 0,
Locked = 1,
Unlocked = 2,
Active = 3,
}
}

View File

@@ -0,0 +1,9 @@
namespace Bit.Core.Enums
{
public enum DiskStorageLocation
{
Default = 1,
Preferences = 2,
SecureStorage = 3
}
}

View File

@@ -0,0 +1,9 @@
namespace Bit.Core.Enums
{
public enum StorageLocation
{
Both = 0,
Disk = 1,
Memory = 2
}
}

View File

@@ -0,0 +1,10 @@
namespace Bit.Core.Models.Data
{
public class PreviousPageInfo
{
public string Page { get; set; }
public string CipherId { get; set; }
public string SendId { get; set; }
public string SearchText { get; set; }
}
}

View File

@@ -0,0 +1,99 @@
using System.Collections.Generic;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
namespace Bit.Core.Models.Domain
{
public class Account : Domain
{
public AccountProfile Profile;
public AccountTokens Tokens;
public AccountSettings Settings;
public AccountKeys Keys;
public Account() { }
public Account(AccountProfile profile, AccountTokens tokens)
{
Profile = profile;
Tokens = tokens;
Settings = new AccountSettings();
Keys = new AccountKeys();
}
public Account(Account account)
{
// Copy constructor excludes Keys (for storage)
Profile = new AccountProfile(account.Profile);
Tokens = new AccountTokens(account.Tokens);
Settings = new AccountSettings(account.Settings);
}
public class AccountProfile
{
public AccountProfile() { }
public AccountProfile(AccountProfile copy)
{
if (copy == null) { return;}
UserId = copy.UserId;
Email = copy.Email;
AuthStatus = copy.AuthStatus;
HasPremiumPersonally = copy.HasPremiumPersonally;
KdfType = copy.KdfType;
KdfIterations = copy.KdfIterations;
}
public string UserId;
public string Email;
public AuthenticationStatus? AuthStatus;
public bool? HasPremiumPersonally;
public KdfType? KdfType;
public int? KdfIterations;
}
public class AccountTokens
{
public AccountTokens() {}
public AccountTokens(AccountTokens copy)
{
if (copy == null) { return;}
AccessToken = copy.AccessToken;
RefreshToken = copy.RefreshToken;
}
public string AccessToken;
public string RefreshToken;
}
public class AccountSettings
{
public AccountSettings() {}
public AccountSettings(AccountSettings copy)
{
if (copy == null) { return;}
EnvironmentUrls = copy.EnvironmentUrls;
PinProtected = copy.PinProtected;
}
public EnvironmentUrlData EnvironmentUrls;
public EncString PinProtected;
}
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

@@ -0,0 +1,10 @@
using System;
namespace Bit.Core.Models.Domain
{
public class GlobalState : Domain
{
public int? StateVersion { get; set; }
public bool EnableBiometrics { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Bit.Core.Models.Domain
{
public class State : Domain
{
public Dictionary<string, Account> Accounts { get; set; }
public string ActiveUserId { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using Bit.Core.Enums;
namespace Bit.Core.Models.Domain
{
public class StorageOptions : Domain
{
public StorageLocation? StorageLocation { get; set; }
public bool? UseSecureStorage { get; set; }
public string UserId { get; set; }
public string Email { get; set; }
}
}

View File

@@ -0,0 +1,31 @@
using Bit.Core.Enums;
using Bit.Core.Models.Domain;
namespace Bit.Core.Models.View
{
public class AccountView : View
{
public AccountView() { }
public AccountView(Account a = null)
{
if (a == null)
{
// null will render as "Add Account" row
return;
}
IsAccount = true;
UserId = a.Profile.UserId;
Email = a.Profile.Email;
Hostname = a.Settings.EnvironmentUrls.Base;
AuthStatus = a.Profile.AuthStatus;
}
public bool IsAccount { get; set; }
public string UserId { get; set; }
public string Email { get; set; }
public string Hostname { get; set; }
public AuthenticationStatus? AuthStatus { get; set; }
}
}

View File

@@ -6,33 +6,28 @@ namespace Bit.Core.Services
{
public class AppIdService : IAppIdService
{
private readonly IStorageService _storageService;
private readonly IStateService _stateService;
public AppIdService(IStorageService storageService)
public AppIdService(IStateService stateService)
{
_storageService = storageService;
_stateService = stateService;
}
public Task<string> GetAppIdAsync()
public async Task<string> GetAppIdAsync()
{
return MakeAndGetAppIdAsync("appId");
}
public Task<string> GetAnonymousAppIdAsync()
{
return MakeAndGetAppIdAsync("anonymousAppId");
}
private async Task<string> MakeAndGetAppIdAsync(string key)
{
var existingId = await _storageService.GetAsync<string>(key);
if (existingId != null)
var appId = await _stateService.GetAppIdAsync();
if (appId != null)
{
return existingId;
return appId;
}
var guid = Guid.NewGuid().ToString();
await _storageService.SaveAsync(key, guid);
return guid;
appId = MakeAppId();
await _stateService.SetAppIdAsync(appId);
return appId;
}
private string MakeAppId()
{
return Guid.NewGuid().ToString();
}
}
}

View File

@@ -14,13 +14,12 @@ namespace Bit.Core.Services
private readonly ICryptoService _cryptoService;
private readonly ICryptoFunctionService _cryptoFunctionService;
private readonly IApiService _apiService;
private readonly IUserService _userService;
private readonly IStateService _stateService;
private readonly ITokenService _tokenService;
private readonly IAppIdService _appIdService;
private readonly II18nService _i18nService;
private readonly IPlatformUtilsService _platformUtilsService;
private readonly IMessagingService _messagingService;
private readonly IVaultTimeoutService _vaultTimeoutService;
private readonly IKeyConnectorService _keyConnectorService;
private readonly bool _setCryptoKeys;
@@ -30,7 +29,7 @@ namespace Bit.Core.Services
ICryptoService cryptoService,
ICryptoFunctionService cryptoFunctionService,
IApiService apiService,
IUserService userService,
IStateService stateService,
ITokenService tokenService,
IAppIdService appIdService,
II18nService i18nService,
@@ -43,13 +42,12 @@ namespace Bit.Core.Services
_cryptoService = cryptoService;
_cryptoFunctionService = cryptoFunctionService;
_apiService = apiService;
_userService = userService;
_stateService = stateService;
_tokenService = tokenService;
_appIdService = appIdService;
_i18nService = i18nService;
_platformUtilsService = platformUtilsService;
_messagingService = messagingService;
_vaultTimeoutService = vaultTimeoutService;
_keyConnectorService = keyConnectorService;
_setCryptoKeys = setCryptoKeys;
@@ -355,8 +353,23 @@ namespace Bit.Core.Services
await _tokenService.SetTwoFactorTokenAsync(tokenResponse.TwoFactorToken, email);
}
await _tokenService.SetTokensAsync(tokenResponse.AccessToken, tokenResponse.RefreshToken);
await _userService.SetInformationAsync(_tokenService.GetUserId(), _tokenService.GetEmail(),
tokenResponse.Kdf, tokenResponse.KdfIterations);
await _stateService.AddAccountAsync(
new Account(
new Account.AccountProfile()
{
UserId = _tokenService.GetUserId(),
Email = _tokenService.GetEmail(),
HasPremiumPersonally = _tokenService.GetPremium(),
KdfType = tokenResponse.Kdf,
KdfIterations = tokenResponse.KdfIterations,
},
new Account.AccountTokens()
{
AccessToken = tokenResponse.AccessToken,
RefreshToken = tokenResponse.RefreshToken,
}
)
);
if (_setCryptoKeys)
{
if (key != null)
@@ -430,7 +443,7 @@ namespace Bit.Core.Services
}
_vaultTimeoutService.BiometricLocked = false;
_stateService.BiometricLocked = false;
_messagingService.Send("loggedIn");
return result;
}

View File

@@ -19,15 +19,11 @@ namespace Bit.Core.Services
{
public class CipherService : ICipherService
{
private const string Keys_CiphersFormat = "ciphers_{0}";
private const string Keys_LocalData = "ciphersLocalData";
private const string Keys_NeverDomains = "neverDomains";
private readonly string[] _ignoredSearchTerms = new string[] { "com", "net", "org", "android",
"io", "co", "uk", "au", "nz", "fr", "de", "tv", "info", "app", "apps", "eu", "me", "dev", "jp", "mobile" };
private List<CipherView> _decryptedCipherCache;
private readonly ICryptoService _cryptoService;
private readonly IUserService _userService;
private readonly IStateService _stateService;
private readonly ISettingsService _settingsService;
private readonly IApiService _apiService;
private readonly IFileUploadService _fileUploadService;
@@ -45,7 +41,7 @@ namespace Bit.Core.Services
public CipherService(
ICryptoService cryptoService,
IUserService userService,
IStateService stateService,
ISettingsService settingsService,
IApiService apiService,
IFileUploadService fileUploadService,
@@ -56,7 +52,7 @@ namespace Bit.Core.Services
string[] allClearCipherCacheKeys)
{
_cryptoService = cryptoService;
_userService = userService;
_stateService = stateService;
_settingsService = settingsService;
_apiService = apiService;
_fileUploadService = fileUploadService;
@@ -211,11 +207,8 @@ namespace Bit.Core.Services
public async Task<Cipher> GetAsync(string id)
{
var userId = await _userService.GetUserIdAsync();
var localData = await _storageService.GetAsync<Dictionary<string, Dictionary<string, object>>>(
Keys_LocalData);
var ciphers = await _storageService.GetAsync<Dictionary<string, CipherData>>(
string.Format(Keys_CiphersFormat, userId));
var localData = await _stateService.GetLocalDataAsync();
var ciphers = await _stateService.GetEncryptedCiphersAsync();
if (!ciphers?.ContainsKey(id) ?? true)
{
return null;
@@ -226,11 +219,8 @@ namespace Bit.Core.Services
public async Task<List<Cipher>> GetAllAsync()
{
var userId = await _userService.GetUserIdAsync();
var localData = await _storageService.GetAsync<Dictionary<string, Dictionary<string, object>>>(
Keys_LocalData);
var ciphers = await _storageService.GetAsync<Dictionary<string, CipherData>>(
string.Format(Keys_CiphersFormat, userId));
var localData = await _stateService.GetLocalDataAsync();
var ciphers = await _stateService.GetEncryptedCiphersAsync();
var response = ciphers?.Select(c => new Cipher(c.Value, false,
localData?.ContainsKey(c.Key) ?? false ? localData[c.Key] : null));
return response?.ToList() ?? new List<Cipher>();
@@ -347,7 +337,7 @@ namespace Bit.Core.Services
var others = new List<CipherView>();
var ciphers = await ciphersTask;
var defaultMatch = (UriMatchType?)(await _storageService.GetAsync<int?>(Constants.DefaultUriMatch));
var defaultMatch = (UriMatchType?)(await _stateService.GetDefaultUriMatchAsync());
if (defaultMatch == null)
{
defaultMatch = UriMatchType.Domain;
@@ -457,8 +447,7 @@ namespace Bit.Core.Services
public async Task UpdateLastUsedDateAsync(string id)
{
var ciphersLocalData = await _storageService.GetAsync<Dictionary<string, Dictionary<string, object>>>(
Keys_LocalData);
var ciphersLocalData = await _stateService.GetLocalDataAsync();
if (ciphersLocalData == null)
{
ciphersLocalData = new Dictionary<string, Dictionary<string, object>>();
@@ -476,7 +465,7 @@ namespace Bit.Core.Services
ciphersLocalData[id].Add("lastUsedDate", DateTime.UtcNow);
}
await _storageService.SaveAsync(Keys_LocalData, ciphersLocalData);
await _stateService.SetLocalDataAsync(ciphersLocalData);
// Update cache
if (DecryptedCipherCache == null)
{
@@ -495,13 +484,13 @@ namespace Bit.Core.Services
{
return;
}
var domains = await _storageService.GetAsync<HashSet<string>>(Keys_NeverDomains);
var domains = await _stateService.GetNeverDomainsAsync();
if (domains == null)
{
domains = new HashSet<string>();
}
domains.Add(domain);
await _storageService.SaveAsync(Keys_NeverDomains, domains);
await _stateService.SetNeverDomainsAsync(domains);
}
public async Task SaveWithServerAsync(Cipher cipher)
@@ -526,7 +515,7 @@ namespace Bit.Core.Services
var request = new CipherRequest(cipher);
response = await _apiService.PutCipherAsync(cipher.Id, request);
}
var userId = await _userService.GetUserIdAsync();
var userId = await _stateService.GetActiveUserIdAsync();
var data = new CipherData(response, userId, cipher.CollectionIds);
await UpsertAsync(data);
}
@@ -550,7 +539,7 @@ namespace Bit.Core.Services
var encCipher = await EncryptAsync(cipher);
var request = new CipherShareRequest(encCipher);
var response = await _apiService.PutShareCipherAsync(cipher.Id, request);
var userId = await _userService.GetUserIdAsync();
var userId = await _stateService.GetActiveUserIdAsync();
var data = new CipherData(response, userId, collectionIds);
await UpsertAsync(data);
}
@@ -581,7 +570,7 @@ namespace Bit.Core.Services
response = await LegacyServerAttachmentFileUploadAsync(cipher.Id, encFileName, encFileData, orgEncAttachmentKey);
}
var userId = await _userService.GetUserIdAsync();
var userId = await _stateService.GetActiveUserIdAsync();
var cData = new CipherData(response, userId, cipher.CollectionIds);
await UpsertAsync(cData);
return new Cipher(cData);
@@ -602,16 +591,14 @@ namespace Bit.Core.Services
{
var request = new CipherCollectionsRequest(cipher.CollectionIds?.ToList());
await _apiService.PutCipherCollectionsAsync(cipher.Id, request);
var userId = await _userService.GetUserIdAsync();
var userId = await _stateService.GetActiveUserIdAsync();
var data = cipher.ToCipherData(userId);
await UpsertAsync(data);
}
public async Task UpsertAsync(CipherData cipher)
{
var userId = await _userService.GetUserIdAsync();
var storageKey = string.Format(Keys_CiphersFormat, userId);
var ciphers = await _storageService.GetAsync<Dictionary<string, CipherData>>(storageKey);
var ciphers = await _stateService.GetEncryptedCiphersAsync();
if (ciphers == null)
{
ciphers = new Dictionary<string, CipherData>();
@@ -621,15 +608,13 @@ namespace Bit.Core.Services
ciphers.Add(cipher.Id, null);
}
ciphers[cipher.Id] = cipher;
await _storageService.SaveAsync(storageKey, ciphers);
await _stateService.SetEncryptedCiphersAsync(ciphers);
await ClearCacheAsync();
}
public async Task UpsertAsync(List<CipherData> cipher)
{
var userId = await _userService.GetUserIdAsync();
var storageKey = string.Format(Keys_CiphersFormat, userId);
var ciphers = await _storageService.GetAsync<Dictionary<string, CipherData>>(storageKey);
var ciphers = await _stateService.GetEncryptedCiphersAsync();
if (ciphers == null)
{
ciphers = new Dictionary<string, CipherData>();
@@ -642,28 +627,25 @@ namespace Bit.Core.Services
}
ciphers[c.Id] = c;
}
await _storageService.SaveAsync(storageKey, ciphers);
await _stateService.SetEncryptedCiphersAsync(ciphers);
await ClearCacheAsync();
}
public async Task ReplaceAsync(Dictionary<string, CipherData> ciphers)
{
var userId = await _userService.GetUserIdAsync();
await _storageService.SaveAsync(string.Format(Keys_CiphersFormat, userId), ciphers);
await _stateService.SetEncryptedCiphersAsync(ciphers);
await ClearCacheAsync();
}
public async Task ClearAsync(string userId)
{
await _storageService.RemoveAsync(string.Format(Keys_CiphersFormat, userId));
await _stateService.SetEncryptedCiphersAsync(null, new StorageOptions { UserId = userId });
await ClearCacheAsync();
}
public async Task DeleteAsync(string id)
{
var userId = await _userService.GetUserIdAsync();
var cipherKey = string.Format(Keys_CiphersFormat, userId);
var ciphers = await _storageService.GetAsync<Dictionary<string, CipherData>>(cipherKey);
var ciphers = await _stateService.GetEncryptedCiphersAsync();
if (ciphers == null)
{
return;
@@ -673,15 +655,13 @@ namespace Bit.Core.Services
return;
}
ciphers.Remove(id);
await _storageService.SaveAsync(cipherKey, ciphers);
await _stateService.SetEncryptedCiphersAsync(ciphers);
await ClearCacheAsync();
}
public async Task DeleteAsync(List<string> ids)
{
var userId = await _userService.GetUserIdAsync();
var cipherKey = string.Format(Keys_CiphersFormat, userId);
var ciphers = await _storageService.GetAsync<Dictionary<string, CipherData>>(cipherKey);
var ciphers = await _stateService.GetEncryptedCiphersAsync();
if (ciphers == null)
{
return;
@@ -694,7 +674,7 @@ namespace Bit.Core.Services
}
ciphers.Remove(id);
}
await _storageService.SaveAsync(cipherKey, ciphers);
await _stateService.SetEncryptedCiphersAsync(ciphers);
await ClearCacheAsync();
}
@@ -706,9 +686,7 @@ namespace Bit.Core.Services
public async Task DeleteAttachmentAsync(string id, string attachmentId)
{
var userId = await _userService.GetUserIdAsync();
var cipherKey = string.Format(Keys_CiphersFormat, userId);
var ciphers = await _storageService.GetAsync<Dictionary<string, CipherData>>(cipherKey);
var ciphers = await _stateService.GetEncryptedCiphersAsync();
if (ciphers == null || !ciphers.ContainsKey(id) || ciphers[id].Attachments == null)
{
return;
@@ -718,7 +696,7 @@ namespace Bit.Core.Services
{
ciphers[id].Attachments.Remove(attachment);
}
await _storageService.SaveAsync(cipherKey, ciphers);
await _stateService.SetEncryptedCiphersAsync(ciphers);
await ClearCacheAsync();
}
@@ -771,9 +749,7 @@ namespace Bit.Core.Services
public async Task SoftDeleteWithServerAsync(string id)
{
var userId = await _userService.GetUserIdAsync();
var cipherKey = string.Format(Keys_CiphersFormat, userId);
var ciphers = await _storageService.GetAsync<Dictionary<string, CipherData>>(cipherKey);
var ciphers = await _stateService.GetEncryptedCiphersAsync();
if (ciphers == null)
{
return;
@@ -785,15 +761,13 @@ namespace Bit.Core.Services
await _apiService.PutDeleteCipherAsync(id);
ciphers[id].DeletedDate = DateTime.UtcNow;
await _storageService.SaveAsync(cipherKey, ciphers);
await _stateService.SetEncryptedCiphersAsync(ciphers);
await ClearCacheAsync();
}
public async Task RestoreWithServerAsync(string id)
{
var userId = await _userService.GetUserIdAsync();
var cipherKey = string.Format(Keys_CiphersFormat, userId);
var ciphers = await _storageService.GetAsync<Dictionary<string, CipherData>>(cipherKey);
var ciphers = await _stateService.GetEncryptedCiphersAsync();
if (ciphers == null)
{
return;
@@ -805,7 +779,7 @@ namespace Bit.Core.Services
var response = await _apiService.PutRestoreCipherAsync(id);
ciphers[id].DeletedDate = null;
ciphers[id].RevisionDate = response.RevisionDate;
await _storageService.SaveAsync(cipherKey, ciphers);
await _stateService.SetEncryptedCiphersAsync(ciphers);
await ClearCacheAsync();
}

View File

@@ -13,24 +13,20 @@ namespace Bit.Core.Services
{
public class CollectionService : ICollectionService
{
private const string Keys_CollectionsFormat = "collections_{0}";
private const char NestingDelimiter = '/';
private List<CollectionView> _decryptedCollectionCache;
private readonly ICryptoService _cryptoService;
private readonly IUserService _userService;
private readonly IStorageService _storageService;
private readonly IStateService _stateService;
private readonly II18nService _i18nService;
public CollectionService(
ICryptoService cryptoService,
IUserService userService,
IStorageService storageService,
IStateService stateService,
II18nService i18nService)
{
_cryptoService = cryptoService;
_userService = userService;
_storageService = storageService;
_stateService = stateService;
_i18nService = i18nService;
}
@@ -83,9 +79,7 @@ namespace Bit.Core.Services
public async Task<Collection> GetAsync(string id)
{
var userId = await _userService.GetUserIdAsync();
var collections = await _storageService.GetAsync<Dictionary<string, CollectionData>>(
string.Format(Keys_CollectionsFormat, userId));
var collections = await _stateService.GetEncryptedCollectionsAsync();
if (!collections?.ContainsKey(id) ?? true)
{
return null;
@@ -95,9 +89,7 @@ namespace Bit.Core.Services
public async Task<List<Collection>> GetAllAsync()
{
var userId = await _userService.GetUserIdAsync();
var collections = await _storageService.GetAsync<Dictionary<string, CollectionData>>(
string.Format(Keys_CollectionsFormat, userId));
var collections = await _stateService.GetEncryptedCollectionsAsync();
var response = collections?.Select(c => new Collection(c.Value));
return response?.ToList() ?? new List<Collection>();
}
@@ -148,9 +140,7 @@ namespace Bit.Core.Services
public async Task UpsertAsync(CollectionData collection)
{
var userId = await _userService.GetUserIdAsync();
var storageKey = string.Format(Keys_CollectionsFormat, userId);
var collections = await _storageService.GetAsync<Dictionary<string, CollectionData>>(storageKey);
var collections = await _stateService.GetEncryptedCollectionsAsync();
if (collections == null)
{
collections = new Dictionary<string, CollectionData>();
@@ -160,15 +150,13 @@ namespace Bit.Core.Services
collections.Add(collection.Id, null);
}
collections[collection.Id] = collection;
await _storageService.SaveAsync(storageKey, collections);
await _stateService.SetEncryptedCollectionsAsync(collections);
_decryptedCollectionCache = null;
}
public async Task UpsertAsync(List<CollectionData> collection)
{
var userId = await _userService.GetUserIdAsync();
var storageKey = string.Format(Keys_CollectionsFormat, userId);
var collections = await _storageService.GetAsync<Dictionary<string, CollectionData>>(storageKey);
var collections = await _stateService.GetEncryptedCollectionsAsync();
if (collections == null)
{
collections = new Dictionary<string, CollectionData>();
@@ -181,34 +169,31 @@ namespace Bit.Core.Services
}
collections[c.Id] = c;
}
await _storageService.SaveAsync(storageKey, collections);
await _stateService.SetEncryptedCollectionsAsync(collections);
_decryptedCollectionCache = null;
}
public async Task ReplaceAsync(Dictionary<string, CollectionData> collections)
{
var userId = await _userService.GetUserIdAsync();
await _storageService.SaveAsync(string.Format(Keys_CollectionsFormat, userId), collections);
await _stateService.SetEncryptedCollectionsAsync(collections);
_decryptedCollectionCache = null;
}
public async Task ClearAsync(string userId)
{
await _storageService.RemoveAsync(string.Format(Keys_CollectionsFormat, userId));
await _stateService.SetEncryptedCollectionsAsync(null, new StorageOptions { UserId = userId });
_decryptedCollectionCache = null;
}
public async Task DeleteAsync(string id)
{
var userId = await _userService.GetUserIdAsync();
var collectionKey = string.Format(Keys_CollectionsFormat, userId);
var collections = await _storageService.GetAsync<Dictionary<string, CollectionData>>(collectionKey);
var collections = await _stateService.GetEncryptedCollectionsAsync();
if (collections == null || !collections.ContainsKey(id))
{
return;
}
collections.Remove(id);
await _storageService.SaveAsync(collectionKey, collections);
await _stateService.SetEncryptedCollectionsAsync(collections);
_decryptedCollectionCache = null;
}

View File

@@ -14,53 +14,38 @@ namespace Bit.Core.Services
{
public class CryptoService : ICryptoService
{
private readonly IStorageService _storageService;
private readonly IStorageService _secureStorageService;
private readonly IStateService _stateService;
private readonly ICryptoFunctionService _cryptoFunctionService;
private SymmetricCryptoKey _key;
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;
private const string Keys_Key = "key";
private const string Keys_EncOrgKeys = "encOrgKeys";
private const string Keys_EncPrivateKey = "encPrivateKey";
private const string Keys_EncKey = "encKey";
private const string Keys_KeyHash = "keyHash";
public CryptoService(
IStorageService storageService,
IStorageService secureStorageService,
IStateService stateService,
ICryptoFunctionService cryptoFunctionService)
{
_storageService = storageService;
_secureStorageService = secureStorageService;
_stateService = stateService;
_cryptoFunctionService = cryptoFunctionService;
}
public async Task SetKeyAsync(SymmetricCryptoKey key)
{
_key = key;
var option = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
var biometric = await _storageService.GetAsync<bool?>(Constants.BiometricUnlockKey);
await _stateService.SetKeyDecryptedAsync(key);
var option = await _stateService.GetVaultTimeoutAsync();
var biometric = await _stateService.GetBiometricUnlockAsync();
if (option.HasValue && !biometric.GetValueOrDefault())
{
// If we have a lock option set, we do not store the key
return;
}
await _secureStorageService.SaveAsync(Keys_Key, key?.KeyB64);
await _stateService.SetKeyEncryptedAsync(key?.KeyB64);
}
public async Task SetKeyHashAsync(string keyHash)
{
_keyHash = keyHash;
await _storageService.SaveAsync(Keys_KeyHash, keyHash);
await _stateService.SetKeyHashCachedAsync(keyHash);
await _stateService.SetKeyHashAsync(keyHash);
}
public async Task SetEncKeyAsync(string encKey)
@@ -69,8 +54,8 @@ namespace Bit.Core.Services
{
return;
}
await _storageService.SaveAsync(Keys_EncKey, encKey);
_encKey = null;
await _stateService.SetEncKeyEncryptedAsync(encKey);
await _stateService.SetEncKeyDecryptedAsync(null);
}
public async Task SetEncPrivateKeyAsync(string encPrivateKey)
@@ -79,50 +64,54 @@ namespace Bit.Core.Services
{
return;
}
await _storageService.SaveAsync(Keys_EncPrivateKey, encPrivateKey);
_privateKey = null;
await _stateService.SetPrivateKeyEncryptedAsync(encPrivateKey);
await _stateService.SetPrivateKeyDecryptedAsync(null);
}
public async Task SetOrgKeysAsync(IEnumerable<ProfileOrganizationResponse> orgs)
{
var orgKeys = orgs.ToDictionary(org => org.Id, org => org.Key);
_orgKeys = null;
await _storageService.SaveAsync(Keys_EncOrgKeys, orgKeys);
await _stateService.SetOrgKeysDecryptedAsync(null);
await _stateService.SetOrgKeysEncryptedAsync(orgKeys);
}
public async Task<SymmetricCryptoKey> GetKeyAsync()
{
if (_key != null)
var inMemoryKey = await _stateService.GetKeyDecryptedAsync();
if (inMemoryKey != null)
{
return _key;
return inMemoryKey;
}
var key = await _secureStorageService.GetAsync<string>(Keys_Key);
var key = await _stateService.GetKeyEncryptedAsync();
if (key != null)
{
_key = new SymmetricCryptoKey(Convert.FromBase64String(key));
inMemoryKey = new SymmetricCryptoKey(Convert.FromBase64String(key));
await _stateService.SetKeyDecryptedAsync(inMemoryKey);
}
return _key;
return inMemoryKey;
}
public async Task<string> GetKeyHashAsync()
{
if (_keyHash != null)
var inMemoryKeyHash = await _stateService.GetKeyHashCachedAsync();
if (inMemoryKeyHash != null)
{
return _keyHash;
return inMemoryKeyHash;
}
var keyHash = await _storageService.GetAsync<string>(Keys_KeyHash);
var keyHash = await _stateService.GetKeyHashAsync();
if (keyHash != null)
{
_keyHash = keyHash;
await _stateService.SetKeyHashCachedAsync(keyHash);
}
return _keyHash;
return keyHash;
}
public Task<SymmetricCryptoKey> GetEncKeyAsync(SymmetricCryptoKey key = null)
{
if (_encKey != null)
var inMemoryKey = _stateService.GetEncKeyDecryptedAsync().GetAwaiter().GetResult();
if (inMemoryKey != null)
{
return Task.FromResult(_encKey);
return Task.FromResult(inMemoryKey);
}
if (_getEncKeysTask != null && !_getEncKeysTask.IsCompleted && !_getEncKeysTask.IsFaulted)
{
@@ -132,7 +121,7 @@ namespace Bit.Core.Services
{
try
{
var encKey = await _storageService.GetAsync<string>(Keys_EncKey);
var encKey = await _stateService.GetEncKeyEncryptedAsync();
if (encKey == null)
{
return null;
@@ -167,8 +156,9 @@ namespace Bit.Core.Services
{
return null;
}
_encKey = new SymmetricCryptoKey(decEncKey);
return _encKey;
var newEncKey = new SymmetricCryptoKey(decEncKey);
await _stateService.SetEncKeyDecryptedAsync(newEncKey);
return newEncKey;
}
finally
{
@@ -181,32 +171,36 @@ namespace Bit.Core.Services
public async Task<byte[]> GetPublicKeyAsync()
{
if (_publicKey != null)
var inMemoryKey = await _stateService.GetPublicKeyAsync();
if (inMemoryKey != null)
{
return _publicKey;
return inMemoryKey;
}
var privateKey = await GetPrivateKeyAsync();
if (privateKey == null)
{
return null;
}
_publicKey = await _cryptoFunctionService.RsaExtractPublicKeyAsync(privateKey);
return _publicKey;
inMemoryKey = await _cryptoFunctionService.RsaExtractPublicKeyAsync(privateKey);
await _stateService.SetPublicKeyAsync(inMemoryKey);
return inMemoryKey;
}
public async Task<byte[]> GetPrivateKeyAsync()
{
if (_privateKey != null)
var inMemoryKey = await _stateService.GetPrivateKeyDecryptedAsync();
if (inMemoryKey != null)
{
return _privateKey;
return inMemoryKey;
}
var encPrivateKey = await _storageService.GetAsync<string>(Keys_EncPrivateKey);
var encPrivateKey = await _stateService.GetPrivateKeyEncryptedAsync();
if (encPrivateKey == null)
{
return null;
}
_privateKey = await DecryptToBytesAsync(new EncString(encPrivateKey), null);
return _privateKey;
inMemoryKey = await DecryptToBytesAsync(new EncString(encPrivateKey), null);
await _stateService.SetPrivateKeyDecryptedAsync(inMemoryKey);
return inMemoryKey;
}
public async Task<List<string>> GetFingerprintAsync(string userId, byte[] publicKey = null)
@@ -226,9 +220,10 @@ namespace Bit.Core.Services
public Task<Dictionary<string, SymmetricCryptoKey>> GetOrgKeysAsync()
{
if (_orgKeys != null && _orgKeys.Count > 0)
var inMemoryKeys = _stateService.GetOrgKeysDecryptedAsync();
if (inMemoryKeys != null && inMemoryKeys.Result.Count > 0)
{
return Task.FromResult(_orgKeys);
return inMemoryKeys;
}
if (_getOrgKeysTask != null && !_getOrgKeysTask.IsCompleted && !_getOrgKeysTask.IsFaulted)
{
@@ -238,7 +233,7 @@ namespace Bit.Core.Services
{
try
{
var encOrgKeys = await _storageService.GetAsync<Dictionary<string, string>>(Keys_EncOrgKeys);
var encOrgKeys = await _stateService.GetOrgKeysEncryptedAsync();
if (encOrgKeys == null)
{
return null;
@@ -254,9 +249,9 @@ namespace Bit.Core.Services
if (setKey)
{
_orgKeys = orgKeys;
await _stateService.SetOrgKeysDecryptedAsync(orgKeys);
}
return _orgKeys;
return orgKeys;
}
finally
{
@@ -311,76 +306,78 @@ namespace Bit.Core.Services
public async Task<bool> HasEncKeyAsync()
{
var encKey = await _storageService.GetAsync<string>(Keys_EncKey);
var encKey = await _stateService.GetEncKeyEncryptedAsync();
return encKey != null;
}
public async Task ClearKeyAsync()
public async Task ClearKeyAsync(string userId = null)
{
_key = _legacyEtmKey = null;
await _secureStorageService.RemoveAsync(Keys_Key);
await _stateService.SetKeyDecryptedAsync(null, new StorageOptions { UserId = userId });
_legacyEtmKey = null;
await _stateService.SetKeyEncryptedAsync(null, new StorageOptions { UserId = userId });
}
public async Task ClearKeyHashAsync()
public async Task ClearKeyHashAsync(string userId = null)
{
_keyHash = null;
await _storageService.RemoveAsync(Keys_KeyHash);
await _stateService.SetKeyHashCachedAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetKeyHashAsync(null, new StorageOptions { UserId = userId });
}
public async Task ClearEncKeyAsync(bool memoryOnly = false)
public async Task ClearEncKeyAsync(bool memoryOnly = false, string userId = null)
{
_encKey = null;
await _stateService.SetEncKeyDecryptedAsync(null, new StorageOptions { UserId = userId });
if (!memoryOnly)
{
await _storageService.RemoveAsync(Keys_EncKey);
await _stateService.SetEncKeyEncryptedAsync(null, new StorageOptions { UserId = userId });
}
}
public async Task ClearKeyPairAsync(bool memoryOnly = false)
public async Task ClearKeyPairAsync(bool memoryOnly = false, string userId = null)
{
_publicKey = _privateKey = null;
await _stateService.SetPublicKeyAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetPrivateKeyDecryptedAsync(null, new StorageOptions { UserId = userId });
if (!memoryOnly)
{
await _storageService.RemoveAsync(Keys_EncPrivateKey);
await _stateService.SetPrivateKeyEncryptedAsync(null, new StorageOptions { UserId = userId });
}
}
public async Task ClearOrgKeysAsync(bool memoryOnly = false)
public async Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null)
{
_orgKeys = null;
await _stateService.SetOrgKeysDecryptedAsync(null, new StorageOptions { UserId = userId });
if (!memoryOnly)
{
await _storageService.RemoveAsync(Keys_EncOrgKeys);
await _stateService.SetOrgKeysEncryptedAsync(null, new StorageOptions { UserId = userId });
}
}
public async Task ClearPinProtectedKeyAsync()
public async Task ClearPinProtectedKeyAsync(string userId = null)
{
await _storageService.RemoveAsync(Constants.PinProtectedKey);
await _stateService.SetPinProtectedAsync(null, new StorageOptions { UserId = userId });
}
public async Task ClearKeysAsync()
public async Task ClearKeysAsync(string userId = null)
{
await Task.WhenAll(new Task[]
{
ClearKeyAsync(),
ClearKeyHashAsync(),
ClearOrgKeysAsync(),
ClearEncKeyAsync(),
ClearKeyPairAsync(),
ClearPinProtectedKeyAsync()
ClearKeyAsync(userId),
ClearKeyHashAsync(userId),
ClearOrgKeysAsync(false, userId),
ClearEncKeyAsync(false, userId),
ClearKeyPairAsync(false, userId),
ClearPinProtectedKeyAsync(userId)
});
}
public async Task ToggleKeyAsync()
{
var key = await GetKeyAsync();
var option = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
var biometric = await _storageService.GetAsync<bool?>(Constants.BiometricUnlockKey);
var option = await _stateService.GetVaultTimeoutAsync();
var biometric = await _stateService.GetBiometricUnlockAsync();
if (!biometric.GetValueOrDefault() && (option != null || option == 0))
{
await ClearKeyAsync();
_key = key;
await _stateService.SetKeyDecryptedAsync(key);
return;
}
await SetKeyAsync(key);
@@ -415,7 +412,7 @@ namespace Bit.Core.Services
{
if (protectedKeyCs == null)
{
var pinProtectedKey = await _storageService.GetAsync<string>(Constants.PinProtectedKey);
var pinProtectedKey = await _stateService.GetPinProtectedAsync();
if (pinProtectedKey == null)
{
throw new Exception("No PIN protected key found.");

View File

@@ -9,14 +9,14 @@ namespace Bit.Core.Services
public class EnvironmentService : IEnvironmentService
{
private readonly IApiService _apiService;
private readonly IStorageService _storageService;
private readonly IStateService _stateService;
public EnvironmentService(
IApiService apiService,
IStorageService storageService)
IStateService stateService)
{
_apiService = apiService;
_storageService = storageService;
_stateService = stateService;
}
public string BaseUrl { get; set; }
@@ -42,7 +42,11 @@ namespace Bit.Core.Services
public async Task SetUrlsFromStorageAsync()
{
var urls = await _storageService.GetAsync<EnvironmentUrlData>(Constants.EnvironmentUrlsKey);
var urls = await _stateService.GetEnvironmentUrlsAsync();
if (urls == null)
{
urls = await _stateService.GetPreAuthEnvironmentUrlsAsync();
}
if (urls == null)
{
urls = new EnvironmentUrlData();
@@ -72,7 +76,7 @@ namespace Bit.Core.Services
urls.Icons = FormatUrl(urls.Icons);
urls.Notifications = FormatUrl(urls.Notifications);
urls.Events = FormatUrl(urls.Events);
await _storageService.SaveAsync(Constants.EnvironmentUrlsKey, urls);
await _stateService.SetPreAuthEnvironmentUrlsAsync(urls);
BaseUrl = urls.Base;
WebVaultUrl = urls.WebVault;
ApiUrl = urls.Api;

View File

@@ -12,31 +12,31 @@ namespace Bit.Core.Services
{
public class EventService : IEventService
{
private readonly IStorageService _storageService;
private readonly IApiService _apiService;
private readonly IUserService _userService;
private readonly IStateService _stateService;
private readonly IOrganizationService _organizationService;
private readonly ICipherService _cipherService;
public EventService(
IStorageService storageService,
IApiService apiService,
IUserService userService,
IStateService stateService,
IOrganizationService organizationService,
ICipherService cipherService)
{
_storageService = storageService;
_apiService = apiService;
_userService = userService;
_stateService = stateService;
_organizationService = organizationService;
_cipherService = cipherService;
}
public async Task CollectAsync(EventType eventType, string cipherId = null, bool uploadImmediately = false)
{
var authed = await _userService.IsAuthenticatedAsync();
var authed = await _stateService.IsAuthenticatedAsync();
if (!authed)
{
return;
}
var organizations = await _userService.GetAllOrganizationAsync();
var organizations = await _organizationService.GetAllAsync();
if (organizations == null)
{
return;
@@ -54,7 +54,7 @@ namespace Bit.Core.Services
return;
}
}
var eventCollection = await _storageService.GetAsync<List<EventData>>(Constants.EventCollectionKey);
var eventCollection = await _stateService.GetEventCollectionAsync();
if (eventCollection == null)
{
eventCollection = new List<EventData>();
@@ -65,7 +65,7 @@ namespace Bit.Core.Services
CipherId = cipherId,
Date = DateTime.UtcNow
});
await _storageService.SaveAsync(Constants.EventCollectionKey, eventCollection);
await _stateService.SetEventCollectionAsync(eventCollection);
if (uploadImmediately)
{
await UploadEventsAsync();
@@ -74,12 +74,12 @@ namespace Bit.Core.Services
public async Task UploadEventsAsync()
{
var authed = await _userService.IsAuthenticatedAsync();
var authed = await _stateService.IsAuthenticatedAsync();
if (!authed)
{
return;
}
var eventCollection = await _storageService.GetAsync<List<EventData>>(Constants.EventCollectionKey);
var eventCollection = await _stateService.GetEventCollectionAsync();
if (eventCollection == null || !eventCollection.Any())
{
return;
@@ -100,7 +100,7 @@ namespace Bit.Core.Services
public async Task ClearEventsAsync()
{
await _storageService.RemoveAsync(Constants.EventCollectionKey);
await _stateService.SetEventCollectionAsync(null);
}
}
}

View File

@@ -15,30 +15,25 @@ namespace Bit.Core.Services
{
public class FolderService : IFolderService
{
private const string Keys_CiphersFormat = "ciphers_{0}";
private const string Keys_FoldersFormat = "folders_{0}";
private const char NestingDelimiter = '/';
private List<FolderView> _decryptedFolderCache;
private readonly ICryptoService _cryptoService;
private readonly IUserService _userService;
private readonly IStateService _stateService;
private readonly IApiService _apiService;
private readonly IStorageService _storageService;
private readonly II18nService _i18nService;
private readonly ICipherService _cipherService;
public FolderService(
ICryptoService cryptoService,
IUserService userService,
IStateService stateService,
IApiService apiService,
IStorageService storageService,
II18nService i18nService,
ICipherService cipherService)
{
_cryptoService = cryptoService;
_userService = userService;
_stateService = stateService;
_apiService = apiService;
_storageService = storageService;
_i18nService = i18nService;
_cipherService = cipherService;
}
@@ -60,9 +55,7 @@ namespace Bit.Core.Services
public async Task<Folder> GetAsync(string id)
{
var userId = await _userService.GetUserIdAsync();
var folders = await _storageService.GetAsync<Dictionary<string, FolderData>>(
string.Format(Keys_FoldersFormat, userId));
var folders = await _stateService.GetEncryptedFoldersAsync();
if (!folders?.ContainsKey(id) ?? true)
{
return null;
@@ -72,9 +65,7 @@ namespace Bit.Core.Services
public async Task<List<Folder>> GetAllAsync()
{
var userId = await _userService.GetUserIdAsync();
var folders = await _storageService.GetAsync<Dictionary<string, FolderData>>(
string.Format(Keys_FoldersFormat, userId));
var folders = await _stateService.GetEncryptedFoldersAsync();
var response = folders?.Select(f => new Folder(f.Value));
return response?.ToList() ?? new List<Folder>();
}
@@ -153,16 +144,14 @@ namespace Bit.Core.Services
{
response = await _apiService.PutFolderAsync(folder.Id, request);
}
var userId = await _userService.GetUserIdAsync();
var userId = await _stateService.GetActiveUserIdAsync();
var data = new FolderData(response, userId);
await UpsertAsync(data);
}
public async Task UpsertAsync(FolderData folder)
{
var userId = await _userService.GetUserIdAsync();
var storageKey = string.Format(Keys_FoldersFormat, userId);
var folders = await _storageService.GetAsync<Dictionary<string, FolderData>>(storageKey);
var folders = await _stateService.GetEncryptedFoldersAsync();
if (folders == null)
{
folders = new Dictionary<string, FolderData>();
@@ -172,15 +161,13 @@ namespace Bit.Core.Services
folders.Add(folder.Id, null);
}
folders[folder.Id] = folder;
await _storageService.SaveAsync(storageKey, folders);
await _stateService.SetEncryptedFoldersAsync(folders);
_decryptedFolderCache = null;
}
public async Task UpsertAsync(List<FolderData> folder)
{
var userId = await _userService.GetUserIdAsync();
var storageKey = string.Format(Keys_FoldersFormat, userId);
var folders = await _storageService.GetAsync<Dictionary<string, FolderData>>(storageKey);
var folders = await _stateService.GetEncryptedFoldersAsync();
if (folders == null)
{
folders = new Dictionary<string, FolderData>();
@@ -193,39 +180,35 @@ namespace Bit.Core.Services
}
folders[f.Id] = f;
}
await _storageService.SaveAsync(storageKey, folders);
await _stateService.SetEncryptedFoldersAsync(folders);
_decryptedFolderCache = null;
}
public async Task ReplaceAsync(Dictionary<string, FolderData> folders)
{
var userId = await _userService.GetUserIdAsync();
await _storageService.SaveAsync(string.Format(Keys_FoldersFormat, userId), folders);
await _stateService.SetEncryptedFoldersAsync(folders);
_decryptedFolderCache = null;
}
public async Task ClearAsync(string userId)
{
await _storageService.RemoveAsync(string.Format(Keys_FoldersFormat, userId));
await _stateService.SetEncryptedFoldersAsync(null, new StorageOptions { UserId = userId });
_decryptedFolderCache = null;
}
public async Task DeleteAsync(string id)
{
var userId = await _userService.GetUserIdAsync();
var folderKey = string.Format(Keys_FoldersFormat, userId);
var folders = await _storageService.GetAsync<Dictionary<string, FolderData>>(folderKey);
var folders = await _stateService.GetEncryptedFoldersAsync();
if (folders == null || !folders.ContainsKey(id))
{
return;
}
folders.Remove(id);
await _storageService.SaveAsync(folderKey, folders);
await _stateService.SetEncryptedFoldersAsync(folders);
_decryptedFolderCache = null;
// Items in a deleted folder are re-assigned to "No Folder"
var ciphers = await _storageService.GetAsync<Dictionary<string, CipherData>>(
string.Format(Keys_CiphersFormat, userId));
var ciphers = await _stateService.GetEncryptedCiphersAsync();
if (ciphers != null)
{
var updates = new List<CipherData>();

View File

@@ -1,7 +1,6 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Abstractions;
using Bit.Core.Exceptions;
using Bit.Core.Models.Domain;
using Bit.Core.Models.Request;
@@ -9,24 +8,20 @@ namespace Bit.Core.Services
{
public class KeyConnectorService : IKeyConnectorService
{
private const string Keys_UsesKeyConnector = "usesKeyConnector";
private readonly IUserService _userService;
private readonly IStateService _stateService;
private readonly ICryptoService _cryptoService;
private readonly IStorageService _storageService;
private readonly ITokenService _tokenService;
private readonly IApiService _apiService;
private readonly IOrganizationService _organizationService;
private bool? _usesKeyConnector;
public KeyConnectorService(IUserService userService, ICryptoService cryptoService,
IStorageService storageService, ITokenService tokenService, IApiService apiService)
public KeyConnectorService(IStateService stateService, ICryptoService cryptoService,
ITokenService tokenService, IApiService apiService, OrganizationService organizationService)
{
_userService = userService;
_stateService = stateService;
_cryptoService = cryptoService;
_storageService = storageService;
_tokenService = tokenService;
_apiService = apiService;
_organizationService = organizationService;
}
public async Task GetAndSetKey(string url)
@@ -46,23 +41,17 @@ namespace Bit.Core.Services
public async Task SetUsesKeyConnector(bool usesKeyConnector)
{
_usesKeyConnector = usesKeyConnector;
await _storageService.SaveAsync(Keys_UsesKeyConnector, usesKeyConnector);
await _stateService.SetUsesKeyConnectorAsync(usesKeyConnector);
}
public async Task<bool> GetUsesKeyConnector()
{
if (!_usesKeyConnector.HasValue)
{
_usesKeyConnector = await _storageService.GetAsync<bool>(Keys_UsesKeyConnector);
}
return _usesKeyConnector.Value;
return await _stateService.GetUsesKeyConnectorAsync();
}
public async Task<Organization> GetManagingOrganization()
{
var orgs = await _userService.GetAllOrganizationAsync();
var orgs = await _organizationService.GetAllAsync();
return orgs.Find(o =>
o.UsesKeyConnector &&
!o.IsAdmin);
@@ -88,7 +77,7 @@ namespace Bit.Core.Services
public async Task<bool> UserNeedsMigration()
{
var loggedInUsingSso = _tokenService.GetIsExternal();
var loggedInUsingSso = await _tokenService.GetIsExternal();
var requiredByOrganization = await GetManagingOrganization() != null;
var userIsNotUsingKeyConnector = !await GetUsesKeyConnector();

View File

@@ -0,0 +1,55 @@
using Bit.Core.Abstractions;
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 OrganizationService : IOrganizationService
{
private readonly IStateService _stateService;
public OrganizationService(IStateService stateService)
{
_stateService = stateService;
}
public async Task<Organization> GetAsync(string id)
{
var organizations = await _stateService.GetOrganizationsAsync();
if (organizations == null || !organizations.ContainsKey(id))
{
return null;
}
return new Organization(organizations[id]);
}
public async Task<Organization> GetByIdentifierAsync(string identifier)
{
var organizations = await GetAllAsync();
if (organizations == null || organizations.Count == 0)
{
return null;
}
return organizations.FirstOrDefault(o => o.Identifier == identifier);
}
public async Task<List<Organization>> GetAllAsync(string userId = null)
{
var organizations = await _stateService.GetOrganizationsAsync(new StorageOptions { UserId = userId });
return organizations?.Select(o => new Organization(o.Value)).ToList() ?? new List<Organization>();
}
public async Task ReplaceAsync(Dictionary<string, OrganizationData> organizations)
{
await _stateService.SetOrganizationsAsync(organizations);
}
public async Task ClearAllAsync(string userId)
{
await _stateService.SetOrganizationsAsync(null, new StorageOptions { UserId = userId });
}
}
}

View File

@@ -14,8 +14,6 @@ namespace Bit.Core.Services
{
public class PasswordGenerationService : IPasswordGenerationService
{
private const string Keys_Options = "passwordGenerationOptions";
private const string Keys_History = "generatedPasswordHistory";
private const int MaxPasswordsInHistory = 100;
private const string LowercaseCharSet = "abcdefghijkmnopqrstuvwxyz";
private const string UppercaseCharSet = "ABCDEFGHJKLMNPQRSTUVWXYZ";
@@ -23,7 +21,7 @@ namespace Bit.Core.Services
private const string SpecialCharSet = "!@#$%^&*";
private readonly ICryptoService _cryptoService;
private readonly IStorageService _storageService;
private readonly IStateService _stateService;
private readonly ICryptoFunctionService _cryptoFunctionService;
private readonly IPolicyService _policyService;
private PasswordGenerationOptions _defaultOptions = new PasswordGenerationOptions(true);
@@ -32,12 +30,12 @@ namespace Bit.Core.Services
public PasswordGenerationService(
ICryptoService cryptoService,
IStorageService storageService,
IStateService stateService,
ICryptoFunctionService cryptoFunctionService,
IPolicyService policyService)
{
_cryptoService = cryptoService;
_storageService = storageService;
_stateService = stateService;
_cryptoFunctionService = cryptoFunctionService;
_policyService = policyService;
}
@@ -160,6 +158,12 @@ namespace Bit.Core.Services
return password.ToString();
}
public void ClearCache()
{
_optionsCache = null;
_history = null;
}
public async Task<string> GeneratePassphraseAsync(PasswordGenerationOptions options)
{
options.Merge(_defaultOptions);
@@ -204,7 +208,7 @@ namespace Bit.Core.Services
{
if (_optionsCache == null)
{
var options = await _storageService.GetAsync<PasswordGenerationOptions>(Keys_Options);
var options = await _stateService.GetPasswordGenerationOptionsAsync();
if (options == null)
{
_optionsCache = _defaultOptions;
@@ -432,7 +436,7 @@ namespace Bit.Core.Services
public async Task SaveOptionsAsync(PasswordGenerationOptions options)
{
await _storageService.SaveAsync(Keys_Options, options);
await _stateService.SetPasswordGenerationOptionsAsync(options);
_optionsCache = options;
}
@@ -445,7 +449,7 @@ namespace Bit.Core.Services
}
if (_history == null)
{
var encrypted = await _storageService.GetAsync<List<GeneratedPasswordHistory>>(Keys_History);
var encrypted = await _stateService.GetEncryptedPasswordGenerationHistory();
_history = await DecryptHistoryAsync(encrypted);
}
return _history ?? new List<GeneratedPasswordHistory>();
@@ -473,13 +477,15 @@ namespace Bit.Core.Services
}
var newHistory = await EncryptHistoryAsync(currentHistory);
token.ThrowIfCancellationRequested();
await _storageService.SaveAsync(Keys_History, newHistory);
var userId = await _stateService.GetActiveUserIdAsync();
await _stateService.SetEncryptedPasswordGenerationHistoryAsync(newHistory);
}
public async Task ClearAsync()
public async Task ClearAsync(string userId = null)
{
_history = new List<GeneratedPasswordHistory>();
await _storageService.RemoveAsync(Keys_History);
await _stateService.SetEncryptedPasswordGenerationHistoryAsync(null,
new StorageOptions { UserId = userId });
}
public Result PasswordStrength(string password, List<string> userInputs = null)

View File

@@ -12,19 +12,17 @@ namespace Bit.Core.Services
{
public class PolicyService : IPolicyService
{
private const string Keys_PoliciesPrefix = "policies_{0}";
private readonly IStorageService _storageService;
private readonly IUserService _userService;
private readonly IStateService _stateService;
private readonly IOrganizationService _organizationService;
private IEnumerable<Policy> _policyCache;
public PolicyService(
IStorageService storageService,
IUserService userService)
IStateService stateService,
IOrganizationService organizationService)
{
_storageService = storageService;
_userService = userService;
_stateService = stateService;
_organizationService = organizationService;
}
public void ClearCache()
@@ -36,9 +34,7 @@ namespace Bit.Core.Services
{
if (_policyCache == null)
{
var userId = await _userService.GetUserIdAsync();
var policies = await _storageService.GetAsync<Dictionary<string, PolicyData>>(
string.Format(Keys_PoliciesPrefix, userId));
var policies = await _stateService.GetEncryptedPoliciesAsync();
if (policies == null)
{
return null;
@@ -58,14 +54,13 @@ namespace Bit.Core.Services
public async Task Replace(Dictionary<string, PolicyData> policies)
{
var userId = await _userService.GetUserIdAsync();
await _storageService.SaveAsync(string.Format(Keys_PoliciesPrefix, userId), policies);
await _stateService.SetEncryptedPoliciesAsync(policies);
_policyCache = null;
}
public async Task Clear(string userId)
{
await _storageService.RemoveAsync(string.Format(Keys_PoliciesPrefix, userId));
await _stateService.SetEncryptedPoliciesAsync(null, new StorageOptions { UserId = userId });
_policyCache = null;
}
@@ -205,7 +200,7 @@ namespace Bit.Core.Services
{
return false;
}
var organizations = await _userService.GetAllOrganizationAsync();
var organizations = await _organizationService.GetAllAsync();
IEnumerable<Policy> filteredPolicies;

View File

@@ -20,9 +20,8 @@ namespace Bit.Core.Services
{
private List<SendView> _decryptedSendsCache;
private readonly ICryptoService _cryptoService;
private readonly IUserService _userService;
private readonly IStateService _stateService;
private readonly IApiService _apiService;
private readonly IStorageService _storageService;
private readonly II18nService _i18nService;
private readonly ICryptoFunctionService _cryptoFunctionService;
private Task<List<SendView>> _getAllDecryptedTask;
@@ -30,27 +29,23 @@ namespace Bit.Core.Services
public SendService(
ICryptoService cryptoService,
IUserService userService,
IStateService stateService,
IApiService apiService,
IFileUploadService fileUploadService,
IStorageService storageService,
II18nService i18nService,
ICryptoFunctionService cryptoFunctionService)
{
_cryptoService = cryptoService;
_userService = userService;
_stateService = stateService;
_apiService = apiService;
_fileUploadService = fileUploadService;
_storageService = storageService;
_i18nService = i18nService;
_cryptoFunctionService = cryptoFunctionService;
}
public static string GetSendKey(string userId) => string.Format("sends_{0}", userId);
public async Task ClearAsync(string userId)
{
await _storageService.RemoveAsync(GetSendKey(userId));
await _stateService.SetEncryptedSendsAsync(null, new StorageOptions { UserId = userId });
ClearCache();
}
@@ -58,8 +53,7 @@ namespace Bit.Core.Services
public async Task DeleteAsync(params string[] ids)
{
var userId = await _userService.GetUserIdAsync();
var sends = await _storageService.GetAsync<Dictionary<string, SendData>>(GetSendKey(userId));
var sends = await _stateService.GetEncryptedSendsAsync();
if (sends == null)
{
@@ -71,7 +65,7 @@ namespace Bit.Core.Services
sends.Remove(id);
}
await _storageService.SaveAsync(GetSendKey(userId), sends);
await _stateService.SetEncryptedSendsAsync(sends);
ClearCache();
}
@@ -138,8 +132,7 @@ namespace Bit.Core.Services
public async Task<List<Send>> GetAllAsync()
{
var userId = await _userService.GetUserIdAsync();
var sends = await _storageService.GetAsync<Dictionary<string, SendData>>(GetSendKey(userId));
var sends = await _stateService.GetEncryptedSendsAsync();
return sends?.Select(kvp => new Send(kvp.Value)).ToList() ?? new List<Send>();
}
@@ -179,8 +172,7 @@ namespace Bit.Core.Services
public async Task<Send> GetAsync(string id)
{
var userId = await _userService.GetUserIdAsync();
var sends = await _storageService.GetAsync<Dictionary<string, SendData>>(GetSendKey(userId));
var sends = await _stateService.GetEncryptedSendsAsync();
if (sends == null || !sends.ContainsKey(id))
{
@@ -192,8 +184,7 @@ namespace Bit.Core.Services
public async Task ReplaceAsync(Dictionary<string, SendData> sends)
{
var userId = await _userService.GetUserIdAsync();
await _storageService.SaveAsync(GetSendKey(userId), sends);
await _stateService.SetEncryptedSendsAsync(sends);
_decryptedSendsCache = null;
}
@@ -237,7 +228,7 @@ namespace Bit.Core.Services
response = await _apiService.PutSendAsync(send.Id, request);
}
var userId = await _userService.GetUserIdAsync();
var userId = await _stateService.GetActiveUserIdAsync();
await UpsertAsync(new SendData(response, userId));
return response.Id;
}
@@ -255,8 +246,7 @@ namespace Bit.Core.Services
public async Task UpsertAsync(params SendData[] sends)
{
var userId = await _userService.GetUserIdAsync();
var knownSends = await _storageService.GetAsync<Dictionary<string, SendData>>(GetSendKey(userId)) ??
var knownSends = await _stateService.GetEncryptedSendsAsync() ??
new Dictionary<string, SendData>();
foreach (var send in sends)
@@ -264,14 +254,14 @@ namespace Bit.Core.Services
knownSends[send.Id] = send;
}
await _storageService.SaveAsync(GetSendKey(userId), knownSends);
await _stateService.SetEncryptedSendsAsync(knownSends);
_decryptedSendsCache = null;
}
public async Task RemovePasswordWithServerAsync(string id)
{
var response = await _apiService.PutSendRemovePasswordAsync(id);
var userId = await _userService.GetUserIdAsync();
var userId = await _stateService.GetActiveUserIdAsync();
await UpsertAsync(new SendData(response, userId));
}

View File

@@ -1,28 +1,23 @@
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Models.Domain;
namespace Bit.Core.Services
{
public class SettingsService : ISettingsService
{
private const string Keys_SettingsFormat = "settings_{0}";
private const string Keys_EquivalentDomains = "equivalentDomains";
private readonly IUserService _userService;
private readonly IStorageService _storageService;
private readonly IStateService _stateService;
private Dictionary<string, object> _settingsCache;
public SettingsService(
IUserService userService,
IStorageService storageService)
IStateService stateService)
{
_userService = userService;
_storageService = storageService;
_stateService = stateService;
}
public void ClearCache()
@@ -49,7 +44,7 @@ namespace Bit.Core.Services
public async Task ClearAsync(string userId)
{
await _storageService.RemoveAsync(string.Format(Keys_SettingsFormat, userId));
await _stateService.SetSettingsAsync(null, new StorageOptions { UserId = userId });
ClearCache();
}
@@ -59,16 +54,13 @@ namespace Bit.Core.Services
{
if (_settingsCache == null)
{
var userId = await _userService.GetUserIdAsync();
_settingsCache = await _storageService.GetAsync<Dictionary<string, object>>(
string.Format(Keys_SettingsFormat, userId));
_settingsCache = await _stateService.GetSettingsAsync();
}
return _settingsCache;
}
private async Task SetSettingsKeyAsync<T>(string key, T value)
{
var userId = await _userService.GetUserIdAsync();
var settings = await GetSettingsAsync();
if (settings == null)
{
@@ -82,7 +74,7 @@ namespace Bit.Core.Services
{
settings.Add(key, value);
}
await _storageService.SaveAsync(string.Format(Keys_SettingsFormat, userId), settings);
await _stateService.SetSettingsAsync(settings);
_settingsCache = settings;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,16 +12,14 @@ namespace Bit.Core.Services
{
public class SyncService : ISyncService
{
private const string Keys_LastSyncFormat = "lastSync_{0}";
private readonly IUserService _userService;
private readonly IStateService _stateService;
private readonly IApiService _apiService;
private readonly ISettingsService _settingsService;
private readonly IFolderService _folderService;
private readonly ICipherService _cipherService;
private readonly ICryptoService _cryptoService;
private readonly ICollectionService _collectionService;
private readonly IStorageService _storageService;
private readonly IOrganizationService _organizationService;
private readonly IMessagingService _messagingService;
private readonly IPolicyService _policyService;
private readonly ISendService _sendService;
@@ -29,28 +27,28 @@ namespace Bit.Core.Services
private readonly Func<bool, Task> _logoutCallbackAsync;
public SyncService(
IUserService userService,
IStateService stateService,
IApiService apiService,
ISettingsService settingsService,
IFolderService folderService,
ICipherService cipherService,
ICryptoService cryptoService,
ICollectionService collectionService,
IStorageService storageService,
IOrganizationService organizationService,
IMessagingService messagingService,
IPolicyService policyService,
ISendService sendService,
IKeyConnectorService keyConnectorService,
Func<bool, Task> logoutCallbackAsync)
{
_userService = userService;
_stateService = stateService;
_apiService = apiService;
_settingsService = settingsService;
_folderService = folderService;
_cipherService = cipherService;
_cryptoService = cryptoService;
_collectionService = collectionService;
_storageService = storageService;
_organizationService = organizationService;
_messagingService = messagingService;
_policyService = policyService;
_sendService = sendService;
@@ -62,28 +60,26 @@ namespace Bit.Core.Services
public async Task<DateTime?> GetLastSyncAsync()
{
var userId = await _userService.GetUserIdAsync();
if (userId == null)
if (await _stateService.GetActiveUserIdAsync() == null)
{
return null;
}
return await _storageService.GetAsync<DateTime?>(string.Format(Keys_LastSyncFormat, userId));
return await _stateService.GetLastSyncAsync();
}
public async Task SetLastSyncAsync(DateTime date)
{
var userId = await _userService.GetUserIdAsync();
if (userId == null)
if (await _stateService.GetActiveUserIdAsync() == null)
{
return;
}
await _storageService.SaveAsync(string.Format(Keys_LastSyncFormat, userId), date);
await _stateService.SetLastSyncAsync(date);
}
public async Task<bool> FullSyncAsync(bool forceSync, bool allowThrowOnError = false)
{
SyncStarted();
var isAuthenticated = await _userService.IsAuthenticatedAsync();
var isAuthenticated = await _stateService.IsAuthenticatedAsync();
if (!isAuthenticated)
{
return SyncCompleted(false);
@@ -101,7 +97,7 @@ namespace Bit.Core.Services
await SetLastSyncAsync(now);
return SyncCompleted(false);
}
var userId = await _userService.GetUserIdAsync();
var userId = await _stateService.GetActiveUserIdAsync();
try
{
var response = await _apiService.GetSyncAsync();
@@ -131,7 +127,7 @@ namespace Bit.Core.Services
public async Task<bool> SyncUpsertFolderAsync(SyncFolderNotification notification, bool isEdit)
{
SyncStarted();
if (await _userService.IsAuthenticatedAsync())
if (await _stateService.IsAuthenticatedAsync())
{
try
{
@@ -142,7 +138,7 @@ namespace Bit.Core.Services
var remoteFolder = await _apiService.GetFolderAsync(notification.Id);
if (remoteFolder != null)
{
var userId = await _userService.GetUserIdAsync();
var userId = await _stateService.GetActiveUserIdAsync();
await _folderService.UpsertAsync(new FolderData(remoteFolder, userId));
_messagingService.Send("syncedUpsertedFolder", new Dictionary<string, string>
{
@@ -160,7 +156,7 @@ namespace Bit.Core.Services
public async Task<bool> SyncDeleteFolderAsync(SyncFolderNotification notification)
{
SyncStarted();
if (await _userService.IsAuthenticatedAsync())
if (await _stateService.IsAuthenticatedAsync())
{
await _folderService.DeleteAsync(notification.Id);
_messagingService.Send("syncedDeletedFolder", new Dictionary<string, string>
@@ -175,7 +171,7 @@ namespace Bit.Core.Services
public async Task<bool> SyncUpsertCipherAsync(SyncCipherNotification notification, bool isEdit)
{
SyncStarted();
if (await _userService.IsAuthenticatedAsync())
if (await _stateService.IsAuthenticatedAsync())
{
try
{
@@ -230,7 +226,7 @@ namespace Bit.Core.Services
var remoteCipher = await _apiService.GetCipherAsync(notification.Id);
if (remoteCipher != null)
{
var userId = await _userService.GetUserIdAsync();
var userId = await _stateService.GetActiveUserIdAsync();
await _cipherService.UpsertAsync(new CipherData(remoteCipher, userId));
_messagingService.Send("syncedUpsertedCipher", new Dictionary<string, string>
{
@@ -259,7 +255,7 @@ namespace Bit.Core.Services
public async Task<bool> SyncDeleteCipherAsync(SyncCipherNotification notification)
{
SyncStarted();
if (await _userService.IsAuthenticatedAsync())
if (await _stateService.IsAuthenticatedAsync())
{
await _cipherService.DeleteAsync(notification.Id);
_messagingService.Send("syncedDeletedCipher", new Dictionary<string, string>
@@ -315,7 +311,7 @@ namespace Bit.Core.Services
private async Task SyncProfileAsync(ProfileResponse response)
{
var stamp = await _userService.GetSecurityStampAsync();
var stamp = await _stateService.GetSecurityStampAsync();
if (stamp != null && stamp != response.SecurityStamp)
{
if (_logoutCallbackAsync != null)
@@ -327,11 +323,11 @@ namespace Bit.Core.Services
await _cryptoService.SetEncKeyAsync(response.Key);
await _cryptoService.SetEncPrivateKeyAsync(response.PrivateKey);
await _cryptoService.SetOrgKeysAsync(response.Organizations);
await _userService.SetSecurityStampAsync(response.SecurityStamp);
await _stateService.SetSecurityStampAsync(response.SecurityStamp);
var organizations = response.Organizations.ToDictionary(o => o.Id, o => new OrganizationData(o));
await _userService.ReplaceOrganizationsAsync(organizations);
await _userService.SetEmailVerifiedAsync(response.EmailVerified);
await _userService.SetForcePasswordReset(response.ForcePasswordReset);
await _organizationService.ReplaceAsync(organizations);
await _stateService.SetEmailVerifiedAsync(response.EmailVerified);
await _stateService.SetForcePasswordResetAsync(response.ForcePasswordReset);
await _keyConnectorService.SetUsesKeyConnector(response.UsesKeyConnector);
}

View File

@@ -5,24 +5,21 @@ using System;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Bit.Core.Models.Domain;
namespace Bit.Core.Services
{
public class TokenService : ITokenService
{
private readonly IStorageService _storageService;
private readonly IStateService _stateService;
private string _token;
private JObject _decodedToken;
private string _refreshToken;
private const string Keys_AccessToken = "accessToken";
private const string Keys_RefreshToken = "refreshToken";
private const string Keys_TwoFactorTokenFormat = "twoFactorToken_{0}";
public TokenService(IStorageService storageService)
public TokenService(IStateService stateService)
{
_storageService = storageService;
_stateService = stateService;
}
public async Task SetTokensAsync(string accessToken, string refreshToken)
@@ -43,7 +40,7 @@ namespace Bit.Core.Services
return;
}
await _storageService.SaveAsync(Keys_AccessToken, token);
// await _stateService.SetAccessTokenAsync(token);
}
public async Task<string> GetTokenAsync()
@@ -52,7 +49,7 @@ namespace Bit.Core.Services
{
return _token;
}
_token = await _storageService.GetAsync<string>(Keys_AccessToken);
_token = await _stateService.GetAccessTokenAsync();
return _token;
}
@@ -66,7 +63,7 @@ namespace Bit.Core.Services
return;
}
await _storageService.SaveAsync(Keys_RefreshToken, refreshToken);
// await _stateService.SetRefreshTokenAsync(refreshToken);
}
public async Task<string> GetRefreshTokenAsync()
@@ -75,7 +72,7 @@ namespace Bit.Core.Services
{
return _refreshToken;
}
_refreshToken = await _storageService.GetAsync<string>(Keys_RefreshToken);
_refreshToken = await _stateService.GetRefreshTokenAsync();
return _refreshToken;
}
@@ -97,27 +94,32 @@ namespace Bit.Core.Services
public async Task SetTwoFactorTokenAsync(string token, string email)
{
await _storageService.SaveAsync(string.Format(Keys_TwoFactorTokenFormat, email), token);
await _stateService.SetTwoFactorTokenAsync(token, new StorageOptions { Email = email });
}
public async Task<string> GetTwoFactorTokenAsync(string email)
{
return await _storageService.GetAsync<string>(string.Format(Keys_TwoFactorTokenFormat, email));
return await _stateService.GetTwoFactorTokenAsync(new StorageOptions { Email = email });
}
public async Task ClearTwoFactorTokenAsync(string email)
{
await _storageService.RemoveAsync(string.Format(Keys_TwoFactorTokenFormat, email));
await _stateService.SetTwoFactorTokenAsync(null, new StorageOptions { Email = email });
}
public async Task ClearTokenAsync()
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 }));
}
public void ClearCache()
{
_token = null;
_decodedToken = null;
_refreshToken = null;
await Task.WhenAll(
_storageService.RemoveAsync(Keys_AccessToken),
_storageService.RemoveAsync(Keys_RefreshToken));
}
public JObject DecodeToken()
@@ -231,8 +233,12 @@ namespace Bit.Core.Services
return decoded["iss"].Value<string>();
}
public bool GetIsExternal()
public async Task<bool> GetIsExternal()
{
if (_token == null)
{
await GetTokenAsync();
}
var decoded = DecodeToken();
if (decoded?["amr"] == null)
{
@@ -243,8 +249,8 @@ namespace Bit.Core.Services
private async Task<bool> SkipTokenStorage()
{
var timeout = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
var action = await _storageService.GetAsync<string>(Constants.VaultTimeoutActionKey);
var timeout = await _stateService.GetVaultTimeoutAsync();
var action = await _stateService.GetVaultTimeoutActionAsync();
return timeout.HasValue && action == "logOut";
}
}

View File

@@ -10,14 +10,14 @@ namespace Bit.Core.Services
{
private const string SteamChars = "23456789BCDFGHJKMNPQRTVWXY";
private readonly IStorageService _storageService;
private readonly IStateService _stateService;
private readonly ICryptoFunctionService _cryptoFunctionService;
public TotpService(
IStorageService storageService,
IStateService stateService,
ICryptoFunctionService cryptoFunctionService)
{
_storageService = storageService;
_stateService = stateService;
_cryptoFunctionService = cryptoFunctionService;
}
@@ -135,7 +135,7 @@ namespace Bit.Core.Services
public async Task<bool> IsAutoCopyEnabledAsync()
{
var disabled = await _storageService.GetAsync<bool?>(Constants.DisableAutoTotpCopyKey);
var disabled = await _stateService.GetDisableAutoTotpCopyAsync();
return !disabled.GetValueOrDefault();
}
}

View File

@@ -10,9 +10,8 @@ namespace Bit.Core.Services
public class VaultTimeoutService : IVaultTimeoutService
{
private readonly ICryptoService _cryptoService;
private readonly IUserService _userService;
private readonly IStateService _stateService;
private readonly IPlatformUtilsService _platformUtilsService;
private readonly IStorageService _storageService;
private readonly IFolderService _folderService;
private readonly ICipherService _cipherService;
private readonly ICollectionService _collectionService;
@@ -22,13 +21,12 @@ namespace Bit.Core.Services
private readonly IPolicyService _policyService;
private readonly IKeyConnectorService _keyConnectorService;
private readonly Action<bool> _lockedCallback;
private readonly Func<bool, Task> _loggedOutCallback;
private readonly Func<Tuple<bool, string>, Task> _loggedOutCallback;
public VaultTimeoutService(
ICryptoService cryptoService,
IUserService userService,
IStateService stateService,
IPlatformUtilsService platformUtilsService,
IStorageService storageService,
IFolderService folderService,
ICipherService cipherService,
ICollectionService collectionService,
@@ -38,12 +36,11 @@ namespace Bit.Core.Services
IPolicyService policyService,
IKeyConnectorService keyConnectorService,
Action<bool> lockedCallback,
Func<bool, Task> loggedOutCallback)
Func<Tuple<bool, string>, Task> loggedOutCallback)
{
_cryptoService = cryptoService;
_userService = userService;
_stateService = stateService;
_platformUtilsService = platformUtilsService;
_storageService = storageService;
_folderService = folderService;
_cipherService = cipherService;
_collectionService = collectionService;
@@ -56,16 +53,13 @@ namespace Bit.Core.Services
_loggedOutCallback = loggedOutCallback;
}
public EncString PinProtectedKey { get; set; } = null;
public bool BiometricLocked { get; set; } = true;
public async Task<bool> IsLockedAsync()
public async Task<bool> IsLockedAsync(string userId = null)
{
var hasKey = await _cryptoService.HasKeyAsync();
if (hasKey)
{
var biometricSet = await IsBiometricLockSetAsync();
if (biometricSet && BiometricLocked)
if (biometricSet && _stateService.BiometricLocked)
{
return true;
}
@@ -79,45 +73,58 @@ namespace Bit.Core.Services
{
return;
}
var authed = await _userService.IsAuthenticatedAsync();
if (!authed)
foreach (var account in _stateService.Accounts)
{
return;
}
if (await IsLockedAsync())
{
return;
}
var vaultTimeoutMinutes = await GetVaultTimeout();
if (vaultTimeoutMinutes < 0 || vaultTimeoutMinutes == null)
{
return;
}
var lastActiveTime = await _storageService.GetAsync<long?>(Constants.LastActiveTimeKey);
if (lastActiveTime == null)
{
return;
}
var diffMs = _platformUtilsService.GetActiveTime() - lastActiveTime;
var vaultTimeoutMs = vaultTimeoutMinutes * 60000;
if (diffMs >= vaultTimeoutMs)
{
// Pivot based on saved action
var action = await _storageService.GetAsync<string>(Constants.VaultTimeoutActionKey);
if (action == "logOut")
if (account.UserId != null && await ShouldLockAsync(account.UserId))
{
await LogOutAsync();
}
else
{
await LockAsync(true);
await ExecuteTimeoutActionAsync(account.UserId);
}
}
}
public async Task LockAsync(bool allowSoftLock = false, bool userInitiated = false)
private async Task<bool> ShouldLockAsync(string userId)
{
var authed = await _userService.IsAuthenticatedAsync();
var authed = await _stateService.IsAuthenticatedAsync(new StorageOptions { UserId = userId });
if (!authed)
{
return false;
}
if (await IsLockedAsync(userId))
{
return false;
}
var vaultTimeoutMinutes = await GetVaultTimeout(userId);
if (vaultTimeoutMinutes < 0 || vaultTimeoutMinutes == null)
{
return false;
}
var lastActiveTime = await _stateService.GetLastActiveTimeAsync(new StorageOptions { UserId = userId });
if (lastActiveTime == null)
{
return false;
}
var diffMs = _platformUtilsService.GetActiveTime() - lastActiveTime;
var vaultTimeoutMs = vaultTimeoutMinutes * 60000;
return diffMs >= vaultTimeoutMs;
}
private async Task ExecuteTimeoutActionAsync(string userId)
{
var action = await _stateService.GetVaultTimeoutActionAsync(new StorageOptions { UserId = userId });
if (action == "logOut")
{
await LogOutAsync(userId);
}
else
{
await LockAsync(true, false, userId);
}
}
public async Task LockAsync(bool allowSoftLock = false, bool userInitiated = false, string userId = null)
{
var authed = await _stateService.IsAuthenticatedAsync(new StorageOptions { UserId = userId });
if (!authed)
{
return;
@@ -125,7 +132,7 @@ namespace Bit.Core.Services
if (await _keyConnectorService.GetUsesKeyConnector()) {
var pinSet = await IsPinLockSetAsync();
var pinLock = (pinSet.Item1 && PinProtectedKey != null) || pinSet.Item2;
var pinLock = (pinSet.Item1 && _stateService.GetPinProtectedAsync() != null) || pinSet.Item2;
if (!pinLock && !await IsBiometricLockSetAsync())
{
@@ -136,19 +143,26 @@ namespace Bit.Core.Services
if (allowSoftLock)
{
BiometricLocked = await IsBiometricLockSetAsync();
if (BiometricLocked)
var biometricLocked = await IsBiometricLockSetAsync();
_stateService.BiometricLocked = biometricLocked;
if (biometricLocked)
{
_messagingService.Send("locked", userInitiated);
_lockedCallback?.Invoke(userInitiated);
return;
}
}
if (userId == null || userId == await _stateService.GetActiveUserIdAsync())
{
_searchService.ClearIndex();
}
await Task.WhenAll(
_cryptoService.ClearKeyAsync(),
_cryptoService.ClearOrgKeysAsync(true),
_cryptoService.ClearKeyPairAsync(true),
_cryptoService.ClearEncKeyAsync(true));
_cryptoService.ClearKeyAsync(userId),
_cryptoService.ClearOrgKeysAsync(true, userId),
_cryptoService.ClearKeyPairAsync(true, userId),
_cryptoService.ClearEncKeyAsync(true, userId));
_folderService.ClearCache();
await _cipherService.ClearCacheAsync();
@@ -158,43 +172,43 @@ namespace Bit.Core.Services
_lockedCallback?.Invoke(userInitiated);
}
public async Task LogOutAsync()
public async Task LogOutAsync(string userId = null)
{
if(_loggedOutCallback != null)
{
await _loggedOutCallback.Invoke(false);
await _loggedOutCallback.Invoke(new Tuple<bool, string>(false, userId));
}
}
public async Task SetVaultTimeoutOptionsAsync(int? timeout, string action)
{
await _storageService.SaveAsync(Constants.VaultTimeoutKey, timeout);
await _storageService.SaveAsync(Constants.VaultTimeoutActionKey, action);
await _stateService.SetVaultTimeoutAsync(timeout);
await _stateService.SetVaultTimeoutActionAsync(action);
await _cryptoService.ToggleKeyAsync();
await _tokenService.ToggleTokensAsync();
}
public async Task<Tuple<bool, bool>> IsPinLockSetAsync()
{
var protectedPin = await _storageService.GetAsync<string>(Constants.ProtectedPin);
var pinProtectedKey = await _storageService.GetAsync<string>(Constants.PinProtectedKey);
var protectedPin = await _stateService.GetProtectedPinAsync();
var pinProtectedKey = await _stateService.GetPinProtectedAsync();
return new Tuple<bool, bool>(protectedPin != null, pinProtectedKey != null);
}
public async Task<bool> IsBiometricLockSetAsync()
{
var biometricLock = await _storageService.GetAsync<bool?>(Constants.BiometricUnlockKey);
var biometricLock = await _stateService.GetBiometricUnlockAsync();
return biometricLock.GetValueOrDefault();
}
public async Task ClearAsync()
public async Task ClearAsync(string userId = null)
{
PinProtectedKey = null;
await _storageService.RemoveAsync(Constants.ProtectedPin);
await _stateService.SetPinProtectedAsync(null, new StorageOptions { UserId = userId });
await _stateService.SetProtectedPinAsync(null, new StorageOptions { UserId = userId });
}
public async Task<int?> GetVaultTimeout() {
var vaultTimeout = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
public async Task<int?> GetVaultTimeout(string userId = null) {
var vaultTimeout = await _stateService.GetVaultTimeoutAsync();
if (await _policyService.PolicyAppliesToUser(PolicyType.MaximumVaultTimeout)) {
var policy = (await _policyService.GetAll(PolicyType.MaximumVaultTimeout)).First();
@@ -213,7 +227,7 @@ namespace Bit.Core.Services
// We really shouldn't need to set the value here, but multiple services relies on this value being correct.
if (vaultTimeout != timeout) {
await _storageService.SaveAsync(Constants.VaultTimeoutKey, timeout);
await _stateService.SetVaultTimeoutAsync(timeout);
}
return timeout;

View File

@@ -22,64 +22,65 @@ namespace Bit.Core.Utilities
var platformUtilsService = Resolve<IPlatformUtilsService>("platformUtilsService");
var storageService = Resolve<IStorageService>("storageService");
var secureStorageService = Resolve<IStorageService>("secureStorageService");
var stateService = Resolve<IStateService>("stateService");
var i18nService = Resolve<II18nService>("i18nService");
var messagingService = Resolve<IMessagingService>("messagingService");
var cryptoFunctionService = Resolve<ICryptoFunctionService>("cryptoFunctionService");
var cryptoService = Resolve<ICryptoService>("cryptoService");
SearchService searchService = null;
var stateService = new StateService();
var tokenService = new TokenService(storageService);
var tokenService = new TokenService(stateService);
var apiService = new ApiService(tokenService, platformUtilsService, (bool expired) =>
{
messagingService.Send("logout", expired);
return Task.FromResult(0);
}, customUserAgent);
var appIdService = new AppIdService(storageService);
var userService = new UserService(storageService, tokenService);
var settingsService = new SettingsService(userService, storageService);
var appIdService = new AppIdService(stateService);
var organizationService = new OrganizationService(stateService);
var settingsService = new SettingsService(stateService);
var fileUploadService = new FileUploadService(apiService);
var cipherService = new CipherService(cryptoService, userService, settingsService, apiService, fileUploadService,
storageService, i18nService, () => searchService, clearCipherCacheKey, allClearCipherCacheKeys);
var folderService = new FolderService(cryptoService, userService, apiService, storageService,
i18nService, cipherService);
var collectionService = new CollectionService(cryptoService, userService, storageService, i18nService);
var sendService = new SendService(cryptoService, userService, apiService, fileUploadService, storageService,
i18nService, cryptoFunctionService);
var cipherService = new CipherService(cryptoService, stateService, settingsService, apiService,
fileUploadService, storageService, i18nService, () => searchService, clearCipherCacheKey,
allClearCipherCacheKeys);
var folderService = new FolderService(cryptoService, stateService, apiService, i18nService, cipherService);
var collectionService = new CollectionService(cryptoService, stateService, i18nService);
var sendService = new SendService(cryptoService, stateService, apiService, fileUploadService, i18nService,
cryptoFunctionService);
searchService = new SearchService(cipherService, sendService);
var policyService = new PolicyService(storageService, userService);
var keyConnectorService = new KeyConnectorService(userService, cryptoService, storageService, tokenService, apiService);
var vaultTimeoutService = new VaultTimeoutService(cryptoService, userService, platformUtilsService,
storageService, folderService, cipherService, collectionService, searchService, messagingService, tokenService,
policyService, keyConnectorService, null, (expired) =>
var policyService = new PolicyService(stateService, organizationService);
var keyConnectorService = new KeyConnectorService(stateService, cryptoService, tokenService, apiService,
organizationService);
var vaultTimeoutService = new VaultTimeoutService(cryptoService, stateService, platformUtilsService,
folderService, cipherService, collectionService, searchService, messagingService, tokenService,
policyService, keyConnectorService, null, (extras) =>
{
messagingService.Send("logout", expired);
messagingService.Send("logout", extras);
return Task.FromResult(0);
});
var syncService = new SyncService(userService, apiService, settingsService, folderService,
cipherService, cryptoService, collectionService, storageService, messagingService, policyService, sendService,
var syncService = new SyncService(stateService, apiService, settingsService, folderService, cipherService,
cryptoService, collectionService, organizationService, messagingService, policyService, sendService,
keyConnectorService, (bool expired) =>
{
messagingService.Send("logout", expired);
return Task.FromResult(0);
});
var passwordGenerationService = new PasswordGenerationService(cryptoService, storageService,
var passwordGenerationService = new PasswordGenerationService(cryptoService, stateService,
cryptoFunctionService, policyService);
var totpService = new TotpService(storageService, cryptoFunctionService);
var authService = new AuthService(cryptoService, cryptoFunctionService, apiService, userService, tokenService, appIdService,
i18nService, platformUtilsService, messagingService, vaultTimeoutService, keyConnectorService);
var totpService = new TotpService(stateService, cryptoFunctionService);
var authService = new AuthService(cryptoService, cryptoFunctionService, apiService, stateService,
tokenService, appIdService, i18nService, platformUtilsService, messagingService, vaultTimeoutService,
keyConnectorService);
var exportService = new ExportService(folderService, cipherService, cryptoService);
var auditService = new AuditService(cryptoFunctionService, apiService);
var environmentService = new EnvironmentService(apiService, storageService);
var eventService = new EventService(storageService, apiService, userService, cipherService);
var userVerificationService = new UserVerificationService(apiService, platformUtilsService, i18nService, cryptoService);
var environmentService = new EnvironmentService(apiService, stateService);
var eventService = new EventService(apiService, stateService, organizationService, cipherService);
var userVerificationService = new UserVerificationService(apiService, platformUtilsService, i18nService,
cryptoService);
Register<IStateService>("stateService", stateService);
Register<ITokenService>("tokenService", tokenService);
Register<IApiService>("apiService", apiService);
Register<IAppIdService>("appIdService", appIdService);
Register<IUserService>("userService", userService);
Register<IOrganizationService>("organizationService", organizationService);
Register<ISettingsService>("settingsService", settingsService);
Register<ICipherService>("cipherService", cipherService);
Register<IFolderService>("folderService", folderService);