add other items to autofill from app page

This commit is contained in:
Kyle Spearrin 2017-11-20 16:07:33 -05:00
parent 6268130998
commit 84e79e92b4
9 changed files with 89 additions and 49 deletions

View file

@ -8,6 +8,7 @@ using Android.App;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.App.Resources; using Bit.App.Resources;
using Bit.App.Enums;
namespace Bit.Android.Autofill namespace Bit.Android.Autofill
{ {
@ -33,7 +34,7 @@ namespace Bit.Android.Autofill
else if(parser.FieldCollection.FillableForCard) else if(parser.FieldCollection.FillableForCard)
{ {
var ciphers = await service.GetAllAsync(); var ciphers = await service.GetAllAsync();
foreach(var cipher in ciphers.Where(c => c.Type == App.Enums.CipherType.Card)) foreach(var cipher in ciphers.Where(c => c.Type == CipherType.Card))
{ {
items.Add(new FilledItem(cipher)); items.Add(new FilledItem(cipher));
} }
@ -80,6 +81,22 @@ namespace Bit.Android.Autofill
AppResources.VaultIsLocked, Resource.Drawable.icon); AppResources.VaultIsLocked, Resource.Drawable.icon);
var intent = new Intent(context, typeof(MainActivity)); var intent = new Intent(context, typeof(MainActivity));
intent.PutExtra("autofillFramework", true); intent.PutExtra("autofillFramework", true);
if(fields.FillableForLogin)
{
intent.PutExtra("autofillFrameworkFillType", (int)CipherType.Login);
}
else if(fields.FillableForCard)
{
intent.PutExtra("autofillFrameworkFillType", (int)CipherType.Card);
}
else if(fields.FillableForIdentity)
{
intent.PutExtra("autofillFrameworkFillType", (int)CipherType.Identity);
}
else
{
return null;
}
intent.PutExtra("autofillFrameworkUri", uri); intent.PutExtra("autofillFrameworkUri", uri);
var pendingIntent = PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.CancelCurrent); var pendingIntent = PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.CancelCurrent);
responseBuilder.SetAuthentication(fields.AutofillIds.ToArray(), pendingIntent.IntentSender, view); responseBuilder.SetAuthentication(fields.AutofillIds.ToArray(), pendingIntent.IntentSender, view);

View file

@ -4,7 +4,6 @@ using Android.Views.Autofill;
using System.Linq; using System.Linq;
using Bit.App.Models; using Bit.App.Models;
using Bit.App.Enums; using Bit.App.Enums;
using Bit.App.Models.Page;
using Android.Views; using Android.Views;
namespace Bit.Android.Autofill namespace Bit.Android.Autofill
@ -107,23 +106,6 @@ namespace Bit.Android.Autofill
} }
} }
public FilledItem(VaultListPageModel.Cipher cipher)
{
Name = cipher.Name ?? "--";
Type = cipher.Type;
switch(Type)
{
case CipherType.Login:
Subtitle = cipher.LoginUsername ?? string.Empty;
_password = cipher.LoginPassword;
Icon = Resource.Drawable.login;
break;
default:
break;
}
}
public string Name { get; set; } public string Name { get; set; }
public string Subtitle { get; set; } = string.Empty; public string Subtitle { get; set; } = string.Empty;
public int Icon { get; set; } = Resource.Drawable.login; public int Icon { get; set; } = Resource.Drawable.login;

View file

