Beispiel #1
0
        void ParseLocked(bool forFill, ViewNode viewNode)
        {
            if (viewNode.GetAutofillHints() != null && viewNode.GetAutofillHints().Length > 0)
            {
                if (forFill)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(viewNode));
                }
                else
                {
                    ClientFormData.Add(new FilledAutofillField(viewNode));
                }
            }
            var childrenSize = viewNode.ChildCount;

            if (childrenSize > 0)
            {
                for (int i = 0; i < childrenSize; i++)
                {
                    ParseLocked(forFill, viewNode.GetChildAt(i));
                }
            }
        }
        /// <summary>
        /// Traverse AssistStructure and add ViewNode metadata to a flat list.
        /// </summary>
        /// <returns>The parse.</returns>
        /// <param name="forFill">If set to <c>true</c> for fill.</param>
        /// <param name="isManualRequest"></param>
        string Parse(bool forFill, bool isManualRequest)
        {
            Log.Debug(CommonUtil.Tag, "Parsing structure for " + Structure.ActivityComponent);
            var nodes = Structure.WindowNodeCount;

            ClientFormData = new FilledAutofillFieldCollection();
            String webDomain = null;

            _editTextsWithoutHint.Clear();

            for (int i = 0; i < nodes; i++)
            {
                var node = Structure.GetWindowNodeAt(i);
                var view = node.RootViewNode;
                ParseLocked(forFill, isManualRequest, view, ref webDomain);
            }



            if (AutofillFields.Empty)
            {
                var passwordFields = _editTextsWithoutHint
                                     .Where(IsPassword).ToList();
                if (!passwordFields.Any())
                {
                    passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList();
                }
                foreach (var passwordField in passwordFields)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(passwordField, new[] { View.AutofillHintPassword }));
                    var usernameField = _editTextsWithoutHint.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
                    if (usernameField != null)
                    {
                        AutofillFields.Add(new AutofillFieldMetadata(usernameField, new[] { View.AutofillHintUsername }));
                    }
                }
                //for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill,
                //let's assume it is a username field:
                if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(_editTextsWithoutHint.First(), new[] { View.AutofillHintUsername }));
                }
            }

            //force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints)
            if (isManualRequest)
            {
                foreach (AssistStructure.ViewNode editText in _editTextsWithoutHint)
                {
                    if (editText.IsFocused)
                    {
                        AutofillFields.Add(new AutofillFieldMetadata(editText, new[] { IsPassword(editText) || HasPasswordHint(editText) ? View.AutofillHintPassword : View.AutofillHintUsername }));
                        break;
                    }
                }
            }



            String packageName = Structure.ActivityComponent.PackageName;

            if (!string.IsNullOrEmpty(webDomain))
            {
                bool valid = Kp2aDigitalAssetLinksDataSource.Instance.IsValid(mContext, webDomain, packageName);
                if (!valid)
                {
                    CommonUtil.loge($"DAL verification failed for {packageName}/{webDomain}");
                    webDomain = null;
                }
            }
            if (string.IsNullOrEmpty(webDomain))
            {
                webDomain = "androidapp://" + packageName;
                Log.Debug(CommonUtil.Tag, "no web domain. Using package name.");
            }
            return(webDomain);
        }
        void ParseLocked(bool forFill, bool isManualRequest, AssistStructure.ViewNode viewNode, ref string validWebdomain)
        {
            String webDomain = viewNode.WebDomain;

            if (webDomain != null)
            {
                Log.Debug(CommonUtil.Tag, $"child web domain: {webDomain}");
                if (!string.IsNullOrEmpty(validWebdomain))
                {
                    if (webDomain == validWebdomain)
                    {
                        throw new Java.Lang.SecurityException($"Found multiple web domains: valid= {validWebdomain}, child={webDomain}");
                    }
                }
                else
                {
                    validWebdomain = webDomain;
                }
            }

            string[] viewHints = viewNode.GetAutofillHints();
            if (viewHints != null && viewHints.Length == 1 && viewHints.First() == "off" && viewNode.IsFocused &&
                isManualRequest)
            {
                viewHints[0] = "on";
            }
            CommonUtil.logd("viewHints=" + viewHints);
            CommonUtil.logd("class=" + viewNode.ClassName);
            CommonUtil.logd("tag=" + (viewNode?.HtmlInfo?.Tag ?? "(null)"));
            if (viewNode?.HtmlInfo?.Tag == "input")
            {
                foreach (var p in viewNode.HtmlInfo.Attributes)
                {
                    CommonUtil.logd("attr=" + p.First + "/" + p.Second);
                }
            }
            if (viewHints != null && viewHints.Length > 0 && viewHints.First() != "on" /*if hint is "on", treat as if there is no hint*/)
            {
                if (forFill)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(viewNode));
                }
                else
                {
                    //TODO implement save
                    throw new NotImplementedException("TODO: Port and use AutoFill hints");
                    //ClientFormData.Add(new FilledAutofillField(viewNode));
                }
            }
            else
            {
                if (viewNode.ClassName == "android.widget.EditText" || viewNode?.HtmlInfo?.Tag == "input")
                {
                    _editTextsWithoutHint.Add(viewNode);
                }
            }
            var childrenSize = viewNode.ChildCount;

            if (childrenSize > 0)
            {
                for (int i = 0; i < childrenSize; i++)
                {
                    ParseLocked(forFill, isManualRequest, viewNode.GetChildAt(i), ref validWebdomain);
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Traverse AssistStructure and add ViewNode metadata to a flat list.
        /// </summary>
        /// <returns>The parse.</returns>
        /// <param name="forFill">If set to <c>true</c> for fill.</param>
        /// <param name="isManualRequest"></param>
        AutofillTargetId Parse(bool forFill, bool isManualRequest)
        {
            AutofillTargetId result = new AutofillTargetId();

            CommonUtil.logd("Parsing structure for " + Structure.ActivityComponent);
            var nodes = Structure.WindowNodeCount;

            ClientFormData = new FilledAutofillFieldCollection();
            String webDomain = null;

            _editTextsWithoutHint.Clear();

            for (int i = 0; i < nodes; i++)
            {
                var node = Structure.GetWindowNodeAt(i);

                var view = node.RootViewNode;
                ParseLocked(forFill, isManualRequest, view, ref webDomain);
            }



            List <AssistStructure.ViewNode> passwordFields = new List <AssistStructure.ViewNode>();
            List <AssistStructure.ViewNode> usernameFields = new List <AssistStructure.ViewNode>();

            if (AutofillFields.Empty)
            {
                passwordFields = _editTextsWithoutHint.Where(IsPassword).ToList();
                if (!passwordFields.Any())
                {
                    passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList();
                }

                usernameFields = _editTextsWithoutHint.Where(HasUsernameHint).ToList();

                if (usernameFields.Any() == false)
                {
                    foreach (var passwordField in passwordFields)
                    {
                        var usernameField = _editTextsWithoutHint
                                            .TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
                        if (usernameField != null)
                        {
                            usernameFields.Add(usernameField);
                        }
                    }
                }
                if (usernameFields.Any() == false)
                {
                    //for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill,
                    //let's assume it is a username field:
                    if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1)
                    {
                        usernameFields.Add(_editTextsWithoutHint.First());
                    }
                }
            }

            //force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints)
            if (isManualRequest)
            {
                foreach (AssistStructure.ViewNode editText in _editTextsWithoutHint)
                {
                    if (editText.IsFocused)
                    {
                        if (IsPassword(editText) || HasPasswordHint(editText))
                        {
                            passwordFields.Add(editText);
                        }
                        else
                        {
                            usernameFields.Add(editText);
                        }
                        break;
                    }
                }
            }

            if (forFill)
            {
                foreach (var uf in usernameFields)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(uf, new[] { View.AutofillHintUsername }));
                }
                foreach (var pf in passwordFields)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(pf, new[] { View.AutofillHintPassword }));
                }
            }
            else
            {
                foreach (var uf in usernameFields)
                {
                    ClientFormData.Add(new FilledAutofillField(uf, new[] { View.AutofillHintUsername }));
                }
                foreach (var pf in passwordFields)
                {
                    ClientFormData.Add(new FilledAutofillField(pf, new[] { View.AutofillHintPassword }));
                }
            }


            result.WebDomain   = webDomain;
            result.PackageName = Structure.ActivityComponent.PackageName;
            if (!string.IsNullOrEmpty(webDomain))
            {
                result.IncompatiblePackageAndDomain = !kp2aDigitalAssetLinksDataSource.IsTrustedLink(webDomain, result.PackageName);
                if (result.IncompatiblePackageAndDomain)
                {
                    CommonUtil.loge($"DAL verification failed for {result.PackageName}/{result.WebDomain}");
                }
            }
            else
            {
                result.IncompatiblePackageAndDomain = false;
            }
            return(result);
        }
