Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 37 additions & 34 deletions src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 = {
Expand Down
57 changes: 40 additions & 17 deletions src/inject.js
Original file line number Diff line number Diff line change
@@ -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]",
Expand All @@ -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: [
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}
}
}
Expand Down Expand Up @@ -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;
Expand Down