@ -169,7 +169,7 @@ namespace Bit.Android
return; return;
} }
var items = new List<FilledItem> { new FilledItem(cipher) }; var items = new List<FilledItem> { new FilledItem(cipher.CipherModel) };
var response = AutofillHelpers.BuildFillResponse(this, parser, items); var response = AutofillHelpers.BuildFillResponse(this, parser, items);
var replyIntent = new Intent(); var replyIntent = new Intent();
replyIntent.PutExtra(AutofillManager.ExtraAuthenticationResult, response); replyIntent.PutExtra(AutofillManager.ExtraAuthenticationResult, response);
@ -435,6 +435,12 @@ namespace Bit.Android
FromAutofillFramework = Intent.GetBooleanExtra("autofillFramework", false) FromAutofillFramework = Intent.GetBooleanExtra("autofillFramework", false)
}; };
var fillType = Intent.GetIntExtra("autofillFrameworkFillType", 0);
if(fillType > 0)
{
options.FillType = (CipherType)fillType;
}
if(Intent.GetBooleanExtra("autofillFrameworkSave", false)) if(Intent.GetBooleanExtra("autofillFrameworkSave", false))
{ {
options.SaveType = (CipherType)Intent.GetIntExtra("autofillFrameworkType", 0); options.SaveType = (CipherType)Intent.GetIntExtra("autofillFrameworkType", 0);

View file

@ -12,7 +12,7 @@ namespace Bit.App.Abstractions
Task<Cipher> GetByIdAsync(string id); Task<Cipher> GetByIdAsync(string id);
Task<IEnumerable<Cipher>> GetAllAsync(); Task<IEnumerable<Cipher>> GetAllAsync();
Task<IEnumerable<Cipher>> GetAllAsync(bool favorites); Task<IEnumerable<Cipher>> GetAllAsync(bool favorites);
Task<Tuple<IEnumerable<Cipher>, IEnumerable<Cipher>>> GetAllAsync(string uriString); Task<Tuple<IEnumerable<Cipher>, IEnumerable<Cipher>, IEnumerable<Cipher>>> GetAllAsync(string uriString);
Task<ApiResult<CipherResponse>> SaveAsync(Cipher cipher); Task<ApiResult<CipherResponse>> SaveAsync(Cipher cipher);
Task UpsertDataAsync(CipherData cipher); Task UpsertDataAsync(CipherData cipher);
Task<ApiResult> DeleteAsync(string id); Task<ApiResult> DeleteAsync(string id);

View file

@ -74,7 +74,7 @@ namespace Bit.App
} }
else if(_options.Uri != null) else if(_options.Uri != null)
{ {
MainPage = new ExtendedNavigationPage(new VaultAutofillListCiphersPage(_options.Uri)); MainPage = new ExtendedNavigationPage(new VaultAutofillListCiphersPage(_options));
} }
else else
{ {

View file

@ -6,6 +6,7 @@ namespace Bit.App.Models
{ {
public bool MyVault { get; set; } public bool MyVault { get; set; }
public bool FromAutofillFramework { get; set; } public bool FromAutofillFramework { get; set; }
public CipherType? FillType { get; set; }
public string Uri { get; set; } public string Uri { get; set; }
public CipherType? SaveType { get; set; } public CipherType? SaveType { get; set; }
public string SaveName { get; set; } public string SaveName { get; set; }

View file

@ -13,6 +13,7 @@ namespace Bit.App.Models.Page
{ {
public Cipher(Models.Cipher cipher, IAppSettingsService appSettings) public Cipher(Models.Cipher cipher, IAppSettingsService appSettings)
{ {
CipherModel = cipher;
Id = cipher.Id; Id = cipher.Id;
Shared = !string.IsNullOrWhiteSpace(cipher.OrganizationId); Shared = !string.IsNullOrWhiteSpace(cipher.OrganizationId);
HasAttachments = cipher.Attachments?.Any() ?? false; HasAttachments = cipher.Attachments?.Any() ?? false;
@ -114,6 +115,7 @@ namespace Bit.App.Models.Page
} }
} }
public Models.Cipher CipherModel { get; set; }
public string Id { get; set; } public string Id { get; set; }
public bool Shared { get; set; } public bool Shared { get; set; }
public bool HasAttachments { get; set; } public bool HasAttachments { get; set; }

View file

@ -25,17 +25,18 @@ namespace Bit.App.Pages
private readonly IAppSettingsService _appSettingsService; private readonly IAppSettingsService _appSettingsService;
private CancellationTokenSource _filterResultsCancellationTokenSource; private CancellationTokenSource _filterResultsCancellationTokenSource;
private readonly string _name; private readonly string _name;
private readonly AppOptions _appOptions;
public VaultAutofillListCiphersPage(string uriString) public VaultAutofillListCiphersPage(AppOptions appOptions)
: base(true) : base(true)
{ {
Uri = uriString; _appOptions = appOptions;
Uri = appOptions.Uri;
if(uriString?.StartsWith(Constants.AndroidAppProtocol) ?? false) if(Uri.StartsWith(Constants.AndroidAppProtocol))
{ {
_name = uriString.Substring(Constants.AndroidAppProtocol.Length); _name = Uri.Substring(Constants.AndroidAppProtocol.Length);
} }
else if(!System.Uri.TryCreate(uriString, UriKind.Absolute, out Uri uri) || else if(!System.Uri.TryCreate(Uri, UriKind.Absolute, out Uri uri) ||
!DomainName.TryParseBaseDomain(uri.Host, out _name)) !DomainName.TryParseBaseDomain(uri.Host, out _name))
{ {
_name = "--"; _name = "--";
@ -166,25 +167,41 @@ namespace Bit.App.Pages
var autofillGroupings = new List<VaultListPageModel.AutofillGrouping>(); var autofillGroupings = new List<VaultListPageModel.AutofillGrouping>();
var ciphers = await _cipherService.GetAllAsync(Uri); var ciphers = await _cipherService.GetAllAsync(Uri);
var normalLogins = ciphers?.Item1.Select(l => new VaultListPageModel.AutofillCipher( if(_appOptions.FillType.HasValue && _appOptions.FillType.Value != CipherType.Login)
l, _appSettingsService, false))
.OrderBy(s => s.Name)
.ThenBy(s => s.Subtitle)
.ToList();
if(normalLogins?.Any() ?? false)
{ {
autofillGroupings.Add(new VaultListPageModel.AutofillGrouping(normalLogins, AppResources.MatchingItems)); var others = ciphers?.Item3.Where(c => c.Type == _appOptions.FillType.Value)
.Select(c => new VaultListPageModel.AutofillCipher(c, _appSettingsService, false))
.OrderBy(s => s.Name)
.ThenBy(s => s.Subtitle)
.ToList();
if(others?.Any() ?? false)
{
autofillGroupings.Add(new VaultListPageModel.AutofillGrouping(others, AppResources.Items));
}
} }
else
var fuzzyLogins = ciphers?.Item2.Select(l => new VaultListPageModel.AutofillCipher(
l, _appSettingsService, true))
.OrderBy(s => s.Name)
.ThenBy(s => s.LoginUsername)
.ToList();
if(fuzzyLogins?.Any() ?? false)
{ {
autofillGroupings.Add(new VaultListPageModel.AutofillGrouping(fuzzyLogins, var normalLogins = ciphers?.Item1
AppResources.PossibleMatchingItems)); .Select(l => new VaultListPageModel.AutofillCipher(l, _appSettingsService, false))
.OrderBy(s => s.Name)
.ThenBy(s => s.Subtitle)
.ToList();
if(normalLogins?.Any() ?? false)
{
autofillGroupings.Add(new VaultListPageModel.AutofillGrouping(normalLogins,
AppResources.MatchingItems));
}
var fuzzyLogins = ciphers?.Item2
.Select(l => new VaultListPageModel.AutofillCipher(l, _appSettingsService, true))
.OrderBy(s => s.Name)
.ThenBy(s => s.Subtitle)
.ToList();
if(fuzzyLogins?.Any() ?? false)
{
autofillGroupings.Add(new VaultListPageModel.AutofillGrouping(fuzzyLogins,
AppResources.PossibleMatchingItems));
}
} }
Device.BeginInvokeOnMainThread(() => Device.BeginInvokeOnMainThread(() =>
@ -235,8 +252,15 @@ namespace Bit.App.Pages
private async void AddCipherAsync() private async void AddCipherAsync()
{ {
var page = new VaultAddCipherPage(CipherType.Login, Uri, _name, true); if(_appOptions.FillType.HasValue && _appOptions.FillType != CipherType.Login)
await Navigation.PushForDeviceAsync(page); {
var pageForOther = new VaultAddCipherPage(_appOptions.FillType.Value, null, null, true);
await Navigation.PushForDeviceAsync(pageForOther);
return;
}
var pageForLogin = new VaultAddCipherPage(CipherType.Login, Uri, _name, true);
await Navigation.PushForDeviceAsync(pageForLogin);
} }
private async void MoreClickedAsync(VaultListPageModel.Cipher cipher) private async void MoreClickedAsync(VaultListPageModel.Cipher cipher)

View file

@ -78,7 +78,7 @@ namespace Bit.App.Services
return cipher; return cipher;
} }
public async Task<Tuple<IEnumerable<Cipher>, IEnumerable<Cipher>>> GetAllAsync(string uriString) public async Task<Tuple<IEnumerable<Cipher>, IEnumerable<Cipher>, IEnumerable<Cipher>>> GetAllAsync(string uriString)
{ {
if(string.IsNullOrWhiteSpace(uriString)) if(string.IsNullOrWhiteSpace(uriString))
{ {
@ -135,9 +135,16 @@ namespace Bit.App.Services
var matchingFuzzyDomainsArray = matchingFuzzyDomains.ToArray(); var matchingFuzzyDomainsArray = matchingFuzzyDomains.ToArray();
var matchingLogins = new List<Cipher>(); var matchingLogins = new List<Cipher>();
var matchingFuzzyLogins = new List<Cipher>(); var matchingFuzzyLogins = new List<Cipher>();
var others = new List<Cipher>();
var ciphers = await GetAllAsync(); var ciphers = await GetAllAsync();
foreach(var cipher in ciphers) foreach(var cipher in ciphers)
{ {
if(cipher.Type != Enums.CipherType.Login)
{
others.Add(cipher);
continue;
}
if(cipher.Type != Enums.CipherType.Login || cipher.Login?.Uri == null) if(cipher.Type != Enums.CipherType.Login || cipher.Login?.Uri == null)
{ {
continue; continue;
@ -190,7 +197,7 @@ namespace Bit.App.Services
if(mobileApp && mobileAppSearchTerms != null && mobileAppSearchTerms.Length > 0) if(mobileApp && mobileAppSearchTerms != null && mobileAppSearchTerms.Length > 0)
{ {
var addedFromSearchTerm = false; var addedFromSearchTerm = false;
var loginNameString = cipher.Name == null ? null : var loginNameString = cipher.Name == null ? null :
cipher.Name.Decrypt(cipher.OrganizationId)?.ToLowerInvariant(); cipher.Name.Decrypt(cipher.OrganizationId)?.ToLowerInvariant();
foreach(var term in mobileAppSearchTerms) foreach(var term in mobileAppSearchTerms)
{ {
@ -216,7 +223,8 @@ namespace Bit.App.Services
} }
} }
return new Tuple<IEnumerable<Cipher>, IEnumerable<Cipher>>(matchingLogins, matchingFuzzyLogins); return new Tuple<IEnumerable<Cipher>, IEnumerable<Cipher>, IEnumerable<Cipher>>(
matchingLogins, matchingFuzzyLogins, others);
} }
public async Task<ApiResult<CipherResponse>> SaveAsync(Cipher cipher) public async Task<ApiResult<CipherResponse>> SaveAsync(Cipher cipher)