Support for establishing a username field without a password field (#880)

* Support for establishing a username field without a password field

* added aws login
This commit is contained in:
Matt Portune 2020-05-06 09:48:34 -04:00 committed by GitHub
parent 4104f6f772
commit b29440556a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 23 deletions

View File

@ -125,6 +125,18 @@ namespace Bit.Droid.Accessibility
"com.treydev.pns" "com.treydev.pns"
}; };
// Be sure to keep these entries sorted alphabetically
public static Dictionary<string, KnownUsernameField> KnownUsernameFields => new List<KnownUsernameField>
{
new KnownUsernameField("accounts.google.com","ServiceLogin", "Email"),
new KnownUsernameField("amazon.com","signin", "ap_email_login"),
new KnownUsernameField("github.com", "", "user[login]-footer"),
new KnownUsernameField("paypal.com","signin", "email"),
new KnownUsernameField("signin.aws.amazon.com","signin", "resolving_input"),
new KnownUsernameField("signin.ebay.com","eBayISAPI.dll", "userid"),
}.ToDictionary(n => n.UriAuthority);
public static void PrintTestData(AccessibilityNodeInfo root, AccessibilityEvent e) public static void PrintTestData(AccessibilityNodeInfo root, AccessibilityEvent e)
{ {
var testNodes = GetWindowNodes(root, e, n => n.ViewIdResourceName != null && n.Text != null, false); var testNodes = GetWindowNodes(root, e, n => n.ViewIdResourceName != null && n.Text != null, false);
@ -289,17 +301,50 @@ namespace Bit.Droid.Accessibility
return nodes; return nodes;
} }
public static void GetNodesAndFill(AccessibilityNodeInfo root, AccessibilityEvent e, public static AccessibilityNodeInfo GetUsernameEditText(string uriString,
IEnumerable<AccessibilityNodeInfo> passwordNodes) IEnumerable<AccessibilityNodeInfo> allEditTexts)
{ {
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false); string uriKey = null;
var usernameEditText = GetUsernameEditTextIfPasswordExists(allEditTexts); string uriLocalPath = null;
FillCredentials(usernameEditText, passwordNodes); if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
allEditTexts.Dispose(); {
usernameEditText = null; uriKey = uri.Authority;
uriLocalPath = uri.LocalPath;
}
if (!string.IsNullOrEmpty(uriKey))
{
// Uncomment this to log values necessary for username field discovery
// foreach (var editText in allEditTexts)
// {
// System.Diagnostics.Debug.WriteLine(">>> uriKey: {0}, uriLocalPath: {1}, viewId: {2}", uriKey,
// uriLocalPath, editText.ViewIdResourceName);
// }
if (KnownUsernameFields.ContainsKey(uriKey))
{
var usernameField = KnownUsernameFields[uriKey];
if (uriLocalPath.EndsWith(usernameField.UriPathEnd))
{
foreach (var editText in allEditTexts)
{
foreach (var usernameViewId in usernameField.UsernameViewId.Split(","))
{
if (usernameViewId == editText.ViewIdResourceName)
{
return editText;
}
}
}
}
}
}
// no match found, attempt to establish username field based on password field
return GetUsernameEditTextIfPasswordExists(allEditTexts);
} }
public static AccessibilityNodeInfo GetUsernameEditTextIfPasswordExists( private static AccessibilityNodeInfo GetUsernameEditTextIfPasswordExists(
IEnumerable<AccessibilityNodeInfo> allEditTexts) IEnumerable<AccessibilityNodeInfo> allEditTexts)
{ {
AccessibilityNodeInfo previousEditText = null; AccessibilityNodeInfo previousEditText = null;
@ -317,7 +362,8 @@ namespace Bit.Droid.Accessibility
public static bool IsUsernameEditText(AccessibilityNodeInfo root, AccessibilityEvent e) public static bool IsUsernameEditText(AccessibilityNodeInfo root, AccessibilityEvent e)
{ {
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false); var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
var usernameEditText = GetUsernameEditTextIfPasswordExists(allEditTexts); var uriString = GetUri(root);
var usernameEditText = GetUsernameEditText(uriString, allEditTexts);
var isUsernameEditText = false; var isUsernameEditText = false;
if (usernameEditText != null) if (usernameEditText != null)

View File

@ -168,22 +168,24 @@ namespace Bit.Droid.Accessibility
public bool ScanAndAutofill(AccessibilityNodeInfo root, AccessibilityEvent e) public bool ScanAndAutofill(AccessibilityNodeInfo root, AccessibilityEvent e)
{ {
var filled = false; var filled = false;
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e, n => n.Password, false); var uri = AccessibilityHelpers.GetUri(root);
if (passwordNodes.Count > 0) if (uri != null && !uri.Contains(BitwardenWebsite) &&
AccessibilityHelpers.NeedToAutofill(AccessibilityHelpers.LastCredentials, uri))
{ {
var uri = AccessibilityHelpers.GetUri(root); var allEditTexts = AccessibilityHelpers.GetWindowNodes(root, e, n => AccessibilityHelpers.EditText(n), false);
if (uri != null && !uri.Contains(BitwardenWebsite)) var usernameEditText = AccessibilityHelpers.GetUsernameEditText(uri, allEditTexts);
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e, n => n.Password, false);
if (usernameEditText != null || passwordNodes.Count > 0)
{ {
if (AccessibilityHelpers.NeedToAutofill(AccessibilityHelpers.LastCredentials, uri)) AccessibilityHelpers.FillCredentials(usernameEditText, passwordNodes);
{ filled = true;
AccessibilityHelpers.GetNodesAndFill(root, e, passwordNodes); _lastAutoFillTime = Java.Lang.JavaSystem.CurrentTimeMillis();
filled = true; AccessibilityHelpers.LastCredentials = null;
_lastAutoFillTime = Java.Lang.JavaSystem.CurrentTimeMillis();
}
} }
AccessibilityHelpers.LastCredentials = null; allEditTexts.Dispose();
passwordNodes.Dispose();
} }
else if (AccessibilityHelpers.LastCredentials != null) if (AccessibilityHelpers.LastCredentials != null)
{ {
Task.Run(async () => Task.Run(async () =>
{ {
@ -191,7 +193,6 @@ namespace Bit.Droid.Accessibility
AccessibilityHelpers.LastCredentials = null; AccessibilityHelpers.LastCredentials = null;
}); });
} }
passwordNodes.Dispose();
return filled; return filled;
} }

View File

@ -0,0 +1,16 @@
namespace Bit.Droid.Accessibility
{
public class KnownUsernameField
{
public KnownUsernameField(string uriAuthority, string uriPathEnd, string usernameViewId)
{
UriAuthority = uriAuthority;
UriPathEnd = uriPathEnd;
UsernameViewId = usernameViewId;
}
public string UriAuthority { get; set; }
public string UriPathEnd { get; set; }
public string UsernameViewId { get; set; }
}
}

View File

@ -100,6 +100,7 @@
<Compile Include="Accessibility\AccessibilityService.cs" /> <Compile Include="Accessibility\AccessibilityService.cs" />
<Compile Include="Accessibility\Browser.cs" /> <Compile Include="Accessibility\Browser.cs" />
<Compile Include="Accessibility\NodeList.cs" /> <Compile Include="Accessibility\NodeList.cs" />
<Compile Include="Accessibility\KnownUsernameField.cs" />
<Compile Include="Autofill\AutofillHelpers.cs" /> <Compile Include="Autofill\AutofillHelpers.cs" />
<Compile Include="Autofill\AutofillService.cs" /> <Compile Include="Autofill\AutofillService.cs" />
<Compile Include="Autofill\Field.cs" /> <Compile Include="Autofill\Field.cs" />