Bug 1045987 - Fix doorhanger notifications for the login manager. r=billm/dolske

This commit is contained in:
Blake Kaplan 2014-09-04 17:01:32 -07:00
parent fd5ab02779
commit cd2c5b48a8
7 changed files with 96 additions and 24 deletions

View File

@ -372,6 +372,16 @@
</body>
</method>
<method name="getBrowserForContentWindow">
<parameter name="aWindow"/>
<body>
<![CDATA[
var tab = this._getTabForContentWindow(aWindow);
return tab ? tab.linkedBrowser : null;
]]>
</body>
</method>
<method name="_getTabForContentWindow">
<parameter name="aWindow"/>
<body>
@ -388,7 +398,9 @@
}
for (let i = 0; i < this.browsers.length; i++) {
if (this.browsers[i].contentWindow == aWindow)
// NB: We use contentWindowAsCPOW so that this code works both
// for remote browsers as well. aWindow may be a CPOW.
if (this.browsers[i].contentWindowAsCPOW == aWindow)
return this.tabs[i];
}
return null;

View File

@ -123,6 +123,12 @@ LoginManagerPrompter.prototype = {
},
setE10sData : function (aBrowser) {
// XXX Implement me!
throw new Error("Not Yet Implemented");
},
/*
* promptToSavePassword
*

View File

@ -108,6 +108,9 @@ LoginManagerPrompter.prototype = {
this.log("===== initialized =====");
},
setE10sData : function (aBrowser) {
throw new Error("This should be filled in when Android is multiprocess");
},
/*
* promptToSavePassword

View File

@ -541,13 +541,17 @@ var LoginManagerContent = {
value: oldPasswordField.value } :
null;
// Make sure to pass the opener's top in case it was in a frame.
let opener = win.opener ? win.opener.top : null;
let messageManager = messageManagerFromWindow(win);
messageManager.sendAsyncMessage("RemoteLogins:onFormSubmit",
{ hostname: hostname,
formSubmitURL: formSubmitURL,
usernameField: mockUsername,
newPasswordField: mockPassword,
oldPasswordField: mockOldPassword });
oldPasswordField: mockOldPassword },
{ openerWin: opener });
},
/*

View File

@ -69,7 +69,6 @@ var LoginManagerParent = {
receiveMessage: function (msg) {
let data = msg.data;
switch (msg.name) {
case "RemoteLogins:findLogins": {
// TODO Verify msg.target's principals against the formOrigin?
@ -88,6 +87,7 @@ var LoginManagerParent = {
data.usernameField,
data.newPasswordField,
data.oldPasswordField,
msg.objects.openerWin,
msg.target);
break;
}
@ -203,7 +203,7 @@ var LoginManagerParent = {
onFormSubmit: function(hostname, formSubmitURL,
usernameField, newPasswordField,
oldPasswordField,
oldPasswordField, opener,
target) {
function getPrompter() {
var prompterSvc = Cc["@mozilla.org/login-manager/prompter;1"].
@ -216,6 +216,8 @@ var LoginManagerParent = {
prompterSvc.init(target.isRemoteBrowser ?
target.ownerDocument.defaultView :
target.contentWindow);
if (target.isRemoteBrowser)
prompterSvc.setE10sData({ browser: target, opener: opener });
return prompterSvc;
}

View File

@ -8,8 +8,7 @@
interface nsILoginInfo;
interface nsIDOMWindow;
[scriptable, uuid(68b3cb59-51b8-4c57-bd7f-b2ce955a593d)]
[scriptable, uuid(88b75787-a78c-43aa-bfe8-52c3248b8dfd)]
interface nsILoginManagerPrompter : nsISupports {
/**
* Initialize the prompter. Must be called before using other interfaces.
@ -22,6 +21,15 @@ interface nsILoginManagerPrompter : nsISupports {
*/
void init(in nsIDOMWindow aWindow);
/**
* If the caller knows which browser this prompter is being created for,
* they can call this function to avoid having to calculate it from the
* window passed to init.
*
* @param aBrowser the <browser> to use for this prompter.
*/
void setE10sData(in jsval aData);
/**
* Ask the user if they want to save a login (Yes, Never, Not Now)
*

View File

@ -1,3 +1,4 @@
/* vim: set ts=4 sts=4 sw=4 et tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -199,6 +200,8 @@ LoginManagerPrompter.prototype = {
_factory : null,
_window : null,
_browser : null,
_opener : null,
_debug : false, // mirrors signon.debug
__pwmgr : null, // Password Manager service
@ -702,12 +705,21 @@ LoginManagerPrompter.prototype = {
init : function (aWindow, aFactory) {
this._window = aWindow;
this._factory = aFactory || null;
this._browser = null;
this._opener = null;
var prefBranch = Services.prefs.getBranch("signon.");
this._debug = prefBranch.getBoolPref("debug");
this.log("===== initialized =====");
},
setE10sData : function (aData) {
if (!(this._window instanceof Ci.nsIDOMChromeWindow))
throw new Error("Unexpected call");
this._browser = aData.browser;
this._opener = aData.opener;
},
/*
* promptToSavePassword
@ -823,10 +835,7 @@ LoginManagerPrompter.prototype = {
}
];
var notifyWin = this._getNotifyWindow();
var chromeWin = this._getChromeWindow(notifyWin).wrappedJSObject;
var browser = chromeWin.gBrowser.
getBrowserForDocument(notifyWin.top.document);
var { browser } = this._getNotifyWindow();
aNotifyObj.show(browser, "password-save", notificationText,
"password-notification-icon", mainAction,
@ -1021,10 +1030,7 @@ LoginManagerPrompter.prototype = {
}
};
var notifyWin = this._getNotifyWindow();
var chromeWin = this._getChromeWindow(notifyWin).wrappedJSObject;
var browser = chromeWin.gBrowser.
getBrowserForDocument(notifyWin.top.document);
var { browser } = this._getNotifyWindow();
aNotifyObj.show(browser, "password-change", notificationText,
"password-notification-icon", mainAction,
@ -1165,6 +1171,9 @@ LoginManagerPrompter.prototype = {
* Given a content DOM window, returns the chrome window it's in.
*/
_getChromeWindow: function (aWindow) {
// In e10s, aWindow may already be a chrome window.
if (aWindow instanceof Ci.nsIDOMChromeWindow)
return aWindow;
var chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
@ -1181,33 +1190,61 @@ LoginManagerPrompter.prototype = {
try {
// Get topmost window, in case we're in a frame.
var notifyWin = this._window.top;
var isE10s = (notifyWin instanceof Ci.nsIDOMChromeWindow);
var useOpener = false;
// Some sites pop up a temporary login window, when disappears
// Some sites pop up a temporary login window, which disappears
// upon submission of credentials. We want to put the notification
// bar in the opener window if this seems to be happening.
if (notifyWin.opener) {
var chromeDoc = this._getChromeWindow(notifyWin).
document.documentElement;
var webnav = notifyWin.
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIWebNavigation);
var hasHistory;
if (isE10s) {
if (!this._browser)
throw new Error("Expected a browser in e10s");
hasHistory = this._browser.canGoBack;
} else {
var webnav = notifyWin.
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIWebNavigation);
hasHistory = webnav.sessionHistory.count > 1;
}
// Check to see if the current window was opened with chrome
// disabled, and if so use the opener window. But if the window
// has been used to visit other pages (ie, has a history),
// assume it'll stick around and *don't* use the opener.
if (chromeDoc.getAttribute("chromehidden") &&
webnav.sessionHistory.count == 1) {
if (chromeDoc.getAttribute("chromehidden") && !hasHistory) {
this.log("Using opener window for notification bar.");
notifyWin = notifyWin.opener;
useOpener = true;
}
}
return notifyWin;
let browser;
if (useOpener && isE10s) {
// In e10s, we have to reconstruct the opener browser from
// the CPOW passed in the message (and then passed to us in
// setE10sData).
// NB: notifyWin is now the chrome window for the opening
// window.
browser = notifyWin.gBrowser.getBrowserForContentWindow(this._opener);
} else if (isE10s) {
browser = this._browser;
} else {
var chromeWin = this._getChromeWindow(notifyWin).wrappedJSObject;
browser = chromeWin.gBrowser
.getBrowserForDocument(notifyWin.top.document);
}
return { notifyWin: notifyWin, browser: browser };
} catch (e) {
// If any errors happen, just assume no notification box.
this.log("Unable to get notify window");
this.log("Unable to get notify window: " + e.fileName + ":" + e.lineNumber + ": " + e.message);
return null;
}
},
@ -1223,7 +1260,7 @@ LoginManagerPrompter.prototype = {
let popupNote = null;
try {
let notifyWin = this._getNotifyWindow();
let { notifyWin } = this._getNotifyWindow();
// Get the chrome window for the content window we're using.
// .wrappedJSObject needed here -- see bug 422974 comment 5.
@ -1248,7 +1285,7 @@ LoginManagerPrompter.prototype = {
let notifyBox = null;
try {
let notifyWin = this._getNotifyWindow();
let { notifyWin } = this._getNotifyWindow();
// Get the chrome window for the content window we're using.
// .wrappedJSObject needed here -- see bug 422974 comment 5.