Added equivalent domain checks to autofill listing filter. centralized logic in login service.

This commit is contained in:
Kyle Spearrin 2017-02-08 23:58:37 -05:00
parent 2a1bd92e1a
commit 539121070a
8 changed files with 114 additions and 69 deletions

View file

@ -1,11 +1,8 @@
using System.Collections.Generic; using Bit.App.Models.Data;
using System.Threading.Tasks;
using Bit.App.Models.Data;
namespace Bit.App.Abstractions namespace Bit.App.Abstractions
{ {
public interface ISettingsRepository : IRepository<SettingsData, string> public interface ISettingsRepository : IRepository<SettingsData, string>
{ {
Task<IEnumerable<IEnumerable<string>>> GetEquivablentDomains(string userId);
} }
} }

View file

@ -10,6 +10,7 @@ namespace Bit.App.Abstractions
Task<Login> GetByIdAsync(string id); Task<Login> GetByIdAsync(string id);
Task<IEnumerable<Login>> GetAllAsync(); Task<IEnumerable<Login>> GetAllAsync();
Task<IEnumerable<Login>> GetAllAsync(bool favorites); Task<IEnumerable<Login>> GetAllAsync(bool favorites);
Task<IEnumerable<Login>> GetAllAsync(string uriString);
Task<ApiResult<LoginResponse>> SaveAsync(Login login); Task<ApiResult<LoginResponse>> SaveAsync(Login login);
Task<ApiResult> DeleteAsync(string id); Task<ApiResult> DeleteAsync(string id);
} }

View file

@ -1,6 +1,10 @@
namespace Bit.App.Abstractions using System.Collections.Generic;
using System.Threading.Tasks;
namespace Bit.App.Abstractions
{ {
public interface ISettingsService public interface ISettingsService
{ {
Task<IEnumerable<IEnumerable<string>>> GetEquivalentDomainsAsync();
} }
} }

View file

@ -26,37 +26,6 @@ namespace Bit.App.Models.Page
public string Username { get; set; } public string Username { get; set; }
public Lazy<string> Password { get; set; } public Lazy<string> Password { get; set; }
public Lazy<string> Uri { get; set; } public Lazy<string> 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<Login> public class Folder : List<Login>

View file

@ -21,34 +21,35 @@ namespace Bit.App.Pages
private readonly IDeviceInfoService _deviceInfoService; private readonly IDeviceInfoService _deviceInfoService;
private readonly IUserDialogs _userDialogs; private readonly IUserDialogs _userDialogs;
private readonly IClipboardService _clipboardService; private readonly IClipboardService _clipboardService;
private readonly ISettingsService _settingsService;
private CancellationTokenSource _filterResultsCancellationTokenSource; private CancellationTokenSource _filterResultsCancellationTokenSource;
private readonly DomainName _domainName;
private readonly string _name; private readonly string _name;
private readonly bool _androidApp = false;
public VaultAutofillListLoginsPage(string uriString) public VaultAutofillListLoginsPage(string uriString)
: base(true) : base(true)
{ {
Uri = uriString; Uri = uriString;
Uri uri; Uri uri;
DomainName domainName;
if(!System.Uri.TryCreate(uriString, UriKind.Absolute, out uri) || 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)) if(uriString != null && uriString.StartsWith(Constants.AndroidAppProtocol))
{ {
_androidApp = true;
_name = uriString.Substring(Constants.AndroidAppProtocol.Length); _name = uriString.Substring(Constants.AndroidAppProtocol.Length);
} }
} }
else else
{ {
_name = _domainName.BaseDomain; _name = domainName.BaseDomain;
} }
_loginService = Resolver.Resolve<ILoginService>(); _loginService = Resolver.Resolve<ILoginService>();
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>(); _deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
_userDialogs = Resolver.Resolve<IUserDialogs>(); _userDialogs = Resolver.Resolve<IUserDialogs>();
_clipboardService = Resolver.Resolve<IClipboardService>(); _clipboardService = Resolver.Resolve<IClipboardService>();
_settingsService = Resolver.Resolve<ISettingsService>();
GoogleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>(); GoogleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init(); Init();
@ -149,17 +150,14 @@ namespace Bit.App.Pages
Task.Run(async () => Task.Run(async () =>
{ {
var logins = await _loginService.GetAllAsync(); var logins = await _loginService.GetAllAsync(Uri);
var filteredLogins = logins var sortedLogins = logins.Select(l => new VaultListPageModel.Login(l))
.Select(s => new VaultListPageModel.Login(s))
.Where(s => (_androidApp && _domainName == null && s.Uri.Value == Uri) ||
(_domainName != null && s.BaseDomain != null && s.BaseDomain == _domainName.BaseDomain))
.OrderBy(s => s.Name) .OrderBy(s => s.Name)
.ThenBy(s => s.Username); .ThenBy(s => s.Username);
Device.BeginInvokeOnMainThread(() => Device.BeginInvokeOnMainThread(() =>
{ {
PresentationLogins.ResetWithRange(filteredLogins); PresentationLogins.ResetWithRange(sortedLogins);
AdjustContent(); AdjustContent();
}); });
}, cts.Token); }, cts.Token);

