mirror of
https://github.com/bitwarden/android.git
synced 2024-11-01 07:35:52 +03:00
add autofill service support for web browsers
This commit is contained in:
parent
519fd212d9
commit
e5d5d8b434
3 changed files with 57 additions and 8 deletions
|
@ -5,6 +5,7 @@ using Android.Views;
|
||||||
using Android.Views.Autofill;
|
using Android.Views.Autofill;
|
||||||
using static Android.App.Assist.AssistStructure;
|
using static Android.App.Assist.AssistStructure;
|
||||||
using Android.Text;
|
using Android.Text;
|
||||||
|
using static Android.Views.ViewStructure;
|
||||||
|
|
||||||
namespace Bit.Android.Autofill
|
namespace Bit.Android.Autofill
|
||||||
{
|
{
|
||||||
|
@ -24,7 +25,9 @@ namespace Bit.Android.Autofill
|
||||||
Clickable = node.IsClickable;
|
Clickable = node.IsClickable;
|
||||||
Visible = node.Visibility == ViewStates.Visible;
|
Visible = node.Visibility == ViewStates.Visible;
|
||||||
Hints = FilterForSupportedHints(node.GetAutofillHints());
|
Hints = FilterForSupportedHints(node.GetAutofillHints());
|
||||||
|
Hint = node.Hint;
|
||||||
AutofillOptions = node.GetAutofillOptions()?.ToList();
|
AutofillOptions = node.GetAutofillOptions()?.ToList();
|
||||||
|
HtmlInfo = node.HtmlInfo;
|
||||||
Node = node;
|
Node = node;
|
||||||
|
|
||||||
if(node.AutofillValue != null)
|
if(node.AutofillValue != null)
|
||||||
|
@ -63,6 +66,7 @@ namespace Bit.Android.Autofill
|
||||||
UpdateSaveTypeFromHints();
|
UpdateSaveTypeFromHints();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public string Hint { get; set; }
|
||||||
public int Id { get; private set; }
|
public int Id { get; private set; }
|
||||||
public string IdEntry { get; set; }
|
public string IdEntry { get; set; }
|
||||||
public AutofillId AutofillId { get; private set; }
|
public AutofillId AutofillId { get; private set; }
|
||||||
|
@ -77,6 +81,7 @@ namespace Bit.Android.Autofill
|
||||||
public long? DateValue { get; set; }
|
public long? DateValue { get; set; }
|
||||||
public int? ListValue { get; set; }
|
public int? ListValue { get; set; }
|
||||||
public bool? ToggleValue { get; set; }
|
public bool? ToggleValue { get; set; }
|
||||||
|
public HtmlInfo HtmlInfo { get; private set; }
|
||||||
public ViewNode Node { get; private set; }
|
public ViewNode Node { get; private set; }
|
||||||
|
|
||||||
private void UpdateSaveTypeFromHints()
|
private void UpdateSaveTypeFromHints()
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace Bit.Android.Autofill
|
||||||
_passwordFields = Fields
|
_passwordFields = Fields
|
||||||
.Where(f =>
|
.Where(f =>
|
||||||
(!f.IdEntry?.ToLowerInvariant().Contains("search") ?? true) &&
|
(!f.IdEntry?.ToLowerInvariant().Contains("search") ?? true) &&
|
||||||
(!f.Node?.Hint?.ToLowerInvariant().Contains("search") ?? true) &&
|
(!f.Hint?.ToLowerInvariant().Contains("search") ?? true) &&
|
||||||
(
|
(
|
||||||
f.InputType.HasFlag(InputTypes.TextVariationPassword) ||
|
f.InputType.HasFlag(InputTypes.TextVariationPassword) ||
|
||||||
f.InputType.HasFlag(InputTypes.TextVariationVisiblePassword) ||
|
f.InputType.HasFlag(InputTypes.TextVariationVisiblePassword) ||
|
||||||
|
@ -71,7 +71,8 @@ namespace Bit.Android.Autofill
|
||||||
if(!_passwordFields.Any())
|
if(!_passwordFields.Any())
|
||||||
{
|
{
|
||||||
_passwordFields = Fields.Where(f =>
|
_passwordFields = Fields.Where(f =>
|
||||||
f.IdEntry?.ToLowerInvariant().Contains("password") ?? false).ToList();
|
(f.IdEntry?.ToLowerInvariant().Contains("password") ?? false)
|
||||||
|
|| (f.Hint?.ToLowerInvariant().Contains("password") ?? false)).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ namespace Bit.Android.Autofill
|
||||||
{
|
{
|
||||||
foreach(var passwordField in PasswordFields)
|
foreach(var passwordField in PasswordFields)
|
||||||
{
|
{
|
||||||
var usernameField = Fields.TakeWhile(f => f.Id != passwordField.Id).LastOrDefault();
|
var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
|
||||||
if(usernameField != null)
|
if(usernameField != null)
|
||||||
{
|
{
|
||||||
_usernameFields.Add(usernameField);
|
_usernameFields.Add(usernameField);
|
||||||
|
@ -137,10 +138,14 @@ namespace Bit.Android.Autofill
|
||||||
|
|
||||||
_passwordFields = _usernameFields = null;
|
_passwordFields = _usernameFields = null;
|
||||||
|
|
||||||
|
if(field.Id > -1)
|
||||||
|
{
|
||||||
Ids.Add(field.Id);
|
Ids.Add(field.Id);
|
||||||
|
IdToFieldMap.Add(field.Id, field);
|
||||||
|
}
|
||||||
|
|
||||||
Fields.Add(field);
|
Fields.Add(field);
|
||||||
AutofillIds.Add(field.AutofillId);
|
AutofillIds.Add(field.AutofillId);
|
||||||
IdToFieldMap.Add(field.Id, field);
|
|
||||||
|
|
||||||
if(field.Hints != null)
|
if(field.Hints != null)
|
||||||
{
|
{
|
||||||
|
@ -181,7 +186,7 @@ namespace Bit.Android.Autofill
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var usernameField = Fields.TakeWhile(f => f.Id != passwordField.Id).LastOrDefault();
|
var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
|
||||||
savedItem.Login.Username = GetFieldValue(usernameField);
|
savedItem.Login.Username = GetFieldValue(usernameField);
|
||||||
|
|
||||||
return savedItem;
|
return savedItem;
|
||||||
|
|
|
@ -1,14 +1,26 @@
|
||||||
using static Android.App.Assist.AssistStructure;
|
using static Android.App.Assist.AssistStructure;
|
||||||
using Android.App.Assist;
|
using Android.App.Assist;
|
||||||
using Bit.App;
|
using Bit.App;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Bit.Android.Autofill
|
namespace Bit.Android.Autofill
|
||||||
{
|
{
|
||||||
public class Parser
|
public class Parser
|
||||||
{
|
{
|
||||||
|
public static HashSet<string> TrustedBrowsers = new HashSet<string>
|
||||||
|
{
|
||||||
|
"org.mozilla.focus","org.mozilla.firefox","org.mozilla.firefox_beta","com.microsoft.emmx",
|
||||||
|
"com.android.chrome","com.chrome.beta","com.android.browser","com.brave.browser","com.opera.browser",
|
||||||
|
"com.opera.browser.beta","com.opera.mini.native","com.chrome.dev","com.chrome.canary",
|
||||||
|
"com.google.android.apps.chrome","com.google.android.apps.chrome_dev","com.yandex.browser",
|
||||||
|
"com.sec.android.app.sbrowser","com.sec.android.app.sbrowser.beta","org.codeaurora.swe.browser",
|
||||||
|
"com.amazon.cloud9"
|
||||||
|
};
|
||||||
|
|
||||||
private readonly AssistStructure _structure;
|
private readonly AssistStructure _structure;
|
||||||
private string _uri;
|
private string _uri;
|
||||||
private string _packageName;
|
private string _packageName;
|
||||||
|
private string _webDomain;
|
||||||
|
|
||||||
public Parser(AssistStructure structure)
|
public Parser(AssistStructure structure)
|
||||||
{
|
{
|
||||||
|
@ -25,10 +37,14 @@ namespace Bit.Android.Autofill
|
||||||
return _uri;
|
return _uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(string.IsNullOrWhiteSpace(PackageName))
|
if(string.IsNullOrWhiteSpace(WebDomain) && string.IsNullOrWhiteSpace(PackageName))
|
||||||
{
|
{
|
||||||
_uri = null;
|
_uri = null;
|
||||||
}
|
}
|
||||||
|
else if(!string.IsNullOrWhiteSpace(WebDomain))
|
||||||
|
{
|
||||||
|
_uri = string.Concat("http://", WebDomain);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_uri = string.Concat(Constants.AndroidAppProtocol, PackageName);
|
_uri = string.Concat(Constants.AndroidAppProtocol, PackageName);
|
||||||
|
@ -50,6 +66,19 @@ namespace Bit.Android.Autofill
|
||||||
_packageName = value;
|
_packageName = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public string WebDomain
|
||||||
|
{
|
||||||
|
get => _webDomain;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
_webDomain = _uri = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_webDomain = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Parse()
|
public void Parse()
|
||||||
{
|
{
|
||||||
|
@ -63,17 +92,27 @@ namespace Bit.Android.Autofill
|
||||||
private void ParseNode(ViewNode node)
|
private void ParseNode(ViewNode node)
|
||||||
{
|
{
|
||||||
var hints = node.GetAutofillHints();
|
var hints = node.GetAutofillHints();
|
||||||
var isEditText = node.ClassName == "android.widget.EditText";
|
var isEditText = node.ClassName == "android.widget.EditText" || node?.HtmlInfo?.Tag == "input";
|
||||||
if(isEditText || (hints?.Length ?? 0) > 0)
|
if(isEditText || (hints?.Length ?? 0) > 0)
|
||||||
{
|
{
|
||||||
if(PackageName == null)
|
if(PackageName == null)
|
||||||
{
|
{
|
||||||
PackageName = node.IdPackage;
|
PackageName = node.IdPackage;
|
||||||
}
|
}
|
||||||
|
if(WebDomain == null && TrustedBrowsers.Contains(node.IdPackage))
|
||||||
|
{
|
||||||
|
WebDomain = node.WebDomain;
|
||||||
|
}
|
||||||
|
|
||||||
FieldCollection.Add(new Field(node));
|
FieldCollection.Add(new Field(node));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if(WebDomain == null && TrustedBrowsers.Contains(node.IdPackage))
|
||||||
|
{
|
||||||
|
WebDomain = node.WebDomain;
|
||||||
|
}
|
||||||
|
|
||||||
FieldCollection.IgnoreAutofillIds.Add(node.AutofillId);
|
FieldCollection.IgnoreAutofillIds.Add(node.AutofillId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue