2019-05-15 20:22:28 +02:00
|
|
|
|
using Bit.Core.Abstractions;
|
2019-09-20 22:43:03 +02:00
|
|
|
|
using Bit.Core.Models.Domain;
|
2019-05-15 20:22:28 +02:00
|
|
|
|
using System;
|
2021-09-23 15:42:38 +02:00
|
|
|
|
using System.Linq;
|
2019-05-15 20:22:28 +02:00
|
|
|
|
using System.Threading.Tasks;
|
2021-09-23 15:42:38 +02:00
|
|
|
|
using Bit.Core.Enums;
|
2019-05-15 20:22:28 +02:00
|
|
|
|
|
|
|
|
|
namespace Bit.Core.Services
|
|
|
|
|
{
|
2020-05-29 18:26:36 +02:00
|
|
|
|
public class VaultTimeoutService : IVaultTimeoutService
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
|
|
|
|
private readonly ICryptoService _cryptoService;
|
|
|
|
|
private readonly IUserService _userService;
|
|
|
|
|
private readonly IPlatformUtilsService _platformUtilsService;
|
|
|
|
|
private readonly IStorageService _storageService;
|
|
|
|
|
private readonly IFolderService _folderService;
|
|
|
|
|
private readonly ICipherService _cipherService;
|
|
|
|
|
private readonly ICollectionService _collectionService;
|
|
|
|
|
private readonly ISearchService _searchService;
|
|
|
|
|
private readonly IMessagingService _messagingService;
|
2020-05-29 18:26:36 +02:00
|
|
|
|
private readonly ITokenService _tokenService;
|
2021-09-23 15:42:38 +02:00
|
|
|
|
private readonly IPolicyService _policyService;
|
2019-06-05 14:58:11 +02:00
|
|
|
|
private readonly Action<bool> _lockedCallback;
|
2020-05-29 18:26:36 +02:00
|
|
|
|
private readonly Func<bool, Task> _loggedOutCallback;
|
2019-05-15 20:22:28 +02:00
|
|
|
|
|
2020-05-29 18:26:36 +02:00
|
|
|
|
public VaultTimeoutService(
|
2019-05-15 20:22:28 +02:00
|
|
|
|
ICryptoService cryptoService,
|
|
|
|
|
IUserService userService,
|
|
|
|
|
IPlatformUtilsService platformUtilsService,
|
|
|
|
|
IStorageService storageService,
|
|
|
|
|
IFolderService folderService,
|
|
|
|
|
ICipherService cipherService,
|
|
|
|
|
ICollectionService collectionService,
|
|
|
|
|
ISearchService searchService,
|
2019-06-05 14:58:11 +02:00
|
|
|
|
IMessagingService messagingService,
|
2020-05-29 18:26:36 +02:00
|
|
|
|
ITokenService tokenService,
|
2021-09-23 15:42:38 +02:00
|
|
|
|
IPolicyService policyService,
|
2020-05-29 18:26:36 +02:00
|
|
|
|
Action<bool> lockedCallback,
|
|
|
|
|
Func<bool, Task> loggedOutCallback)
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
|
|
|
|
_cryptoService = cryptoService;
|
|
|
|
|
_userService = userService;
|
|
|
|
|
_platformUtilsService = platformUtilsService;
|
|
|
|
|
_storageService = storageService;
|
|
|
|
|
_folderService = folderService;
|
|
|
|
|
_cipherService = cipherService;
|
|
|
|
|
_collectionService = collectionService;
|
|
|
|
|
_searchService = searchService;
|
|
|
|
|
_messagingService = messagingService;
|
2020-05-29 18:26:36 +02:00
|
|
|
|
_tokenService = tokenService;
|
2021-09-23 15:42:38 +02:00
|
|
|
|
_policyService = policyService;
|
2019-06-05 14:58:11 +02:00
|
|
|
|
_lockedCallback = lockedCallback;
|
2020-05-29 18:26:36 +02:00
|
|
|
|
_loggedOutCallback = loggedOutCallback;
|
2019-05-15 20:22:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 22:27:14 +02:00
|
|
|
|
public EncString PinProtectedKey { get; set; } = null;
|
2020-06-08 14:25:13 +02:00
|
|
|
|
public bool BiometricLocked { get; set; } = true;
|
2019-05-15 20:22:28 +02:00
|
|
|
|
|
|
|
|
|
public async Task<bool> IsLockedAsync()
|
|
|
|
|
{
|
|
|
|
|
var hasKey = await _cryptoService.HasKeyAsync();
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (hasKey)
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
2020-06-08 14:25:13 +02:00
|
|
|
|
var biometricSet = await IsBiometricLockSetAsync();
|
|
|
|
|
if (biometricSet && BiometricLocked)
|
2019-05-16 23:30:07 +02:00
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-05-15 20:22:28 +02:00
|
|
|
|
}
|
|
|
|
|
return !hasKey;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-29 18:26:36 +02:00
|
|
|
|
public async Task CheckVaultTimeoutAsync()
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (_platformUtilsService.IsViewOpen())
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var authed = await _userService.IsAuthenticatedAsync();
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (!authed)
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (await IsLockedAsync())
|
2019-05-16 18:29:55 +02:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-09-23 15:42:38 +02:00
|
|
|
|
var vaultTimeoutMinutes = await GetVaultTimeout();
|
2021-10-29 16:31:38 +02:00
|
|
|
|
if (vaultTimeoutMinutes < 0 || vaultTimeoutMinutes == null)
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-01-15 20:04:07 +01:00
|
|
|
|
var lastActiveTime = await _storageService.GetAsync<long?>(Constants.LastActiveTimeKey);
|
|
|
|
|
if (lastActiveTime == null)
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-01-15 20:04:07 +01:00
|
|
|
|
var diffMs = _platformUtilsService.GetActiveTime() - lastActiveTime;
|
|
|
|
|
var vaultTimeoutMs = vaultTimeoutMinutes * 60000;
|
|
|
|
|
if (diffMs >= vaultTimeoutMs)
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
2020-05-29 18:26:36 +02:00
|
|
|
|
// Pivot based on saved action
|
|
|
|
|
var action = await _storageService.GetAsync<string>(Constants.VaultTimeoutActionKey);
|
|
|
|
|
if (action == "logOut")
|
|
|
|
|
{
|
|
|
|
|
await LogOutAsync();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
await LockAsync(true);
|
|
|
|
|
}
|
2019-05-15 20:22:28 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-01 07:07:02 +02:00
|
|
|
|
public async Task LockAsync(bool allowSoftLock = false, bool userInitiated = false)
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
|
|
|
|
var authed = await _userService.IsAuthenticatedAsync();
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (!authed)
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (allowSoftLock)
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
2020-06-08 14:25:13 +02:00
|
|
|
|
BiometricLocked = await IsBiometricLockSetAsync();
|
|
|
|
|
if (BiometricLocked)
|
2019-05-16 23:30:07 +02:00
|
|
|
|
{
|
2019-06-01 07:07:02 +02:00
|
|
|
|
_messagingService.Send("locked", userInitiated);
|
2019-06-05 14:58:11 +02:00
|
|
|
|
_lockedCallback?.Invoke(userInitiated);
|
2019-05-15 20:22:28 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
await Task.WhenAll(
|
|
|
|
|
_cryptoService.ClearKeyAsync(),
|
|
|
|
|
_cryptoService.ClearOrgKeysAsync(true),
|
|
|
|
|
_cryptoService.ClearKeyPairAsync(true),
|
|
|
|
|
_cryptoService.ClearEncKeyAsync(true));
|
|
|
|
|
|
|
|
|
|
_folderService.ClearCache();
|
2020-10-13 21:39:36 +02:00
|
|
|
|
await _cipherService.ClearCacheAsync();
|
2019-05-15 20:22:28 +02:00
|
|
|
|
_collectionService.ClearCache();
|
|
|
|
|
_searchService.ClearIndex();
|
2019-06-01 07:07:02 +02:00
|
|
|
|
_messagingService.Send("locked", userInitiated);
|
2019-06-05 14:58:11 +02:00
|
|
|
|
_lockedCallback?.Invoke(userInitiated);
|
2019-05-15 20:22:28 +02:00
|
|
|
|
}
|
2020-05-29 18:26:36 +02:00
|
|
|
|
|
|
|
|
|
public async Task LogOutAsync()
|
|
|
|
|
{
|
|
|
|
|
if(_loggedOutCallback != null)
|
|
|
|
|
{
|
|
|
|
|
await _loggedOutCallback.Invoke(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-15 20:22:28 +02:00
|
|
|
|
|
2020-05-29 18:26:36 +02:00
|
|
|
|
public async Task SetVaultTimeoutOptionsAsync(int? timeout, string action)
|
2019-05-15 20:22:28 +02:00
|
|
|
|
{
|
2020-05-29 18:26:36 +02:00
|
|
|
|
await _storageService.SaveAsync(Constants.VaultTimeoutKey, timeout);
|
|
|
|
|
await _storageService.SaveAsync(Constants.VaultTimeoutActionKey, action);
|
2019-05-15 20:22:28 +02:00
|
|
|
|
await _cryptoService.ToggleKeyAsync();
|
2020-05-29 18:26:36 +02:00
|
|
|
|
await _tokenService.ToggleTokensAsync();
|
2019-05-15 20:22:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<Tuple<bool, bool>> IsPinLockSetAsync()
|
|
|
|
|
{
|
|
|
|
|
var protectedPin = await _storageService.GetAsync<string>(Constants.ProtectedPin);
|
|
|
|
|
var pinProtectedKey = await _storageService.GetAsync<string>(Constants.PinProtectedKey);
|
|
|
|
|
return new Tuple<bool, bool>(protectedPin != null, pinProtectedKey != null);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-08 14:25:13 +02:00
|
|
|
|
public async Task<bool> IsBiometricLockSetAsync()
|
2019-05-16 23:30:07 +02:00
|
|
|
|
{
|
2020-06-08 14:25:13 +02:00
|
|
|
|
var biometricLock = await _storageService.GetAsync<bool?>(Constants.BiometricUnlockKey);
|
|
|
|
|
return biometricLock.GetValueOrDefault();
|
2019-05-16 23:30:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-15 20:22:28 +02:00
|
|
|
|
public async Task ClearAsync()
|
|
|
|
|
{
|
2019-09-20 22:43:03 +02:00
|
|
|
|
PinProtectedKey = null;
|
2019-05-15 20:22:28 +02:00
|
|
|
|
await _storageService.RemoveAsync(Constants.ProtectedPin);
|
|
|
|
|
}
|
2021-09-23 15:42:38 +02:00
|
|
|
|
|
2021-10-29 16:31:38 +02:00
|
|
|
|
public async Task<int?> GetVaultTimeout() {
|
|
|
|
|
var vaultTimeout = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
|
2021-09-23 15:42:38 +02:00
|
|
|
|
|
|
|
|
|
if (await _policyService.PolicyAppliesToUser(PolicyType.MaximumVaultTimeout)) {
|
|
|
|
|
var policy = (await _policyService.GetAll(PolicyType.MaximumVaultTimeout)).First();
|
|
|
|
|
// Remove negative values, and ensure it's smaller than maximum allowed value according to policy
|
|
|
|
|
var policyTimeout = _policyService.GetPolicyInt(policy, "minutes");
|
|
|
|
|
if (!policyTimeout.HasValue)
|
|
|
|
|
{
|
|
|
|
|
return vaultTimeout;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-29 16:31:38 +02:00
|
|
|
|
var timeout = vaultTimeout.HasValue ? Math.Min(vaultTimeout.Value, policyTimeout.Value) : policyTimeout.Value;
|
2021-09-23 15:42:38 +02:00
|
|
|
|
|
|
|
|
|
if (timeout < 0) {
|
|
|
|
|
timeout = policyTimeout.Value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return timeout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return vaultTimeout;
|
|
|
|
|
}
|
2019-05-15 20:22:28 +02:00
|
|
|
|
}
|
|
|
|
|
}
|