From 539121070af73e3292cb3931b3405d406e502a36 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Wed, 8 Feb 2017 23:58:37 -0500 Subject: [PATCH] Added equivalent domain checks to autofill listing filter. centralized logic in login service. --- .../Repositories/ISettingsRepository.cs | 5 +- .../Abstractions/Services/ILoginService.cs | 1 + .../Abstractions/Services/ISettingsService.cs | 6 +- src/App/Models/Page/VaultListPageModel.cs | 31 ------- .../Vault/VaultAutofillListLoginsPage.cs | 20 +++-- src/App/Repositories/SettingsRepository.cs | 20 +---- src/App/Services/LoginService.cs | 81 ++++++++++++++++++- src/App/Services/SettingsService.cs | 19 ++++- 8 files changed, 114 insertions(+), 69 deletions(-) diff --git a/src/App/Abstractions/Repositories/ISettingsRepository.cs b/src/App/Abstractions/Repositories/ISettingsRepository.cs index d0871a87c..0b5fc2c8c 100644 --- a/src/App/Abstractions/Repositories/ISettingsRepository.cs +++ b/src/App/Abstractions/Repositories/ISettingsRepository.cs @@ -1,11 +1,8 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Bit.App.Models.Data; +using Bit.App.Models.Data; namespace Bit.App.Abstractions { public interface ISettingsRepository : IRepository { - Task>> GetEquivablentDomains(string userId); } } diff --git a/src/App/Abstractions/Services/ILoginService.cs b/src/App/Abstractions/Services/ILoginService.cs index 1e2c56789..be490465d 100644 --- a/src/App/Abstractions/Services/ILoginService.cs +++ b/src/App/Abstractions/Services/ILoginService.cs @@ -10,6 +10,7 @@ namespace Bit.App.Abstractions Task GetByIdAsync(string id); Task> GetAllAsync(); Task> GetAllAsync(bool favorites); + Task> GetAllAsync(string uriString); Task> SaveAsync(Login login); Task DeleteAsync(string id); } diff --git a/src/App/Abstractions/Services/ISettingsService.cs b/src/App/Abstractions/Services/ISettingsService.cs index 49d94adc0..7438d04ff 100644 --- a/src/App/Abstractions/Services/ISettingsService.cs +++ b/src/App/Abstractions/Services/ISettingsService.cs @@ -1,6 +1,10 @@ -namespace Bit.App.Abstractions +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Bit.App.Abstractions { public interface ISettingsService { + Task>> GetEquivalentDomainsAsync(); } } diff --git a/src/App/Models/Page/VaultListPageModel.cs b/src/App/Models/Page/VaultListPageModel.cs index cc6ef2f71..7983eb38b 100644 --- a/src/App/Models/Page/VaultListPageModel.cs +++ b/src/App/Models/Page/VaultListPageModel.cs @@ -26,37 +26,6 @@ namespace Bit.App.Models.Page public string Username { get; set; } public Lazy Password { get; set; } public Lazy Uri { get; set; } - - public string BaseDomain - { - get - { - if(_baseDomain != null) - { - return _baseDomain; - } - - if(string.IsNullOrWhiteSpace(Uri.Value)) - { - return null; - } - - Uri uri; - if(!System.Uri.TryCreate(Uri.Value, UriKind.Absolute, out uri)) - { - return null; - } - - DomainName domain; - if(!DomainName.TryParse(uri.Host, out domain)) - { - return null; - } - - _baseDomain = domain.BaseDomain; - return _baseDomain; - } - } } public class Folder : List diff --git a/src/App/Pages/Vault/VaultAutofillListLoginsPage.cs b/src/App/Pages/Vault/VaultAutofillListLoginsPage.cs index 1fcb6dfca..e629172a9 100644 --- a/src/App/Pages/Vault/VaultAutofillListLoginsPage.cs +++ b/src/App/Pages/Vault/VaultAutofillListLoginsPage.cs @@ -21,34 +21,35 @@ namespace Bit.App.Pages private readonly IDeviceInfoService _deviceInfoService; private readonly IUserDialogs _userDialogs; private readonly IClipboardService _clipboardService; + private readonly ISettingsService _settingsService; private CancellationTokenSource _filterResultsCancellationTokenSource; - private readonly DomainName _domainName; private readonly string _name; - private readonly bool _androidApp = false; public VaultAutofillListLoginsPage(string uriString) : base(true) { Uri = uriString; + Uri uri; + DomainName domainName; if(!System.Uri.TryCreate(uriString, UriKind.Absolute, out uri) || - !DomainName.TryParse(uri.Host, out _domainName)) + !DomainName.TryParse(uri.Host, out domainName)) { if(uriString != null && uriString.StartsWith(Constants.AndroidAppProtocol)) { - _androidApp = true; _name = uriString.Substring(Constants.AndroidAppProtocol.Length); } } else { - _name = _domainName.BaseDomain; + _name = domainName.BaseDomain; } _loginService = Resolver.Resolve(); _deviceInfoService = Resolver.Resolve(); _userDialogs = Resolver.Resolve(); _clipboardService = Resolver.Resolve(); + _settingsService = Resolver.Resolve(); GoogleAnalyticsService = Resolver.Resolve(); Init(); @@ -149,17 +150,14 @@ namespace Bit.App.Pages Task.Run(async () => { - var logins = await _loginService.GetAllAsync(); - var filteredLogins = logins - .Select(s => new VaultListPageModel.Login(s)) - .Where(s => (_androidApp && _domainName == null && s.Uri.Value == Uri) || - (_domainName != null && s.BaseDomain != null && s.BaseDomain == _domainName.BaseDomain)) + var logins = await _loginService.GetAllAsync(Uri); + var sortedLogins = logins.Select(l => new VaultListPageModel.Login(l)) .OrderBy(s => s.Name) .ThenBy(s => s.Username); Device.BeginInvokeOnMainThread(() => { - PresentationLogins.ResetWithRange(filteredLogins); + PresentationLogins.ResetWithRange(sortedLogins); AdjustContent(); }); }, cts.Token); diff --git a/src/App/Repositories/SettingsRepository.cs b/src/App/Repositories/SettingsRepository.cs index 9d55c13d3..22ac074e0 100644 --- a/src/App/Repositories/SettingsRepository.cs +++ b/src/App/Repositories/SettingsRepository.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Bit.App.Abstractions; +using Bit.App.Abstractions; using Bit.App.Models.Data; -using Newtonsoft.Json; namespace Bit.App.Repositories { @@ -12,19 +8,5 @@ namespace Bit.App.Repositories public SettingsRepository(ISqlService sqlService) : base(sqlService) { } - - public Task>> GetEquivablentDomains(string userId) - { - var equivalentDomainsJson = Connection.Table().Where(f => f.Id == userId) - .Select(f => f.EquivalentDomains).FirstOrDefault(); - - if(string.IsNullOrWhiteSpace(equivalentDomainsJson)) - { - return Task.FromResult>>(null); - } - - var equivalentDomains = JsonConvert.DeserializeObject>>(equivalentDomainsJson); - return Task.FromResult(equivalentDomains); - } } } diff --git a/src/App/Services/LoginService.cs b/src/App/Services/LoginService.cs index 091f8b64a..32af84d9e 100644 --- a/src/App/Services/LoginService.cs +++ b/src/App/Services/LoginService.cs @@ -15,15 +15,18 @@ namespace Bit.App.Services private readonly ILoginRepository _loginRepository; private readonly IAuthService _authService; private readonly ILoginApiRepository _loginApiRepository; + private readonly ISettingsService _settingsService; public LoginService( ILoginRepository loginRepository, IAuthService authService, - ILoginApiRepository loginApiRepository) + ILoginApiRepository loginApiRepository, + ISettingsService settingsService) { _loginRepository = loginRepository; _authService = authService; _loginApiRepository = loginApiRepository; + _settingsService = settingsService; } public async Task GetByIdAsync(string id) @@ -52,6 +55,80 @@ namespace Bit.App.Services return logins; } + public async Task> GetAllAsync(string uriString) + { + if(string.IsNullOrWhiteSpace(uriString)) + { + return new List(); + } + + Uri uri = null; + DomainName domainName = null; + var androidApp = false; + + if(!Uri.TryCreate(uriString, UriKind.Absolute, out uri) || !DomainName.TryParse(uri.Host, out domainName)) + { + if(domainName == null) + { + androidApp = uriString.StartsWith(Constants.AndroidAppProtocol); + } + } + + + if(!androidApp && domainName == null) + { + return new List(); + } + + var eqDomains = (await _settingsService.GetEquivalentDomainsAsync()).Select(d => d.ToArray()); + var matchingDomains = eqDomains + .Where(d => (androidApp && Array.IndexOf(d, uriString) >= 0) || + (!androidApp && Array.IndexOf(d, domainName.BaseDomain) >= 0)) + .SelectMany(d => d).ToList(); + if(!matchingDomains.Any()) + { + matchingDomains.Add(androidApp ? uriString : domainName.BaseDomain); + } + + var matchingDomainsArray = matchingDomains.ToArray(); + var matchingLogins = new List(); + var logins = await _loginRepository.GetAllByUserIdAsync(_authService.UserId); + foreach(var login in logins) + { + if(string.IsNullOrWhiteSpace(login.Uri)) + { + continue; + } + + var loginUriString = new CipherString(login.Uri).Decrypt(); + if(string.IsNullOrWhiteSpace(loginUriString)) + { + continue; + } + + if(androidApp && Array.IndexOf(matchingDomainsArray, loginUriString) >= 0) + { + matchingLogins.Add(new Login(login)); + continue; + } + + Uri loginUri; + DomainName loginDomainName; + if(!Uri.TryCreate(loginUriString, UriKind.Absolute, out loginUri) + || !DomainName.TryParse(loginUri.Host, out loginDomainName)) + { + continue; + } + + if(Array.IndexOf(matchingDomainsArray, loginDomainName.BaseDomain) >= 0) + { + matchingLogins.Add(new Login(login)); + } + } + + return matchingLogins; + } + public async Task> SaveAsync(Login login) { ApiResult response = null; @@ -79,7 +156,7 @@ namespace Bit.App.Services await _loginRepository.UpdateAsync(data); } } - else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden + else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden || response.StatusCode == System.Net.HttpStatusCode.Unauthorized) { MessagingCenter.Send(Application.Current, "Logout", (string)null); diff --git a/src/App/Services/SettingsService.cs b/src/App/Services/SettingsService.cs index a224f4528..438429dd1 100644 --- a/src/App/Services/SettingsService.cs +++ b/src/App/Services/SettingsService.cs @@ -1,5 +1,8 @@ using Bit.App.Abstractions; using Plugin.Settings.Abstractions; +using System.Collections.Generic; +using System.Threading.Tasks; +using Newtonsoft.Json; namespace Bit.App.Services { @@ -7,13 +10,27 @@ namespace Bit.App.Services { private readonly ISettingsRepository _settingsRepository; private readonly ISettings _settings; + private readonly IAuthService _authService; public SettingsService( ISettingsRepository settingsRepository, - ISettings settings) + ISettings settings, + IAuthService authService) { _settingsRepository = settingsRepository; _settings = settings; + _authService = authService; + } + + public async Task>> GetEquivalentDomainsAsync() + { + var settings = await _settingsRepository.GetByIdAsync(_authService.UserId); + if(string.IsNullOrWhiteSpace(settings?.EquivalentDomains)) + { + return null; + } + + return JsonConvert.DeserializeObject>>(settings.EquivalentDomains); } } }