diff --git a/src/background.js b/src/background.js index da46cfa..b929372 100644 --- a/src/background.js +++ b/src/background.js @@ -278,13 +278,6 @@ async function dispatchFocusOrSubmit(settings, request, allFrames, allowForeign) * @return array List of filled fields */ async function fillFields(settings, login, fields) { - // check that required fields are present - for (var field of fields) { - if (login.fields[field] === null) { - throw new Error(`Required field is missing: ${field}`); - } - } - // inject script await chrome.tabs.executeScript(settings.tab.id, { allFrames: true, @@ -298,49 +291,55 @@ async function fillFields(settings, login, fields) { fields: fields }; - // fill form via injected script let allFrames = false; let allowForeign = false; - let allowNoSecret = false; - let filledFields = await dispatchFill( - settings, - fillRequest, - allFrames, - allowForeign, - allowNoSecret + let allowNoSecret = !fields.includes("secret"); + let filledFields = []; + let importantFieldToFill = fields.includes("openid") ? "openid" : "secret"; + + // fill form via injected script + filledFields = filledFields.concat( + await dispatchFill(settings, fillRequest, allFrames, allowForeign, allowNoSecret) ); - // try again using same-origin frames if we couldn't fill a password field - if (!filledFields.includes("secret")) { + // try again using same-origin frames if we couldn't fill an "important" field + if (!filledFields.includes(importantFieldToFill)) { allFrames = true; filledFields = filledFields.concat( await dispatchFill(settings, fillRequest, allFrames, allowForeign, allowNoSecret) ); } - // try again using all available frames if we couldn't fill a password field - if (!filledFields.includes("secret") && settings.foreignFills[settings.host] !== false) { + // try again using all available frames if we couldn't fill an "important" field + if ( + !filledFields.includes(importantFieldToFill) && + settings.foreignFills[settings.host] !== false + ) { allowForeign = true; filledFields = filledFields.concat( await dispatchFill(settings, fillRequest, allFrames, allowForeign, allowNoSecret) ); } - // try again using same-origin frames, and don't require a password field - if (!filledFields.length) { - allowForeign = false; + // try again, but don't require a password field (if it was required until now) + if (!allowNoSecret) { allowNoSecret = true; - filledFields = filledFields.concat( - await dispatchFill(settings, fillRequest, allFrames, allowForeign, allowNoSecret) - ); - } - // try again using all available frames, and don't require a password field - if (!filledFields.length && settings.foreignFills[settings.host] !== false) { - allowForeign = true; - filledFields = filledFields.concat( - await dispatchFill(settings, fillRequest, allFrames, allowForeign, allowNoSecret) - ); + // try again using same-origin frames + if (!filledFields.length) { + allowForeign = false; + filledFields = filledFields.concat( + await dispatchFill(settings, fillRequest, allFrames, allowForeign, allowNoSecret) + ); + } + + // try again using all available frames + if (!filledFields.length && settings.foreignFills[settings.host] !== false) { + allowForeign = true; + filledFields = filledFields.concat( + await dispatchFill(settings, fillRequest, allFrames, allowForeign, allowNoSecret) + ); + } } if (!filledFields.length) { @@ -350,7 +349,8 @@ async function fillFields(settings, login, fields) { // build focus or submit request let focusOrSubmitRequest = { origin: new URL(settings.tab.url).origin, - autoSubmit: getSetting("autoSubmit", login, settings) + autoSubmit: getSetting("autoSubmit", login, settings), + filledFields: filledFields }; // try to focus or submit form with the settings that were used to fill it @@ -675,8 +675,10 @@ async function handleMessage(settings, message, sendResponse) { break; case "fill": try { + let fields = message.login.fields.openid ? ["openid"] : ["login", "secret"]; + // dispatch initial fill request - var filledFields = await fillFields(settings, message.login, ["login", "secret"]); + var filledFields = await fillFields(settings, message.login, fields); saveRecent(settings, message.login); // no need to check filledFields, because fillFields() already throws an error if empty @@ -751,6 +753,7 @@ async function parseFields(settings, login) { login.fields = { secret: ["secret", "password", "pass"], login: ["login", "username", "user", "email"], + openid: ["openid"], url: ["url", "uri", "website", "site", "link", "launch"] }; login.settings = { diff --git a/src/inject.js b/src/inject.js index 5fc0ac5..d217d0e 100644 --- a/src/inject.js +++ b/src/inject.js @@ -1,11 +1,11 @@ (function() { const FORM_MARKERS = ["login", "log-in", "log_in", "signin", "sign-in", "sign_in"]; + const OPENID_FIELDS = { + selectors: ["input[name*=openid i]", "input[id*=openid i]", "input[class*=openid i]"], + types: ["text"] + }; const USERNAME_FIELDS = { selectors: [ - "input[id*=openid i]", - "input[name*=openid i]", - "input[class*=openid i]", - "input[name*=login i]", "input[name*=user i]", "input[name*=email i]", @@ -25,7 +25,9 @@ selectors: ["input[type=password i]"] }; const INPUT_FIELDS = { - selectors: PASSWORD_FIELDS.selectors.concat(USERNAME_FIELDS.selectors) + selectors: PASSWORD_FIELDS.selectors + .concat(USERNAME_FIELDS.selectors) + .concat(OPENID_FIELDS.selectors) }; const SUBMIT_FIELDS = { selectors: [ @@ -84,10 +86,17 @@ }; // get the login form - var loginForm = form(); + let loginForm = undefined; + if (request.fields.includes("openid")) { + // this is an attempt to fill a form containing only openid field + loginForm = form(OPENID_FIELDS); + } else { + // this is an attempt to fill a regular login form + loginForm = form(INPUT_FIELDS); + } // don't attempt to fill non-secret forms unless non-secret filling is allowed - if (!find(PASSWORD_FIELDS, loginForm) && !request.allowNoSecret) { + if (!request.allowNoSecret && !find(PASSWORD_FIELDS, loginForm)) { return result; } @@ -126,6 +135,14 @@ result.filledFields.push("secret"); } + // fill openid field + if ( + request.fields.includes("openid") && + update(OPENID_FIELDS, request.login.fields.openid, loginForm) + ) { + result.filledFields.push("openid"); + } + // finished filling things successfully return result; } @@ -144,7 +161,14 @@ }; // get the login form - var loginForm = form(); + let loginForm = undefined; + if (request.filledFields.includes("openid")) { + // this is an attempt to focus or submit a form containing only openid field + loginForm = form(OPENID_FIELDS); + } else { + // this is an attempt to focus or submit a regular login form + loginForm = form(INPUT_FIELDS); + } // ensure the origin is the same or allowed if (window.location.origin !== request.origin) { @@ -176,13 +200,11 @@ result.needPressEnter = true; } // We need to keep focus somewhere within the form, so that Enter hopefully submits the form. - var password = find(PASSWORD_FIELDS, loginForm); - if (password) { - password.focus(); - } else { - var username = find(USERNAME_FIELDS, loginForm); - if (username) { - username.focus(); + for (let selectors of [OPENID_FIELDS, PASSWORD_FIELDS, USERNAME_FIELDS]) { + let field = find(selectors, loginForm); + if (field) { + field.focus(); + break; } } } @@ -265,10 +287,11 @@ * * @since 3.0.0 * + * @param array selectors Selectors to use to find the right form * @return The login form */ - function form() { - const elems = queryAllVisible(document, INPUT_FIELDS, undefined); + function form(selectors) { + const elems = queryAllVisible(document, selectors, undefined); const forms = []; for (let elem of elems) { const form = elem.form;