mirror of
https://github.com/bitwarden/mobile.git
synced 2024-09-30 04:17:55 +02:00
added support for cards and identity to view page
This commit is contained in:
parent
d2468d144e
commit
70aa2309b7
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using Bit.App.Resources;
|
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Bit.App.Enums;
|
using Bit.App.Enums;
|
||||||
@ -9,127 +8,40 @@ namespace Bit.App.Models.Page
|
|||||||
{
|
{
|
||||||
public class VaultViewCipherPageModel : INotifyPropertyChanged
|
public class VaultViewCipherPageModel : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
private string _name;
|
private string _name, _notes;
|
||||||
private string _username;
|
|
||||||
private string _password;
|
|
||||||
private string _uri;
|
|
||||||
private string _notes;
|
|
||||||
private string _totpCode;
|
|
||||||
private int _totpSec = 30;
|
|
||||||
private bool _revealPassword;
|
|
||||||
private List<Attachment> _attachments;
|
private List<Attachment> _attachments;
|
||||||
private List<Field> _fields;
|
private List<Field> _fields;
|
||||||
|
|
||||||
|
// Login
|
||||||
|
private string _loginUsername, _loginPassword, _loginUri, _loginTotpCode;
|
||||||
|
private int _loginTotpSec = 30;
|
||||||
|
private bool _loginRevealPassword;
|
||||||
|
|
||||||
|
// Card
|
||||||
|
private string _cardName, _cardNumber, _cardBrand, _cardExpMonth, _cardExpYear, _cardCode;
|
||||||
|
|
||||||
|
// Identity
|
||||||
|
private string _idFirstName, _idLastName, _idMiddleName, _idCompany, _idEmail, _idPhone, _idUsername,
|
||||||
|
_idPassportNumber, _idLicenseNumber, _idSsn, _idAddress1, _idAddress2, _idAddress3, _idCity,
|
||||||
|
_idState, _idCountry, _idPostalCode, _idTitle;
|
||||||
|
|
||||||
public VaultViewCipherPageModel() { }
|
public VaultViewCipherPageModel() { }
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get { return _name; }
|
get => _name;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_name = value;
|
_name = value;
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public string Username
|
|
||||||
{
|
|
||||||
get { return _username; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_username = value;
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Username)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowUsername)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public bool ShowUsername => !string.IsNullOrWhiteSpace(Username);
|
|
||||||
|
|
||||||
public string Password
|
|
||||||
{
|
|
||||||
get { return _password; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_password = value;
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Password)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowPassword)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public bool ShowPassword => !string.IsNullOrWhiteSpace(Password);
|
|
||||||
|
|
||||||
public string Uri
|
|
||||||
{
|
|
||||||
get { return _uri; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_uri = value;
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Uri)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(UriHost)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowUri)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowLaunch)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public bool ShowUri => !string.IsNullOrWhiteSpace(Uri);
|
|
||||||
|
|
||||||
public bool ShowLaunch
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if(!ShowUri)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Device.RuntimePlatform == Device.Android && !Uri.StartsWith("http") &&
|
|
||||||
!Uri.StartsWith("androidapp://"))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Device.RuntimePlatform != Device.Android && !Uri.StartsWith("http"))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri uri;
|
|
||||||
if(!System.Uri.TryCreate(Uri, UriKind.Absolute, out uri))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string UriHost
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if(!ShowUri)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri uri;
|
|
||||||
if(!System.Uri.TryCreate(Uri, UriKind.Absolute, out uri))
|
|
||||||
{
|
|
||||||
return Uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
string domain;
|
|
||||||
if(DomainName.TryParseBaseDomain(uri.Host, out domain))
|
|
||||||
{
|
|
||||||
return domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
return uri.Host;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Notes
|
public string Notes
|
||||||
{
|
{
|
||||||
get { return _notes; }
|
get => _notes;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_notes = value;
|
_notes = value;
|
||||||
@ -138,48 +50,10 @@ namespace Bit.App.Models.Page
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public bool ShowNotes => !string.IsNullOrWhiteSpace(Notes);
|
public bool ShowNotes => !string.IsNullOrWhiteSpace(Notes);
|
||||||
public bool RevealPassword
|
|
||||||
{
|
|
||||||
get { return _revealPassword; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_revealPassword = value;
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(RevealPassword)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideImage)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string MaskedPassword => RevealPassword ? Password : Password == null ? null : new string('●', Password.Length);
|
|
||||||
public ImageSource ShowHideImage => RevealPassword ? ImageSource.FromFile("eye_slash") : ImageSource.FromFile("eye");
|
|
||||||
|
|
||||||
public string TotpCode
|
|
||||||
{
|
|
||||||
get { return _totpCode; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_totpCode = value;
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(TotpCode)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(TotpCodeFormatted)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public int TotpSecond
|
|
||||||
{
|
|
||||||
get { return _totpSec; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_totpSec = value;
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(TotpSecond)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(TotpColor)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public bool TotpLow => TotpSecond <= 7;
|
|
||||||
public Color TotpColor => !string.IsNullOrWhiteSpace(TotpCode) && TotpLow ? Color.Red : Color.Black;
|
|
||||||
public string TotpCodeFormatted => !string.IsNullOrWhiteSpace(TotpCode) ?
|
|
||||||
string.Format("{0} {1}", TotpCode.Substring(0, 3), TotpCode.Substring(3)) : null;
|
|
||||||
|
|
||||||
public List<Attachment> Attachments
|
public List<Attachment> Attachments
|
||||||
{
|
{
|
||||||
get { return _attachments; }
|
get => _attachments;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_attachments = value;
|
_attachments = value;
|
||||||
@ -191,7 +65,7 @@ namespace Bit.App.Models.Page
|
|||||||
|
|
||||||
public List<Field> Fields
|
public List<Field> Fields
|
||||||
{
|
{
|
||||||
get { return _fields; }
|
get => _fields;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_fields = value;
|
_fields = value;
|
||||||
@ -201,12 +75,484 @@ namespace Bit.App.Models.Page
|
|||||||
}
|
}
|
||||||
public bool ShowFields => (Fields?.Count ?? 0) > 0;
|
public bool ShowFields => (Fields?.Count ?? 0) > 0;
|
||||||
|
|
||||||
|
// Login
|
||||||
|
public string LoginUsername
|
||||||
|
{
|
||||||
|
get => _loginUsername;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_loginUsername = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginUsername)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowLoginUsername)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowLoginUsername => !string.IsNullOrWhiteSpace(LoginUsername);
|
||||||
|
|
||||||
|
public string LoginPassword
|
||||||
|
{
|
||||||
|
get => _loginPassword;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_loginPassword = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginPassword)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedLoginPassword)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowLoginPassword)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowLoginPassword => !string.IsNullOrWhiteSpace(LoginPassword);
|
||||||
|
public bool RevealLoginPassword
|
||||||
|
{
|
||||||
|
get => _loginRevealPassword;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_loginRevealPassword = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(RevealLoginPassword)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedLoginPassword)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginShowHideImage)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string MaskedLoginPassword => RevealLoginPassword ?
|
||||||
|
LoginPassword : LoginPassword == null ? null : new string('●', LoginPassword.Length);
|
||||||
|
public ImageSource LoginShowHideImage => RevealLoginPassword ?
|
||||||
|
ImageSource.FromFile("eye_slash.png") : ImageSource.FromFile("eye.png");
|
||||||
|
|
||||||
|
public string LoginUri
|
||||||
|
{
|
||||||
|
get => _loginUri;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_loginUri = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginUri)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginUriHost)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowLoginUri)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowLoginLaunch)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowLoginUri => !string.IsNullOrWhiteSpace(LoginUri);
|
||||||
|
public bool ShowLoginLaunch
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(!ShowLoginUri)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Device.RuntimePlatform == Device.Android && !LoginUri.StartsWith("http") &&
|
||||||
|
!LoginUri.StartsWith("androidapp://"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Device.RuntimePlatform != Device.Android && !LoginUri.StartsWith("http"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Uri.TryCreate(LoginUri, UriKind.Absolute, out Uri uri))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string LoginUriHost
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(!ShowLoginUri)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Uri.TryCreate(LoginUri, UriKind.Absolute, out Uri uri))
|
||||||
|
{
|
||||||
|
return LoginUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(DomainName.TryParseBaseDomain(uri.Host, out string domain))
|
||||||
|
{
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri.Host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string LoginTotpCode
|
||||||
|
{
|
||||||
|
get => _loginTotpCode;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_loginTotpCode = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginTotpCode)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginTotpCodeFormatted)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int LoginTotpSecond
|
||||||
|
{
|
||||||
|
get => _loginTotpSec;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_loginTotpSec = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginTotpSecond)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginTotpColor)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool LoginTotpLow => LoginTotpSecond <= 7;
|
||||||
|
public Color LoginTotpColor => !string.IsNullOrWhiteSpace(LoginTotpCode) && LoginTotpLow ?
|
||||||
|
Color.Red : Color.Black;
|
||||||
|
public string LoginTotpCodeFormatted => !string.IsNullOrWhiteSpace(LoginTotpCode) ?
|
||||||
|
string.Format("{0} {1}", LoginTotpCode.Substring(0, 3), LoginTotpCode.Substring(3)) : null;
|
||||||
|
|
||||||
|
// Card
|
||||||
|
public string CardName
|
||||||
|
{
|
||||||
|
get => _cardName;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_cardName = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardName)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardName)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowCardName => !string.IsNullOrWhiteSpace(CardName);
|
||||||
|
|
||||||
|
public string CardNumber
|
||||||
|
{
|
||||||
|
get => _cardNumber;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_cardNumber = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardNumber)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardNumber)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowCardNumber => !string.IsNullOrWhiteSpace(CardNumber);
|
||||||
|
|
||||||
|
public string CardBrand
|
||||||
|
{
|
||||||
|
get => _cardBrand;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_cardBrand = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardBrand)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardBrand)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowCardBrand => !string.IsNullOrWhiteSpace(CardBrand);
|
||||||
|
|
||||||
|
public string CardExpMonth
|
||||||
|
{
|
||||||
|
private get => _cardExpMonth;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_cardExpMonth = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardExpMonth)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardExp)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardExp)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CardExpYear
|
||||||
|
{
|
||||||
|
private get => _cardExpYear;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_cardExpYear = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardExpYear)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardExp)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardExp)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CardExp
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var expMonth = !string.IsNullOrWhiteSpace(CardExpMonth) ? CardExpMonth.PadLeft(2, '0') : "__";
|
||||||
|
var expYear = "____";
|
||||||
|
if(!string.IsNullOrWhiteSpace(CardExpYear))
|
||||||
|
{
|
||||||
|
expYear = CardExpYear;
|
||||||
|
}
|
||||||
|
if(expYear.Length == 2)
|
||||||
|
{
|
||||||
|
expYear = "20" + expYear;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{expMonth} / {expYear}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowCardExp => !string.IsNullOrWhiteSpace(CardExpMonth) && !string.IsNullOrWhiteSpace(CardExpYear);
|
||||||
|
|
||||||
|
public string CardCode
|
||||||
|
{
|
||||||
|
get => _cardCode;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_cardCode = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardCode)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardCode)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowCardCode => !string.IsNullOrWhiteSpace(CardCode);
|
||||||
|
|
||||||
|
// Identity
|
||||||
|
|
||||||
|
public string IdTitle
|
||||||
|
{
|
||||||
|
get => _idTitle;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idTitle = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdTitle)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdFirstName
|
||||||
|
{
|
||||||
|
private get => _idFirstName;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idFirstName = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdFirstName)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdName)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdMiddleName
|
||||||
|
{
|
||||||
|
private get => _idMiddleName;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idMiddleName = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdMiddleName)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdLastName
|
||||||
|
{
|
||||||
|
private get => _idLastName;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idLastName = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdLastName)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdName)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var name = IdTitle;
|
||||||
|
if(!string.IsNullOrWhiteSpace(IdFirstName))
|
||||||
|
{
|
||||||
|
name += ((!string.IsNullOrWhiteSpace(name) ? " " : string.Empty) + IdFirstName);
|
||||||
|
}
|
||||||
|
if(!string.IsNullOrWhiteSpace(IdMiddleName))
|
||||||
|
{
|
||||||
|
name += ((!string.IsNullOrWhiteSpace(name) ? " " : string.Empty) + IdMiddleName);
|
||||||
|
}
|
||||||
|
if(!string.IsNullOrWhiteSpace(IdLastName))
|
||||||
|
{
|
||||||
|
name += ((!string.IsNullOrWhiteSpace(name) ? " " : string.Empty) + IdLastName);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowIdName => !string.IsNullOrWhiteSpace(IdFirstName) || !string.IsNullOrWhiteSpace(IdLastName);
|
||||||
|
|
||||||
|
public string IdUsername
|
||||||
|
{
|
||||||
|
get => _idUsername;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idUsername = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdUsername)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdUsername)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowIdUsername => !string.IsNullOrWhiteSpace(IdUsername);
|
||||||
|
|
||||||
|
public string IdCompany
|
||||||
|
{
|
||||||
|
get => _idCompany;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idCompany = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdCompany)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdCompany)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowIdCompany => !string.IsNullOrWhiteSpace(IdCompany);
|
||||||
|
|
||||||
|
public string IdSsn
|
||||||
|
{
|
||||||
|
get => _idSsn;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idSsn = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdSsn)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdSsn)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowIdSsn => !string.IsNullOrWhiteSpace(IdSsn);
|
||||||
|
|
||||||
|
public string IdPassportNumber
|
||||||
|
{
|
||||||
|
get => _idPassportNumber;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idPassportNumber = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdPassportNumber)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdPassportNumber)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowIdPassportNumber => !string.IsNullOrWhiteSpace(IdPassportNumber);
|
||||||
|
|
||||||
|
public string IdLicenseNumber
|
||||||
|
{
|
||||||
|
get => _idLicenseNumber;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idLicenseNumber = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdLicenseNumber)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdLicenseNumber)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowIdLicenseNumber => !string.IsNullOrWhiteSpace(IdLicenseNumber);
|
||||||
|
|
||||||
|
public string IdEmail
|
||||||
|
{
|
||||||
|
get => _idEmail;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idEmail = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdEmail)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdEmail)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowIdEmail => !string.IsNullOrWhiteSpace(IdEmail);
|
||||||
|
|
||||||
|
public string IdPhone
|
||||||
|
{
|
||||||
|
get => _idPhone;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idPhone = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdPhone)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdPhone)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowIdPhone => !string.IsNullOrWhiteSpace(IdPhone);
|
||||||
|
|
||||||
|
public string IdAddress1
|
||||||
|
{
|
||||||
|
get => _idAddress1;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idAddress1 = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress1)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdAddress)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdAddress2
|
||||||
|
{
|
||||||
|
get => _idAddress2;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idAddress2 = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress2)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdAddress3
|
||||||
|
{
|
||||||
|
get => _idAddress3;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idAddress3 = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress3)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdCity
|
||||||
|
{
|
||||||
|
get => _idCity;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idCity = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdCity)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdAddress)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdState
|
||||||
|
{
|
||||||
|
get => _idState;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idState = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdState)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdPostalCode
|
||||||
|
{
|
||||||
|
get => _idPostalCode;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idPostalCode = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdPostalCode)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdCountry
|
||||||
|
{
|
||||||
|
get => _idCountry;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_idCountry = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdCountry)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdAddress)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string IdAddress
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var address = IdAddress1;
|
||||||
|
if(!string.IsNullOrWhiteSpace(IdAddress2))
|
||||||
|
{
|
||||||
|
address += ((!string.IsNullOrWhiteSpace(address) ? "\n" : string.Empty) + IdAddress2);
|
||||||
|
}
|
||||||
|
if(!string.IsNullOrWhiteSpace(IdAddress3))
|
||||||
|
{
|
||||||
|
address += ((!string.IsNullOrWhiteSpace(address) ? "\n" : string.Empty) + IdAddress3);
|
||||||
|
}
|
||||||
|
if(!string.IsNullOrWhiteSpace(IdCity) || !string.IsNullOrWhiteSpace(IdState) ||
|
||||||
|
!string.IsNullOrWhiteSpace(IdPostalCode))
|
||||||
|
{
|
||||||
|
var cityLine = IdCity + ", ";
|
||||||
|
cityLine += !string.IsNullOrWhiteSpace(IdState) ? IdState : "-";
|
||||||
|
cityLine += " ";
|
||||||
|
cityLine += !string.IsNullOrWhiteSpace(IdPostalCode) ? IdPostalCode : "-";
|
||||||
|
address += ((!string.IsNullOrWhiteSpace(address) ? "\n" : string.Empty) + cityLine);
|
||||||
|
}
|
||||||
|
if(!string.IsNullOrWhiteSpace(IdCountry))
|
||||||
|
{
|
||||||
|
address += ((!string.IsNullOrWhiteSpace(address) ? "\n" : string.Empty) + IdCountry);
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ShowIdAddress => !string.IsNullOrWhiteSpace(IdAddress1) || !string.IsNullOrWhiteSpace(IdCity) ||
|
||||||
|
!string.IsNullOrWhiteSpace(IdCountry);
|
||||||
|
|
||||||
public void Update(Cipher cipher)
|
public void Update(Cipher cipher)
|
||||||
{
|
{
|
||||||
Name = cipher.Name?.Decrypt(cipher.OrganizationId);
|
Name = cipher.Name?.Decrypt(cipher.OrganizationId);
|
||||||
Username = cipher.Login?.Username?.Decrypt(cipher.OrganizationId);
|
|
||||||
Password = cipher.Login?.Password?.Decrypt(cipher.OrganizationId);
|
|
||||||
Uri = cipher.Login?.Uri?.Decrypt(cipher.OrganizationId);
|
|
||||||
Notes = cipher.Notes?.Decrypt(cipher.OrganizationId);
|
Notes = cipher.Notes?.Decrypt(cipher.OrganizationId);
|
||||||
|
|
||||||
if(cipher.Attachments != null)
|
if(cipher.Attachments != null)
|
||||||
@ -248,6 +594,45 @@ namespace Bit.App.Models.Page
|
|||||||
{
|
{
|
||||||
cipher.Fields = null;
|
cipher.Fields = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch(cipher.Type)
|
||||||
|
{
|
||||||
|
case CipherType.Login:
|
||||||
|
LoginUsername = cipher.Login.Username?.Decrypt(cipher.OrganizationId);
|
||||||
|
LoginPassword = cipher.Login.Password?.Decrypt(cipher.OrganizationId);
|
||||||
|
LoginUri = cipher.Login.Uri?.Decrypt(cipher.OrganizationId);
|
||||||
|
break;
|
||||||
|
case CipherType.Card:
|
||||||
|
CardName = cipher.Card.CardholderName?.Decrypt(cipher.OrganizationId);
|
||||||
|
CardNumber = cipher.Card.Number?.Decrypt(cipher.OrganizationId);
|
||||||
|
CardBrand = cipher.Card.Brand?.Decrypt(cipher.OrganizationId);
|
||||||
|
CardExpMonth = cipher.Card.ExpMonth?.Decrypt(cipher.OrganizationId);
|
||||||
|
CardExpYear = cipher.Card.ExpYear?.Decrypt(cipher.OrganizationId);
|
||||||
|
CardCode = cipher.Card.Code?.Decrypt(cipher.OrganizationId);
|
||||||
|
break;
|
||||||
|
case CipherType.Identity:
|
||||||
|
IdTitle = cipher.Identity.Title?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdFirstName = cipher.Identity.FirstName?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdMiddleName = cipher.Identity.MiddleName?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdLastName = cipher.Identity.LastName?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdCompany = cipher.Identity.Company?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdUsername = cipher.Identity.Username?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdSsn = cipher.Identity.SSN?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdPassportNumber = cipher.Identity.PassportNumber?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdLicenseNumber = cipher.Identity.LicenseNumber?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdEmail = cipher.Identity.Email?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdPhone = cipher.Identity.Phone?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdAddress1 = cipher.Identity.Address1?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdAddress2 = cipher.Identity.Address2?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdAddress3 = cipher.Identity.Address3?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdCity = cipher.Identity.City?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdState = cipher.Identity.State?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdPostalCode = cipher.Identity.PostalCode?.Decrypt(cipher.OrganizationId);
|
||||||
|
IdCountry = cipher.Identity.Country?.Decrypt(cipher.OrganizationId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Attachment
|
public class Attachment
|
||||||
|
@ -267,7 +267,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
if(selection == AppResources.View)
|
if(selection == AppResources.View)
|
||||||
{
|
{
|
||||||
var page = new VaultViewCipherPage(cipher.Id);
|
var page = new VaultViewCipherPage(cipher.Type, cipher.Id);
|
||||||
await Navigation.PushForDeviceAsync(page);
|
await Navigation.PushForDeviceAsync(page);
|
||||||
}
|
}
|
||||||
else if(selection == AppResources.Edit)
|
else if(selection == AppResources.Edit)
|
||||||
|
@ -398,7 +398,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
if(selection == AppResources.View || string.IsNullOrWhiteSpace(Uri))
|
if(selection == AppResources.View || string.IsNullOrWhiteSpace(Uri))
|
||||||
{
|
{
|
||||||
var page = new VaultViewCipherPage(cipher.Id);
|
var page = new VaultViewCipherPage(cipher.Type, cipher.Id);
|
||||||
await Navigation.PushForDeviceAsync(page);
|
await Navigation.PushForDeviceAsync(page);
|
||||||
}
|
}
|
||||||
else if(selection == AppResources.Autofill)
|
else if(selection == AppResources.Autofill)
|
||||||
@ -453,7 +453,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
if(selection == AppResources.View)
|
if(selection == AppResources.View)
|
||||||
{
|
{
|
||||||
var page = new VaultViewCipherPage(cipher.Id);
|
var page = new VaultViewCipherPage(cipher.Type, cipher.Id);
|
||||||
await Navigation.PushForDeviceAsync(page);
|
await Navigation.PushForDeviceAsync(page);
|
||||||
}
|
}
|
||||||
else if(selection == AppResources.Edit)
|
else if(selection == AppResources.Edit)
|
||||||
|
@ -17,6 +17,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
public class VaultViewCipherPage : ExtendedContentPage
|
public class VaultViewCipherPage : ExtendedContentPage
|
||||||
{
|
{
|
||||||
|
private readonly CipherType _type;
|
||||||
private readonly string _cipherId;
|
private readonly string _cipherId;
|
||||||
private readonly ICipherService _cipherService;
|
private readonly ICipherService _cipherService;
|
||||||
private readonly IUserDialogs _userDialogs;
|
private readonly IUserDialogs _userDialogs;
|
||||||
@ -24,8 +25,9 @@ namespace Bit.App.Pages
|
|||||||
private readonly ITokenService _tokenService;
|
private readonly ITokenService _tokenService;
|
||||||
private bool _pageDisappeared = true;
|
private bool _pageDisappeared = true;
|
||||||
|
|
||||||
public VaultViewCipherPage(string cipherId)
|
public VaultViewCipherPage(CipherType type, string cipherId)
|
||||||
{
|
{
|
||||||
|
_type = type;
|
||||||
_cipherId = cipherId;
|
_cipherId = cipherId;
|
||||||
_cipherService = Resolver.Resolve<ICipherService>();
|
_cipherService = Resolver.Resolve<ICipherService>();
|
||||||
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
@ -41,15 +43,35 @@ namespace Bit.App.Pages
|
|||||||
private TableSection NotesSection { get; set; }
|
private TableSection NotesSection { get; set; }
|
||||||
private TableSection AttachmentsSection { get; set; }
|
private TableSection AttachmentsSection { get; set; }
|
||||||
private TableSection FieldsSection { get; set; }
|
private TableSection FieldsSection { get; set; }
|
||||||
public LabeledValueCell UsernameCell { get; set; }
|
|
||||||
public LabeledValueCell PasswordCell { get; set; }
|
|
||||||
public LabeledValueCell UriCell { get; set; }
|
|
||||||
public LabeledValueCell NotesCell { get; set; }
|
public LabeledValueCell NotesCell { get; set; }
|
||||||
public LabeledValueCell TotpCodeCell { get; set; }
|
|
||||||
private EditCipherToolBarItem EditItem { get; set; }
|
private EditCipherToolBarItem EditItem { get; set; }
|
||||||
public List<LabeledValueCell> FieldsCells { get; set; }
|
public List<LabeledValueCell> FieldsCells { get; set; }
|
||||||
public List<AttachmentViewCell> AttachmentCells { get; set; }
|
public List<AttachmentViewCell> AttachmentCells { get; set; }
|
||||||
|
|
||||||
|
// Login
|
||||||
|
public LabeledValueCell LoginUsernameCell { get; set; }
|
||||||
|
public LabeledValueCell LoginPasswordCell { get; set; }
|
||||||
|
public LabeledValueCell LoginUriCell { get; set; }
|
||||||
|
public LabeledValueCell LoginTotpCodeCell { get; set; }
|
||||||
|
|
||||||
|
// Card
|
||||||
|
public LabeledValueCell CardNameCell { get; set; }
|
||||||
|
public LabeledValueCell CardNumberCell { get; set; }
|
||||||
|
public LabeledValueCell CardBrandCell { get; set; }
|
||||||
|
public LabeledValueCell CardExpCell { get; set; }
|
||||||
|
public LabeledValueCell CardCodeCell { get; set; }
|
||||||
|
|
||||||
|
// Card
|
||||||
|
public LabeledValueCell IdNameCell { get; set; }
|
||||||
|
public LabeledValueCell IdUsernameCell { get; set; }
|
||||||
|
public LabeledValueCell IdCompanyCell { get; set; }
|
||||||
|
public LabeledValueCell IdSsnCell { get; set; }
|
||||||
|
public LabeledValueCell IdPassportNumberCell { get; set; }
|
||||||
|
public LabeledValueCell IdLicenseNumberCell { get; set; }
|
||||||
|
public LabeledValueCell IdEmailCell { get; set; }
|
||||||
|
public LabeledValueCell IdPhoneCell { get; set; }
|
||||||
|
public LabeledValueCell IdAddressCell { get; set; }
|
||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
EditItem = new EditCipherToolBarItem(this, _cipherId);
|
EditItem = new EditCipherToolBarItem(this, _cipherId);
|
||||||
@ -59,60 +81,151 @@ namespace Bit.App.Pages
|
|||||||
ToolbarItems.Add(new DismissModalToolBarItem(this));
|
ToolbarItems.Add(new DismissModalToolBarItem(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InitProps();
|
||||||
|
Title = AppResources.ViewItem;
|
||||||
|
Content = Table;
|
||||||
|
BindingContext = Model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitProps()
|
||||||
|
{
|
||||||
// Name
|
// Name
|
||||||
var nameCell = new LabeledValueCell(AppResources.Name);
|
var nameCell = new LabeledValueCell(AppResources.Name);
|
||||||
nameCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.Name));
|
nameCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.Name));
|
||||||
|
|
||||||
// Username
|
|
||||||
UsernameCell = new LabeledValueCell(AppResources.Username, button1Image: "clipboard.png");
|
|
||||||
UsernameCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.Username));
|
|
||||||
UsernameCell.Button1.Command = new Command(() => Copy(Model.Username, AppResources.Username));
|
|
||||||
UsernameCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
|
||||||
|
|
||||||
// Password
|
|
||||||
PasswordCell = new LabeledValueCell(AppResources.Password, button1Image: string.Empty,
|
|
||||||
button2Image: "clipboard.png");
|
|
||||||
PasswordCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.MaskedPassword));
|
|
||||||
PasswordCell.Button1.SetBinding(Button.ImageProperty, nameof(VaultViewCipherPageModel.ShowHideImage));
|
|
||||||
if(Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
PasswordCell.Button1.Margin = new Thickness(10, 0);
|
|
||||||
}
|
|
||||||
PasswordCell.Button1.Command = new Command(() => Model.RevealPassword = !Model.RevealPassword);
|
|
||||||
PasswordCell.Button2.Command = new Command(() => Copy(Model.Password, AppResources.Password));
|
|
||||||
PasswordCell.Value.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
|
|
||||||
PasswordCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
|
||||||
|
|
||||||
// URI
|
|
||||||
UriCell = new LabeledValueCell(AppResources.Website, button1Image: "launch.png");
|
|
||||||
UriCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.UriHost));
|
|
||||||
UriCell.Button1.SetBinding(IsVisibleProperty, nameof(VaultViewCipherPageModel.ShowLaunch));
|
|
||||||
UriCell.Button1.Command = new Command(() =>
|
|
||||||
{
|
|
||||||
if(Device.RuntimePlatform == Device.Android && Model.Uri.StartsWith("androidapp://"))
|
|
||||||
{
|
|
||||||
MessagingCenter.Send(Application.Current, "LaunchApp", Model.Uri);
|
|
||||||
}
|
|
||||||
else if(Model.Uri.StartsWith("http://") || Model.Uri.StartsWith("https://"))
|
|
||||||
{
|
|
||||||
Device.OpenUri(new Uri(Model.Uri));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Totp
|
|
||||||
TotpCodeCell = new LabeledValueCell(AppResources.VerificationCodeTotp, button1Image: "clipboard.png", subText: "--");
|
|
||||||
TotpCodeCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.TotpCodeFormatted));
|
|
||||||
TotpCodeCell.Value.SetBinding(Label.TextColorProperty, nameof(VaultViewCipherPageModel.TotpColor));
|
|
||||||
TotpCodeCell.Button1.Command = new Command(() => Copy(Model.TotpCode, AppResources.VerificationCodeTotp));
|
|
||||||
TotpCodeCell.Sub.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.TotpSecond));
|
|
||||||
TotpCodeCell.Sub.SetBinding(Label.TextColorProperty, nameof(VaultViewCipherPageModel.TotpColor));
|
|
||||||
TotpCodeCell.Value.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
|
|
||||||
|
|
||||||
// Notes
|
// Notes
|
||||||
NotesCell = new LabeledValueCell();
|
NotesCell = new LabeledValueCell();
|
||||||
NotesCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.Notes));
|
NotesCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.Notes));
|
||||||
NotesCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
NotesCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
||||||
|
|
||||||
|
switch(_type)
|
||||||
|
{
|
||||||
|
case CipherType.Login:
|
||||||
|
// Username
|
||||||
|
LoginUsernameCell = new LabeledValueCell(AppResources.Username, button1Image: "clipboard.png");
|
||||||
|
LoginUsernameCell.Value.SetBinding(Label.TextProperty,
|
||||||
|
nameof(VaultViewCipherPageModel.LoginUsername));
|
||||||
|
LoginUsernameCell.Button1.Command =
|
||||||
|
new Command(() => Copy(Model.LoginUsername, AppResources.Username));
|
||||||
|
LoginUsernameCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
||||||
|
|
||||||
|
// Password
|
||||||
|
LoginPasswordCell = new LabeledValueCell(AppResources.Password, button1Image: string.Empty,
|
||||||
|
button2Image: "clipboard.png");
|
||||||
|
LoginPasswordCell.Value.SetBinding(Label.TextProperty,
|
||||||
|
nameof(VaultViewCipherPageModel.MaskedLoginPassword));
|
||||||
|
LoginPasswordCell.Button1.SetBinding(Button.ImageProperty,
|
||||||
|
nameof(VaultViewCipherPageModel.LoginShowHideImage));
|
||||||
|
if(Device.RuntimePlatform == Device.iOS)
|
||||||
|
{
|
||||||
|
LoginPasswordCell.Button1.Margin = new Thickness(10, 0);
|
||||||
|
}
|
||||||
|
LoginPasswordCell.Button1.Command =
|
||||||
|
new Command(() => Model.RevealLoginPassword = !Model.RevealLoginPassword);
|
||||||
|
LoginPasswordCell.Button2.Command =
|
||||||
|
new Command(() => Copy(Model.LoginPassword, AppResources.Password));
|
||||||
|
LoginPasswordCell.Value.FontFamily =
|
||||||
|
Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
|
||||||
|
LoginPasswordCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
||||||
|
|
||||||
|
// URI
|
||||||
|
LoginUriCell = new LabeledValueCell(AppResources.Website, button1Image: "launch.png");
|
||||||
|
LoginUriCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.LoginUriHost));
|
||||||
|
LoginUriCell.Button1.SetBinding(IsVisibleProperty, nameof(VaultViewCipherPageModel.ShowLoginLaunch));
|
||||||
|
LoginUriCell.Button1.Command = new Command(() =>
|
||||||
|
{
|
||||||
|
if(Device.RuntimePlatform == Device.Android && Model.LoginUri.StartsWith("androidapp://"))
|
||||||
|
{
|
||||||
|
MessagingCenter.Send(Application.Current, "LaunchApp", Model.LoginUri);
|
||||||
|
}
|
||||||
|
else if(Model.LoginUri.StartsWith("http://") || Model.LoginUri.StartsWith("https://"))
|
||||||
|
{
|
||||||
|
Device.OpenUri(new Uri(Model.LoginUri));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Totp
|
||||||
|
LoginTotpCodeCell = new LabeledValueCell(
|
||||||
|
AppResources.VerificationCodeTotp, button1Image: "clipboard.png", subText: "--");
|
||||||
|
LoginTotpCodeCell.Value.SetBinding(Label.TextProperty,
|
||||||
|
nameof(VaultViewCipherPageModel.LoginTotpCodeFormatted));
|
||||||
|
LoginTotpCodeCell.Value.SetBinding(Label.TextColorProperty,
|
||||||
|
nameof(VaultViewCipherPageModel.LoginTotpColor));
|
||||||
|
LoginTotpCodeCell.Button1.Command =
|
||||||
|
new Command(() => Copy(Model.LoginTotpCode, AppResources.VerificationCodeTotp));
|
||||||
|
LoginTotpCodeCell.Sub.SetBinding(Label.TextProperty,
|
||||||
|
nameof(VaultViewCipherPageModel.LoginTotpSecond));
|
||||||
|
LoginTotpCodeCell.Sub.SetBinding(Label.TextColorProperty,
|
||||||
|
nameof(VaultViewCipherPageModel.LoginTotpColor));
|
||||||
|
LoginTotpCodeCell.Value.FontFamily =
|
||||||
|
Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
|
||||||
|
break;
|
||||||
|
case CipherType.Card:
|
||||||
|
CardNameCell = new LabeledValueCell(AppResources.CardholderName);
|
||||||
|
CardNameCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.CardName));
|
||||||
|
|
||||||
|
CardNumberCell = new LabeledValueCell(AppResources.Number, button1Image: "clipboard.png");
|
||||||
|
CardNumberCell.Button1.Command = new Command(() => Copy(Model.CardNumber, AppResources.Number));
|
||||||
|
CardNumberCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.CardNumber));
|
||||||
|
CardNumberCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
||||||
|
|
||||||
|
CardBrandCell = new LabeledValueCell(AppResources.Brand);
|
||||||
|
CardBrandCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.CardBrand));
|
||||||
|
|
||||||
|
CardExpCell = new LabeledValueCell(AppResources.Expiration);
|
||||||
|
CardExpCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.CardExp));
|
||||||
|
|
||||||
|
CardCodeCell = new LabeledValueCell(AppResources.SecurityCode, button1Image: "clipboard.png");
|
||||||
|
CardCodeCell.Button1.Command = new Command(() => Copy(Model.CardCode, AppResources.SecurityCode));
|
||||||
|
CardCodeCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.CardCode));
|
||||||
|
break;
|
||||||
|
case CipherType.Identity:
|
||||||
|
IdNameCell = new LabeledValueCell(AppResources.Name);
|
||||||
|
IdNameCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.IdName));
|
||||||
|
IdNameCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
||||||
|
|
||||||
|
IdUsernameCell = new LabeledValueCell(AppResources.Username, button1Image: "clipboard.png");
|
||||||
|
IdUsernameCell.Button1.Command = new Command(() => Copy(Model.IdUsername, AppResources.Username));
|
||||||
|
IdUsernameCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.IdUsername));
|
||||||
|
IdUsernameCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
||||||
|
|
||||||
|
IdCompanyCell = new LabeledValueCell(AppResources.Company);
|
||||||
|
IdCompanyCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.IdCompany));
|
||||||
|
|
||||||
|
IdSsnCell = new LabeledValueCell(AppResources.SSN);
|
||||||
|
IdSsnCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.IdSsn));
|
||||||
|
|
||||||
|
IdPassportNumberCell = new LabeledValueCell(AppResources.PassportNumber,
|
||||||
|
button1Image: "clipboard.png");
|
||||||
|
IdPassportNumberCell.Button1.Command =
|
||||||
|
new Command(() => Copy(Model.IdPassportNumber, AppResources.PassportNumber));
|
||||||
|
IdPassportNumberCell.Value.SetBinding(Label.TextProperty,
|
||||||
|
nameof(VaultViewCipherPageModel.IdPassportNumber));
|
||||||
|
IdPassportNumberCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
||||||
|
|
||||||
|
IdLicenseNumberCell = new LabeledValueCell(AppResources.LicenseNumber,
|
||||||
|
button1Image: "clipboard.png");
|
||||||
|
IdLicenseNumberCell.Button1.Command =
|
||||||
|
new Command(() => Copy(Model.IdLicenseNumber, AppResources.LicenseNumber));
|
||||||
|
IdLicenseNumberCell.Value.SetBinding(Label.TextProperty,
|
||||||
|
nameof(VaultViewCipherPageModel.IdLicenseNumber));
|
||||||
|
IdLicenseNumberCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
||||||
|
|
||||||
|
IdEmailCell = new LabeledValueCell(AppResources.Email);
|
||||||
|
IdEmailCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.IdEmail));
|
||||||
|
|
||||||
|
IdPhoneCell = new LabeledValueCell(AppResources.Phone);
|
||||||
|
IdPhoneCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.IdPhone));
|
||||||
|
|
||||||
|
IdAddressCell = new LabeledValueCell(AppResources.Address, button1Image: "clipboard.png");
|
||||||
|
IdAddressCell.Button1.Command = new Command(() => Copy(Model.IdAddress, AppResources.Address));
|
||||||
|
IdAddressCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewCipherPageModel.IdAddress));
|
||||||
|
IdAddressCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ItemInformationSection = new TableSection(AppResources.ItemInformation)
|
ItemInformationSection = new TableSection(AppResources.ItemInformation)
|
||||||
{
|
{
|
||||||
nameCell
|
nameCell
|
||||||
@ -140,10 +253,6 @@ namespace Bit.App.Pages
|
|||||||
Table.RowHeight = -1;
|
Table.RowHeight = -1;
|
||||||
Table.EstimatedRowHeight = 70;
|
Table.EstimatedRowHeight = 70;
|
||||||
}
|
}
|
||||||
|
|
||||||
Title = AppResources.ViewItem;
|
|
||||||
Content = Table;
|
|
||||||
BindingContext = Model;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async override void OnAppearing()
|
protected async override void OnAppearing()
|
||||||
@ -160,34 +269,20 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
Model.Update(cipher);
|
Model.Update(cipher);
|
||||||
|
BuildTable(cipher);
|
||||||
|
base.OnAppearing();
|
||||||
|
}
|
||||||
|
|
||||||
if(ItemInformationSection.Contains(UriCell))
|
protected override void OnDisappearing()
|
||||||
{
|
{
|
||||||
ItemInformationSection.Remove(UriCell);
|
_pageDisappeared = true;
|
||||||
}
|
NotesCell.Tapped -= NotesCell_Tapped;
|
||||||
if(Model.ShowUri)
|
EditItem.Dispose();
|
||||||
{
|
CleanupAttachmentCells();
|
||||||
ItemInformationSection.Add(UriCell);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(ItemInformationSection.Contains(UsernameCell))
|
|
||||||
{
|
|
||||||
ItemInformationSection.Remove(UsernameCell);
|
|
||||||
}
|
|
||||||
if(Model.ShowUsername)
|
|
||||||
{
|
|
||||||
ItemInformationSection.Add(UsernameCell);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ItemInformationSection.Contains(PasswordCell))
|
|
||||||
{
|
|
||||||
ItemInformationSection.Remove(PasswordCell);
|
|
||||||
}
|
|
||||||
if(Model.ShowPassword)
|
|
||||||
{
|
|
||||||
ItemInformationSection.Add(PasswordCell);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private void BuildTable(Cipher cipher)
|
||||||
|
{
|
||||||
if(Table.Root.Contains(NotesSection))
|
if(Table.Root.Contains(NotesSection))
|
||||||
{
|
{
|
||||||
Table.Root.Remove(NotesSection);
|
Table.Root.Remove(NotesSection);
|
||||||
@ -197,36 +292,7 @@ namespace Bit.App.Pages
|
|||||||
Table.Root.Add(NotesSection);
|
Table.Root.Add(NotesSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Totp
|
// Attachments
|
||||||
if(ItemInformationSection.Contains(TotpCodeCell))
|
|
||||||
{
|
|
||||||
ItemInformationSection.Remove(TotpCodeCell);
|
|
||||||
}
|
|
||||||
if(cipher.Login?.Totp != null && (_tokenService.TokenPremium || cipher.OrganizationUseTotp))
|
|
||||||
{
|
|
||||||
var totpKey = cipher.Login?.Totp.Decrypt(cipher.OrganizationId);
|
|
||||||
if(!string.IsNullOrWhiteSpace(totpKey))
|
|
||||||
{
|
|
||||||
Model.TotpCode = Crypto.Totp(totpKey);
|
|
||||||
if(!string.IsNullOrWhiteSpace(Model.TotpCode))
|
|
||||||
{
|
|
||||||
TotpTick(totpKey);
|
|
||||||
Device.StartTimer(new TimeSpan(0, 0, 1), () =>
|
|
||||||
{
|
|
||||||
if(_pageDisappeared)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
TotpTick(totpKey);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
ItemInformationSection.Add(TotpCodeCell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CleanupAttachmentCells();
|
CleanupAttachmentCells();
|
||||||
if(Table.Root.Contains(AttachmentsSection))
|
if(Table.Root.Contains(AttachmentsSection))
|
||||||
{
|
{
|
||||||
@ -249,6 +315,7 @@ namespace Bit.App.Pages
|
|||||||
Table.Root.Add(AttachmentsSection);
|
Table.Root.Add(AttachmentsSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fields
|
||||||
if(Table.Root.Contains(FieldsSection))
|
if(Table.Root.Contains(FieldsSection))
|
||||||
{
|
{
|
||||||
Table.Root.Remove(FieldsSection);
|
Table.Root.Remove(FieldsSection);
|
||||||
@ -278,15 +345,76 @@ namespace Bit.App.Pages
|
|||||||
Table.Root.Add(FieldsSection);
|
Table.Root.Add(FieldsSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnAppearing();
|
// Various types
|
||||||
|
switch(cipher.Type)
|
||||||
|
{
|
||||||
|
case CipherType.Login:
|
||||||
|
AddSectionCell(LoginUriCell, Model.ShowLoginUri);
|
||||||
|
AddSectionCell(LoginUsernameCell, Model.ShowLoginUsername);
|
||||||
|
AddSectionCell(LoginPasswordCell, Model.ShowLoginPassword);
|
||||||
|
|
||||||
|
if(ItemInformationSection.Contains(LoginTotpCodeCell))
|
||||||
|
{
|
||||||
|
ItemInformationSection.Remove(LoginTotpCodeCell);
|
||||||
|
}
|
||||||
|
if(cipher.Login?.Totp != null && (_tokenService.TokenPremium || cipher.OrganizationUseTotp))
|
||||||
|
{
|
||||||
|
var totpKey = cipher.Login?.Totp.Decrypt(cipher.OrganizationId);
|
||||||
|
if(!string.IsNullOrWhiteSpace(totpKey))
|
||||||
|
{
|
||||||
|
Model.LoginTotpCode = Crypto.Totp(totpKey);
|
||||||
|
if(!string.IsNullOrWhiteSpace(Model.LoginTotpCode))
|
||||||
|
{
|
||||||
|
TotpTick(totpKey);
|
||||||
|
Device.StartTimer(new TimeSpan(0, 0, 1), () =>
|
||||||
|
{
|
||||||
|
if(_pageDisappeared)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TotpTick(totpKey);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
ItemInformationSection.Add(LoginTotpCodeCell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CipherType.Card:
|
||||||
|
AddSectionCell(CardNameCell, Model.ShowCardName);
|
||||||
|
AddSectionCell(CardNumberCell, Model.ShowCardNumber);
|
||||||
|
AddSectionCell(CardBrandCell, Model.ShowCardBrand);
|
||||||
|
AddSectionCell(CardExpCell, Model.ShowCardExp);
|
||||||
|
AddSectionCell(CardCodeCell, Model.ShowCardCode);
|
||||||
|
break;
|
||||||
|
case CipherType.Identity:
|
||||||
|
AddSectionCell(IdNameCell, Model.ShowIdName);
|
||||||
|
AddSectionCell(IdUsernameCell, Model.ShowIdUsername);
|
||||||
|
AddSectionCell(IdCompanyCell, Model.ShowIdCompany);
|
||||||
|
AddSectionCell(IdSsnCell, Model.ShowIdSsn);
|
||||||
|
AddSectionCell(IdPassportNumberCell, Model.ShowIdPassportNumber);
|
||||||
|
AddSectionCell(IdLicenseNumberCell, Model.ShowIdLicenseNumber);
|
||||||
|
AddSectionCell(IdEmailCell, Model.ShowIdEmail);
|
||||||
|
AddSectionCell(IdPhoneCell, Model.ShowIdPhone);
|
||||||
|
AddSectionCell(IdAddressCell, Model.ShowIdAddress);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisappearing()
|
private void AddSectionCell(LabeledValueCell cell, bool show)
|
||||||
{
|
{
|
||||||
_pageDisappeared = true;
|
if(ItemInformationSection.Contains(cell))
|
||||||
NotesCell.Tapped -= NotesCell_Tapped;
|
{
|
||||||
EditItem.Dispose();
|
ItemInformationSection.Remove(cell);
|
||||||
CleanupAttachmentCells();
|
}
|
||||||
|
if(show)
|
||||||
|
{
|
||||||
|
ItemInformationSection.Add(cell);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CleanupAttachmentCells()
|
private void CleanupAttachmentCells()
|
||||||
@ -353,11 +481,11 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
var now = Helpers.EpocUtcNow() / 1000;
|
var now = Helpers.EpocUtcNow() / 1000;
|
||||||
var mod = now % 30;
|
var mod = now % 30;
|
||||||
Model.TotpSecond = (int)(30 - mod);
|
Model.LoginTotpSecond = (int)(30 - mod);
|
||||||
|
|
||||||
if(mod == 0)
|
if(mod == 0)
|
||||||
{
|
{
|
||||||
Model.TotpCode = Crypto.Totp(totpKey);
|
Model.LoginTotpCode = Crypto.Totp(totpKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +562,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
Button1.Margin = new Thickness(10, 0);
|
Button1.Margin = new Thickness(10, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Button1.Image = "eye";
|
Button1.Image = "eye";
|
||||||
Button1.Command = new Command(() =>
|
Button1.Command = new Command(() =>
|
||||||
{
|
{
|
||||||
|
18
src/App/Resources/AppResources.Designer.cs
generated
18
src/App/Resources/AppResources.Designer.cs
generated
@ -133,6 +133,15 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Address.
|
||||||
|
/// </summary>
|
||||||
|
public static string Address {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Address", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Address 1.
|
/// Looks up a localized string similar to Address 1.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1078,6 +1087,15 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Expiration.
|
||||||
|
/// </summary>
|
||||||
|
public static string Expiration {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Expiration", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Expiration Month.
|
/// Looks up a localized string similar to Expiration Month.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1170,4 +1170,10 @@
|
|||||||
<data name="ZipPostalCode" xml:space="preserve">
|
<data name="ZipPostalCode" xml:space="preserve">
|
||||||
<value>Zip / Postal Code</value>
|
<value>Zip / Postal Code</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Address" xml:space="preserve">
|
||||||
|
<value>Address</value>
|
||||||
|
</data>
|
||||||
|
<data name="Expiration" xml:space="preserve">
|
||||||
|
<value>Expiration</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
Loading…
Reference in New Issue
Block a user