mirror of
https://github.com/bitwarden/android.git
synced 2024-12-24 18:08:26 +03:00
search service
This commit is contained in:
parent
594a491251
commit
3d50133fa8
8 changed files with 270 additions and 3 deletions
|
@ -28,6 +28,9 @@
|
||||||
<Compile Update="Pages\GeneratorPage.xaml.cs">
|
<Compile Update="Pages\GeneratorPage.xaml.cs">
|
||||||
<DependentUpon>GeneratorPage.xaml</DependentUpon>
|
<DependentUpon>GeneratorPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="Pages\Vault\CiphersPage.xaml.cs">
|
||||||
|
<DependentUpon>CiphersPage.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Update="Pages\Vault\ViewPage.xaml.cs">
|
<Compile Update="Pages\Vault\ViewPage.xaml.cs">
|
||||||
<DependentUpon>ViewPage.xaml</DependentUpon>
|
<DependentUpon>ViewPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
38
src/App/Pages/Vault/CiphersPage.xaml
Normal file
38
src/App/Pages/Vault/CiphersPage.xaml
Normal 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>
|
54
src/App/Pages/Vault/CiphersPage.xaml.cs
Normal file
54
src/App/Pages/Vault/CiphersPage.xaml.cs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
src/App/Pages/Vault/CiphersPageViewModel.cs
Normal file
50
src/App/Pages/Vault/CiphersPageViewModel.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/Core/Abstractions/ISearchService.cs
Normal file
17
src/Core/Abstractions/ISearchService.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ namespace Bit.Core.Services
|
||||||
private readonly IApiService _apiService;
|
private readonly IApiService _apiService;
|
||||||
private readonly IStorageService _storageService;
|
private readonly IStorageService _storageService;
|
||||||
private readonly II18nService _i18nService;
|
private readonly II18nService _i18nService;
|
||||||
|
private readonly Func<ISearchService> _searchService;
|
||||||
private Dictionary<string, HashSet<string>> _domainMatchBlacklist = new Dictionary<string, HashSet<string>>
|
private Dictionary<string, HashSet<string>> _domainMatchBlacklist = new Dictionary<string, HashSet<string>>
|
||||||
{
|
{
|
||||||
["google.com"] = new HashSet<string> { "script.google.com" }
|
["google.com"] = new HashSet<string> { "script.google.com" }
|
||||||
|
@ -45,7 +46,8 @@ namespace Bit.Core.Services
|
||||||
ISettingsService settingsService,
|
ISettingsService settingsService,
|
||||||
IApiService apiService,
|
IApiService apiService,
|
||||||
IStorageService storageService,
|
IStorageService storageService,
|
||||||
II18nService i18nService)
|
II18nService i18nService,
|
||||||
|
Func<ISearchService> searchService)
|
||||||
{
|
{
|
||||||
_cryptoService = cryptoService;
|
_cryptoService = cryptoService;
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
|
@ -53,6 +55,7 @@ namespace Bit.Core.Services
|
||||||
_apiService = apiService;
|
_apiService = apiService;
|
||||||
_storageService = storageService;
|
_storageService = storageService;
|
||||||
_i18nService = i18nService;
|
_i18nService = i18nService;
|
||||||
|
_searchService = searchService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<CipherView> DecryptedCipherCache
|
private List<CipherView> DecryptedCipherCache
|
||||||
|
@ -65,7 +68,17 @@ namespace Bit.Core.Services
|
||||||
_decryptedCipherCache.Clear();
|
_decryptedCipherCache.Clear();
|
||||||
}
|
}
|
||||||
_decryptedCipherCache = value;
|
_decryptedCipherCache = value;
|
||||||
// TODO: update search index
|
if(_searchService != null)
|
||||||
|
{
|
||||||
|
if(value == null)
|
||||||
|
{
|
||||||
|
_searchService().ClearIndex();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_searchService().IndexCiphersAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
90
src/Core/Services/SearchService.cs
Normal file
90
src/Core/Services/SearchService.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ namespace Bit.Core.Utilities
|
||||||
var cryptoPrimitiveService = Resolve<ICryptoPrimitiveService>("cryptoPrimitiveService");
|
var cryptoPrimitiveService = Resolve<ICryptoPrimitiveService>("cryptoPrimitiveService");
|
||||||
var i18nService = Resolve<II18nService>("i18nService");
|
var i18nService = Resolve<II18nService>("i18nService");
|
||||||
var messagingService = Resolve<IMessagingService>("messagingService");
|
var messagingService = Resolve<IMessagingService>("messagingService");
|
||||||
|
ISearchService searchService = null;
|
||||||
|
|
||||||
var stateService = new StateService();
|
var stateService = new StateService();
|
||||||
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
||||||
|
@ -35,10 +36,11 @@ namespace Bit.Core.Utilities
|
||||||
var userService = new UserService(storageService, tokenService);
|
var userService = new UserService(storageService, tokenService);
|
||||||
var settingsService = new SettingsService(userService, storageService);
|
var settingsService = new SettingsService(userService, storageService);
|
||||||
var cipherService = new CipherService(cryptoService, userService, settingsService, apiService,
|
var cipherService = new CipherService(cryptoService, userService, settingsService, apiService,
|
||||||
storageService, i18nService);
|
storageService, i18nService, () => searchService);
|
||||||
var folderService = new FolderService(cryptoService, userService, apiService, storageService,
|
var folderService = new FolderService(cryptoService, userService, apiService, storageService,
|
||||||
i18nService, cipherService);
|
i18nService, cipherService);
|
||||||
var collectionService = new CollectionService(cryptoService, userService, storageService, i18nService);
|
var collectionService = new CollectionService(cryptoService, userService, storageService, i18nService);
|
||||||
|
searchService = new SearchService(cipherService);
|
||||||
// TODO: lock service
|
// TODO: lock service
|
||||||
var syncService = new SyncService(userService, apiService, settingsService, folderService,
|
var syncService = new SyncService(userService, apiService, settingsService, folderService,
|
||||||
cipherService, cryptoService, collectionService, storageService, messagingService);
|
cipherService, cryptoService, collectionService, storageService, messagingService);
|
||||||
|
|
Loading…
Reference in a new issue