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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Tests that mailbox: URLs of .eml files only open the file when the channel
* is read, not when it's created, so that the content policy is consulted
* before the file is opened.
*/
const { NetUtil } = ChromeUtils.importESModule(
);
/**
* @param {string} path
* @returns {string} A mailbox: URL for the file at `path`.
*/
function mailboxURL(path) {
const fileURL = Services.io.newURI(PathUtils.toFileURI(path));
return `mailbox://${fileURL.pathQueryRef}?number=0`;
}
/**
* @param {string} path
* @returns {nsIChannel}
*/
function newChannel(path) {
return NetUtil.newChannel({
uri: mailboxURL(path),
loadUsingSystemPrincipal: true,
});
}
/**
* @param {nsIChannel} channel
* @returns {Promise<{status: nsresult, data: string}>}
*/
function readChannel(channel) {
return new Promise(resolve => {
try {
NetUtil.asyncFetch(channel, (stream, status) => {
resolve({
status,
data: Components.isSuccessCode(status)
? NetUtil.readInputStreamToString(stream, stream.available())
: "",
});
});
} catch (ex) {
resolve({ status: ex.result, data: "" });
}
});
}
add_task(async function test_missingFile() {
const path = PathUtils.join(PathUtils.tempDir, "missing.eml");
const channel = newChannel(path);
Assert.ok(channel, "creating a channel should not open the file");
const { status } = await readChannel(channel);
Assert.equal(
status,
Cr.NS_ERROR_FILE_NOT_FOUND,
"reading the channel should fail"
);
});
add_task(async function test_existingFile() {
const path = PathUtils.join(PathUtils.tempDir, "existing.eml");
await IOUtils.writeUTF8(
path,
"From: sender@example.com\r\nSubject: Deferred open\r\n\r\nBody\r\n"
);
registerCleanupFunction(() => IOUtils.remove(path));
const { status, data } = await readChannel(newChannel(path));
Assert.equal(status, Cr.NS_OK, "reading the channel should succeed");
Assert.stringContains(
data,
"Subject: Deferred open",
"the message should be read"
);
});
add_task(async function test_contentPolicyRejection() {
// Load the file as an image in another message, which the mail content
// policy rejects. The file doesn't exist, so the load would fail differently
// if the file was opened before the content policy was consulted.
const path = PathUtils.join(PathUtils.tempDir, "rejected.eml");
const messagePrincipal =
Services.scriptSecurityManager.createContentPrincipal(
Services.io.newURI(
mailboxURL(PathUtils.join(PathUtils.tempDir, "message.eml"))
),
{}
);
const channel = NetUtil.newChannel({
uri: mailboxURL(path),
loadingPrincipal: messagePrincipal,
securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT,
contentPolicyType: Ci.nsIContentPolicy.TYPE_IMAGE,
});
const { status } = await readChannel(channel);
Assert.equal(
status,
Cr.NS_ERROR_CONTENT_BLOCKED,
"the content policy should reject the load before the file is opened"
);
});