View file

@ -1,9 +1,5 @@
using System; using Bit.App.Abstractions;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Models.Data; using Bit.App.Models.Data;
using Newtonsoft.Json;
namespace Bit.App.Repositories namespace Bit.App.Repositories
{ {
@ -12,19 +8,5 @@ namespace Bit.App.Repositories
public SettingsRepository(ISqlService sqlService) public SettingsRepository(ISqlService sqlService)
: base(sqlService) : base(sqlService)
{ } { }
public Task<IEnumerable<IEnumerable<string>>> GetEquivablentDomains(string userId)
{
var equivalentDomainsJson = Connection.Table<SettingsData>().Where(f => f.Id == userId)
.Select(f => f.EquivalentDomains).FirstOrDefault();
if(string.IsNullOrWhiteSpace(equivalentDomainsJson))
{
return Task.FromResult<IEnumerable<IEnumerable<string>>>(null);
}
var equivalentDomains = JsonConvert.DeserializeObject<IEnumerable<IEnumerable<string>>>(equivalentDomainsJson);
return Task.FromResult(equivalentDomains);
}
} }
} }

View file

@ -15,15 +15,18 @@ namespace Bit.App.Services
private readonly ILoginRepository _loginRepository; private readonly ILoginRepository _loginRepository;
private readonly IAuthService _authService; private readonly IAuthService _authService;
private readonly ILoginApiRepository _loginApiRepository; private readonly ILoginApiRepository _loginApiRepository;
private readonly ISettingsService _settingsService;
public LoginService( public LoginService(
ILoginRepository loginRepository, ILoginRepository loginRepository,
IAuthService authService, IAuthService authService,
ILoginApiRepository loginApiRepository) ILoginApiRepository loginApiRepository,
ISettingsService settingsService)
{ {
_loginRepository = loginRepository; _loginRepository = loginRepository;
_authService = authService; _authService = authService;
_loginApiRepository = loginApiRepository; _loginApiRepository = loginApiRepository;
_settingsService = settingsService;
} }
public async Task<Login> GetByIdAsync(string id) public async Task<Login> GetByIdAsync(string id)
@ -52,6 +55,80 @@ namespace Bit.App.Services
return logins; return logins;
} }
public async Task<IEnumerable<Login>> GetAllAsync(string uriString)
{
if(string.IsNullOrWhiteSpace(uriString))
{
return new List<Login>();
}
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<Login>();
}
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<Login>();
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<ApiResult<LoginResponse>> SaveAsync(Login login) public async Task<ApiResult<LoginResponse>> SaveAsync(Login login)
{ {
ApiResult<LoginResponse> response = null; ApiResult<LoginResponse> response = null;

View file

@ -1,5 +1,8 @@
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Plugin.Settings.Abstractions; using Plugin.Settings.Abstractions;
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Bit.App.Services namespace Bit.App.Services
{ {
@ -7,13 +10,27 @@ namespace Bit.App.Services
{ {
private readonly ISettingsRepository _settingsRepository; private readonly ISettingsRepository _settingsRepository;
private readonly ISettings _settings; private readonly ISettings _settings;
private readonly IAuthService _authService;
public SettingsService( public SettingsService(
ISettingsRepository settingsRepository, ISettingsRepository settingsRepository,
ISettings settings) ISettings settings,
IAuthService authService)
{ {
_settingsRepository = settingsRepository; _settingsRepository = settingsRepository;
_settings = settings; _settings = settings;
_authService = authService;
}
public async Task<IEnumerable<IEnumerable<string>>> GetEquivalentDomainsAsync()
{
var settings = await _settingsRepository.GetByIdAsync(_authService.UserId);
if(string.IsNullOrWhiteSpace(settings?.EquivalentDomains))
{
return null;
}
return JsonConvert.DeserializeObject<IEnumerable<IEnumerable<string>>>(settings.EquivalentDomains);
} }
} }
} }