From d64bffb6e42636d25fe72649dcee200efcfd9059 Mon Sep 17 00:00:00 2001 From: Torbjorn Tyridal Date: Mon, 13 Mar 2017 14:57:07 +0100 Subject: [PATCH] autofill / inject username, Issue #30 will inject if: * is configured to do so * username is set for site * current input is a type=text (or type='') and has name matching user|email|name|login * current input is empty * current input is just before a input[type=password] * current input is on same form as password input will also automatically move to the password field and enter password. --- ext/lib/main.js | 1 + ext/package.json | 3 ++ ext/webextension/src/bg/background.js | 53 +++++++++++++++---- .../src/browser_action/main_popup.js | 6 +-- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/ext/lib/main.js b/ext/lib/main.js index ff6301a..ef7aea1 100644 --- a/ext/lib/main.js +++ b/ext/lib/main.js @@ -94,6 +94,7 @@ function store_get() { 'pass_store': prefs.pass_store, 'pass_to_clipboard': prefs.pass_to_clipboard, 'auto_submit_pass': prefs.auto_submit_pass, + 'auto_submit_username': prefs.auto_submit_username, 'hotkeycombo': prefs.hotkeycombo, 'max_alg_version': global_prefs.get('extensions.' + self.id + '.max_alg_version', 3), }; diff --git a/ext/package.json b/ext/package.json index 2856868..206ba07 100644 --- a/ext/package.json +++ b/ext/package.json @@ -48,6 +48,9 @@ { "name":"auto_submit_pass", "title":"Submit after password inject", "type": "bool", "value": false }, + { + "name":"auto_submit_username", "title":"Inject username", "type": "bool", "value": false + }, { "name":"sdk.console.logLevel", "title":"Log level", "type":"menulist", "value":"error", "options": [ {"label":"Error", "value":"error"}, {"label":"Warnings & Errors", "value":"warn"}, diff --git a/ext/webextension/src/bg/background.js b/ext/webextension/src/bg/background.js index 070f3fb..17969bd 100644 --- a/ext/webextension/src/bg/background.js +++ b/ext/webextension/src/bg/background.js @@ -129,6 +129,7 @@ function store_get(keys) { 'pass_store': xul.pass_store, 'pass_to_clipboard': xul.pass_to_clipboard, 'auto_submit_pass': xul.auto_submit_pass, + 'auto_submit_username': xul.auto_submit_username, 'hotkeycombo': xul.hotkeycombo, 'max_alg_version': xul.max_alg_version }; @@ -145,6 +146,7 @@ function store_get(keys) { case 'pass_store': case 'pass_to_clipboard': case 'auto_submit_pass': + case 'auto_submit_username': case 'hotkeycombo': case 'max_alg_version': r[k] = settings[k]; @@ -236,29 +238,60 @@ Update_pass_failed.prototype = new IntermediateInheritor(); function _insert_password(args) { - document.activeElement.dispatchEvent(new Event('focus', {bubbles: false, cancelable: true})); - document.activeElement.dispatchEvent(new Event('focusin', {bubbles: true, cancelable: true})); + let inputf = (document.activeElement && + document.activeElement.matches('input') && + document.activeElement); + let pwinput = (inputf && inputf.type.toLowerCase() === 'password' && inputf); + + if (!inputf) { + console.warn("inject - but not an active input"); + return; + } + + if (!pwinput) { + let inputs = document.querySelectorAll('input'); + let idx = 0; + for (; inputs[idx] && inputs[idx] != inputf; idx++){}; + let sib = inputs[idx+1]; + + if (args.username && sib && sib.type.toLowerCase() === 'password' && inputf.form == sib.form) { + pwinput = sib; + if (!inputf.value) { + inputf.value = args.username; + inputf.dispatchEvent(new Event('change', {bubbles: true, cancelable: true})); + } + } else { + console.warn("inject - but nextSibling input is not password"); + return; + } + } + + pwinput.dispatchEvent(new Event('focus', {bubbles: false, cancelable: true})); + pwinput.dispatchEvent(new Event('focusin', {bubbles: true, cancelable: true})); window.setTimeout(()=>{ - document.activeElement.value = args.pass; - document.activeElement.dispatchEvent(new Event('change', {bubbles: true, cancelable: true})); - if (args.autosubmit && document.activeElement.form) + pwinput.value = args.pass; + pwinput.dispatchEvent(new Event('change', {bubbles: true, cancelable: true})); + if (args.autosubmit && pwinput.form) window.setTimeout(()=>{ - document.activeElement.form.dispatchEvent(new Event('submit', {bubbles: true, cancelable: true})); + pwinput.form.dispatchEvent(new Event('submit', {bubbles: true, cancelable: true})); },20); },20); } -function update_page_password(pass, allow_subframe) { +function update_page_password(pass, username, allow_subframe) { return current_tab() .then(find_active_input) .then(r=>{ - if (r.tgt.type !== 'password') + if (r.tgt.type.toLowerCase() === 'password') {} + else if ((r.tgt.type === '' || r.tgt.type.toLowerCase() === 'text') && + r.tgt.name.match(/.*(user|name|email|login).*/ig)) {} + else throw new Update_pass_failed("no password field selected"); if (!allow_subframe && r.frameId) throw new Update_pass_failed("Not pasting to subframe"); - - let args = { pass: pass, autosubmit: settings.auto_submit_pass }; + username = (settings.auto_submit_username && username); + let args = { pass: pass, username: username, autosubmit: settings.auto_submit_pass }; return chrome.tabs.executeScript(r.tab.id, { code: ';('+_insert_password+'('+JSON.stringify(args)+'));', frameId: r.frameId, diff --git a/ext/webextension/src/browser_action/main_popup.js b/ext/webextension/src/browser_action/main_popup.js index 1340b13..bd2bd25 100644 --- a/ext/webextension/src/browser_action/main_popup.js +++ b/ext/webextension/src/browser_action/main_popup.js @@ -133,8 +133,8 @@ function copy_to_clipboard(mimetype, data) { document.execCommand("Copy", false, null); document.oncopy=null; } -function update_page_password_input(pass) { - chrome.extension.getBackgroundPage().update_page_password(pass, true) +function update_page_password_input(pass, username) { + chrome.extension.getBackgroundPage().update_page_password(pass, username, true) .then(()=>{ }) .catch(e=>{ @@ -194,7 +194,7 @@ function recalculate(hide_after_copy, retry) { if (session_store.pass_to_clipboard) copy_to_clipboard("text/plain", pass); - update_page_password_input(pass); + update_page_password_input(pass, siteconfig.username); if (hide_after_copy) { addon.port.emit('close'); }