Bug 1567175, move password manager event listener attachment from content framescript to LoginManagerChild, and use the current window instead of the top level window for the argument passed to DOMInputPasswordAdded, r=MattN

Differential Revision: https://phabricator.services.mozilla.com/D47826

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Neil Deakin 2019-10-21 20:26:21 +00:00
parent 7410901165
commit e00aa26593
4 changed files with 74 additions and 107 deletions

View File

@ -15,46 +15,6 @@ var { XPCOMUtils } = ChromeUtils.import(
XPCOMUtils.defineLazyModuleGetters(this, {
ContentMetaHandler: "resource:///modules/ContentMetaHandler.jsm",
LoginFormFactory: "resource://gre/modules/LoginFormFactory.jsm",
LoginManagerChild: "resource://gre/modules/LoginManagerChild.jsm",
InsecurePasswordUtils: "resource://gre/modules/InsecurePasswordUtils.jsm",
});
function shouldIgnoreLoginManagerEvent(event) {
let nodePrincipal = event.target.nodePrincipal;
// If we have a system or null principal then prevent any more password manager code from running and
// incorrectly using the document `location`. Also skip password manager for about: pages.
return (
nodePrincipal.isSystemPrincipal ||
nodePrincipal.isNullPrincipal ||
nodePrincipal.schemeIs("about")
);
}
addEventListener("DOMFormBeforeSubmit", function(event) {
if (shouldIgnoreLoginManagerEvent(event)) {
return;
}
let window = event.target.ownerGlobal;
LoginManagerChild.forWindow(window).onDOMFormBeforeSubmit(event);
});
addEventListener("DOMFormHasPassword", function(event) {
if (shouldIgnoreLoginManagerEvent(event)) {
return;
}
let window = event.target.ownerGlobal;
LoginManagerChild.forWindow(window).onDOMFormHasPassword(event);
let formLike = LoginFormFactory.createFromForm(event.originalTarget);
InsecurePasswordUtils.reportInsecurePasswords(formLike);
});
addEventListener("DOMInputPasswordAdded", function(event) {
if (shouldIgnoreLoginManagerEvent(event)) {
return;
}
let window = event.target.ownerGlobal;
LoginManagerChild.forWindow(window).onDOMInputPasswordAdded(event, content);
let formLike = LoginFormFactory.createFromField(event.originalTarget);
InsecurePasswordUtils.reportInsecurePasswords(formLike);
});
ContentMetaHandler.init(this);

View File

@ -73,13 +73,6 @@ BrowserCLH.prototype = {
"invalidformsubmit"
);
GeckoViewUtils.addLazyGetter(this, "LoginManagerParent", {
module: "resource://gre/modules/LoginManagerParent.jsm",
});
GeckoViewUtils.addLazyGetter(this, "LoginManagerChild", {
module: "resource://gre/modules/LoginManagerChild.jsm",
});
GeckoViewUtils.addLazyGetter(this, "ActionBarHandler", {
module: "resource://gre/modules/ActionBarHandler.jsm",
});
@ -141,8 +134,6 @@ BrowserCLH.prototype = {
}
);
this._initLoginManagerEvents(win);
GeckoViewUtils.registerLazyWindowEventListener(
win,
["TextSelection:Get", "TextSelection:Action", "TextSelection:End"],
@ -193,58 +184,6 @@ BrowserCLH.prototype = {
}
},
_initLoginManagerEvents: function(aWindow) {
if (Services.prefs.getBoolPref("reftest.remote", false)) {
// XXX known incompatibility between reftest harness and form-fill.
return;
}
function shouldIgnoreLoginManagerEvent(event) {
let nodePrincipal = event.target.nodePrincipal;
// If we have a null principal then prevent any more password manager code from running and
// incorrectly using the document `location`. Also skip password manager for about: pages.
return nodePrincipal.isNullPrincipal || nodePrincipal.schemeIs("about");
}
let options = {
capture: true,
mozSystemGroup: true,
};
// NOTE: Much of this logic is duplicated in browser/base/content/content.js
// for desktop.
aWindow.addEventListener("DOMFormBeforeSubmit", event => {
if (shouldIgnoreLoginManagerEvent(event)) {
return;
}
this.LoginManagerChild.forWindow(aWindow).onDOMFormBeforeSubmit(event);
});
aWindow.addEventListener(
"DOMFormHasPassword",
event => {
if (shouldIgnoreLoginManagerEvent(event)) {
return;
}
this.LoginManagerChild.forWindow(aWindow).onDOMFormHasPassword(event);
},
options
);
aWindow.addEventListener(
"DOMInputPasswordAdded",
event => {
if (shouldIgnoreLoginManagerEvent(event)) {
return;
}
this.LoginManagerChild.forWindow(aWindow).onDOMInputPasswordAdded(
event,
event.target.ownerGlobal.top
);
},
options
);
},
// QI
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),

