mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 1527828 - Remove insecure password field detection code for the address bar. r=sfoster
Differential Revision: https://phabricator.services.mozilla.com/D48975 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
2ebb010408
commit
87888ef235
@ -132,12 +132,8 @@ var gIdentityHandler = {
|
||||
},
|
||||
|
||||
get _hasInsecureLoginForms() {
|
||||
// checks if the page has been flagged for an insecure login. Also checks
|
||||
// if the pref to degrade the UI is set to true
|
||||
return (
|
||||
LoginManagerParent.hasInsecureLoginForms(gBrowser.selectedBrowser) &&
|
||||
Services.prefs.getBoolPref("security.insecure_password.ui.enabled")
|
||||
);
|
||||
// This function will be deleted in bug 1567827.
|
||||
return false;
|
||||
},
|
||||
|
||||
// smart getters
|
||||
|
@ -13,22 +13,13 @@ var { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
// BrowserChildGlobal
|
||||
var global = this;
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
ContentMetaHandler: "resource:///modules/ContentMetaHandler.jsm",
|
||||
LoginFormFactory: "resource://gre/modules/LoginFormFactory.jsm",
|
||||
LoginManagerContent: "resource://gre/modules/LoginManagerContent.jsm",
|
||||
InsecurePasswordUtils: "resource://gre/modules/InsecurePasswordUtils.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "LoginManagerContent", () => {
|
||||
let tmp = {};
|
||||
ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm", tmp);
|
||||
tmp.LoginManagerContent.setupEventListeners(global);
|
||||
return tmp.LoginManagerContent;
|
||||
});
|
||||
|
||||
// NOTE: Much of this logic is duplicated in BrowserCLH.js for Android.
|
||||
addMessageListener("PasswordManager:fillForm", function(message) {
|
||||
// intercept if ContextMenu.jsm had sent a plain object for remote targets
|
||||
|
@ -61,13 +61,6 @@ support-files =
|
||||
skip-if = (fission && debug) || (os == "linux" && bits == 64) # Bug 1577395
|
||||
[browser_identityPopup_custom_roots.js]
|
||||
[browser_identityPopup_focus.js]
|
||||
[browser_insecureLoginForms.js]
|
||||
support-files =
|
||||
insecure_opener.html
|
||||
!/toolkit/components/passwordmgr/test/browser/form_basic.html
|
||||
!/toolkit/components/passwordmgr/test/browser/insecure_test.html
|
||||
!/toolkit/components/passwordmgr/test/browser/insecure_test_subframe.html
|
||||
skip-if = fission
|
||||
[browser_mcb_redirect.js]
|
||||
tags = mcb
|
||||
support-files =
|
||||
|
@ -1,306 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Load directly from the browser-chrome support files of login tests.
|
||||
const TEST_URL_PATH = "/browser/toolkit/components/passwordmgr/test/browser/";
|
||||
|
||||
/**
|
||||
* Waits for the given number of occurrences of InsecureLoginFormsStateChange
|
||||
* on the given browser element.
|
||||
*/
|
||||
function waitForInsecureLoginFormsStateChange(browser, count) {
|
||||
return BrowserTestUtils.waitForEvent(
|
||||
browser,
|
||||
"InsecureLoginFormsStateChange",
|
||||
false,
|
||||
() => --count == 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the insecure login forms logic for the identity block.
|
||||
*/
|
||||
add_task(async function test_simple() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["security.insecure_password.ui.enabled", true],
|
||||
// By default, proxies don't apply to 127.0.0.1. We need them to for this test, though:
|
||||
["network.proxy.allow_hijacking_localhost", true],
|
||||
],
|
||||
});
|
||||
|
||||
for (let [origin, expectWarning] of [
|
||||
["http://example.com", true],
|
||||
["http://127.0.0.1", false],
|
||||
["https://example.com", false],
|
||||
]) {
|
||||
let testUrlPath = origin + TEST_URL_PATH;
|
||||
let tab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
testUrlPath + "form_basic.html"
|
||||
);
|
||||
let browser = tab.linkedBrowser;
|
||||
await Promise.all([
|
||||
BrowserTestUtils.switchTab(gBrowser, tab),
|
||||
BrowserTestUtils.browserLoaded(browser),
|
||||
// One event is triggered by pageshow and one by DOMFormHasPassword.
|
||||
waitForInsecureLoginFormsStateChange(browser, 2),
|
||||
]);
|
||||
|
||||
let { gIdentityHandler } = gBrowser.ownerGlobal;
|
||||
let promisePanelOpen = BrowserTestUtils.waitForEvent(
|
||||
gIdentityHandler._identityPopup,
|
||||
"popupshown"
|
||||
);
|
||||
gIdentityHandler._identityBox.click();
|
||||
await promisePanelOpen;
|
||||
|
||||
// Messages should be visible when the scheme is HTTP, and invisible when
|
||||
// the scheme is HTTPS.
|
||||
is(
|
||||
Array.prototype.every.call(
|
||||
document
|
||||
.getElementById("identity-popup-mainView")
|
||||
.querySelectorAll("[when-loginforms=insecure]"),
|
||||
element => !BrowserTestUtils.is_hidden(element)
|
||||
),
|
||||
expectWarning,
|
||||
"The relevant messages should be visible or hidden in the main view."
|
||||
);
|
||||
|
||||
let promiseViewShown = BrowserTestUtils.waitForEvent(
|
||||
gIdentityHandler._identityPopup,
|
||||
"ViewShown"
|
||||
);
|
||||
document.getElementById("identity-popup-security-expander").click();
|
||||
await promiseViewShown;
|
||||
|
||||
if (expectWarning) {
|
||||
ok(
|
||||
BrowserTestUtils.is_visible(document.getElementById("identity-icon")),
|
||||
"Identity icon should be visible"
|
||||
);
|
||||
let identityIconImage = gBrowser.ownerGlobal
|
||||
.getComputedStyle(document.getElementById("identity-icon"))
|
||||
.getPropertyValue("list-style-image");
|
||||
let securityViewBG = gBrowser.ownerGlobal
|
||||
.getComputedStyle(
|
||||
document
|
||||
.getElementById("identity-popup-securityView")
|
||||
.getElementsByClassName("identity-popup-security-connection")[0]
|
||||
)
|
||||
.getPropertyValue("background-image");
|
||||
let securityContentBG = gBrowser.ownerGlobal
|
||||
.getComputedStyle(
|
||||
document
|
||||
.getElementById("identity-popup-mainView")
|
||||
.getElementsByClassName("identity-popup-security-connection")[0]
|
||||
)
|
||||
.getPropertyValue("background-image");
|
||||
is(
|
||||
identityIconImage,
|
||||
'url("chrome://browser/skin/connection-mixed-active-loaded.svg")',
|
||||
"Using expected icon image in the identity block"
|
||||
);
|
||||
is(
|
||||
securityViewBG,
|
||||
'url("chrome://browser/skin/controlcenter/mcb-disabled.svg")',
|
||||
"Using expected icon image in the Control Center main view"
|
||||
);
|
||||
is(
|
||||
securityContentBG,
|
||||
'url("chrome://browser/skin/controlcenter/mcb-disabled.svg")',
|
||||
"Using expected icon image in the Control Center subview"
|
||||
);
|
||||
ok(
|
||||
!BrowserTestUtils.is_hidden(
|
||||
document.getElementById(
|
||||
"identity-popup-insecure-login-forms-learn-more"
|
||||
)
|
||||
),
|
||||
"The 'Learn more' link should be visible."
|
||||
);
|
||||
}
|
||||
|
||||
// Messages should be visible when the scheme is HTTP, and invisible when
|
||||
// the scheme is HTTPS.
|
||||
is(
|
||||
Array.prototype.every.call(
|
||||
document
|
||||
.getElementById("identity-popup-securityView")
|
||||
.querySelectorAll("[when-loginforms=insecure]"),
|
||||
element => !BrowserTestUtils.is_hidden(element)
|
||||
),
|
||||
expectWarning,
|
||||
"The relevant messages should be visible or hidden in the security view."
|
||||
);
|
||||
|
||||
if (gIdentityHandler._identityPopup.state != "closed") {
|
||||
let hideEvent = BrowserTestUtils.waitForEvent(
|
||||
gIdentityHandler._identityPopup,
|
||||
"popuphidden"
|
||||
);
|
||||
info("hiding popup");
|
||||
gIdentityHandler._identityPopup.hidePopup();
|
||||
await hideEvent;
|
||||
}
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that the insecure login forms logic does not regress mixed content
|
||||
* blocking messages when mixed active content is loaded.
|
||||
*/
|
||||
add_task(async function test_mixedcontent() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["security.mixed_content.block_active_content", false]],
|
||||
});
|
||||
|
||||
// Load the page with the subframe in a new tab.
|
||||
let testUrlPath = "://example.com" + TEST_URL_PATH;
|
||||
let tab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
"https" + testUrlPath + "insecure_test.html"
|
||||
);
|
||||
let browser = tab.linkedBrowser;
|
||||
await Promise.all([
|
||||
BrowserTestUtils.switchTab(gBrowser, tab),
|
||||
BrowserTestUtils.browserLoaded(browser),
|
||||
// Two events are triggered by pageshow and one by DOMFormHasPassword.
|
||||
waitForInsecureLoginFormsStateChange(browser, 3),
|
||||
]);
|
||||
|
||||
await assertMixedContentBlockingState(browser, {
|
||||
activeLoaded: true,
|
||||
activeBlocked: false,
|
||||
passiveLoaded: false,
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that insecure window.opener does not trigger a warning.
|
||||
*/
|
||||
add_task(async function test_ignoring_window_opener() {
|
||||
let path = getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"http://example.com"
|
||||
);
|
||||
let url = path + "insecure_opener.html";
|
||||
|
||||
await BrowserTestUtils.withNewTab(url, async function(browser) {
|
||||
// Clicking the link will spawn a new tab.
|
||||
let stateChangePromise;
|
||||
let tabOpenPromise = new Promise(resolve => {
|
||||
gBrowser.tabContainer.addEventListener(
|
||||
"TabOpen",
|
||||
event => {
|
||||
let tab = event.target;
|
||||
let newTabBrowser = tab.linkedBrowser;
|
||||
stateChangePromise = waitForInsecureLoginFormsStateChange(
|
||||
newTabBrowser,
|
||||
2
|
||||
);
|
||||
resolve(tab);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
|
||||
await ContentTask.spawn(browser, {}, function() {
|
||||
content.document.getElementById("link").click();
|
||||
});
|
||||
let tab = await tabOpenPromise;
|
||||
await stateChangePromise;
|
||||
|
||||
// Open the identity popup.
|
||||
let { gIdentityHandler } = gBrowser.ownerGlobal;
|
||||
let promisePanelOpen = BrowserTestUtils.waitForEvent(
|
||||
gIdentityHandler._identityPopup,
|
||||
"popupshown"
|
||||
);
|
||||
gIdentityHandler._identityBox.click();
|
||||
await promisePanelOpen;
|
||||
|
||||
ok(
|
||||
Array.prototype.every.call(
|
||||
document
|
||||
.getElementById("identity-popup-mainView")
|
||||
.querySelectorAll("[when-loginforms=insecure]"),
|
||||
element => BrowserTestUtils.is_hidden(element)
|
||||
),
|
||||
"All messages should be hidden in the main view."
|
||||
);
|
||||
|
||||
let promiseViewShown = BrowserTestUtils.waitForEvent(
|
||||
gIdentityHandler._identityPopup,
|
||||
"ViewShown"
|
||||
);
|
||||
document.getElementById("identity-popup-security-expander").click();
|
||||
await promiseViewShown;
|
||||
|
||||
ok(
|
||||
BrowserTestUtils.is_visible(document.getElementById("identity-icon")),
|
||||
"Identity icon is visible"
|
||||
);
|
||||
|
||||
// Assert that the identity indicators are still "secure".
|
||||
let identityIconImage = gBrowser.ownerGlobal
|
||||
.getComputedStyle(document.getElementById("identity-icon"))
|
||||
.getPropertyValue("list-style-image");
|
||||
let securityViewBG = gBrowser.ownerGlobal
|
||||
.getComputedStyle(
|
||||
document
|
||||
.getElementById("identity-popup-securityView")
|
||||
.getElementsByClassName("identity-popup-security-connection")[0]
|
||||
)
|
||||
.getPropertyValue("background-image");
|
||||
let securityContentBG = gBrowser.ownerGlobal
|
||||
.getComputedStyle(
|
||||
document
|
||||
.getElementById("identity-popup-mainView")
|
||||
.getElementsByClassName("identity-popup-security-connection")[0]
|
||||
)
|
||||
.getPropertyValue("background-image");
|
||||
is(
|
||||
identityIconImage,
|
||||
'url("chrome://browser/skin/connection-secure.svg")',
|
||||
"Using expected icon image in the identity block"
|
||||
);
|
||||
is(
|
||||
securityViewBG,
|
||||
'url("chrome://browser/skin/connection-secure.svg")',
|
||||
"Using expected icon image in the Control Center main view"
|
||||
);
|
||||
is(
|
||||
securityContentBG,
|
||||
'url("chrome://browser/skin/connection-secure.svg")',
|
||||
"Using expected icon image in the Control Center subview"
|
||||
);
|
||||
|
||||
ok(
|
||||
Array.prototype.every.call(
|
||||
document
|
||||
.getElementById("identity-popup-securityView")
|
||||
.querySelectorAll("[when-loginforms=insecure]"),
|
||||
element => BrowserTestUtils.is_hidden(element)
|
||||
),
|
||||
"All messages should be hidden in the security view."
|
||||
);
|
||||
|
||||
if (gIdentityHandler._identityPopup.state != "closed") {
|
||||
info("hiding popup");
|
||||
let hideEvent = BrowserTestUtils.waitForEvent(
|
||||
gIdentityHandler._identityPopup,
|
||||
"popuphidden"
|
||||
);
|
||||
gIdentityHandler._identityPopup.hidePopup();
|
||||
await hideEvent;
|
||||
}
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
});
|
@ -650,7 +650,6 @@ const listeners = {
|
||||
"PasswordManager:onGeneratedPasswordFilledOrEdited": ["LoginManagerParent"],
|
||||
"PasswordManager:autoCompleteLogins": ["LoginManagerParent"],
|
||||
"PasswordManager:removeLogin": ["LoginManagerParent"],
|
||||
"PasswordManager:insecureLoginFormPresent": ["LoginManagerParent"],
|
||||
"PasswordManager:OpenPreferences": ["LoginManagerParent"],
|
||||
// PLEASE KEEP THIS LIST IN SYNC WITH THE MOBILE LISTENERS IN BrowserCLH.js
|
||||
"rtcpeer:CancelRequest": ["webrtcUI"],
|
||||
|
@ -83,7 +83,6 @@ BrowserCLH.prototype = {
|
||||
"PasswordManager:onFormSubmit",
|
||||
"PasswordManager:autoCompleteLogins",
|
||||
"PasswordManager:removeLogin",
|
||||
"PasswordManager:insecureLoginFormPresent",
|
||||
// PLEASE KEEP THIS LIST IN SYNC WITH THE DESKTOP LIST IN
|
||||
// BrowserGlue.jsm
|
||||
],
|
||||
|
@ -616,12 +616,6 @@ this.LoginManagerContent = {
|
||||
);
|
||||
},
|
||||
|
||||
setupEventListeners(global) {
|
||||
global.addEventListener("pageshow", event => {
|
||||
this.onPageShow(event);
|
||||
});
|
||||
},
|
||||
|
||||
setupProgressListener(window) {
|
||||
if (!LoginHelper.formlessCaptureEnabled) {
|
||||
return;
|
||||
@ -838,8 +832,6 @@ this.LoginManagerContent = {
|
||||
*/
|
||||
_fetchLoginsFromParentAndFillForm(form) {
|
||||
let window = form.ownerDocument.defaultView;
|
||||
this._detectInsecureFormLikes(window.top);
|
||||
|
||||
let messageManager = window.docShell.messageManager;
|
||||
messageManager.sendAsyncMessage("LoginStats:LoginEncountered");
|
||||
|
||||
@ -852,11 +844,6 @@ this.LoginManagerContent = {
|
||||
.catch(Cu.reportError);
|
||||
},
|
||||
|
||||
onPageShow(event) {
|
||||
let window = event.target.ownerGlobal;
|
||||
this._detectInsecureFormLikes(window);
|
||||
},
|
||||
|
||||
/**
|
||||
* Maps all DOM content documents in this content process, including those in
|
||||
* frames, to the current state used by the Login Manager.
|
||||
@ -886,39 +873,6 @@ this.LoginManagerContent = {
|
||||
return loginFormState;
|
||||
},
|
||||
|
||||
/**
|
||||
* Compute whether there is an insecure login form on any frame of the current page, and
|
||||
* notify the parent process. This is used to control whether insecure password UI appears.
|
||||
*/
|
||||
_detectInsecureFormLikes(topWindow) {
|
||||
log("_detectInsecureFormLikes", topWindow.location.href);
|
||||
|
||||
// Returns true if this window or any subframes have insecure login forms.
|
||||
let hasInsecureLoginForms = thisWindow => {
|
||||
let doc = thisWindow.document;
|
||||
let rootElsWeakSet = LoginFormFactory.getRootElementsWeakSetForDocument(
|
||||
doc
|
||||
);
|
||||
let hasLoginForm = !!ChromeUtils.nondeterministicGetWeakSetKeys(
|
||||
rootElsWeakSet
|
||||
).filter(el => el.isConnected).length;
|
||||
return (
|
||||
(hasLoginForm && !thisWindow.isSecureContext) ||
|
||||
Array.prototype.some.call(thisWindow.frames, frame =>
|
||||
hasInsecureLoginForms(frame)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
let messageManager = topWindow.docShell.messageManager;
|
||||
messageManager.sendAsyncMessage(
|
||||
"PasswordManager:insecureLoginFormPresent",
|
||||
{
|
||||
hasInsecureLoginForms: hasInsecureLoginForms(topWindow),
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform a password fill upon user request coming from the parent process.
|
||||
* The fill will be in the form previously identified during page navigation.
|
||||
|
@ -169,11 +169,6 @@ this.LoginManagerParent = {
|
||||
break;
|
||||
}
|
||||
|
||||
case "PasswordManager:insecureLoginFormPresent": {
|
||||
this.setHasInsecureLoginForms(msg.target, data.hasInsecureLoginForms);
|
||||
break;
|
||||
}
|
||||
|
||||
case "PasswordManager:autoCompleteLogins": {
|
||||
this.doAutocompleteSearch(data, msg.target);
|
||||
break;
|
||||
@ -922,62 +917,6 @@ this.LoginManagerParent = {
|
||||
shouldAutoSaveLogin // notifySaved
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Maps all the <browser> elements for tabs in the parent process to the
|
||||
* current state used to display tab-specific UI.
|
||||
*
|
||||
* This mapping is not updated in case a web page is moved to a different
|
||||
* chrome window by the swapDocShells method. In this case, it is possible
|
||||
* that a UI update just requested for the login fill doorhanger and then
|
||||
* delayed by a few hundred milliseconds will be lost. Later requests would
|
||||
* use the new browser reference instead.
|
||||
*
|
||||
* Given that the case above is rare, and it would not cause any origin
|
||||
* mismatch at the time of filling because the origin is checked later in the
|
||||
* content process, this case is left unhandled.
|
||||
*/
|
||||
loginFormStateByBrowser: new WeakMap(),
|
||||
|
||||
/**
|
||||
* Retrieves a reference to the state object associated with the given
|
||||
* browser. This is initialized to an empty object.
|
||||
*/
|
||||
stateForBrowser(browser) {
|
||||
let loginFormState = this.loginFormStateByBrowser.get(browser);
|
||||
if (!loginFormState) {
|
||||
loginFormState = {};
|
||||
this.loginFormStateByBrowser.set(browser, loginFormState);
|
||||
}
|
||||
return loginFormState;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if the page currently loaded in the given browser element has
|
||||
* insecure login forms. This state may be updated asynchronously, in which
|
||||
* case a custom event named InsecureLoginFormsStateChange will be dispatched
|
||||
* on the browser element.
|
||||
*/
|
||||
hasInsecureLoginForms(browser) {
|
||||
return !!this.stateForBrowser(browser).hasInsecureLoginForms;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called to indicate whether an insecure password field is present so
|
||||
* insecure password UI can know when to show.
|
||||
*/
|
||||
setHasInsecureLoginForms(browser, hasInsecureLoginForms) {
|
||||
let state = this.stateForBrowser(browser);
|
||||
|
||||
// Update the data to use to the latest known values. Since messages are
|
||||
// processed in order, this will always be the latest version to use.
|
||||
state.hasInsecureLoginForms = hasInsecureLoginForms;
|
||||
|
||||
// Report the insecure login form state immediately.
|
||||
browser.dispatchEvent(
|
||||
new browser.ownerGlobal.CustomEvent("InsecureLoginFormsStateChange")
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
|
@ -10,10 +10,7 @@ support-files =
|
||||
form_cross_origin_secure_action.html
|
||||
form_cross_origin_insecure_action.html
|
||||
head.js
|
||||
insecure_test.html
|
||||
insecure_test_subframe.html
|
||||
multiple_forms.html
|
||||
streamConverter_content.sjs
|
||||
|
||||
[browser_autocomplete_footer.js]
|
||||
[browser_autocomplete_insecure_warning.js]
|
||||
@ -65,10 +62,6 @@ support-files =
|
||||
support-files =
|
||||
form_password_change.html
|
||||
[browser_generated_password_private_window.js]
|
||||
[browser_hasInsecureLoginForms.js]
|
||||
skip-if = fission || verify
|
||||
[browser_hasInsecureLoginForms_streamConverter.js]
|
||||
skip-if = fission
|
||||
[browser_http_autofill.js]
|
||||
fail-if = fission
|
||||
skip-if = fission || verify
|
||||
|
@ -1,106 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/LoginManagerParent.jsm", this);
|
||||
|
||||
const testUrlPath =
|
||||
"://example.com/browser/toolkit/components/passwordmgr/test/browser/";
|
||||
|
||||
/**
|
||||
* Waits for the given number of occurrences of InsecureLoginFormsStateChange
|
||||
* on the given browser element.
|
||||
*/
|
||||
function waitForInsecureLoginFormsStateChange(browser, count) {
|
||||
return BrowserTestUtils.waitForEvent(
|
||||
browser,
|
||||
"InsecureLoginFormsStateChange",
|
||||
false,
|
||||
() => --count == 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that hasInsecureLoginForms is true for a simple HTTP page and false
|
||||
* for a simple HTTPS page.
|
||||
*/
|
||||
add_task(async function test_simple() {
|
||||
for (let scheme of ["http", "https"]) {
|
||||
let tab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
scheme + testUrlPath + "form_basic.html"
|
||||
);
|
||||
let browser = tab.linkedBrowser;
|
||||
await Promise.all([
|
||||
BrowserTestUtils.switchTab(gBrowser, tab),
|
||||
BrowserTestUtils.browserLoaded(browser),
|
||||
// One event is triggered by pageshow and one by DOMFormHasPassword.
|
||||
waitForInsecureLoginFormsStateChange(browser, 2),
|
||||
]);
|
||||
|
||||
Assert.equal(
|
||||
LoginManagerParent.hasInsecureLoginForms(browser),
|
||||
scheme == "http"
|
||||
);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that hasInsecureLoginForms is true if a password field is present in
|
||||
* an HTTP page loaded as a subframe of a top-level HTTPS page, when mixed
|
||||
* active content blocking is disabled.
|
||||
*
|
||||
* When the subframe is navigated to an HTTPS page, hasInsecureLoginForms should
|
||||
* be set to false.
|
||||
*
|
||||
* Moving back in history should set hasInsecureLoginForms to true again.
|
||||
*/
|
||||
add_task(async function test_subframe_navigation() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["security.mixed_content.block_active_content", false]],
|
||||
});
|
||||
|
||||
// Load the page with the subframe in a new tab.
|
||||
let tab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
"https" + testUrlPath + "insecure_test.html"
|
||||
);
|
||||
let browser = tab.linkedBrowser;
|
||||
await Promise.all([
|
||||
BrowserTestUtils.switchTab(gBrowser, tab),
|
||||
BrowserTestUtils.browserLoaded(browser),
|
||||
// Two events are triggered by pageshow and one by DOMFormHasPassword.
|
||||
waitForInsecureLoginFormsStateChange(browser, 3),
|
||||
]);
|
||||
|
||||
Assert.ok(LoginManagerParent.hasInsecureLoginForms(browser));
|
||||
|
||||
// Navigate the subframe to a secure page.
|
||||
let promiseSubframeReady = Promise.all([
|
||||
BrowserTestUtils.browserLoaded(browser, true),
|
||||
// One event is triggered by pageshow and one by DOMFormHasPassword.
|
||||
waitForInsecureLoginFormsStateChange(browser, 2),
|
||||
]);
|
||||
await ContentTask.spawn(browser, null, async function() {
|
||||
content.document
|
||||
.getElementById("test-iframe")
|
||||
.contentDocument.getElementById("test-link")
|
||||
.click();
|
||||
});
|
||||
await promiseSubframeReady;
|
||||
|
||||
Assert.ok(!LoginManagerParent.hasInsecureLoginForms(browser));
|
||||
|
||||
// Navigate back to the insecure page. We only have to wait for the
|
||||
// InsecureLoginFormsStateChange event that is triggered by pageshow.
|
||||
let promise = waitForInsecureLoginFormsStateChange(browser, 1);
|
||||
await ContentTask.spawn(browser, null, async function() {
|
||||
content.document.getElementById("test-iframe").contentWindow.history.back();
|
||||
});
|
||||
await promise;
|
||||
|
||||
Assert.ok(LoginManagerParent.hasInsecureLoginForms(browser));
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
@ -1,115 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/LoginManagerParent.jsm", this);
|
||||
|
||||
function registerConverter() {
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
|
||||
ChromeUtils.import("resource://gre/modules/NetUtil.jsm", this);
|
||||
|
||||
/**
|
||||
* Converts the "test/content" MIME type, served by the test over HTTP, to an
|
||||
* HTML viewer page containing the "form_basic.html" code. The viewer is
|
||||
* served from a "resource:" URI while keeping the "resource:" principal.
|
||||
*/
|
||||
function TestStreamConverter() {}
|
||||
|
||||
TestStreamConverter.prototype = {
|
||||
classID: Components.ID("{5f01d6ef-c090-45a4-b3e5-940d64713eb7}"),
|
||||
contractID: "@mozilla.org/streamconv;1?from=test/content&to=*/*",
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsIRequestObserver,
|
||||
Ci.nsIStreamListener,
|
||||
Ci.nsIStreamConverter,
|
||||
]),
|
||||
|
||||
// nsIStreamConverter
|
||||
convert() {},
|
||||
|
||||
// nsIStreamConverter
|
||||
asyncConvertData(aFromType, aToType, aListener, aCtxt) {
|
||||
this.listener = aListener;
|
||||
},
|
||||
|
||||
// nsIRequestObserver
|
||||
onStartRequest(aRequest) {
|
||||
let channel = NetUtil.newChannel({
|
||||
uri: "resource://testing-common/form_basic.html",
|
||||
loadUsingSystemPrincipal: true,
|
||||
});
|
||||
channel.originalURI = aRequest.QueryInterface(Ci.nsIChannel).URI;
|
||||
channel.loadGroup = aRequest.loadGroup;
|
||||
channel.owner = Services.scriptSecurityManager.createContentPrincipal(
|
||||
channel.URI,
|
||||
{}
|
||||
);
|
||||
// In this test, we pass the new channel to the listener but don't fire a
|
||||
// redirect notification, even if it would be required. This keeps the
|
||||
// test code simpler and doesn't impact the principal check we're testing.
|
||||
channel.asyncOpen(this.listener);
|
||||
},
|
||||
|
||||
// nsIRequestObserver
|
||||
onStopRequest() {},
|
||||
|
||||
// nsIStreamListener
|
||||
onDataAvailable() {},
|
||||
};
|
||||
|
||||
let factory = XPCOMUtils._getFactory(TestStreamConverter);
|
||||
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.registerFactory(
|
||||
TestStreamConverter.prototype.classID,
|
||||
"",
|
||||
TestStreamConverter.prototype.contractID,
|
||||
factory
|
||||
);
|
||||
this.cleanupFunction = function() {
|
||||
registrar.unregisterFactory(TestStreamConverter.prototype.classID, factory);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the given number of occurrences of InsecureLoginFormsStateChange
|
||||
* on the given browser element.
|
||||
*/
|
||||
function waitForInsecureLoginFormsStateChange(browser, count) {
|
||||
return BrowserTestUtils.waitForEvent(
|
||||
browser,
|
||||
"InsecureLoginFormsStateChange",
|
||||
false,
|
||||
() => --count == 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that hasInsecureLoginForms is false for a viewer served internally
|
||||
* using a "resource:" URI.
|
||||
*/
|
||||
add_task(async function test_streamConverter() {
|
||||
let originalBrowser = gBrowser.selectedTab.linkedBrowser;
|
||||
|
||||
await ContentTask.spawn(originalBrowser, null, registerConverter);
|
||||
|
||||
let tab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
"http://example.com/browser/toolkit/components/" +
|
||||
"passwordmgr/test/browser/streamConverter_content.sjs",
|
||||
{ sameProcessAsFrameLoader: originalBrowser.frameLoader }
|
||||
);
|
||||
let browser = tab.linkedBrowser;
|
||||
await Promise.all([
|
||||
BrowserTestUtils.switchTab(gBrowser, tab),
|
||||
BrowserTestUtils.browserLoaded(browser),
|
||||
// One event is triggered by pageshow and one by DOMFormHasPassword.
|
||||
waitForInsecureLoginFormsStateChange(browser, 2),
|
||||
]);
|
||||
|
||||
Assert.ok(!LoginManagerParent.hasInsecureLoginForms(browser));
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
await ContentTask.spawn(originalBrowser, null, async function() {
|
||||
this.cleanupFunction();
|
||||
});
|
||||
});
|
@ -1,6 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.setHeader("Content-Type", "test/content", false);
|
||||
}
|
Loading…
Reference in New Issue
Block a user