From b60be97b1fb6c6701d96f0a2adf03c7900fe92d0 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Tue, 4 Oct 2016 00:26:05 -0400 Subject: [PATCH] updated fill script to support multiple forms on the same page and no form at all (only fields) --- src/iOS.Extension/Models/FillScript.cs | 109 ++++++++----------------- 1 file changed, 35 insertions(+), 74 deletions(-) diff --git a/src/iOS.Extension/Models/FillScript.cs b/src/iOS.Extension/Models/FillScript.cs index bc2ca595b..8b0f98df4 100644 --- a/src/iOS.Extension/Models/FillScript.cs +++ b/src/iOS.Extension/Models/FillScript.cs @@ -16,109 +16,70 @@ namespace Bit.iOS.Extension.Models DocumentUUID = pageDetails.DocumentUUID; + List usernames = new List(); + List passwords = new List(); + var passwordFields = pageDetails.Fields.Where(f => f.Type == "password").ToArray(); - var passwordForms = pageDetails.Forms.Where(form => passwordFields.Any(f => f.Form == form.Key)).ToArray(); - - PageDetails.Form loginForm = null; - PageDetails.Field username = null, password = null; - - if(passwordForms.Any()) + foreach(var form in pageDetails.Forms) { - if(passwordForms.Count() > 1) + var passwordFieldsForForm = passwordFields.Where(f => f.Form == form.Key).ToArray(); + passwords.AddRange(passwordFieldsForForm); + + if(string.IsNullOrWhiteSpace(fillUsername)) { - // More than one form with a password field is on the page. - // This usually occurs when a website has a login and signup form on the same page. - // Let's try to guess which one is the login form. - - // First let's try to guess the correct login form by examining the form attribute strings - // for common login form attribute. - foreach(var form in passwordForms) - { - var formDescriptor = string.Format("{0}~{1}~{2}", - form.Value?.HtmlName, form.Value?.HtmlId, form.Value?.HtmlAction) - ?.ToLowerInvariant()?.Replace('_', '-'); - - if(formDescriptor.Contains("login") || formDescriptor.Contains("log-in") - || formDescriptor.Contains("signin") || formDescriptor.Contains("sign-in") - || formDescriptor.Contains("logon") || formDescriptor.Contains("log-on")) - { - loginForm = form.Value; - break; - } - } - - if(loginForm == null) - { - // Next we can try to find the login form that only has one password field. Typically - // a registration form may have two password fields for password confirmation. - var fieldGroups = passwordFields.GroupBy(f => f.Form); - var singleFields = fieldGroups.FirstOrDefault(f => f.Count() == 1); - if(singleFields.Any()) - { - var singlePasswordForms = passwordForms.Where(f => f.Key == singleFields.Key); - if(singlePasswordForms.Any()) - { - loginForm = singlePasswordForms.First().Value; - } - } - } + continue; } - if(loginForm == null) + foreach(var pf in passwordFieldsForForm) { - loginForm = passwordForms.FirstOrDefault().Value; - } - - password = pageDetails.Fields.FirstOrDefault(f => - f.Form == loginForm.OpId - && f.Type == "password"); - - username = pageDetails.Fields.LastOrDefault(f => - f.Form == loginForm.OpId - && (f.Type == "text" || f.Type == "email") - && f.ElementNumber < password.ElementNumber); - - if(loginForm.HtmlAction != null) - { - AutoSubmit = new Submit { FocusOpId = password.OpId }; + var username = pageDetails.Fields.LastOrDefault(f => f.Form == pf.Form + && f.ElementNumber < pf.ElementNumber && (f.Type == "text" || f.Type == "email" || f.Type == "tel")); + if(username != null) + { + usernames.Add(username); + } } } - else if(passwordFields.Count() == 1) + + if(passwordFields.Any() && !passwords.Any()) { - // The page does not have any forms with password fields. Use the one password field on the page and the + // The page does not have any forms with password fields. Use the first password field on the page and the // input field just before it as the username. - password = passwordFields.First(); - if(password.ElementNumber > 0) - { - username = pageDetails.Fields.LastOrDefault(f => - (f.Type == "text" || f.Type == "email") - && f.ElementNumber < password.ElementNumber); + var pf = passwordFields.First(); + passwords.Add(pf); - if(username == null) + if(!string.IsNullOrWhiteSpace(fillUsername) && pf.ElementNumber > 0) + { + var username = pageDetails.Fields.LastOrDefault(f => f.ElementNumber < pf.ElementNumber + && (f.Type == "text" || f.Type == "email" || f.Type == "tel")); + if(username != null) { - username = pageDetails.Fields[password.ElementNumber - 1]; + usernames.Add(username); } } } - Script = new List>(); - - if(username != null) + foreach(var username in usernames) { Script.Add(new List { "click_on_opid", username.OpId }); Script.Add(new List { "fill_by_opid", username.OpId, fillUsername }); } - if(password != null) + foreach(var password in passwords) { Script.Add(new List { "click_on_opid", password.OpId }); Script.Add(new List { "fill_by_opid", password.OpId, fillPassword }); } + + if(passwords.Any()) + { + AutoSubmit = new Submit { FocusOpId = passwords.First().OpId }; + } } [JsonProperty(PropertyName = "script")] - public List> Script { get; set; } + public List> Script { get; set; } = new List>(); [JsonProperty(PropertyName = "autosubmit")] public Submit AutoSubmit { get; set; } [JsonProperty(PropertyName = "documentUUID")]