Source code
Revision control
Copy as Markdown
Other Tools
function openIdentityPopup() {
gIdentityHandler._initializePopup();
let mainView = document.getElementById("identity-popup-mainView");
let viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
gIdentityHandler._identityIconBox.click();
return viewShown;
}
function openPermissionPopup() {
gPermissionPanel._initializePopup();
let mainView = document.getElementById("permission-popup-mainView");
let viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
gPermissionPanel.openPopup();
return viewShown;
}
function getIdentityMode(aWindow = window) {
return aWindow.document.getElementById("identity-box").className;
}
/**
* Waits for a load (or custom) event to finish in a given tab. If provided
* load an uri into the tab.
*
* @param tab
* The tab to load into.
* @param [optional] url
* The url to load, or the current url.
* @return {Promise} resolved when the event is handled.
* @resolves to the received event
* @rejects if a valid load event is not received within a meaningful interval
*/
function promiseTabLoadEvent(tab, url) {
info("Wait tab event: load");
function handle(loadedUrl) {
if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) {
info(`Skipping spurious load event for ${loadedUrl}`);
return false;
}
info("Tab event received: load");
return true;
}
let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
if (url) {
BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, url);
}
return loaded;
}
// Compares the security state of the page with what is expected
function isSecurityState(browser, expectedState) {
let ui = browser.securityUI;
if (!ui) {
ok(false, "No security UI to get the security state");
return;
}
const wpl = Ci.nsIWebProgressListener;
// determine the security state
let isSecure = ui.state & wpl.STATE_IS_SECURE;
let isBroken = ui.state & wpl.STATE_IS_BROKEN;
let isInsecure = ui.state & wpl.STATE_IS_INSECURE;
let actualState;
if (isSecure && !(isBroken || isInsecure)) {
actualState = "secure";
} else if (isBroken && !(isSecure || isInsecure)) {
actualState = "broken";
} else if (isInsecure && !(isSecure || isBroken)) {
actualState = "insecure";
} else {
actualState = "unknown";
}
is(
expectedState,
actualState,
"Expected state " +
expectedState +
" and the actual state is " +
actualState +
"."
);
}
/**
* Test the state of the identity box and control center to make
* sure they are correctly showing the expected mixed content states.
*
* @note The checks are done synchronously, but new code should wait on the
* returned Promise object to ensure the identity panel has closed.
*
* @param tabbrowser
* @param Object states
* MUST include the following properties:
* {
* activeLoaded: true|false,
* activeBlocked: true|false,
* passiveLoaded: true|false,
* }
*
* @return {Promise}
* @resolves When the operation has finished and the identity panel has closed.
*/
async function assertMixedContentBlockingState(tabbrowser, states = {}) {
if (
!tabbrowser ||
!("activeLoaded" in states) ||
!("activeBlocked" in states) ||
!("passiveLoaded" in states)
) {
throw new Error(
"assertMixedContentBlockingState requires a browser and a states object"
);
}
let { passiveLoaded, activeLoaded, activeBlocked } = states;
let { gIdentityHandler } = tabbrowser.ownerGlobal;
let doc = tabbrowser.ownerDocument;
let identityBox = gIdentityHandler._identityBox;
let classList = identityBox.classList;
let identityIcon = doc.getElementById("identity-icon");
let identityIconImage = tabbrowser.ownerGlobal
.getComputedStyle(identityIcon)
.getPropertyValue("list-style-image");
let stateSecure =
gIdentityHandler._state & Ci.nsIWebProgressListener.STATE_IS_SECURE;
let stateBroken =
gIdentityHandler._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN;
let stateInsecure =
gIdentityHandler._state & Ci.nsIWebProgressListener.STATE_IS_INSECURE;
let stateActiveBlocked =
gIdentityHandler._state &
Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT;
let stateActiveLoaded =
gIdentityHandler._state &
Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT;
let statePassiveLoaded =
gIdentityHandler._state &
Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT;
is(
activeBlocked,
!!stateActiveBlocked,
"Expected state for activeBlocked matches UI state"
);
is(
activeLoaded,
!!stateActiveLoaded,
"Expected state for activeLoaded matches UI state"
);
is(
passiveLoaded,
!!statePassiveLoaded,
"Expected state for passiveLoaded matches UI state"
);
if (stateInsecure) {
// HTTP request, there should be a broken padlock shown always.
ok(classList.contains("notSecure"), "notSecure on HTTP page");
ok(
!BrowserTestUtils.isHidden(identityIcon),
"information icon should be visible"
);
ok(!classList.contains("mixedActiveContent"), "No MCB icon on HTTP page");
ok(!classList.contains("mixedActiveBlocked"), "No MCB icon on HTTP page");
ok(!classList.contains("mixedDisplayContent"), "No MCB icon on HTTP page");
ok(
!classList.contains("mixedDisplayContentLoadedActiveBlocked"),
"No MCB icon on HTTP page"
);
} else {
// Make sure the identity box UI has the correct mixedcontent states and icons
is(
classList.contains("mixedActiveContent"),
activeLoaded,
"identityBox has expected class for activeLoaded"
);
is(
classList.contains("mixedActiveBlocked"),
activeBlocked && !passiveLoaded,
"identityBox has expected class for activeBlocked && !passiveLoaded"
);
is(
classList.contains("mixedDisplayContent"),
passiveLoaded && !(activeLoaded || activeBlocked),
"identityBox has expected class for passiveLoaded && !(activeLoaded || activeBlocked)"
);
is(
classList.contains("mixedDisplayContentLoadedActiveBlocked"),
passiveLoaded && activeBlocked,
"identityBox has expected class for passiveLoaded && activeBlocked"
);
ok(
!BrowserTestUtils.isHidden(identityIcon),
"information icon should be visible"
);
if (activeLoaded) {
is(
identityIconImage,
'url("chrome://global/skin/icons/security-broken.svg")',
"Using active loaded icon"
);
}
if (activeBlocked && !passiveLoaded) {
is(
identityIconImage,
'url("chrome://global/skin/icons/security.svg")',
"Using active blocked icon"
);
}
if (passiveLoaded && !(activeLoaded || activeBlocked)) {
is(
identityIconImage,
'url("chrome://global/skin/icons/security-warning.svg")',
"Using passive loaded icon"
);
}
if (passiveLoaded && activeBlocked) {
is(
identityIconImage,
'url("chrome://global/skin/icons/security-warning.svg")',
"Using active blocked and passive loaded icon"
);
}
}
// Make sure the identity popup has the correct mixedcontent states
let promisePanelOpen = BrowserTestUtils.waitForEvent(
tabbrowser.ownerGlobal,
"popupshown",
true,
event => event.target == gIdentityHandler._identityPopup
);
gIdentityHandler._identityIconBox.click();
await promisePanelOpen;
let popupAttr =
doc.getElementById("identity-popup").getAttribute("mixedcontent") || "";
let bodyAttr =
doc
.getElementById("identity-popup-securityView-extended-info")
.getAttribute("mixedcontent") || "";
is(
popupAttr.includes("active-loaded"),
activeLoaded,
"identity-popup has expected attr for activeLoaded"
);
is(
bodyAttr.includes("active-loaded"),
activeLoaded,
"securityView-body has expected attr for activeLoaded"
);
is(
popupAttr.includes("active-blocked"),
activeBlocked,
"identity-popup has expected attr for activeBlocked"
);
is(
bodyAttr.includes("active-blocked"),
activeBlocked,
"securityView-body has expected attr for activeBlocked"
);
is(
popupAttr.includes("passive-loaded"),
passiveLoaded,
"identity-popup has expected attr for passiveLoaded"
);
is(
bodyAttr.includes("passive-loaded"),
passiveLoaded,
"securityView-body has expected attr for passiveLoaded"
);
// Make sure the correct icon is visible in the Control Center.
// This logic is controlled with CSS, so this helps prevent regressions there.
let securityViewBG = tabbrowser.ownerGlobal
.getComputedStyle(
document
.getElementById("identity-popup-securityView")
.getElementsByClassName("identity-popup-security-connection")[0]
)
.getPropertyValue("list-style-image");
let securityContentBG = tabbrowser.ownerGlobal
.getComputedStyle(
document
.getElementById("identity-popup-mainView")
.getElementsByClassName("identity-popup-security-connection")[0]
)
.getPropertyValue("list-style-image");
if (stateInsecure) {
is(
securityViewBG,
'url("chrome://global/skin/icons/security-broken.svg")',
"CC using 'not secure' icon"
);
is(
securityContentBG,
'url("chrome://global/skin/icons/security-broken.svg")',
"CC using 'not secure' icon"
);
}
if (stateSecure) {
is(
securityViewBG,
'url("chrome://global/skin/icons/security.svg")',
"CC using secure icon"
);
is(
securityContentBG,
'url("chrome://global/skin/icons/security.svg")',
"CC using secure icon"
);
}
if (stateBroken) {
if (activeLoaded) {
is(
securityViewBG,
'url("chrome://browser/skin/controlcenter/mcb-disabled.svg")',
"CC using active loaded icon"
);
is(
securityContentBG,
'url("chrome://browser/skin/controlcenter/mcb-disabled.svg")',
"CC using active loaded icon"
);
} else if (activeBlocked || passiveLoaded) {
is(
securityViewBG,
'url("chrome://global/skin/icons/security-warning.svg")',
"CC using degraded icon"
);
is(
securityContentBG,
'url("chrome://global/skin/icons/security-warning.svg")',
"CC using degraded icon"
);
} else {
// There is a case here with weak ciphers, but no bc tests are handling this yet.
is(
securityViewBG,
'url("chrome://global/skin/icons/security.svg")',
"CC using degraded icon"
);
is(
securityContentBG,
'url("chrome://global/skin/icons/security.svg")',
"CC using degraded icon"
);
}
}
if (activeLoaded || activeBlocked || passiveLoaded) {
let promiseViewShown = BrowserTestUtils.waitForEvent(
gIdentityHandler._identityPopup,
"ViewShown"
);
doc.getElementById("identity-popup-security-button").click();
await promiseViewShown;
is(
Array.prototype.filter.call(
doc
.getElementById("identity-popup-securityView")
.querySelectorAll(".identity-popup-mcb-learn-more"),
element => !BrowserTestUtils.isHidden(element)
).length,
1,
"The 'Learn more' link should be visible once."
);
}
if (gIdentityHandler._identityPopup.state != "closed") {
let hideEvent = BrowserTestUtils.waitForEvent(
gIdentityHandler._identityPopup,
"popuphidden"
);
info("Hiding identity popup");
gIdentityHandler._identityPopup.hidePopup();
await hideEvent;
}
}
async function loadBadCertPage(url) {
let loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser);
BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, url);
await loaded;
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
content.document.getElementById("exceptionDialogButton").click();
});
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
}
// nsITLSServerSocket needs a certificate with a corresponding private key
// available. In mochitests, the certificate with the common name "Mochitest
// client" has such a key.
function getTestServerCertificate() {
const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
Ci.nsIX509CertDB
);
for (const cert of certDB.getCerts()) {
if (cert.commonName == "Mochitest client") {
return cert;
}
}
return null;
}