diff --git a/src/Core/Models/Domain/Cipher.cs b/src/Core/Models/Domain/Cipher.cs index 8c1c6ad25..4471789e8 100644 --- a/src/Core/Models/Domain/Cipher.cs +++ b/src/Core/Models/Domain/Cipher.cs @@ -28,7 +28,7 @@ namespace Bit.Core.Models.Domain OrganizationUseTotp = obj.OrganizationUseTotp; Edit = obj.Edit; RevisionDate = obj.RevisionDate; - CollectionIds = obj.CollectionIds; + CollectionIds = new HashSet(obj.CollectionIds); LocalData = localData; switch(Type) @@ -72,7 +72,7 @@ namespace Bit.Core.Models.Domain public List Attachments { get; set; } public List Fields { get; set; } public List PasswordHistory { get; set; } - public List CollectionIds { get; set; } + public HashSet CollectionIds { get; set; } public async Task DecryptAsync() { @@ -153,7 +153,7 @@ namespace Bit.Core.Models.Domain Favorite = Favorite, RevisionDate = RevisionDate, Type = Type, - CollectionIds = CollectionIds + CollectionIds = CollectionIds.ToList() }; BuildDataModel(this, c, new HashSet { diff --git a/src/Core/Models/View/CipherView.cs b/src/Core/Models/View/CipherView.cs index a43c291ec..cc6dabafc 100644 --- a/src/Core/Models/View/CipherView.cs +++ b/src/Core/Models/View/CipherView.cs @@ -41,7 +41,7 @@ namespace Bit.Core.Models.View public List Attachments { get; set; } public List Fields { get; set; } public List PasswordHistory { get; set; } - public List CollectionIds { get; set; } + public HashSet CollectionIds { get; set; } public DateTime RevisionDate { get; set; } @@ -56,10 +56,9 @@ namespace Bit.Core.Models.View case CipherType.SecureNote: return SecureNote.SubTitle; case CipherType.Card: - // TODO - // return Card.SubTitle; + return Card.SubTitle; case CipherType.Identity: - // return Identity.SubTitle; + return Identity.SubTitle; default: break; } diff --git a/src/Core/Models/View/IdentityView.cs b/src/Core/Models/View/IdentityView.cs index e1c5dfff2..89ae988ed 100644 --- a/src/Core/Models/View/IdentityView.cs +++ b/src/Core/Models/View/IdentityView.cs @@ -4,14 +4,34 @@ namespace Bit.Core.Models.View { public class IdentityView : View { + private string _firstName; + private string _lastName; + private string _subTitle; + public IdentityView() { } public IdentityView(Identity i) { } public string Title { get; set; } - public string FirstName { get; set; } + public string FirstName + { + get => _firstName; + set + { + _firstName = value; + _subTitle = null; + } + } public string MiddleName { get; set; } - public string LastName { get; set; } + public string LastName + { + get => _lastName; + set + { + _lastName = value; + _subTitle = null; + } + } public string Address1 { get; set; } public string Address2 { get; set; } public string Address3 { get; set; } @@ -27,6 +47,83 @@ namespace Bit.Core.Models.View public string PassportNumber { get; set; } public string LicenseNumber { get; set; } - // TODO + public string SubTitle + { + get + { + if(_subTitle == null && (FirstName != null || LastName != null)) + { + _subTitle = string.Empty; + if(FirstName != null) + { + _subTitle = FirstName; + } + if(LastName != null) + { + if(_subTitle != string.Empty) + { + _subTitle += " "; + } + _subTitle += LastName; + } + } + return _subTitle; + } + } + + public string FullName + { + get + { + if(string.IsNullOrWhiteSpace(Title) || string.IsNullOrWhiteSpace(FirstName) || + string.IsNullOrWhiteSpace(MiddleName) || string.IsNullOrWhiteSpace(LastName)) + { + var name = string.Empty; + if(string.IsNullOrWhiteSpace(Title)) + { + name = string.Concat(name, Title, " "); + } + if(string.IsNullOrWhiteSpace(FirstName)) + { + name = string.Concat(name, FirstName, " "); + } + if(string.IsNullOrWhiteSpace(MiddleName)) + { + name = string.Concat(name, MiddleName, " "); + } + if(string.IsNullOrWhiteSpace(LastName)) + { + name = string.Concat(name, LastName); + } + return name.Trim(); + } + return null; + } + } + + public string FullAddress + { + get + { + var address = Address1; + if(string.IsNullOrWhiteSpace(Address2)) + { + if(string.IsNullOrWhiteSpace(address)) + { + address += ", "; + } + address += Address2; + } + if(string.IsNullOrWhiteSpace(Address3)) + { + if(string.IsNullOrWhiteSpace(address)) + { + address += ", "; + } + address += Address3; + } + return address; + } + } } } diff --git a/src/Core/Models/View/LoginUriView.cs b/src/Core/Models/View/LoginUriView.cs index 23d1a99c4..8dc3e27e2 100644 --- a/src/Core/Models/View/LoginUriView.cs +++ b/src/Core/Models/View/LoginUriView.cs @@ -1,10 +1,28 @@ using Bit.Core.Enums; using Bit.Core.Models.Domain; +using Bit.Core.Utilities; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; namespace Bit.Core.Models.View { public class LoginUriView : View { + private HashSet _canLaunchWhitelist = new HashSet + { + "https://", + "http://", + "ssh://", + "ftp://", + "sftp://", + "irc://", + "vnc://", + "chrome://", + "iosapp://", + "androidapp://", + }; + private string _uri; private string _domain; private string _hostname; @@ -29,6 +47,63 @@ namespace Bit.Core.Models.View } } - // TODO + public string Domain + { + get + { + if(_domain == null && Uri != null) + { + _domain = CoreHelpers.GetDomain(Uri); + if(_domain == string.Empty) + { + _domain = null; + } + } + return _domain; + } + } + + public string Hostname + { + get + { + if(_hostname == null && Uri != null) + { + _hostname = CoreHelpers.GetHostname(Uri); + if(_hostname == string.Empty) + { + _hostname = null; + } + } + return _hostname; + } + } + + public string HostnameOrUri => Hostname ?? Uri; + + public bool IsWebsite => Uri != null && (Uri.StartsWith("http://") || Uri.StartsWith("https://") || + (Uri.Contains("://") && Regex.IsMatch(Uri, CoreHelpers.TldEndingRegex))); + + public bool CanLaunch + { + get + { + if(_canLaunch != null) + { + return _canLaunch.Value; + } + if(Uri != null && Match != UriMatchType.RegularExpression) + { + var uri = LaunchUri; + _canLaunch = _canLaunchWhitelist.Any(prefix => uri.StartsWith(prefix)); + return _canLaunch.Value; + } + _canLaunch = false; + return _canLaunch.Value; + } + } + + public string LaunchUri => !Uri.Contains("://") && Regex.IsMatch(Uri, CoreHelpers.TldEndingRegex) ? + string.Concat("http://", Uri) : Uri; } } diff --git a/src/Core/Models/View/LoginView.cs b/src/Core/Models/View/LoginView.cs index e8adb7844..0164ca9cf 100644 --- a/src/Core/Models/View/LoginView.cs +++ b/src/Core/Models/View/LoginView.cs @@ -1,6 +1,7 @@ using Bit.Core.Models.Domain; using System; using System.Collections.Generic; +using System.Linq; namespace Bit.Core.Models.View { @@ -21,7 +22,8 @@ namespace Bit.Core.Models.View public string Uri => HashUris ? Uris[0].Uri : null; public string MaskedPassword => Password != null ? "••••••••" : null; public string SubTitle => Username; - // TODO: uri launch props + public bool CanLaunch => HashUris && Uris.Any(u => u.CanLaunch); + public string LaunchUri => HashUris ? Uris.FirstOrDefault(u => u.CanLaunch)?.LaunchUri : null; public bool HashUris => (Uris?.Count ?? 0) > 0; } }