mirror of
https://github.com/bitwarden/mobile
synced 2025-12-12 06:13:21 +00:00
Compare commits
8 Commits
feature/tr
...
add-bio-ke
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc2a91c435 | ||
|
|
4e1361e94a | ||
|
|
d6567fe819 | ||
|
|
bf749d39de | ||
|
|
2522bbc60f | ||
|
|
b620a9c09f | ||
|
|
903f099134 | ||
|
|
fd5ef49811 |
@@ -156,9 +156,9 @@ namespace Bit.Droid
|
|||||||
messagingService, broadcasterService);
|
messagingService, broadcasterService);
|
||||||
var autofillHandler = new AutofillHandler(stateService, messagingService, clipboardService,
|
var autofillHandler = new AutofillHandler(stateService, messagingService, clipboardService,
|
||||||
platformUtilsService, new LazyResolve<IEventService>());
|
platformUtilsService, new LazyResolve<IEventService>());
|
||||||
var biometricService = new BiometricService(stateService);
|
|
||||||
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
||||||
var cryptoService = new CryptoService(stateService, cryptoFunctionService);
|
var cryptoService = new CryptoService(stateService, cryptoFunctionService);
|
||||||
|
var biometricService = new BiometricService(stateService, cryptoService);
|
||||||
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService);
|
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService);
|
||||||
|
|
||||||
ServiceContainer.Register<ISynchronousStorageService>(preferencesStorage);
|
ServiceContainer.Register<ISynchronousStorageService>(preferencesStorage);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Security.Keystore;
|
using Android.Security.Keystore;
|
||||||
|
using Bit.App.Services;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Java.Security;
|
using Java.Security;
|
||||||
@@ -9,10 +10,8 @@ using Javax.Crypto;
|
|||||||
|
|
||||||
namespace Bit.Droid.Services
|
namespace Bit.Droid.Services
|
||||||
{
|
{
|
||||||
public class BiometricService : IBiometricService
|
public class BiometricService : BaseBiometricService
|
||||||
{
|
{
|
||||||
private readonly IStateService _stateService;
|
|
||||||
|
|
||||||
private const string KeyName = "com.8bit.bitwarden.biometric_integrity";
|
private const string KeyName = "com.8bit.bitwarden.biometric_integrity";
|
||||||
|
|
||||||
private const string KeyStoreName = "AndroidKeyStore";
|
private const string KeyStoreName = "AndroidKeyStore";
|
||||||
@@ -24,14 +23,14 @@ namespace Bit.Droid.Services
|
|||||||
|
|
||||||
private readonly KeyStore _keystore;
|
private readonly KeyStore _keystore;
|
||||||
|
|
||||||
public BiometricService(IStateService stateService)
|
public BiometricService(IStateService stateService, ICryptoService cryptoService)
|
||||||
|
: base(stateService, cryptoService)
|
||||||
{
|
{
|
||||||
_stateService = stateService;
|
|
||||||
_keystore = KeyStore.GetInstance(KeyStoreName);
|
_keystore = KeyStore.GetInstance(KeyStoreName);
|
||||||
_keystore.Load(null);
|
_keystore.Load(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
|
public override async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
|
||||||
{
|
{
|
||||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
|
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
|
||||||
{
|
{
|
||||||
@@ -41,7 +40,7 @@ namespace Bit.Droid.Services
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
|
public override async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
|
||||||
{
|
{
|
||||||
if (Build.VERSION.SdkInt < BuildVersionCodes.M)
|
if (Build.VERSION.SdkInt < BuildVersionCodes.M)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -168,10 +168,10 @@ namespace Bit.App.Pages
|
|||||||
PinEnabled = (_pinStatus == PinLockType.Transient && ephemeralPinSet != null) ||
|
PinEnabled = (_pinStatus == PinLockType.Transient && ephemeralPinSet != null) ||
|
||||||
_pinStatus == PinLockType.Persistent;
|
_pinStatus == PinLockType.Persistent;
|
||||||
|
|
||||||
BiometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _cryptoService.HasEncryptedUserKeyAsync();
|
BiometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _biometricService.CanUseBiometricsUnlockAsync();
|
||||||
|
|
||||||
// Users with key connector and without biometric or pin has no MP to unlock with
|
// Users with key connector and without biometric or pin has no MP to unlock with
|
||||||
_usingKeyConnector = await _keyConnectorService.GetUsesKeyConnector();
|
_usingKeyConnector = await _keyConnectorService.GetUsesKeyConnectorAsync();
|
||||||
if (_usingKeyConnector && !(BiometricEnabled || PinEnabled))
|
if (_usingKeyConnector && !(BiometricEnabled || PinEnabled))
|
||||||
{
|
{
|
||||||
await _vaultTimeoutService.LogOutAsync();
|
await _vaultTimeoutService.LogOutAsync();
|
||||||
@@ -297,7 +297,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
Pin = string.Empty;
|
Pin = string.Empty;
|
||||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
||||||
await SetKeyAndContinueAsync(userKey);
|
await SetUserKeyAndContinueAsync(userKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -364,7 +364,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey);
|
var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey);
|
||||||
await _cryptoService.SetMasterKeyAsync(masterKey);
|
await _cryptoService.SetMasterKeyAsync(masterKey);
|
||||||
await SetKeyAndContinueAsync(userKey);
|
await SetUserKeyAndContinueAsync(userKey);
|
||||||
|
|
||||||
// Re-enable biometrics
|
// Re-enable biometrics
|
||||||
if (BiometricEnabled & !BiometricIntegrityValid)
|
if (BiometricEnabled & !BiometricIntegrityValid)
|
||||||
@@ -462,11 +462,12 @@ namespace Bit.App.Pages
|
|||||||
await _stateService.SetBiometricLockedAsync(!success);
|
await _stateService.SetBiometricLockedAsync(!success);
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
await DoContinueAsync();
|
var userKey = await _cryptoService.GetBiometricUnlockKeyAsync();
|
||||||
|
await SetUserKeyAndContinueAsync(userKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetKeyAndContinueAsync(UserKey key)
|
private async Task SetUserKeyAndContinueAsync(UserKey key)
|
||||||
{
|
{
|
||||||
var hasKey = await _cryptoService.HasUserKeyAsync();
|
var hasKey = await _cryptoService.HasUserKeyAsync();
|
||||||
if (!hasKey)
|
if (!hasKey)
|
||||||
|
|||||||
@@ -30,14 +30,14 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public async Task Init()
|
public async Task Init()
|
||||||
{
|
{
|
||||||
Organization = await _keyConnectorService.GetManagingOrganization();
|
Organization = await _keyConnectorService.GetManagingOrganizationAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MigrateAccount()
|
public async Task MigrateAccount()
|
||||||
{
|
{
|
||||||
await _deviceActionService.ShowLoadingAsync(AppResources.Loading);
|
await _deviceActionService.ShowLoadingAsync(AppResources.Loading);
|
||||||
|
|
||||||
await _keyConnectorService.MigrateUser();
|
await _keyConnectorService.MigrateUserAsync();
|
||||||
await _syncService.FullSyncAsync(true);
|
await _syncService.FullSyncAsync(true);
|
||||||
|
|
||||||
await _deviceActionService.HideLoadingAsync();
|
await _deviceActionService.HideLoadingAsync();
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace Bit.App.Pages
|
|||||||
_initialized = true;
|
_initialized = true;
|
||||||
FileFormatSelectedIndex = FileFormatOptions.FindIndex(k => k.Key == "json");
|
FileFormatSelectedIndex = FileFormatOptions.FindIndex(k => k.Key == "json");
|
||||||
DisablePrivateVaultPolicyEnabled = await _policyService.PolicyAppliesToUser(PolicyType.DisablePersonalVaultExport);
|
DisablePrivateVaultPolicyEnabled = await _policyService.PolicyAppliesToUser(PolicyType.DisablePersonalVaultExport);
|
||||||
UseOTPVerification = await _keyConnectorService.GetUsesKeyConnector();
|
UseOTPVerification = await _keyConnectorService.GetUsesKeyConnectorAsync();
|
||||||
|
|
||||||
if (UseOTPVerification)
|
if (UseOTPVerification)
|
||||||
{
|
{
|
||||||
@@ -165,7 +165,7 @@ namespace Bit.App.Pages
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var verificationType = await _keyConnectorService.GetUsesKeyConnector()
|
var verificationType = await _keyConnectorService.GetUsesKeyConnectorAsync()
|
||||||
? VerificationType.OTP
|
? VerificationType.OTP
|
||||||
: VerificationType.MasterPassword;
|
: VerificationType.MasterPassword;
|
||||||
if (!await _userVerificationService.VerifyUser(Secret, verificationType))
|
if (!await _userVerificationService.VerifyUser(Secret, verificationType))
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
_showChangeMasterPassword = IncludeLinksWithSubscriptionInfo() &&
|
_showChangeMasterPassword = IncludeLinksWithSubscriptionInfo() &&
|
||||||
!await _keyConnectorService.GetUsesKeyConnector();
|
!await _keyConnectorService.GetUsesKeyConnectorAsync();
|
||||||
_reportLoggingEnabled = await _loggerService.IsEnabled();
|
_reportLoggingEnabled = await _loggerService.IsEnabled();
|
||||||
_approvePasswordlessLoginRequests = await _stateService.GetApprovePasswordlessLoginsAsync();
|
_approvePasswordlessLoginRequests = await _stateService.GetApprovePasswordlessLoginsAsync();
|
||||||
_shouldConnectToWatch = await _stateService.GetShouldConnectToWatchAsync();
|
_shouldConnectToWatch = await _stateService.GetShouldConnectToWatchAsync();
|
||||||
@@ -429,7 +429,7 @@ namespace Bit.App.Pages
|
|||||||
if (!string.IsNullOrWhiteSpace(pin))
|
if (!string.IsNullOrWhiteSpace(pin))
|
||||||
{
|
{
|
||||||
var masterPassOnRestart = false;
|
var masterPassOnRestart = false;
|
||||||
if (!await _keyConnectorService.GetUsesKeyConnector())
|
if (!await _keyConnectorService.GetUsesKeyConnectorAsync())
|
||||||
{
|
{
|
||||||
masterPassOnRestart = await _platformUtilsService.ShowDialogAsync(
|
masterPassOnRestart = await _platformUtilsService.ShowDialogAsync(
|
||||||
AppResources.PINRequireMasterPasswordRestart, AppResources.UnlockWithPIN,
|
AppResources.PINRequireMasterPasswordRestart, AppResources.UnlockWithPIN,
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
await UpdateVaultButtonTitleAsync();
|
await UpdateVaultButtonTitleAsync();
|
||||||
if (await _keyConnectorService.UserNeedsMigration())
|
if (await _keyConnectorService.UserNeedsMigrationAsync())
|
||||||
{
|
{
|
||||||
_messagingService.Send("convertAccountToKeyConnector");
|
_messagingService.Send("convertAccountToKeyConnector");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Hide password reprompt option if using key connector
|
// Hide password reprompt option if using key connector
|
||||||
_passwordPrompt.IsVisible = !await _keyConnectorService.GetUsesKeyConnector();
|
_passwordPrompt.IsVisible = !await _keyConnectorService.GetUsesKeyConnectorAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisappearing()
|
protected override void OnDisappearing()
|
||||||
|
|||||||
25
src/App/Services/BaseBiometricService.cs
Normal file
25
src/App/Services/BaseBiometricService.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
|
||||||
|
namespace Bit.App.Services
|
||||||
|
{
|
||||||
|
public abstract class BaseBiometricService : IBiometricService
|
||||||
|
{
|
||||||
|
protected readonly IStateService _stateService;
|
||||||
|
protected readonly ICryptoService _cryptoService;
|
||||||
|
|
||||||
|
protected BaseBiometricService(IStateService stateService, ICryptoService cryptoService)
|
||||||
|
{
|
||||||
|
_stateService = stateService;
|
||||||
|
_cryptoService = cryptoService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> CanUseBiometricsUnlockAsync()
|
||||||
|
{
|
||||||
|
return await _cryptoService.HasEncryptedUserKeyAsync() || await _stateService.GetKeyEncryptedAsync() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null);
|
||||||
|
public abstract Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ namespace Bit.App.Services
|
|||||||
public async Task<bool> Enabled()
|
public async Task<bool> Enabled()
|
||||||
{
|
{
|
||||||
var keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
|
var keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
|
||||||
return !await keyConnectorService.GetUsesKeyConnector();
|
return !await keyConnectorService.GetUsesKeyConnectorAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ namespace Bit.App.Utilities
|
|||||||
|
|
||||||
public async Task ValidateAndExecuteAsync()
|
public async Task ValidateAndExecuteAsync()
|
||||||
{
|
{
|
||||||
var verificationType = await _keyConnectorService.GetUsesKeyConnector()
|
var verificationType = await _keyConnectorService.GetUsesKeyConnectorAsync()
|
||||||
? VerificationType.OTP
|
? VerificationType.OTP
|
||||||
: VerificationType.MasterPassword;
|
: VerificationType.MasterPassword;
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ namespace Bit.Core.Abstractions
|
|||||||
Task<OrganizationAutoEnrollStatusResponse> GetOrganizationAutoEnrollStatusAsync(string identifier);
|
Task<OrganizationAutoEnrollStatusResponse> GetOrganizationAutoEnrollStatusAsync(string identifier);
|
||||||
Task PutOrganizationUserResetPasswordEnrollmentAsync(string orgId, string userId,
|
Task PutOrganizationUserResetPasswordEnrollmentAsync(string orgId, string userId,
|
||||||
OrganizationUserResetPasswordEnrollmentRequest request);
|
OrganizationUserResetPasswordEnrollmentRequest request);
|
||||||
Task<KeyConnectorUserKeyResponse> GetMasterKeyFromKeyConnector(string keyConnectorUrl);
|
Task<KeyConnectorUserKeyResponse> GetMasterKeyFromKeyConnectorAsync(string keyConnectorUrl);
|
||||||
Task PostUserKeyToKeyConnector(string keyConnectorUrl, KeyConnectorUserKeyRequest request);
|
Task PostUserKeyToKeyConnector(string keyConnectorUrl, KeyConnectorUserKeyRequest request);
|
||||||
Task PostSetKeyConnectorKey(SetKeyConnectorKeyRequest request);
|
Task PostSetKeyConnectorKey(SetKeyConnectorKeyRequest request);
|
||||||
Task PostConvertToKeyConnector();
|
Task PostConvertToKeyConnector();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace Bit.Core.Abstractions
|
|||||||
{
|
{
|
||||||
public interface IBiometricService
|
public interface IBiometricService
|
||||||
{
|
{
|
||||||
|
Task<bool> CanUseBiometricsUnlockAsync();
|
||||||
Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null);
|
Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null);
|
||||||
Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null);
|
Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace Bit.Core.Abstractions
|
|||||||
Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null);
|
Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null);
|
||||||
Task<UserKey> GetAutoUnlockKeyAsync(string userId = null);
|
Task<UserKey> GetAutoUnlockKeyAsync(string userId = null);
|
||||||
Task<bool> HasAutoUnlockKeyAsync(string userId = null);
|
Task<bool> HasAutoUnlockKeyAsync(string userId = null);
|
||||||
|
Task<UserKey> GetBiometricUnlockKeyAsync(string userId = null);
|
||||||
Task SetMasterKeyAsync(MasterKey masterKey, string userId = null);
|
Task SetMasterKeyAsync(MasterKey masterKey, string userId = null);
|
||||||
Task<MasterKey> GetMasterKeyAsync(string userId = null);
|
Task<MasterKey> GetMasterKeyAsync(string userId = null);
|
||||||
Task<MasterKey> MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig);
|
Task<MasterKey> MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig);
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ namespace Bit.Core.Abstractions
|
|||||||
{
|
{
|
||||||
public interface IKeyConnectorService
|
public interface IKeyConnectorService
|
||||||
{
|
{
|
||||||
Task SetUsesKeyConnector(bool usesKeyConnector);
|
Task SetUsesKeyConnectorAsync(bool usesKeyConnector);
|
||||||
Task<bool> GetUsesKeyConnector();
|
Task<bool> GetUsesKeyConnectorAsync();
|
||||||
Task<bool> UserNeedsMigration();
|
Task<bool> UserNeedsMigrationAsync();
|
||||||
Task MigrateUser();
|
Task MigrateUserAsync();
|
||||||
Task GetAndSetKey(string url);
|
Task GetAndSetMasterKeyAsync(string url);
|
||||||
Task<Organization> GetManagingOrganization();
|
Task<Organization> GetManagingOrganizationAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace Bit.Core.Abstractions
|
|||||||
Task<string> GetMasterKeyEncryptedUserKeyAsync(string userId = null);
|
Task<string> GetMasterKeyEncryptedUserKeyAsync(string userId = null);
|
||||||
Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null);
|
Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null);
|
||||||
Task<UserKey> GetUserKeyAutoUnlockAsync(string userId = null);
|
Task<UserKey> GetUserKeyAutoUnlockAsync(string userId = null);
|
||||||
Task SetUserKeyAutoUnlockAsync(string value, string userId = null);
|
Task SetUserKeyAutoUnlockAsync(UserKey value, string userId = null);
|
||||||
Task<string> GetActiveUserIdAsync();
|
Task<string> GetActiveUserIdAsync();
|
||||||
Task<string> GetActiveUserEmailAsync();
|
Task<string> GetActiveUserEmailAsync();
|
||||||
Task<T> GetActiveUserCustomDataAsync<T>(Func<Account, T> dataMapper);
|
Task<T> GetActiveUserCustomDataAsync<T>(Func<Account, T> dataMapper);
|
||||||
@@ -35,6 +35,8 @@ namespace Bit.Core.Abstractions
|
|||||||
Task<EnvironmentUrlData> GetPreAuthEnvironmentUrlsAsync();
|
Task<EnvironmentUrlData> GetPreAuthEnvironmentUrlsAsync();
|
||||||
Task SetPreAuthEnvironmentUrlsAsync(EnvironmentUrlData value);
|
Task SetPreAuthEnvironmentUrlsAsync(EnvironmentUrlData value);
|
||||||
Task<EnvironmentUrlData> GetEnvironmentUrlsAsync(string userId = null);
|
Task<EnvironmentUrlData> GetEnvironmentUrlsAsync(string userId = null);
|
||||||
|
Task<UserKey> GetUserKeyBiometricUnlockAsync(string userId = null);
|
||||||
|
Task SetUserKeyBiometricUnlockAsync(UserKey value, string userId = null);
|
||||||
Task<bool?> GetBiometricUnlockAsync(string userId = null);
|
Task<bool?> GetBiometricUnlockAsync(string userId = null);
|
||||||
Task SetBiometricUnlockAsync(bool? value, string userId = null);
|
Task SetBiometricUnlockAsync(bool? value, string userId = null);
|
||||||
Task<bool> GetBiometricLockedAsync(string userId = null);
|
Task<bool> GetBiometricLockedAsync(string userId = null);
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ namespace Bit.Core
|
|||||||
public static string VaultTimeoutActionKey(string userId) => $"vaultTimeoutAction_{userId}";
|
public static string VaultTimeoutActionKey(string userId) => $"vaultTimeoutAction_{userId}";
|
||||||
public static string MasterKeyEncryptedUserKeyKey(string userId) => $"masterKeyEncryptedUserKey_{userId}";
|
public static string MasterKeyEncryptedUserKeyKey(string userId) => $"masterKeyEncryptedUserKey_{userId}";
|
||||||
public static string UserKeyAutoUnlockKey(string userId) => $"autoUnlock_{userId}";
|
public static string UserKeyAutoUnlockKey(string userId) => $"autoUnlock_{userId}";
|
||||||
|
public static string UserKeyBiometricUnlockKey(string userId) => $"biometricUnlock_{userId}";
|
||||||
public static string CiphersKey(string userId) => $"ciphers_{userId}";
|
public static string CiphersKey(string userId) => $"ciphers_{userId}";
|
||||||
public static string FoldersKey(string userId) => $"folders_{userId}";
|
public static string FoldersKey(string userId) => $"folders_{userId}";
|
||||||
public static string CollectionsKey(string userId) => $"collections_{userId}";
|
public static string CollectionsKey(string userId) => $"collections_{userId}";
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ namespace Bit.Core.Models.Domain
|
|||||||
{
|
{
|
||||||
public UserKey UserKey;
|
public UserKey UserKey;
|
||||||
public MasterKey MasterKey;
|
public MasterKey MasterKey;
|
||||||
public EncString UserKeyPinEphemeral;
|
public EncString PinKeyEncryptedUserKeyEphemeral;
|
||||||
public bool? BiometricLocked;
|
public bool? BiometricLocked;
|
||||||
[Obsolete("Jul 6 2023: Key has been deprecated. We will use the User Key in the future. It remains here for migration during app upgrade.")]
|
[Obsolete("Jul 6 2023: Key has been deprecated. We will use the User Key in the future. It remains here for migration during app upgrade.")]
|
||||||
public SymmetricCryptoKey Key;
|
public SymmetricCryptoKey Key;
|
||||||
|
|||||||
@@ -485,7 +485,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
#region Key Connector
|
#region Key Connector
|
||||||
|
|
||||||
public async Task<KeyConnectorUserKeyResponse> GetMasterKeyFromKeyConnector(string keyConnectorUrl)
|
public async Task<KeyConnectorUserKeyResponse> GetMasterKeyFromKeyConnectorAsync(string keyConnectorUrl)
|
||||||
{
|
{
|
||||||
using (var requestMessage = new HttpRequestMessage())
|
using (var requestMessage = new HttpRequestMessage())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,8 +46,6 @@ namespace Bit.Core.Services
|
|||||||
II18nService i18nService,
|
II18nService i18nService,
|
||||||
IPlatformUtilsService platformUtilsService,
|
IPlatformUtilsService platformUtilsService,
|
||||||
IMessagingService messagingService,
|
IMessagingService messagingService,
|
||||||
IVaultTimeoutService vaultTimeoutService,
|
|
||||||
IKeyConnectorService keyConnectorService,
|
|
||||||
IPasswordGenerationService passwordGenerationService,
|
IPasswordGenerationService passwordGenerationService,
|
||||||
IPolicyService policyService,
|
IPolicyService policyService,
|
||||||
bool setCryptoKeys = true)
|
bool setCryptoKeys = true)
|
||||||
@@ -61,7 +59,6 @@ namespace Bit.Core.Services
|
|||||||
_i18nService = i18nService;
|
_i18nService = i18nService;
|
||||||
_platformUtilsService = platformUtilsService;
|
_platformUtilsService = platformUtilsService;
|
||||||
_messagingService = messagingService;
|
_messagingService = messagingService;
|
||||||
_keyConnectorService = keyConnectorService;
|
|
||||||
_passwordGenerationService = passwordGenerationService;
|
_passwordGenerationService = passwordGenerationService;
|
||||||
_policyService = policyService;
|
_policyService = policyService;
|
||||||
_setCryptoKeys = setCryptoKeys;
|
_setCryptoKeys = setCryptoKeys;
|
||||||
@@ -480,7 +477,7 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
if (tokenResponse.KeyConnectorUrl != null)
|
if (tokenResponse.KeyConnectorUrl != null)
|
||||||
{
|
{
|
||||||
await _keyConnectorService.GetAndSetKey(tokenResponse.KeyConnectorUrl);
|
await _keyConnectorService.GetAndSetMasterKeyAsync(tokenResponse.KeyConnectorUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(tokenResponse.Key);
|
await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(tokenResponse.Key);
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public async Task<UserKey> GetAutoUnlockKeyAsync(string userId = null)
|
public async Task<UserKey> GetAutoUnlockKeyAsync(string userId = null)
|
||||||
{
|
{
|
||||||
await MigrateAutoUnlockKeyIfNeededAsync(userId);
|
await MigrateAutoAndBioKeysIfNeededAsync(userId);
|
||||||
return await _stateService.GetUserKeyAutoUnlockAsync(userId);
|
return await _stateService.GetUserKeyAutoUnlockAsync(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +110,12 @@ namespace Bit.Core.Services
|
|||||||
return await GetAutoUnlockKeyAsync(userId) != null;
|
return await GetAutoUnlockKeyAsync(userId) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<UserKey> GetBiometricUnlockKeyAsync(string userId = null)
|
||||||
|
{
|
||||||
|
await MigrateAutoAndBioKeysIfNeededAsync(userId);
|
||||||
|
return await _stateService.GetUserKeyBiometricUnlockAsync(userId);
|
||||||
|
}
|
||||||
|
|
||||||
public Task SetMasterKeyAsync(MasterKey masterKey, string userId = null)
|
public Task SetMasterKeyAsync(MasterKey masterKey, string userId = null)
|
||||||
{
|
{
|
||||||
return _stateService.SetMasterKeyAsync(masterKey, userId);
|
return _stateService.SetMasterKeyAsync(masterKey, userId);
|
||||||
@@ -143,7 +149,7 @@ namespace Bit.Core.Services
|
|||||||
public async Task<Tuple<UserKey, EncString>> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey)
|
public async Task<Tuple<UserKey, EncString>> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey)
|
||||||
{
|
{
|
||||||
var userKey = await GetUserKeyAsync() ?? await MakeUserKeyAsync();
|
var userKey = await GetUserKeyAsync() ?? await MakeUserKeyAsync();
|
||||||
return await BuildProtectedSymmetricKey(masterKey, userKey.Key, keyBytes => new UserKey(keyBytes));
|
return await BuildProtectedSymmetricKeyAsync(masterKey, userKey.Key, keyBytes => new UserKey(keyBytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UserKey> DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null)
|
public async Task<UserKey> DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null)
|
||||||
@@ -157,10 +163,26 @@ namespace Bit.Core.Services
|
|||||||
if (encUserKey == null)
|
if (encUserKey == null)
|
||||||
{
|
{
|
||||||
var userKeyMasterKey = await _stateService.GetMasterKeyEncryptedUserKeyAsync(userId);
|
var userKeyMasterKey = await _stateService.GetMasterKeyEncryptedUserKeyAsync(userId);
|
||||||
if (userKeyMasterKey == null)
|
|
||||||
|
if (userKeyMasterKey is null)
|
||||||
{
|
{
|
||||||
throw new Exception("No encrypted user key found");
|
// Migrate old key
|
||||||
|
var oldEncUserKey = await _stateService.GetEncKeyEncryptedAsync(userId);
|
||||||
|
|
||||||
|
if (oldEncUserKey is null)
|
||||||
|
{
|
||||||
|
throw new Exception("No encrypted user key nor old encKeyEncrypted found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var userKey = await DecryptUserKeyWithMasterKeyAsync(
|
||||||
|
masterKey,
|
||||||
|
new EncString(oldEncUserKey),
|
||||||
|
userId
|
||||||
|
);
|
||||||
|
await SetMasterKeyEncryptedUserKeyAsync(oldEncUserKey, userId);
|
||||||
|
return userKey;
|
||||||
|
}
|
||||||
|
|
||||||
encUserKey = new EncString(userKeyMasterKey);
|
encUserKey = new EncString(userKeyMasterKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +220,7 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64);
|
var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64);
|
||||||
return await BuildProtectedSymmetricKey(key, newSymKey, keyBytes => new SymmetricCryptoKey(keyBytes));
|
return await BuildProtectedSymmetricKeyAsync(key, newSymKey, keyBytes => new SymmetricCryptoKey(keyBytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> HashMasterKeyAsync(string password, MasterKey masterKey, HashPurpose hashPurpose = HashPurpose.ServerAuthorization)
|
public async Task<string> HashMasterKeyAsync(string password, MasterKey masterKey, HashPurpose hashPurpose = HashPurpose.ServerAuthorization)
|
||||||
@@ -670,10 +692,10 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
private async Task StoreAdditionalKeysAsync(UserKey userKey, string userId = null)
|
private async Task StoreAdditionalKeysAsync(UserKey userKey, string userId = null)
|
||||||
{
|
{
|
||||||
// Refresh, set, or clear the pin key
|
// Set, refresh, or clear the pin key
|
||||||
if (await _stateService.GetProtectedPinAsync(userId) != null)
|
if (await _stateService.GetProtectedPinAsync(userId) != null)
|
||||||
{
|
{
|
||||||
await UpdateUserKeyPinAsync(userKey, userId);
|
await UpdatePinKeyAsync(userKey, userId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -681,18 +703,28 @@ namespace Bit.Core.Services
|
|||||||
await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(null, userId);
|
await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(null, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh, set, or clear the auto key
|
// Set, refresh, or clear the auto unlock key
|
||||||
if (await _stateService.GetVaultTimeoutAsync(userId) == null)
|
if (await _stateService.GetVaultTimeoutAsync(userId) == null)
|
||||||
{
|
{
|
||||||
await _stateService.SetUserKeyAutoUnlockAsync(userKey.KeyB64, userId);
|
await _stateService.SetUserKeyAutoUnlockAsync(userKey, userId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _stateService.SetUserKeyAutoUnlockAsync(null, userId);
|
await _stateService.SetUserKeyAutoUnlockAsync(null, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set, refresh, or clear the biometric unlock key
|
||||||
|
if ((await _stateService.GetBiometricUnlockAsync(userId)).GetValueOrDefault())
|
||||||
|
{
|
||||||
|
await _stateService.SetUserKeyBiometricUnlockAsync(userKey, userId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _stateService.SetUserKeyBiometricUnlockAsync(null, userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateUserKeyPinAsync(UserKey userKey, string userId = null)
|
private async Task UpdatePinKeyAsync(UserKey userKey, string userId = null)
|
||||||
{
|
{
|
||||||
var pin = await DecryptToUtf8Async(new EncString(await _stateService.GetProtectedPinAsync(userId)));
|
var pin = await DecryptToUtf8Async(new EncString(await _stateService.GetProtectedPinAsync(userId)));
|
||||||
var pinKey = await MakePinKeyAsync(
|
var pinKey = await MakePinKeyAsync(
|
||||||
@@ -874,7 +906,7 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This needs to be moved into SymmetricCryptoKey model to remove the keyCreator hack
|
// TODO: This needs to be moved into SymmetricCryptoKey model to remove the keyCreator hack
|
||||||
private async Task<Tuple<TKey, EncString>> BuildProtectedSymmetricKey<TKey>(SymmetricCryptoKey key,
|
private async Task<Tuple<TKey, EncString>> BuildProtectedSymmetricKeyAsync<TKey>(SymmetricCryptoKey key,
|
||||||
byte[] encKey, Func<byte[], TKey> keyCreator) where TKey : SymmetricCryptoKey
|
byte[] encKey, Func<byte[], TKey> keyCreator) where TKey : SymmetricCryptoKey
|
||||||
{
|
{
|
||||||
EncString encKeyEnc = null;
|
EncString encKeyEnc = null;
|
||||||
@@ -898,7 +930,7 @@ namespace Bit.Core.Services
|
|||||||
private async Task<TKey> MakeKeyAsync<TKey>(string password, string salt, KdfConfig kdfConfig, Func<byte[], TKey> keyCreator)
|
private async Task<TKey> MakeKeyAsync<TKey>(string password, string salt, KdfConfig kdfConfig, Func<byte[], TKey> keyCreator)
|
||||||
where TKey : SymmetricCryptoKey
|
where TKey : SymmetricCryptoKey
|
||||||
{
|
{
|
||||||
byte[] key = null;
|
byte[] key;
|
||||||
if (kdfConfig.Type == null || kdfConfig.Type == KdfType.PBKDF2_SHA256)
|
if (kdfConfig.Type == null || kdfConfig.Type == KdfType.PBKDF2_SHA256)
|
||||||
{
|
{
|
||||||
var iterations = kdfConfig.Iterations.GetValueOrDefault(5000);
|
var iterations = kdfConfig.Iterations.GetValueOrDefault(5000);
|
||||||
@@ -956,23 +988,33 @@ namespace Bit.Core.Services
|
|||||||
// We previously used the master key for additional keys, but now we use the user key.
|
// We previously used the master key for additional keys, but now we use the user key.
|
||||||
// These methods support migrating the old keys to the new ones.
|
// These methods support migrating the old keys to the new ones.
|
||||||
|
|
||||||
private async Task MigrateAutoUnlockKeyIfNeededAsync(string userId = null)
|
private async Task MigrateAutoAndBioKeysIfNeededAsync(string userId = null)
|
||||||
{
|
{
|
||||||
var oldAutoKey = await _stateService.GetKeyEncryptedAsync(userId);
|
var oldKey = await _stateService.GetKeyEncryptedAsync(userId);
|
||||||
if (oldAutoKey == null)
|
if (oldKey == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt
|
// Decrypt
|
||||||
var masterKey = new MasterKey(Convert.FromBase64String(oldAutoKey));
|
var masterKey = new MasterKey(Convert.FromBase64String(oldKey));
|
||||||
var encryptedUserKey = await _stateService.GetEncKeyEncryptedAsync(userId);
|
var encryptedUserKey = await _stateService.GetEncKeyEncryptedAsync(userId);
|
||||||
var userKey = await DecryptUserKeyWithMasterKeyAsync(
|
var userKey = await DecryptUserKeyWithMasterKeyAsync(
|
||||||
masterKey,
|
masterKey,
|
||||||
new EncString(encryptedUserKey),
|
new EncString(encryptedUserKey),
|
||||||
userId);
|
userId);
|
||||||
|
|
||||||
// Migrate
|
// Migrate
|
||||||
await _stateService.SetUserKeyAutoUnlockAsync(userKey.KeyB64, userId);
|
if (await _stateService.GetVaultTimeoutAsync(userId) == null)
|
||||||
|
{
|
||||||
|
await _stateService.SetUserKeyAutoUnlockAsync(userKey, userId);
|
||||||
|
}
|
||||||
|
if ((await _stateService.GetBiometricUnlockAsync(userId)).GetValueOrDefault())
|
||||||
|
{
|
||||||
|
await _stateService.SetUserKeyBiometricUnlockAsync(userKey, userId);
|
||||||
|
}
|
||||||
await _stateService.SetKeyEncryptedAsync(null, userId);
|
await _stateService.SetKeyEncryptedAsync(null, userId);
|
||||||
|
|
||||||
// Set encrypted user key just in case the user locks without syncing
|
// Set encrypted user key just in case the user locks without syncing
|
||||||
await SetMasterKeyEncryptedUserKeyAsync(encryptedUserKey);
|
await SetMasterKeyEncryptedUserKeyAsync(encryptedUserKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ namespace Bit.Core.Services
|
|||||||
_organizationService = organizationService;
|
_organizationService = organizationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GetAndSetKey(string url)
|
public async Task GetAndSetMasterKeyAsync(string url)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var masterKeyResponse = await _apiService.GetMasterKeyFromKeyConnector(url);
|
var masterKeyResponse = await _apiService.GetMasterKeyFromKeyConnectorAsync(url);
|
||||||
var masterKeyArr = Convert.FromBase64String(masterKeyResponse.Key);
|
var masterKeyArr = Convert.FromBase64String(masterKeyResponse.Key);
|
||||||
var masterKey = new MasterKey(masterKeyArr);
|
var masterKey = new MasterKey(masterKeyArr);
|
||||||
await _cryptoService.SetMasterKeyAsync(masterKey);
|
await _cryptoService.SetMasterKeyAsync(masterKey);
|
||||||
@@ -39,17 +39,17 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetUsesKeyConnector(bool usesKeyConnector)
|
public async Task SetUsesKeyConnectorAsync(bool usesKeyConnector)
|
||||||
{
|
{
|
||||||
await _stateService.SetUsesKeyConnectorAsync(usesKeyConnector);
|
await _stateService.SetUsesKeyConnectorAsync(usesKeyConnector);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> GetUsesKeyConnector()
|
public async Task<bool> GetUsesKeyConnectorAsync()
|
||||||
{
|
{
|
||||||
return await _stateService.GetUsesKeyConnectorAsync();
|
return await _stateService.GetUsesKeyConnectorAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Organization> GetManagingOrganization()
|
public async Task<Organization> GetManagingOrganizationAsync()
|
||||||
{
|
{
|
||||||
var orgs = await _organizationService.GetAllAsync();
|
var orgs = await _organizationService.GetAllAsync();
|
||||||
return orgs.Find(o =>
|
return orgs.Find(o =>
|
||||||
@@ -57,9 +57,9 @@ namespace Bit.Core.Services
|
|||||||
!o.IsAdmin);
|
!o.IsAdmin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MigrateUser()
|
public async Task MigrateUserAsync()
|
||||||
{
|
{
|
||||||
var organization = await GetManagingOrganization();
|
var organization = await GetManagingOrganizationAsync();
|
||||||
var masterKey = await _cryptoService.GetMasterKeyAsync();
|
var masterKey = await _cryptoService.GetMasterKeyAsync();
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -75,11 +75,11 @@ namespace Bit.Core.Services
|
|||||||
await _apiService.PostConvertToKeyConnector();
|
await _apiService.PostConvertToKeyConnector();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> UserNeedsMigration()
|
public async Task<bool> UserNeedsMigrationAsync()
|
||||||
{
|
{
|
||||||
var loggedInUsingSso = await _tokenService.GetIsExternal();
|
var loggedInUsingSso = await _tokenService.GetIsExternal();
|
||||||
var requiredByOrganization = await GetManagingOrganization() != null;
|
var requiredByOrganization = await GetManagingOrganizationAsync() != null;
|
||||||
var userIsNotUsingKeyConnector = !await GetUsesKeyConnector();
|
var userIsNotUsingKeyConnector = !await GetUsesKeyConnectorAsync();
|
||||||
|
|
||||||
return loggedInUsingSso && requiredByOrganization && userIsNotUsingKeyConnector;
|
return loggedInUsingSso && requiredByOrganization && userIsNotUsingKeyConnector;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,6 +241,19 @@ namespace Bit.Core.Services
|
|||||||
))?.Settings?.EnvironmentUrls;
|
))?.Settings?.EnvironmentUrls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<UserKey> GetUserKeyBiometricUnlockAsync(string userId = null)
|
||||||
|
{
|
||||||
|
var keyB64 = await _storageMediatorService.GetAsync<string>(
|
||||||
|
await ComposeKeyAsync(Constants.UserKeyBiometricUnlockKey, userId), true);
|
||||||
|
return keyB64 == null ? null : new UserKey(Convert.FromBase64String(keyB64));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SetUserKeyBiometricUnlockAsync(UserKey value, string userId = null)
|
||||||
|
{
|
||||||
|
await _storageMediatorService.SaveAsync(
|
||||||
|
await ComposeKeyAsync(Constants.UserKeyBiometricUnlockKey, userId), value?.KeyB64, true);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool?> GetBiometricUnlockAsync(string userId = null)
|
public async Task<bool?> GetBiometricUnlockAsync(string userId = null)
|
||||||
{
|
{
|
||||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||||
@@ -353,10 +366,10 @@ namespace Bit.Core.Services
|
|||||||
return keyB64 == null ? null : new UserKey(Convert.FromBase64String(keyB64));
|
return keyB64 == null ? null : new UserKey(Convert.FromBase64String(keyB64));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetUserKeyAutoUnlockAsync(string value, string userId = null)
|
public async Task SetUserKeyAutoUnlockAsync(UserKey value, string userId = null)
|
||||||
{
|
{
|
||||||
await _storageMediatorService.SaveAsync(
|
await _storageMediatorService.SaveAsync(
|
||||||
await ComposeKeyAsync(Constants.UserKeyAutoUnlockKey, userId), value, true);
|
await ComposeKeyAsync(Constants.UserKeyAutoUnlockKey, userId), value?.KeyB64, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> CanAccessPremiumAsync(string userId = null)
|
public async Task<bool> CanAccessPremiumAsync(string userId = null)
|
||||||
@@ -428,7 +441,7 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
return (await GetAccountAsync(
|
return (await GetAccountAsync(
|
||||||
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync())
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync())
|
||||||
))?.VolatileData?.UserKeyPinEphemeral;
|
))?.VolatileData?.PinKeyEncryptedUserKeyEphemeral;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetPinKeyEncryptedUserKeyEphemeralAsync(EncString value, string userId = null)
|
public async Task SetPinKeyEncryptedUserKeyEphemeralAsync(EncString value, string userId = null)
|
||||||
@@ -436,7 +449,7 @@ namespace Bit.Core.Services
|
|||||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||||
await GetDefaultInMemoryOptionsAsync());
|
await GetDefaultInMemoryOptionsAsync());
|
||||||
var account = await GetAccountAsync(reconciledOptions);
|
var account = await GetAccountAsync(reconciledOptions);
|
||||||
account.VolatileData.UserKeyPinEphemeral = value;
|
account.VolatileData.PinKeyEncryptedUserKeyEphemeral = value;
|
||||||
await SaveAccountAsync(account, reconciledOptions);
|
await SaveAccountAsync(account, reconciledOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1465,6 +1478,7 @@ namespace Bit.Core.Services
|
|||||||
// Non-state storage
|
// Non-state storage
|
||||||
await Task.WhenAll(
|
await Task.WhenAll(
|
||||||
SetUserKeyAutoUnlockAsync(null, userId),
|
SetUserKeyAutoUnlockAsync(null, userId),
|
||||||
|
SetUserKeyBiometricUnlockAsync(null, userId),
|
||||||
SetProtectedPinAsync(null, userId),
|
SetProtectedPinAsync(null, userId),
|
||||||
SetKeyHashAsync(null, userId),
|
SetKeyHashAsync(null, userId),
|
||||||
SetOrgKeysEncryptedAsync(null, userId),
|
SetOrgKeysEncryptedAsync(null, userId),
|
||||||
|
|||||||
@@ -337,7 +337,7 @@ namespace Bit.Core.Services
|
|||||||
await _stateService.SetNameAsync(response.Name);
|
await _stateService.SetNameAsync(response.Name);
|
||||||
await _stateService.SetPersonalPremiumAsync(response.Premium);
|
await _stateService.SetPersonalPremiumAsync(response.Premium);
|
||||||
await _stateService.SetAvatarColorAsync(response.AvatarColor);
|
await _stateService.SetAvatarColorAsync(response.AvatarColor);
|
||||||
await _keyConnectorService.SetUsesKeyConnector(response.UsesKeyConnector);
|
await _keyConnectorService.SetUsesKeyConnectorAsync(response.UsesKeyConnector);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SyncFoldersAsync(string userId, List<FolderResponse> response)
|
private async Task SyncFoldersAsync(string userId, List<FolderResponse> response)
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ namespace Bit.Core.Services
|
|||||||
userId = await _stateService.GetActiveUserIdAsync();
|
userId = await _stateService.GetActiveUserIdAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await _keyConnectorService.GetUsesKeyConnector())
|
if (await _keyConnectorService.GetUsesKeyConnectorAsync())
|
||||||
{
|
{
|
||||||
var pinStatus = await GetPinLockTypeAsync(userId);
|
var pinStatus = await GetPinLockTypeAsync(userId);
|
||||||
var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync()
|
var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync()
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ namespace Bit.Core.Utilities
|
|||||||
var passwordGenerationService = new PasswordGenerationService(cryptoService, stateService, cryptoFunctionService, policyService);
|
var passwordGenerationService = new PasswordGenerationService(cryptoService, stateService, cryptoFunctionService, policyService);
|
||||||
var totpService = new TotpService(cryptoFunctionService);
|
var totpService = new TotpService(cryptoFunctionService);
|
||||||
var authService = new AuthService(cryptoService, cryptoFunctionService, apiService, stateService,
|
var authService = new AuthService(cryptoService, cryptoFunctionService, apiService, stateService,
|
||||||
tokenService, appIdService, i18nService, platformUtilsService, messagingService, vaultTimeoutService,
|
tokenService, appIdService, i18nService, platformUtilsService, messagingService,
|
||||||
keyConnectorService, passwordGenerationService, policyService);
|
passwordGenerationService, policyService);
|
||||||
var exportService = new ExportService(folderService, cipherService, cryptoService);
|
var exportService = new ExportService(folderService, cipherService, cryptoService);
|
||||||
var auditService = new AuditService(cryptoFunctionService, apiService);
|
var auditService = new AuditService(cryptoFunctionService, apiService);
|
||||||
var environmentService = new EnvironmentService(apiService, stateService, conditionedRunner);
|
var environmentService = new EnvironmentService(apiService, stateService, conditionedRunner);
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ namespace Bit.iOS.Core.Controllers
|
|||||||
&& await _cryptoService.HasEncryptedUserKeyAsync();
|
&& await _cryptoService.HasEncryptedUserKeyAsync();
|
||||||
_biometricIntegrityValid =
|
_biometricIntegrityValid =
|
||||||
await _platformUtilsService.IsBiometricIntegrityValidAsync(BiometricIntegritySourceKey);
|
await _platformUtilsService.IsBiometricIntegrityValidAsync(BiometricIntegritySourceKey);
|
||||||
_usesKeyConnector = await _keyConnectorService.GetUsesKeyConnector();
|
_usesKeyConnector = await _keyConnectorService.GetUsesKeyConnectorAsync();
|
||||||
_biometricUnlockOnly = _usesKeyConnector && _biometricEnabled && !_pinEnabled;
|
_biometricUnlockOnly = _usesKeyConnector && _biometricEnabled && !_pinEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ namespace Bit.iOS.Core.Controllers
|
|||||||
&& await _cryptoService.HasEncryptedUserKeyAsync();
|
&& await _cryptoService.HasEncryptedUserKeyAsync();
|
||||||
_biometricIntegrityValid =
|
_biometricIntegrityValid =
|
||||||
await _platformUtilsService.IsBiometricIntegrityValidAsync(BiometricIntegritySourceKey);
|
await _platformUtilsService.IsBiometricIntegrityValidAsync(BiometricIntegritySourceKey);
|
||||||
_usesKeyConnector = await _keyConnectorService.GetUsesKeyConnector();
|
_usesKeyConnector = await _keyConnectorService.GetUsesKeyConnectorAsync();
|
||||||
_biometricUnlockOnly = _usesKeyConnector && _biometricEnabled && !_pinEnabled;
|
_biometricUnlockOnly = _usesKeyConnector && _biometricEnabled && !_pinEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Services;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Foundation;
|
using Foundation;
|
||||||
using LocalAuthentication;
|
using LocalAuthentication;
|
||||||
|
|
||||||
namespace Bit.iOS.Core.Services
|
namespace Bit.iOS.Core.Services
|
||||||
{
|
{
|
||||||
public class BiometricService : IBiometricService
|
public class BiometricService : BaseBiometricService
|
||||||
{
|
{
|
||||||
private IStateService _stateService;
|
public BiometricService(IStateService stateService, ICryptoService cryptoService)
|
||||||
|
: base(stateService, cryptoService)
|
||||||
public BiometricService(IStateService stateService)
|
|
||||||
{
|
{
|
||||||
_stateService = stateService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
|
public override async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
|
||||||
{
|
{
|
||||||
if (bioIntegritySrcKey == null)
|
if (bioIntegritySrcKey == null)
|
||||||
{
|
{
|
||||||
@@ -30,7 +29,7 @@ namespace Bit.iOS.Core.Services
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
|
public override async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
|
||||||
{
|
{
|
||||||
var state = GetState();
|
var state = GetState();
|
||||||
if (state == null)
|
if (state == null)
|
||||||
|
|||||||
@@ -112,9 +112,9 @@ namespace Bit.iOS.Core.Utilities
|
|||||||
var clipboardService = new ClipboardService(stateService);
|
var clipboardService = new ClipboardService(stateService);
|
||||||
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, clipboardService,
|
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, clipboardService,
|
||||||
messagingService, broadcasterService);
|
messagingService, broadcasterService);
|
||||||
var biometricService = new BiometricService(stateService);
|
|
||||||
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
||||||
var cryptoService = new CryptoService(stateService, cryptoFunctionService);
|
var cryptoService = new CryptoService(stateService, cryptoFunctionService);
|
||||||
|
var biometricService = new BiometricService(stateService, cryptoService);
|
||||||
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService);
|
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService);
|
||||||
|
|
||||||
ServiceContainer.Register<ISynchronousStorageService>(preferencesStorage);
|
ServiceContainer.Register<ISynchronousStorageService>(preferencesStorage);
|
||||||
|
|||||||
Reference in New Issue
Block a user