Bug 1676216 - Use login storage for HTTP auth on Android r=dimi,owlish
This commit allows Android to use the login storage for HTTP auth by migrating some common toolkit code to promptUsernameAndPassword and promptPassword which use the login storage. Differential Revision: https://phabricator.services.mozilla.com/D122508
This commit is contained in:
@@ -68,6 +68,12 @@ class LoginStorageDelegate {
|
||||
GeckoViewAutocomplete.onLoginSave(selectedLogin);
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
dismiss() {
|
||||
prompt.dismiss();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
promptToChangePassword(
|
||||
@@ -105,6 +111,12 @@ class LoginStorageDelegate {
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
dismiss() {
|
||||
prompt.dismiss();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
promptToChangePasswordWithUsernames(aBrowser, aLogins, aNewLogin) {
|
||||
|
||||
@@ -7,6 +7,8 @@ import org.mozilla.geckoview.GeckoSession.NavigationDelegate
|
||||
import org.mozilla.geckoview.GeckoSession.NavigationDelegate.LoadRequest
|
||||
import org.mozilla.geckoview.GeckoSession.ProgressDelegate
|
||||
import org.mozilla.geckoview.GeckoSession.PromptDelegate
|
||||
import org.mozilla.geckoview.GeckoSession.PromptDelegate.AuthPrompt
|
||||
import org.mozilla.geckoview.GeckoSession.PromptDelegate.PromptResponse
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
|
||||
|
||||
@@ -17,6 +19,7 @@ import org.junit.Assert
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.geckoview.Autocomplete
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
@@ -103,6 +106,88 @@ class PromptDelegateTest : BaseSessionTest() {
|
||||
})
|
||||
}
|
||||
|
||||
// This test checks that saved logins are returned to the app when calling onAuthPrompt
|
||||
@Test fun loginStorageHttpAuthWithPassword() {
|
||||
mainSession.loadTestPath("/basic-auth/foo/bar")
|
||||
sessionRule.delegateDuringNextWait(object : Autocomplete.StorageDelegate {
|
||||
@AssertCalled
|
||||
override fun onLoginFetch(domain: String): GeckoResult<Array<Autocomplete.LoginEntry>>? {
|
||||
return GeckoResult.fromValue(arrayOf(
|
||||
Autocomplete.LoginEntry.Builder()
|
||||
.origin(GeckoSessionTestRule.TEST_ENDPOINT)
|
||||
.formActionOrigin(GeckoSessionTestRule.TEST_ENDPOINT)
|
||||
.httpRealm("Fake Realm")
|
||||
.username("test-username")
|
||||
.password("test-password")
|
||||
.formActionOrigin(null)
|
||||
.guid("test-guid")
|
||||
.build()
|
||||
));
|
||||
}
|
||||
})
|
||||
sessionRule.waitUntilCalled(object : PromptDelegate, Autocomplete.StorageDelegate {
|
||||
@AssertCalled
|
||||
override fun onAuthPrompt(session: GeckoSession, prompt: AuthPrompt): GeckoResult<PromptResponse>? {
|
||||
assertThat("Saved login should appear here",
|
||||
prompt.authOptions.username, equalTo("test-username"))
|
||||
assertThat("Saved login should appear here",
|
||||
prompt.authOptions.password, equalTo("test-password"))
|
||||
return null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// This test checks that we store login information submitted through HTTP basic auth
|
||||
// This also tests that the login save prompt gets automatically dismissed if
|
||||
// the login information is incorrect.
|
||||
@Test fun loginStorageHttpAuth() {
|
||||
sessionRule.setPrefsUntilTestEnd(mapOf(
|
||||
"signon.rememberSignons" to true))
|
||||
val result = GeckoResult<PromptDelegate.BasePrompt>()
|
||||
val promptInstanceDelegate = object : PromptDelegate.PromptInstanceDelegate {
|
||||
var prompt: PromptDelegate.BasePrompt? = null
|
||||
override fun onPromptDismiss(prompt: PromptDelegate.BasePrompt) {
|
||||
result.complete(prompt)
|
||||
}
|
||||
}
|
||||
|
||||
sessionRule.delegateUntilTestEnd(object : PromptDelegate, Autocomplete.StorageDelegate {
|
||||
@AssertCalled
|
||||
override fun onAuthPrompt(session: GeckoSession, prompt: AuthPrompt): GeckoResult<PromptResponse>? {
|
||||
return GeckoResult.fromValue(prompt.confirm("foo", "bar"));
|
||||
}
|
||||
|
||||
@AssertCalled
|
||||
override fun onLoginFetch(domain: String): GeckoResult<Array<Autocomplete.LoginEntry>>? {
|
||||
return GeckoResult.fromValue(arrayOf());
|
||||
}
|
||||
|
||||
@AssertCalled
|
||||
override fun onLoginSave(
|
||||
session: GeckoSession,
|
||||
request: PromptDelegate.AutocompleteRequest<Autocomplete.LoginSaveOption>
|
||||
): GeckoResult<PromptResponse>? {
|
||||
val authInfo = request.options[0].value
|
||||
assertThat("auth matches", authInfo.formActionOrigin, isEmptyOrNullString())
|
||||
assertThat("auth matches", authInfo.httpRealm, equalTo("Fake Realm"))
|
||||
assertThat("auth matches", authInfo.origin, equalTo(GeckoSessionTestRule.TEST_ENDPOINT))
|
||||
assertThat("auth matches", authInfo.username, equalTo("foo"))
|
||||
assertThat("auth matches", authInfo.password, equalTo("bar"))
|
||||
promptInstanceDelegate.prompt = request
|
||||
request.setDelegate(promptInstanceDelegate)
|
||||
return GeckoResult()
|
||||
}
|
||||
})
|
||||
|
||||
mainSession.loadTestPath("/basic-auth/foo/bar")
|
||||
|
||||
// The server we try to hit will always reject the login so we should
|
||||
// get a request to reauth which should dismiss the prompt
|
||||
val actualPrompt = sessionRule.waitForResult(result)
|
||||
|
||||
assertThat("Prompt object should match", actualPrompt, equalTo(promptInstanceDelegate.prompt))
|
||||
}
|
||||
|
||||
@Test fun dismissAuthTest() {
|
||||
sessionRule.delegateUntilTestEnd(object : PromptDelegate {
|
||||
@AssertCalled(count = 2)
|
||||
|
||||
@@ -13,6 +13,13 @@ const { PromptUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/SharedPromptUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"gPrompterService",
|
||||
"@mozilla.org/login-manager/prompter;1",
|
||||
Ci.nsILoginManagerPrompter
|
||||
);
|
||||
|
||||
/* eslint-disable block-scoped-var, no-var */
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
@@ -110,6 +117,7 @@ LoginManagerAuthPromptFactory.prototype = {
|
||||
// This enables us to consolidate auth prompts with the same browser and
|
||||
// hashkey (level, origin, realm).
|
||||
_pendingPrompts: new WeakMap(),
|
||||
_pendingSavePrompts: new WeakMap(),
|
||||
// We use a separate bucket for when we don't have a browser.
|
||||
// _noBrowser -> hashkey -> prompt
|
||||
_noBrowser: {},
|
||||
@@ -144,6 +152,15 @@ LoginManagerAuthPromptFactory.prototype = {
|
||||
return this._pendingPrompts.get(browser)?.get(hashKey);
|
||||
},
|
||||
|
||||
_dismissPendingSavePrompt(browser) {
|
||||
this._pendingSavePrompts.get(browser)?.dismiss();
|
||||
this._pendingSavePrompts.delete(browser);
|
||||
},
|
||||
|
||||
_setPendingSavePrompt(browser, prompt) {
|
||||
this._pendingSavePrompts.set(browser, prompt);
|
||||
},
|
||||
|
||||
_setPendingPrompt(prompt, hashKey) {
|
||||
let browser = prompt.prompter.browser || this._noBrowser;
|
||||
let hashToPrompt = this._pendingPrompts.get(browser);
|
||||
@@ -288,7 +305,6 @@ LoginManagerAuthPrompter.prototype = {
|
||||
_factory: null,
|
||||
_chromeWindow: null,
|
||||
_browser: null,
|
||||
_openerBrowser: null,
|
||||
|
||||
__strBundle: null, // String bundle for L10N
|
||||
get _strBundle() {
|
||||
@@ -618,13 +634,23 @@ LoginManagerAuthPrompter.prototype = {
|
||||
return [formattedOrigin, formattedOrigin + pathname, uri.username];
|
||||
},
|
||||
|
||||
_canPromptToSaveLogin() {
|
||||
// Cannot prompt if we don't have a window
|
||||
if (!this._chromeWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Can only prompt if we have the prompter service
|
||||
return !!gPrompterService;
|
||||
},
|
||||
|
||||
async promptAuthInternal(aChannel, aLevel, aAuthInfo) {
|
||||
var selectedLogin = null;
|
||||
var checkbox = { value: false };
|
||||
var checkboxLabel = null;
|
||||
var epicfail = false;
|
||||
var canAutologin = false;
|
||||
var notifyObj;
|
||||
var canPromptToSave = this._canPromptToSaveLogin();
|
||||
var foundLogins;
|
||||
let autofilled = false;
|
||||
|
||||
@@ -634,12 +660,12 @@ LoginManagerAuthPrompter.prototype = {
|
||||
// If the user submits a login but it fails, we need to remove the
|
||||
// notification prompt that was displayed. Conveniently, the user will
|
||||
// be prompted for authentication again, which brings us here.
|
||||
this._removeLoginNotifications();
|
||||
this._factory._dismissPendingSavePrompt(this._browser);
|
||||
|
||||
var [origin, httpRealm] = this._getAuthTarget(aChannel, aAuthInfo);
|
||||
|
||||
// Looks for existing logins to prefill the prompt with.
|
||||
foundLogins = LoginHelper.searchLoginsWithObject({
|
||||
foundLogins = await Services.logins.searchLoginsAsync({
|
||||
origin,
|
||||
httpRealm,
|
||||
schemeUpgrades: LoginHelper.schemeUpgrades,
|
||||
@@ -683,9 +709,9 @@ LoginManagerAuthPrompter.prototype = {
|
||||
canRememberLogin = false;
|
||||
}
|
||||
|
||||
// if checkboxLabel is null, the checkbox won't be shown at all.
|
||||
notifyObj = this._getPopupNote();
|
||||
if (canRememberLogin && !notifyObj) {
|
||||
if (canRememberLogin && !canPromptToSave) {
|
||||
// If we cannot prompt the user to save the login, we display
|
||||
// a checkbox on the auth prompt instead.
|
||||
checkboxLabel = this._getLocalizedString("rememberPassword");
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -752,7 +778,7 @@ LoginManagerAuthPrompter.prototype = {
|
||||
// determine if the login should be saved. If there isn't a
|
||||
// notification prompt, only save the login if the user set the
|
||||
// checkbox to do so.
|
||||
var rememberLogin = notifyObj ? canRememberLogin : checkbox.value;
|
||||
var rememberLogin = canPromptToSave ? canRememberLogin : checkbox.value;
|
||||
if (!ok || !rememberLogin || epicfail) {
|
||||
return ok;
|
||||
}
|
||||
@@ -782,17 +808,13 @@ LoginManagerAuthPrompter.prototype = {
|
||||
")"
|
||||
);
|
||||
|
||||
if (notifyObj) {
|
||||
if (canPromptToSave) {
|
||||
let promptBrowser = LoginHelper.getBrowserForPrompt(browser);
|
||||
LoginManagerPrompter._showLoginCaptureDoorhanger(
|
||||
let savePrompt = gPrompterService.promptToSavePassword(
|
||||
promptBrowser,
|
||||
newLogin,
|
||||
"password-save",
|
||||
{
|
||||
dismissed: this._inPrivateBrowsing,
|
||||
}
|
||||
newLogin
|
||||
);
|
||||
Services.obs.notifyObservers(newLogin, "passwordmgr-prompt-save");
|
||||
this._factory._setPendingSavePrompt(promptBrowser, savePrompt);
|
||||
} else {
|
||||
Services.logins.addLogin(newLogin);
|
||||
}
|
||||
@@ -806,8 +828,14 @@ LoginManagerAuthPrompter.prototype = {
|
||||
httpRealm +
|
||||
")"
|
||||
);
|
||||
if (notifyObj) {
|
||||
this._showChangeLoginNotification(browser, selectedLogin, newLogin);
|
||||
if (canPromptToSave) {
|
||||
let promptBrowser = LoginHelper.getBrowserForPrompt(browser);
|
||||
let savePrompt = gPrompterService.promptToChangePassword(
|
||||
promptBrowser,
|
||||
selectedLogin,
|
||||
newLogin
|
||||
);
|
||||
this._factory._setPendingSavePrompt(promptBrowser, savePrompt);
|
||||
} else {
|
||||
this._updateLogin(selectedLogin, newLogin);
|
||||
}
|
||||
@@ -858,7 +886,7 @@ LoginManagerAuthPrompter.prototype = {
|
||||
// If the user submits a login but it fails, we need to remove the
|
||||
// notification prompt that was displayed. Conveniently, the user will
|
||||
// be prompted for authentication again, which brings us here.
|
||||
this._removeLoginNotifications();
|
||||
this._factory._dismissPendingSavePrompt(this._browser);
|
||||
|
||||
cancelable = this._newAsyncPromptConsumer(aCallback, aContext);
|
||||
|
||||
@@ -920,7 +948,6 @@ LoginManagerAuthPrompter.prototype = {
|
||||
this._chromeWindow = win;
|
||||
this._browser = browser;
|
||||
}
|
||||
this._openerBrowser = null;
|
||||
this._factory = aFactory || null;
|
||||
|
||||
this.log("===== initialized =====");
|
||||
@@ -934,86 +961,6 @@ LoginManagerAuthPrompter.prototype = {
|
||||
return this._browser;
|
||||
},
|
||||
|
||||
set openerBrowser(aOpenerBrowser) {
|
||||
this._openerBrowser = aOpenerBrowser;
|
||||
},
|
||||
|
||||
_removeLoginNotifications() {
|
||||
var popupNote = this._getPopupNote();
|
||||
if (popupNote) {
|
||||
popupNote = popupNote.getNotification("password");
|
||||
}
|
||||
if (popupNote) {
|
||||
popupNote.remove();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the Change Password popup notification.
|
||||
*
|
||||
* @param aBrowser
|
||||
* The relevant <browser>.
|
||||
* @param aOldLogin
|
||||
* The stored login we want to update.
|
||||
* @param aNewLogin
|
||||
* The login object with the changes we want to make.
|
||||
* @param dismissed
|
||||
* A boolean indicating if the prompt should be automatically
|
||||
* dismissed on being shown.
|
||||
* @param notifySaved
|
||||
* A boolean value indicating whether the notification should indicate that
|
||||
* a login has been saved
|
||||
*/
|
||||
_showChangeLoginNotification(
|
||||
aBrowser,
|
||||
aOldLogin,
|
||||
aNewLogin,
|
||||
dismissed = false,
|
||||
notifySaved = false,
|
||||
autoSavedLoginGuid = ""
|
||||
) {
|
||||
let login = aOldLogin.clone();
|
||||
login.origin = aNewLogin.origin;
|
||||
login.formActionOrigin = aNewLogin.formActionOrigin;
|
||||
login.password = aNewLogin.password;
|
||||
login.username = aNewLogin.username;
|
||||
|
||||
let messageStringID;
|
||||
if (
|
||||
aOldLogin.username === "" &&
|
||||
login.username !== "" &&
|
||||
login.password == aOldLogin.password
|
||||
) {
|
||||
// If the saved password matches the password we're prompting with then we
|
||||
// are only prompting to let the user add a username since there was one in
|
||||
// the form. Change the message so the purpose of the prompt is clearer.
|
||||
messageStringID = "updateLoginMsgAddUsername";
|
||||
}
|
||||
|
||||
let promptBrowser = LoginHelper.getBrowserForPrompt(aBrowser);
|
||||
LoginManagerPrompter._showLoginCaptureDoorhanger(
|
||||
promptBrowser,
|
||||
login,
|
||||
"password-change",
|
||||
{
|
||||
dismissed,
|
||||
extraAttr: notifySaved ? "attention" : "",
|
||||
},
|
||||
{
|
||||
notifySaved,
|
||||
messageStringID,
|
||||
autoSavedLoginGuid,
|
||||
}
|
||||
);
|
||||
|
||||
let oldGUID = aOldLogin.QueryInterface(Ci.nsILoginMetaInfo).guid;
|
||||
Services.obs.notifyObservers(
|
||||
aNewLogin,
|
||||
"passwordmgr-prompt-change",
|
||||
oldGUID
|
||||
);
|
||||
},
|
||||
|
||||
/* ---------- Internal Methods ---------- */
|
||||
|
||||
_updateLogin(login, aNewLogin) {
|
||||
@@ -1053,48 +1000,6 @@ LoginManagerAuthPrompter.prototype = {
|
||||
return { win: chromeWin, browser };
|
||||
},
|
||||
|
||||
_getNotifyWindow() {
|
||||
if (this._openerBrowser) {
|
||||
let chromeDoc = this._chromeWindow.document.documentElement;
|
||||
|
||||
// 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") && !this._browser.canGoBack) {
|
||||
this.log("Using opener window for notification prompt.");
|
||||
return {
|
||||
win: this._openerBrowser.ownerGlobal,
|
||||
browser: this._openerBrowser,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
win: this._chromeWindow,
|
||||
browser: this._browser,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the popup notification to this prompter,
|
||||
* or null if there isn't one available.
|
||||
*/
|
||||
_getPopupNote() {
|
||||
let popupNote = null;
|
||||
|
||||
try {
|
||||
let { win: notifyWin } = this._getNotifyWindow();
|
||||
|
||||
// .wrappedJSObject needed here -- see bug 422974 comment 5.
|
||||
popupNote = notifyWin.wrappedJSObject.PopupNotifications;
|
||||
} catch (e) {
|
||||
this.log("Popup notifications not available on window");
|
||||
}
|
||||
|
||||
return popupNote;
|
||||
},
|
||||
|
||||
/**
|
||||
* The user might enter a login that isn't the one we prefilled, but
|
||||
* is the same as some other existing login. So, pick a login with a
|
||||
|
||||
@@ -138,7 +138,7 @@ class LoginManagerPrompter {
|
||||
) {
|
||||
log.debug("promptToSavePassword");
|
||||
let inPrivateBrowsing = PrivateBrowsingUtils.isBrowserPrivate(aBrowser);
|
||||
LoginManagerPrompter._showLoginCaptureDoorhanger(
|
||||
let notification = LoginManagerPrompter._showLoginCaptureDoorhanger(
|
||||
aBrowser,
|
||||
aLogin,
|
||||
"password-save",
|
||||
@@ -153,6 +153,13 @@ class LoginManagerPrompter {
|
||||
}
|
||||
);
|
||||
Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save");
|
||||
|
||||
return {
|
||||
dismiss() {
|
||||
let { PopupNotifications } = aBrowser.ownerGlobal.wrappedJSObject;
|
||||
PopupNotifications.remove(notification);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -786,6 +793,8 @@ class LoginManagerPrompter {
|
||||
log.debug("Showing the ConfirmationHint");
|
||||
anchor.ownerGlobal.ConfirmationHint.show(anchor, "passwordSaved");
|
||||
}
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -840,7 +849,7 @@ class LoginManagerPrompter {
|
||||
messageStringID = "updateLoginMsgAddUsername2";
|
||||
}
|
||||
|
||||
LoginManagerPrompter._showLoginCaptureDoorhanger(
|
||||
let notification = LoginManagerPrompter._showLoginCaptureDoorhanger(
|
||||
aBrowser,
|
||||
login,
|
||||
"password-change",
|
||||
@@ -863,6 +872,13 @@ class LoginManagerPrompter {
|
||||
"passwordmgr-prompt-change",
|
||||
oldGUID
|
||||
);
|
||||
|
||||
return {
|
||||
dismiss() {
|
||||
let { PopupNotifications } = aBrowser.ownerGlobal.wrappedJSObject;
|
||||
PopupNotifications.remove(notification);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@ XPIDL_SOURCES += [
|
||||
"nsILoginManagerPrompter.idl",
|
||||
"nsILoginManagerStorage.idl",
|
||||
"nsILoginMetaInfo.idl",
|
||||
"nsIPromptInstance.idl",
|
||||
]
|
||||
|
||||
XPIDL_MODULE = "loginmgr"
|
||||
|
||||
@@ -36,13 +36,6 @@ interface nsILoginManagerAuthPrompter : nsISupports {
|
||||
* This is required if the init function received a chrome window as argument.
|
||||
*/
|
||||
attribute Element browser;
|
||||
|
||||
/**
|
||||
* The opener browser that was used to open the window passed to init.
|
||||
* The opener can be used to determine in which window the prompt
|
||||
* should be shown.
|
||||
*/
|
||||
attribute Element openerBrowser;
|
||||
};
|
||||
%{C++
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIPromptInstance.idl"
|
||||
|
||||
interface nsILoginInfo;
|
||||
interface nsIDOMWindow;
|
||||
@@ -32,12 +33,13 @@ interface nsILoginManagerPrompter : nsISupports {
|
||||
* Contains values from anything that we think, but are not sure, might be
|
||||
* a username or password. Has two properties, 'usernames' and 'passwords'.
|
||||
*/
|
||||
void promptToSavePassword(in Element aBrowser,
|
||||
in nsILoginInfo aLogin,
|
||||
[optional] in boolean dismissed,
|
||||
[optional] in boolean notifySaved,
|
||||
[optional] in AString autoFilledLoginGuid,
|
||||
[optional] in jsval possibleValues);
|
||||
nsIPromptInstance promptToSavePassword(
|
||||
in Element aBrowser,
|
||||
in nsILoginInfo aLogin,
|
||||
[optional] in boolean dismissed,
|
||||
[optional] in boolean notifySaved,
|
||||
[optional] in AString autoFilledLoginGuid,
|
||||
[optional] in jsval possibleValues);
|
||||
|
||||
/**
|
||||
* Ask the user if they want to change a login's password or username.
|
||||
@@ -61,14 +63,15 @@ interface nsILoginManagerPrompter : nsISupports {
|
||||
* Contains values from anything that we think, but are not sure, might be
|
||||
* a username or password. Has two properties, 'usernames' and 'passwords'.
|
||||
*/
|
||||
void promptToChangePassword(in Element aBrowser,
|
||||
in nsILoginInfo aOldLogin,
|
||||
in nsILoginInfo aNewLogin,
|
||||
[optional] in boolean dismissed,
|
||||
[optional] in boolean notifySaved,
|
||||
[optional] in AString autoSavedLoginGuid,
|
||||
[optional] in AString autoFilledLoginGuid,
|
||||
[optional] in jsval possibleValues);
|
||||
nsIPromptInstance promptToChangePassword(
|
||||
in Element aBrowser,
|
||||
in nsILoginInfo aOldLogin,
|
||||
in nsILoginInfo aNewLogin,
|
||||
[optional] in boolean dismissed,
|
||||
[optional] in boolean notifySaved,
|
||||
[optional] in AString autoSavedLoginGuid,
|
||||
[optional] in AString autoFilledLoginGuid,
|
||||
[optional] in jsval possibleValues);
|
||||
|
||||
/**
|
||||
* Ask the user if they want to change the password for one of
|
||||
@@ -88,7 +91,7 @@ interface nsILoginManagerPrompter : nsISupports {
|
||||
* will be set (using the user's selection) before modifyLogin()
|
||||
* is called.
|
||||
*/
|
||||
void promptToChangePasswordWithUsernames(
|
||||
nsIPromptInstance promptToChangePasswordWithUsernames(
|
||||
in Element aBrowser,
|
||||
in Array<nsILoginInfo> logins,
|
||||
in nsILoginInfo aNewLogin);
|
||||
|
||||
17
toolkit/components/passwordmgr/nsIPromptInstance.idl
Normal file
17
toolkit/components/passwordmgr/nsIPromptInstance.idl
Normal file
@@ -0,0 +1,17 @@
|
||||
/* 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/. */
|
||||
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* An object representing a prompt or doorhanger.
|
||||
*/
|
||||
[scriptable, uuid(889842e9-052c-46c9-99f3-f4a426571e38)]
|
||||
interface nsIPromptInstance : nsISupports {
|
||||
/**
|
||||
* Dismiss this prompt (e.g. because it's not relevant anymore).
|
||||
*/
|
||||
void dismiss();
|
||||
};
|
||||
Reference in New Issue
Block a user