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">
|
||||
<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>
|
||||
|
|
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 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
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 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);
|
||||
|
|
Loading…
Reference in a new issue