View File

@ -21,6 +21,9 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const { PrivateBrowsingUtils } = ChromeUtils.import(
"resource://gre/modules/PrivateBrowsingUtils.jsm"
);
@ -497,6 +500,58 @@ this.LoginManagerChild = class LoginManagerChild extends JSWindowActorChild {
return undefined;
}
shouldIgnoreLoginManagerEvent(event) {
let nodePrincipal = event.target.nodePrincipal;
// If we have a system or null principal then prevent any more password manager code from running and
// incorrectly using the document `location`. Also skip password manager for about: pages.
return (
nodePrincipal.isSystemPrincipal ||
nodePrincipal.isNullPrincipal ||
nodePrincipal.schemeIs("about")
);
}
handleEvent(event) {
if (
AppConstants.platform == "android" &&
Services.prefs.getBoolPref("reftest.remote", false)
) {
// XXX known incompatibility between reftest harness and form-fill. Is this still needed?
return;
}
switch (event.type) {
case "DOMFormBeforeSubmit": {
if (this.shouldIgnoreLoginManagerEvent(event)) {
break;
}
this.onDOMFormBeforeSubmit(event);
break;
}
case "DOMFormHasPassword": {
if (this.shouldIgnoreLoginManagerEvent(event)) {
break;
}
this.onDOMFormHasPassword(event);
let formLike = LoginFormFactory.createFromForm(event.originalTarget);
InsecurePasswordUtils.reportInsecurePasswords(formLike);
break;
}
case "DOMInputPasswordAdded": {
if (this.shouldIgnoreLoginManagerEvent(event)) {
break;
}
this.onDOMInputPasswordAdded(event, this.document.defaultView);
let formLike = LoginFormFactory.createFromField(event.originalTarget);
InsecurePasswordUtils.reportInsecurePasswords(formLike);
break;
}
}
}
notifyObserversOfFormProcessed(formid) {
Services.obs.notifyObservers(this, "passwordmgr-processed-form", formid);
}
@ -580,8 +635,16 @@ this.LoginManagerChild = class LoginManagerChild extends JSWindowActorChild {
return;
}
// Get the highest accessible docshell and attach the progress listener to that.
let browsingContext = window.getWindowGlobalChild().browsingContext;
let docShell;
while (browsingContext && browsingContext.docShell) {
docShell = browsingContext.docShell;
browsingContext = browsingContext.parent;
}
try {
let webProgress = window.docShell
let webProgress = docShell
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
webProgress.addProgressListener(
@ -681,12 +744,12 @@ this.LoginManagerChild = class LoginManagerChild extends JSWindowActorChild {
this._fetchLoginsFromParentAndFillForm(formLike);
}
onDOMInputPasswordAdded(event, topWindow) {
onDOMInputPasswordAdded(event, window) {
if (!event.isTrusted) {
return;
}
this.setupProgressListener(topWindow);
this.setupProgressListener(window);
let pwField = event.originalTarget;
if (pwField.form) {
@ -709,16 +772,16 @@ this.LoginManagerChild = class LoginManagerChild extends JSWindowActorChild {
// Showing the MP modal as soon as possible minimizes its interference with tab interactions
// See bug 1539091 and bug 1538460.
if (document.visibilityState == "visible" || isMasterPasswordSet) {
this._processDOMInputPasswordAddedEvent(event, topWindow);
this._processDOMInputPasswordAddedEvent(event);
} else {
// wait until the document becomes visible before handling this event
this._deferHandlingEventUntilDocumentVisible(event, document, () => {
this._processDOMInputPasswordAddedEvent(event, topWindow);
this._processDOMInputPasswordAddedEvent(event);
});
}
}
_processDOMInputPasswordAddedEvent(event, topWindow) {
_processDOMInputPasswordAddedEvent(event) {
let pwField = event.originalTarget;
let formLike = LoginFormFactory.createFromField(pwField);

View File

@ -291,6 +291,11 @@ let ACTORS = {
},
child: {
moduleURI: "resource://gre/modules/LoginManagerChild.jsm",
events: {
DOMFormBeforeSubmit: {},
DOMFormHasPassword: {},
DOMInputPasswordAdded: {},
},
messages: [
"PasswordManager:fillForm",
"PasswordManager:fillGeneratedPassword",