search service

This commit is contained in:
Kyle Spearrin 2019-04-24 14:52:26 -04:00
parent 594a491251
commit 3d50133fa8
8 changed files with 270 additions and 3 deletions

View file

@ -28,6 +28,9 @@
<Compile Update="Pages\GeneratorPage.xaml.cs">
<DependentUpon>GeneratorPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\CiphersPage.xaml.cs">
<DependentUpon>CiphersPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\ViewPage.xaml.cs">
<DependentUpon>ViewPage.xaml</DependentUpon>
</Compile>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.ViewPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
x:DataType="pages:ViewPageViewModel"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:ViewPageViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Icon="cogs.png"
Text="{u:I18n Edit}" />
</ContentPage.ToolbarItems>
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row">
<Label
Text="{u:I18n Name}"
StyleClass="box-label" />
<Label
Text="{Binding Cipher.Name, Mode=OneWay}"
StyleClass="box-value" />
</StackLayout>
<StackLayout StyleClass="box-row">
<Label
Text="{u:I18n Notes}"
StyleClass="box-label" />
<Label
Text="{Binding Cipher.Notes, Mode=OneWay}"
StyleClass="box-value" />
</StackLayout>
</StackLayout>
</ContentPage>

View file

@ -0,0 +1,54 @@
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Bit.App.Pages
{
public partial class ViewPage : ContentPage
{
private readonly IBroadcasterService _broadcasterService;
private ViewPageViewModel _vm;
public ViewPage(string cipherId)
{
InitializeComponent();
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
_vm = BindingContext as ViewPageViewModel;
_vm.Page = this;
_vm.CipherId = cipherId;
}
protected async override void OnAppearing()
{
base.OnAppearing();
_broadcasterService.Subscribe(nameof(ViewPage), async (message) =>
{
if(message.Command == "syncCompleted")
{
var data = message.Data as Dictionary<string, object>;
if(data.ContainsKey("successfully"))
{
var success = data["successfully"] as bool?;
if(success.HasValue && success.Value)
{
await _vm.LoadAsync();
}
}
}
});
await _vm.LoadAsync();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
_broadcasterService.Unsubscribe(nameof(ViewPage));
}
}
}

View file

@ -0,0 +1,50 @@
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using System.Threading.Tasks;
namespace Bit.App.Pages
{
public class CiphersPageViewModel : BaseViewModel
{
private readonly IDeviceActionService _deviceActionService;
private readonly ICipherService _cipherService;
private readonly IUserService _userService;
private CipherView _cipher;
private bool _canAccessPremium;
public CiphersPageViewModel()
{
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
_userService = ServiceContainer.Resolve<IUserService>("userService");
PageTitle = AppResources.ViewItem;
}
public string CipherId { get; set; }
public CipherView Cipher
{
get => _cipher;
set => SetProperty(ref _cipher, value);
}
public bool CanAccessPremium
{
get => _canAccessPremium;
set => SetProperty(ref _canAccessPremium, value);
}
public async Task LoadAsync()
{
// TODO: Cleanup
var cipher = await _cipherService.GetAsync(CipherId);
Cipher = await cipher.DecryptAsync();
CanAccessPremium = await _userService.CanAccessPremiumAsync();
// TODO: Totp
}
}
}

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Models.View;
namespace Bit.Core.Abstractions
{
public interface ISearchService
{
void ClearIndex();
Task IndexCiphersAsync();
bool IsSearchable(string query);
Task<List<CipherView>> SearchCiphersAsync(string query, Func<CipherView, bool> filter = null,
List<CipherView> ciphers = null);
List<CipherView> SearchCiphersBasic(List<CipherView> ciphers, string query);
}
}

View file