Beispiel #5
0
        void ParseLocked(bool forFill, bool isManualRequest, AssistStructure.ViewNode viewNode, ref string validWebdomain)
        {
            String webDomain = viewNode.WebDomain;

            if ((PackageId == null) && (!string.IsNullOrWhiteSpace(viewNode.IdPackage)) &&
                (viewNode.IdPackage != "android"))
            {
                PackageId = viewNode.IdPackage;
            }

            DomainName outDomain;

            if (DomainName.TryParse(webDomain, domainSuffixParserCache, out outDomain))
            {
                webDomain = outDomain.RegisterableDomainName;
            }

            if (webDomain != null)
            {
                if (!string.IsNullOrEmpty(validWebdomain))
                {
                    if (webDomain != validWebdomain)
                    {
                        throw new Java.Lang.SecurityException($"Found multiple web domains: valid= {validWebdomain}, child={webDomain}");
                    }
                }
                else
                {
                    validWebdomain = webDomain;
                }
            }

            string[] viewHints = viewNode.GetAutofillHints();
            if (viewHints != null && viewHints.Length == 1 && viewHints.First() == "off" && viewNode.IsFocused &&
                isManualRequest)
            {
                viewHints[0] = "on";
            }
            if (viewHints != null && viewHints.Any())
            {
                CommonUtil.logd("viewHints=" + viewHints);
                CommonUtil.logd("class=" + viewNode.ClassName);
                CommonUtil.logd("tag=" + (viewNode?.HtmlInfo?.Tag ?? "(null)"));
            }

            if (viewNode?.HtmlInfo?.Tag == "input")
            {
                foreach (var p in viewNode.HtmlInfo.Attributes)
                {
                    CommonUtil.logd("attr=" + p.First + "/" + p.Second);
                }
            }
            if (viewHints != null && viewHints.Length > 0 && viewHints.First() != "on" /*if hint is "on", treat as if there is no hint*/)
            {
                if (forFill)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(viewNode));
                }
                else
                {
                    FilledAutofillField filledAutofillField = new FilledAutofillField(viewNode);
                    ClientFormData.Add(filledAutofillField);
                }
            }
            else
            {
                if (viewNode.ClassName == "android.widget.EditText" || viewNode?.HtmlInfo?.Tag == "input")
                {
                    _editTextsWithoutHint.Add(viewNode);
                }
            }
            var childrenSize = viewNode.ChildCount;

            if (childrenSize > 0)
            {
                for (int i = 0; i < childrenSize; i++)
                {
                    ParseLocked(forFill, isManualRequest, viewNode.GetChildAt(i), ref validWebdomain);
                }
            }
        }