Revision control
Copy as Markdown
Other Tools
/* 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
/**
* Remote content must stay hard-blocked for S/MIME encrypted messages, which do
* integrity-protected OpenPGP mail, an S/MIME encrypted message never gets the
* remote-content override.
*
* The test message (data/alice.remoteimage.env.eml) is an S/MIME enveloped HTML
* message with a remote <img> inside the encrypted body; it is generated by
* NSS's tests/smime/smime.sh and copied here by
* mailnews/test/data/smime/local-gen.sh.
*
* The message is viewed in a real folder (not opened from file) so it is
* registered with the encrypted-URI service exactly as in normal use.
*/
"use strict";
const {
assert_selected_and_displayed,
be_in_folder,
create_folder,
get_about_message,
select_click_row,
} = ChromeUtils.importESModule(
);
const { get_notification, wait_for_notification_to_show } =
ChromeUtils.importESModule(
);
const { SmimeUtils } = ChromeUtils.importESModule(
);
const NOTIFICATION_BOX = "mail-notification-top";
const NOTIFICATION_VALUE = "remoteContent";
const DISABLE_PREF = "mailnews.message_display.disable_remote_image";
let folder;
let gMsgNo = 0;
add_setup(async function () {
SmimeUtils.ensureNSS();
SmimeUtils.loadPEMCertificate(
new FileUtils.File(getTestFilePath("data/TestCA.pem")),
Ci.nsIX509Cert.CA_CERT
);
SmimeUtils.loadCertificateAndKey(
new FileUtils.File(getTestFilePath("data/Bob.p12")),
"nss"
);
folder = await create_folder("SMIMERemoteContent");
registerCleanupFunction(async () => {
// A later test loading the same certificates would block on a
// confirmation prompt.
await SmimeUtils.removeCertificates(["NSS Test CA (RSA)", "Bob"]);
});
});
async function addAndSelect(eml) {
const source = await IOUtils.readUTF8(getTestFilePath(`data/${eml}`));
folder.QueryInterface(Ci.nsIMsgLocalMailFolder);
folder.gettingNewMessages = true;
folder.addMessage(
"X-Mozilla-Status: 0001\r\nX-Mozilla-Status2: 00000000\r\n" + source
);
folder.gettingNewMessages = false;
gMsgNo++;
await be_in_folder(folder);
await select_click_row(gMsgNo - 1);
await assert_selected_and_displayed(gMsgNo - 1);
}
function messagePaneDoc() {
return get_about_message().getMessagePaneBrowser().contentDocument;
}
// Assert an S/MIME encrypted message decrypts and renders, but its remote image
// stays blocked (with remote content globally enabled) and no override is
// offered (with remote content blocked).
async function assertSmimeBlocked(eml) {
await SpecialPowers.pushPrefEnv({
set: [[DISABLE_PREF, false]],
});
await addAndSelect(eml);
const doc = messagePaneDoc();
Assert.ok(
doc.documentElement.textContent.includes(
"This is a test message from Alice to Bob."
),
`${eml}: S/MIME message was decrypted and rendered`
);
// A blocked image never loads, so once layout has ticked naturalWidth stays 0.
await new Promise(resolve => window.requestAnimationFrame(resolve));
const img = doc.getElementById("testelement");
Assert.ok(img, `${eml}: remote image element present in decrypted body`);
Assert.equal(
img.naturalWidth,
0,
`${eml}: S/MIME remote image stays blocked even with remote content enabled`
);
await SpecialPowers.pushPrefEnv({
set: [[DISABLE_PREF, true]],
});
await addAndSelect(eml);
const aboutMessage = get_about_message();
await wait_for_notification_to_show(
aboutMessage,
NOTIFICATION_BOX,
NOTIFICATION_VALUE
);
const notification = get_notification(
aboutMessage,
NOTIFICATION_BOX,
NOTIFICATION_VALUE
);
const buttons = notification.buttonContainer.querySelectorAll(
"button, toolbarbutton"
);
Assert.equal(buttons.length, 0, `${eml}: no remote-content override offered`);
}
add_task(async function test_smime_encrypted_blocked() {
// A plain S/MIME enveloped message with remote content stays blocked, with no
// override (invariant #5).
await assertSmimeBlocked("alice.remoteimage.env.eml");
});
add_task(async function test_pgp_sig_wrapping_smime_blocked() {
// A top-level OpenPGP signature wrapping an inner S/MIME encrypted part must
// stay blocked: S/MIME is never integrity protected, so the signature-wrapper
// not surface this exotic nesting at the top level, so the inner content is
// not even rendered -- also a safe outcome. Either way, no remote content may
// load, even with remote content globally enabled.
await SpecialPowers.pushPrefEnv({
set: [[DISABLE_PREF, false]],
});
await addAndSelect("pgp-sig-wrapping-smime-enc.eml");
await new Promise(resolve => window.requestAnimationFrame(resolve));
const img = messagePaneDoc().getElementById("testelement");
Assert.ok(
!img || !img.complete || img.naturalWidth === 0,
"outer-PGP-sig / inner-S/MIME: remote image does not load"
);
await SpecialPowers.pushPrefEnv({
set: [[DISABLE_PREF, true]],
});
});