@ -32,6 +32,7 @@ namespace Bit.Core.Services
private readonly IApiService _apiService;
private readonly IStorageService _storageService;
private readonly II18nService _i18nService;
private readonly Func<ISearchService> _searchService;
private Dictionary<string, HashSet<string>> _domainMatchBlacklist = new Dictionary<string, HashSet<string>>
{
["google.com"] = new HashSet<string> { "script.google.com" }
@ -45,7 +46,8 @@ namespace Bit.Core.Services
ISettingsService settingsService,
IApiService apiService,
IStorageService storageService,
II18nService i18nService)
II18nService i18nService,
Func<ISearchService> searchService)
{
_cryptoService = cryptoService;
_userService = userService;
@ -53,6 +55,7 @@ namespace Bit.Core.Services
_apiService = apiService;
_storageService = storageService;
_i18nService = i18nService;
_searchService = searchService;
}
private List<CipherView> DecryptedCipherCache
@ -65,7 +68,17 @@ namespace Bit.Core.Services
_decryptedCipherCache.Clear();
}
_decryptedCipherCache = value;
// TODO: update search index
if(_searchService != null)
{
if(value == null)
{
_searchService().ClearIndex();
}
else
{
_searchService().IndexCiphersAsync();
}
}
}
}

View file

@ -0,0 +1,90 @@
using Bit.Core.Abstractions;
using Bit.Core.Models.View;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Bit.Core.Services
{
public class SearchService : ISearchService
{
private readonly ICipherService _cipherService;
public SearchService(
ICipherService cipherService)
{
_cipherService = cipherService;
}
public void ClearIndex()
{
// TODO
}
public bool IsSearchable(string query)
{
return true;
}
public Task IndexCiphersAsync()
{
// TODO
return Task.FromResult(0);
}
public async Task<List<CipherView>> SearchCiphersAsync(string query, Func<CipherView, bool> filter = null,
List<CipherView> ciphers = null)
{
var results = new List<CipherView>();
if(query != null)
{
query = query.Trim().ToLower();
}
if(query == string.Empty)
{
query = null;
}
if(ciphers == null)
{
ciphers = await _cipherService.GetAllDecryptedAsync();
}
if(filter != null)
{
ciphers = ciphers.Where(filter).ToList();
}
if(!IsSearchable(query))
{
return ciphers;
}
return SearchCiphersBasic(ciphers, query);
// TODO: advanced searching with index
}
public List<CipherView> SearchCiphersBasic(List<CipherView> ciphers, string query)
{
query = query.Trim().ToLower();
return ciphers.Where(c =>
{
if(c.Name?.ToLower().Contains(query) ?? false)
{
return true;
}
if(query.Length >= 8 && c.Id.StartsWith(query))
{
return true;
}
if(c.SubTitle?.ToLower().Contains(query) ?? false)
{
return true;
}
if(c.Login?.Uri?.ToLower()?.Contains(query) ?? false)
{
return true;
}
return false;
}).ToList();
}
}
}

View file

@ -25,6 +25,7 @@ namespace Bit.Core.Utilities
var cryptoPrimitiveService = Resolve<ICryptoPrimitiveService>("cryptoPrimitiveService");
var i18nService = Resolve<II18nService>("i18nService");
var messagingService = Resolve<IMessagingService>("messagingService");
ISearchService searchService = null;
var stateService = new StateService();
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
@ -35,10 +36,11 @@ namespace Bit.Core.Utilities
var userService = new UserService(storageService, tokenService);
var settingsService = new SettingsService(userService, storageService);
var cipherService = new CipherService(cryptoService, userService, settingsService, apiService,
storageService, i18nService);
storageService, i18nService, () => searchService);
var folderService = new FolderService(cryptoService, userService, apiService, storageService,
i18nService, cipherService);
var collectionService = new CollectionService(cryptoService, userService, storageService, i18nService);
searchService = new SearchService(cipherService);
// TODO: lock service
var syncService = new SyncService(userService, apiService, settingsService, folderService,
cipherService, cryptoService, collectionService, storageService, messagingService);