2019-04-24 18:23:03 +03:00
|
|
|
|
using Bit.App.Abstractions;
|
|
|
|
|
using Bit.App.Resources;
|
|
|
|
|
using Bit.Core.Abstractions;
|
|
|
|
|
using Bit.Core.Models.View;
|
|
|
|
|
using Bit.Core.Utilities;
|
2019-04-26 07:26:09 +03:00
|
|
|
|
using System;
|
2019-04-24 18:23:03 +03:00
|
|
|
|
using System.Threading.Tasks;
|
2019-04-26 07:26:09 +03:00
|
|
|
|
using Xamarin.Forms;
|
2019-04-24 18:23:03 +03:00
|
|
|
|
|
|
|
|
|
namespace Bit.App.Pages
|
|
|
|
|
{
|
|
|
|
|
public class ViewPageViewModel : BaseViewModel
|
|
|
|
|
{
|
|
|
|
|
private readonly IDeviceActionService _deviceActionService;
|
|
|
|
|
private readonly ICipherService _cipherService;
|
|
|
|
|
private readonly IUserService _userService;
|
2019-04-26 07:26:09 +03:00
|
|
|
|
private readonly ITotpService _totpService;
|
|
|
|
|
private readonly IPlatformUtilsService _platformUtilsService;
|
2019-04-24 18:23:03 +03:00
|
|
|
|
private CipherView _cipher;
|
|
|
|
|
private bool _canAccessPremium;
|
2019-04-26 07:26:09 +03:00
|
|
|
|
private string _totpCode;
|
|
|
|
|
private string _totpCodeFormatted;
|
|
|
|
|
private string _totpSec;
|
|
|
|
|
private bool _totpLow;
|
|
|
|
|
private DateTime? _totpInterval = null;
|
2019-04-24 18:23:03 +03:00
|
|
|
|
|
|
|
|
|
public ViewPageViewModel()
|
|
|
|
|
{
|
|
|
|
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
|
|
|
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
|
|
|
|
_userService = ServiceContainer.Resolve<IUserService>("userService");
|
2019-04-26 07:26:09 +03:00
|
|
|
|
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
|
|
|
|
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
|
|
|
CopyCommand = new Command<string>(CopyAsync);
|
2019-04-24 18:23:03 +03:00
|
|
|
|
|
|
|
|
|
PageTitle = AppResources.ViewItem;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-26 07:26:09 +03:00
|
|
|
|
public Command CopyCommand { get; set; }
|
|
|
|
|
public string CipherId { get; set; }
|
2019-04-24 18:23:03 +03:00
|
|
|
|
public CipherView Cipher
|
|
|
|
|
{
|
|
|
|
|
get => _cipher;
|
2019-04-26 07:26:09 +03:00
|
|
|
|
set => SetProperty(ref _cipher, value,
|
|
|
|
|
additionalPropertyNames: new string[]
|
|
|
|
|
{
|
|
|
|
|
nameof(IsLogin),
|
|
|
|
|
nameof(IsIdentity),
|
|
|
|
|
nameof(IsCard),
|
|
|
|
|
nameof(IsSecureNote)
|
|
|
|
|
});
|
2019-04-24 18:23:03 +03:00
|
|
|
|
}
|
|
|
|
|
public bool CanAccessPremium
|
|
|
|
|
{
|
|
|
|
|
get => _canAccessPremium;
|
|
|
|
|
set => SetProperty(ref _canAccessPremium, value);
|
|
|
|
|
}
|
2019-04-26 07:26:09 +03:00
|
|
|
|
public bool IsLogin => _cipher?.Type == Core.Enums.CipherType.Login;
|
|
|
|
|
public bool IsIdentity => _cipher?.Type == Core.Enums.CipherType.Identity;
|
|
|
|
|
public bool IsCard => _cipher?.Type == Core.Enums.CipherType.Card;
|
|
|
|
|
public bool IsSecureNote => _cipher?.Type == Core.Enums.CipherType.SecureNote;
|
|
|
|
|
public string TotpCodeFormatted
|
|
|
|
|
{
|
|
|
|
|
get => _totpCodeFormatted;
|
|
|
|
|
set => SetProperty(ref _totpCodeFormatted, value);
|
|
|
|
|
}
|
|
|
|
|
public string TotpSec
|
|
|
|
|
{
|
|
|
|
|
get => _totpSec;
|
|
|
|
|
set => SetProperty(ref _totpSec, value);
|
|
|
|
|
}
|
|
|
|
|
public bool TotpLow
|
|
|
|
|
{
|
|
|
|
|
get => _totpLow;
|
|
|
|
|
set => SetProperty(ref _totpLow, value);
|
|
|
|
|
}
|
2019-04-24 18:23:03 +03:00
|
|
|
|
|
|
|
|
|
public async Task LoadAsync()
|
|
|
|
|
{
|
2019-04-26 07:26:09 +03:00
|
|
|
|
CleanUp();
|
2019-04-24 18:23:03 +03:00
|
|
|
|
var cipher = await _cipherService.GetAsync(CipherId);
|
|
|
|
|
Cipher = await cipher.DecryptAsync();
|
|
|
|
|
CanAccessPremium = await _userService.CanAccessPremiumAsync();
|
|
|
|
|
|
2019-04-26 07:26:09 +03:00
|
|
|
|
if(Cipher.Type == Core.Enums.CipherType.Login && !string.IsNullOrWhiteSpace(Cipher.Login.Totp) &&
|
|
|
|
|
(Cipher.OrganizationUseTotp || CanAccessPremium))
|
|
|
|
|
{
|
|
|
|
|
await TotpUpdateCodeAsync();
|
|
|
|
|
var interval = _totpService.GetTimeInterval(Cipher.Login.Totp);
|
|
|
|
|
await TotpTickAsync(interval);
|
|
|
|
|
_totpInterval = DateTime.UtcNow;
|
|
|
|
|
Device.StartTimer(new TimeSpan(0, 0, 1), () =>
|
|
|
|
|
{
|
|
|
|
|
if(_totpInterval == null)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
var task = TotpTickAsync(interval);
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void CleanUp()
|
|
|
|
|
{
|
|
|
|
|
_totpInterval = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task TotpUpdateCodeAsync()
|
|
|
|
|
{
|
|
|
|
|
if(Cipher == null || Cipher.Type != Core.Enums.CipherType.Login || Cipher.Login.Totp == null)
|
|
|
|
|
{
|
|
|
|
|
_totpInterval = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_totpCode = await _totpService.GetCodeAsync(Cipher.Login.Totp);
|
|
|
|
|
if(_totpCode != null)
|
|
|
|
|
{
|
|
|
|
|
if(_totpCode.Length > 4)
|
|
|
|
|
{
|
|
|
|
|
var half = (int)Math.Floor(_totpCode.Length / 2M);
|
|
|
|
|
TotpCodeFormatted = string.Format("{0} {1}", _totpCode.Substring(0, half),
|
|
|
|
|
_totpCode.Substring(half));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TotpCodeFormatted = _totpCode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TotpCodeFormatted = null;
|
|
|
|
|
_totpInterval = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task TotpTickAsync(int intervalSeconds)
|
|
|
|
|
{
|
|
|
|
|
var epoc = CoreHelpers.EpocUtcNow() / 1000;
|
|
|
|
|
var mod = epoc % intervalSeconds;
|
|
|
|
|
var totpSec = intervalSeconds - mod;
|
|
|
|
|
TotpSec = totpSec.ToString();
|
|
|
|
|
TotpLow = totpSec < 7;
|
|
|
|
|
if(mod == 0)
|
|
|
|
|
{
|
|
|
|
|
await TotpUpdateCodeAsync();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void CopyAsync(string id)
|
|
|
|
|
{
|
|
|
|
|
string text = null;
|
|
|
|
|
string name = null;
|
|
|
|
|
if(id == "LoginUsername")
|
|
|
|
|
{
|
|
|
|
|
text = Cipher.Login.Username;
|
|
|
|
|
name = AppResources.Username;
|
|
|
|
|
}
|
|
|
|
|
else if(id == "LoginPassword")
|
|
|
|
|
{
|
|
|
|
|
text = Cipher.Login.Password;
|
|
|
|
|
name = AppResources.Password;
|
|
|
|
|
}
|
|
|
|
|
else if(id == "LoginTotp")
|
|
|
|
|
{
|
|
|
|
|
text = _totpCode;
|
|
|
|
|
name = AppResources.VerificationCodeTotp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(text != null)
|
|
|
|
|
{
|
|
|
|
|
await _platformUtilsService.CopyToClipboardAsync(text);
|
|
|
|
|
if(!string.IsNullOrWhiteSpace(name))
|
|
|
|
|
{
|
|
|
|
|
_platformUtilsService.ShowToast("info", null, string.Format(AppResources.ValueHasBeenCopied, name));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-24 18:23:03 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|