Bitwarden-app-android-iphon.../src/App/Services/BaseWatchDeviceService.cs

143 lines
4.9 KiB
C#

using System.Linq;
using System.Threading.Tasks;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Models.View;
using MessagePack;
using MessagePack.Resolvers;
namespace Bit.App.Services
{
public abstract class BaseWatchDeviceService : IWatchDeviceService
{
private readonly ICipherService _cipherService;
private readonly IEnvironmentService _environmentService;
private readonly IStateService _stateService;
private readonly IVaultTimeoutService _vaultTimeoutService;
protected BaseWatchDeviceService(ICipherService cipherService,
IEnvironmentService environmentService,
IStateService stateService,
IVaultTimeoutService vaultTimeoutService)
{
_cipherService = cipherService;
_environmentService = environmentService;
_stateService = stateService;
_vaultTimeoutService = vaultTimeoutService;
}
public abstract bool IsConnected { get; }
protected abstract bool CanSendData { get; }
protected abstract bool IsSupported { get; }
public async Task SyncDataToWatchAsync()
{
if (!IsSupported)
{
return;
}
var shouldConnect = await _stateService.GetShouldConnectToWatchAsync();
if (shouldConnect && !IsConnected)
{
ConnectToWatch();
}
if (!CanSendData)
{
return;
}
var userData = await _stateService.GetActiveUserCustomDataAsync(a => a?.Profile is null ? null : new WatchDTO.UserDataDto
{
Id = a.Profile.UserId,
Name = a.Profile.Name,
Email = a.Profile.Email
});
var state = await GetStateAsync(userData?.Id, shouldConnect);
if (state != WatchState.Valid)
{
await SendDataToWatchAsync(new WatchDTO(state));
return;
}
var ciphersWithTotp = await _cipherService.GetAllDecryptedAsync(c => c.DeletedDate == null && c.Login?.Totp != null);
if (!ciphersWithTotp.Any())
{
await SendDataToWatchAsync(new WatchDTO(WatchState.Need2FAItem));
return;
}
var watchDto = new WatchDTO(state)
{
Ciphers = ciphersWithTotp.Select(c => new SimpleCipherView(c)).ToList(),
UserData = userData,
EnvironmentData = new WatchDTO.EnvironmentUrlDataDto
{
Base = _environmentService.BaseUrl,
Icons = _environmentService.IconsUrl
}
//SettingsData = new WatchDTO.SettingsDataDto
//{
// VaultTimeoutInMinutes = await _vaultTimeoutService.GetVaultTimeout(userData?.Id),
// VaultTimeoutAction = await _stateService.GetVaultTimeoutActionAsync(userData?.Id) ?? VaultTimeoutAction.Lock
//}
};
await SendDataToWatchAsync(watchDto);
}
private async Task<WatchState> GetStateAsync(string userId, bool shouldConnectToWatch)
{
if (await _stateService.GetLastUserShouldConnectToWatchAsync()
&&
(userId is null || !await _stateService.IsAuthenticatedAsync()))
{
// if the last user had "Connect to Watch" enabled and there's no user authenticated
return WatchState.NeedLogin;
}
if (!shouldConnectToWatch)
{
return WatchState.NeedSetup;
}
//if (await _vaultTimeoutService.IsLockedAsync() ||
// await _vaultTimeoutService.ShouldLockAsync())
//{
// return WatchState.NeedUnlock;
//}
if (!await _stateService.CanAccessPremiumAsync(userId))
{
return WatchState.NeedPremium;
}
return WatchState.Valid;
}
public async Task SetShouldConnectToWatchAsync(bool shouldConnectToWatch)
{
await _stateService.SetShouldConnectToWatchAsync(shouldConnectToWatch);
await SyncDataToWatchAsync();
}
protected async Task SendDataToWatchAsync(WatchDTO watchDto)
{
var options = MessagePackSerializerOptions.Standard
.WithResolver(CompositeResolver.Create(
GeneratedResolver.Instance,
StandardResolver.Instance
));
await SendDataToWatchAsync(MessagePackSerializer.Serialize(watchDto, options));
}
protected abstract Task SendDataToWatchAsync(byte[] rawData);
protected abstract void ConnectToWatch();
}
}