[Patch] Fix form detection for password manager

Davide Baldini baldiniebaldini at gmail.com
Thu Oct 5 15:19:53 BST 2023


I fixed the form detection script in src/lib/tools/scripts.cpp used to capture the login credentials for the password manager. I tested this on many websites, all work correctly.

This fixes two problems:

1) Some websites collect data from login forms without properly submit()ting them, thus the 'submit' event handler currently in use does not trigger;
2) the current script collects the DOM forms by reading 'document.forms', but this property often holds an empty set, and MutationObserver doesn't subsequently detect further forms. This patch circumvents this issue.

# This patch file was generated by NetBeans IDE
# It uses platform neutral UTF-8 encoding and \n newlines.
--- a/src/lib/tools/scripts.cpp
+++ b/src/lib/tools/scripts.cpp
@@ -74,31 +74,37 @@
  QString Scripts::setupFormObserver()
  {
      QString source = QL1S("(function() {"
-                          "function findUsername(inputs) {"
-                          "    var usernameNames = ['user', 'name', 'login'];"
-                          "    for (var i = 0; i < usernameNames.length; ++i) {"
-                          "        for (var j = 0; j < inputs.length; ++j)"
-                          "            if (inputs[j].type == 'text' && inputs[j].value.length && inputs[j].name.indexOf(usernameNames[i]) != -1)"
-                          "                return inputs[j].value;"
+                          "    let eFormsOld  = [],"
+                          "        eFormsDone = [];"
+                          ""
+                          "    function findUsername(inputs) {"
+                          "        let usernameNames = ['user', 'name', 'login'];"
+                          ""
+                          "        for (let i = 0; i < usernameNames.length; ++i) {"
+                          "            for (let j = 0; j < inputs.length; ++j)"
+                          "                if (inputs[j].type == 'text' && inputs[j].value.length && inputs[j].name.indexOf(usernameNames[i]) != -1)"
+                          "                    return inputs[j].value;"
+                          "        }"
+                          ""
+                          "        for (let i = 0; i < inputs.length; ++i)"
+                          "            if (inputs[i].type == 'text' && inputs[i].value.length)"
+                          "                return inputs[i].value;"
+                          ""
+                          "        for (let i = 0; i < inputs.length; ++i)"
+                          "            if (inputs[i].type == 'email' && inputs[i].value.length)"
+                          "                return inputs[i].value;"
+                          ""
+                          "        return '';"
                            "    }"
-                          "    for (var i = 0; i < inputs.length; ++i)"
-                          "        if (inputs[i].type == 'text' && inputs[i].value.length)"
-                          "            return inputs[i].value;"
-                          "    for (var i = 0; i < inputs.length; ++i)"
-                          "        if (inputs[i].type == 'email' && inputs[i].value.length)"
-                          "            return inputs[i].value;"
-                          "    return '';"
-                          "}"
                            ""
-                          "function registerForm(form) {"
-                          "    form.addEventListener('submit', function() {"
-                          "        var form = this;"
-                          "        var data = '';"
-                          "        var password = '';"
-                          "        var inputs = form.getElementsByTagName('input');"
-                          "        for (var i = 0; i < inputs.length; ++i) {"
-                          "            var input = inputs[i];"
-                          "            var type = input.type.toLowerCase();"
+                          "    function processForm(eForm) {"
+                          "        let data = '';"
+                          "        let password = '';"
+                          "        let inputs = eForm.getElementsByTagName('input');"
+                          ""
+                          "        for (let i = 0; i < inputs.length; ++i) {"
+                          "            let input = inputs[i];"
+                          "            let type = input.type.toLowerCase();"
                            "            if (type != 'text' && type != 'password' && type != 'email')"
                            "                continue;"
                            "            if (!password && type == 'password')"
@@ -108,30 +114,61 @@
                            "            data += encodeURIComponent(input.value);"
                            "            data += '&';"
                            "        }"
+                          ""
                            "        if (!password)"
                            "            return;"
+                          ""
+                          "        if (eFormsDone.every(e => e != eForm)) {"
+                          "            eFormsDone.push(eForm);"
+                          "        } else {"
+                          "            return;"
+                          "        }"
+                          ""
                            "        data = data.substring(0, data.length - 1);"
-                          "        var url = window.location.href;"
-                          "        var username = findUsername(inputs);"
+                          "        let url = window.location.href;"
+                          "        let username = findUsername(inputs);"
                            "        external.autoFill.formSubmitted(url, username, password, data);"
-                          "    }, true);"
-                          "}"
+                          "    }"
                            ""
-                          "if (!document.documentElement) return;"
+                          "    function undoForm(eForm) {"
+                          "        let i = eFormsDone.indexOf(eForm);"
                            ""
-                          "for (var i = 0; i < document.forms.length; ++i)"
-                          "    registerForm(document.forms[i]);"
+                          "        if (i >= 0) {"
+                          "            eFormsDone.splice(i, 1);"
+                          "        }"
+                          "    }"
                            ""
-                          "var observer = new MutationObserver(function(mutations) {"
-                          "    for (var mutation of mutations)"
-                          "        for (var node of mutation.addedNodes)"
-                          "            if (node.tagName && node.tagName.toLowerCase() == 'form')"
-                          "                registerForm(node);"
-                          "});"
-                          "observer.observe(document.documentElement, { childList: true, subtree: true });"
+                          "    function registerForm(eForm) {"
+                          "        let eInputs = eForm.getElementsByTagName('input');"
                            ""
+                          "        eForm.addEventListener('submit', () => processForm(eForm), true);"
+                          ""
+                          "        for (let eInput of eInputs) {"
+                          "            let type = eInput.type.toLowerCase();"
+                          "            "
+                          "            if (type == 'password') {"
+                          "                eInput.addEventListener('blur', () => processForm(eForm), true);"
+                          "                eInput.addEventListener('input', () => undoForm(eForm), true);"
+                          "                eInput.addEventListener('keydown', () => event.keyCode === 13 && processForm(eForm), true);"
+                          "            }"
+                          "        }"
+                          "    }"
+                          ""
+                          "    setInterval(() => {"
+                          "        try {"
+                          "            let eFormsNew = Array.from(document.forms);"
+                          ""
+                          "            for (let eFormNew of eFormsNew) {"
+                          "                if (eFormsOld.every(e => e != eFormNew)) {"
+                          "                    eFormsOld.push(eFormNew);"
+                          "                    registerForm(eFormNew);"
+                          "                }"
+                          "            }"
+                          ""
+                          "        } catch (e) {}"
+                          "    }, 100);"
                            "})()");
-
+
      return source;
  }


More information about the Falkon mailing list