Bug 1852746 - Fix listAttachments() being empty for encrypted messages. r=mkmelin
This is a regression from switching to the MimeTreeEmitter. The old implementation always tried to decrpypt the message for attachment extraction. The new implementation did not, which is fixed by this patch. This also adds an extended test to actually check listAttachments() on an encrypted message (including nested messages). Note: getRaw() and getFull() have an option to work on the original or on the decrypted message. This patch does not add the same option for listAttachments(). We currently do not handle encrypted parts as "attachments" (this is why listAttachments() did not return the raw encrypted part before this patch) and there has not been a request to access the raw enrcrypted part. We may come back to this at a later time. The changes in `utils.js` are fixing an incomplete type check. Only `boolean`, `number` and `string` variables where type checked, but not `date` for example. This patch also adds some more verbose output to make it easier to track errors. Differential Revision: https://phabricator.services.mozilla.com/D212990 --HG-- extra : amend_source : 4bb7d6715e9337f42d2da1837aa67b31b9339a0b
This commit is contained in:
Родитель
b42d23ba49
Коммит
fa1c537868
|
@ -597,7 +597,7 @@ export class MsgHdrProcessor {
|
|||
* @returns {Promise<MimeTreePart[]>}
|
||||
*/
|
||||
async getAttachmentParts(options) {
|
||||
const rawMessage = await this.getOriginalMessage();
|
||||
const rawMessage = await this.getDecryptedMessage();
|
||||
const mimeTree = this.#parseMessage(
|
||||
rawMessage,
|
||||
{
|
||||
|
@ -645,7 +645,7 @@ export class MsgHdrProcessor {
|
|||
* @returns {Promise<MimeTreePart>}
|
||||
*/
|
||||
async getAttachmentPart(partName, options) {
|
||||
const rawMessage = await this.getOriginalMessage();
|
||||
const rawMessage = await this.getDecryptedMessage();
|
||||
const includeRaw = options?.includeRaw ?? false;
|
||||
const mimeTree = this.#parseMessage(
|
||||
rawMessage,
|
||||
|
|
|
@ -201,7 +201,7 @@
|
|||
"size": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"description": "The size of this part. The size of <em>message/*</em> parts is not the actual message size (on disc), but the total size of its decoded body parts, excluding headers."
|
||||
"description": "The size of this part. The size of parts with content type <em>message/rfc822</em> is not the actual message size (on disc), but the total size of its decoded body parts, excluding headers."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -27,31 +27,46 @@ function assertDeepEqual(
|
|||
}
|
||||
}
|
||||
|
||||
function assertDeepEqualNested(expected, actual, strict) {
|
||||
function assertDeepEqualNested(expected, actual, strict, description) {
|
||||
if (expected === null) {
|
||||
browser.test.assertTrue(actual === null);
|
||||
browser.test.assertTrue(actual === null, description);
|
||||
return actual === null;
|
||||
}
|
||||
|
||||
if (expected === undefined) {
|
||||
browser.test.assertTrue(actual === undefined);
|
||||
browser.test.assertTrue(actual === undefined, description);
|
||||
return actual === undefined;
|
||||
}
|
||||
|
||||
browser.test.assertEq(
|
||||
typeof expected,
|
||||
typeof actual,
|
||||
`${description} (type check)`
|
||||
);
|
||||
if (["boolean", "number", "string"].includes(typeof expected)) {
|
||||
browser.test.assertEq(typeof expected, typeof actual);
|
||||
browser.test.assertEq(expected, actual);
|
||||
browser.test.assertEq(expected, actual, `${description} (value check)`);
|
||||
return typeof expected == typeof actual && expected == actual;
|
||||
}
|
||||
|
||||
if (Array.isArray(expected)) {
|
||||
browser.test.assertTrue(Array.isArray(actual));
|
||||
browser.test.assertEq(expected.length, actual.length);
|
||||
browser.test.assertTrue(Array.isArray(actual), `${description} (exist)`);
|
||||
browser.test.assertEq(
|
||||
expected.length,
|
||||
actual.length,
|
||||
`${description} (length check)`
|
||||
);
|
||||
let ok = 0;
|
||||
let all = 0;
|
||||
for (let i = 0; i < expected.length; i++) {
|
||||
all++;
|
||||
if (assertDeepEqualNested(expected[i], actual[i], strict)) {
|
||||
if (
|
||||
assertDeepEqualNested(
|
||||
expected[i],
|
||||
actual[i],
|
||||
strict,
|
||||
`Array entry #${i} is correct`
|
||||
)
|
||||
) {
|
||||
ok++;
|
||||
}
|
||||
}
|
||||
|
@ -66,14 +81,36 @@ function assertDeepEqualNested(expected, actual, strict) {
|
|||
const lengthOk = strict
|
||||
? expectedKeys.length == actualKeys.length
|
||||
: expectedKeys.length <= actualKeys.length;
|
||||
browser.test.assertTrue(lengthOk);
|
||||
if (strict) {
|
||||
browser.test.assertEq(
|
||||
expectedKeys.length,
|
||||
actualKeys.length,
|
||||
`strict length check for ${description}, expected exactly: ${JSON.stringify(
|
||||
expectedKeys
|
||||
)}, actual: ${JSON.stringify(actualKeys)}`
|
||||
);
|
||||
} else {
|
||||
browser.test.assertTrue(
|
||||
lengthOk,
|
||||
`lazy length check for ${description}, expected at least: ${JSON.stringify(
|
||||
expectedKeys
|
||||
)}, actual: ${JSON.stringify(actualKeys)}`
|
||||
);
|
||||
}
|
||||
|
||||
let ok = 0;
|
||||
let all = 0;
|
||||
for (const key of expectedKeys) {
|
||||
all++;
|
||||
browser.test.assertTrue(actualKeys.includes(key), `Key ${key} exists`);
|
||||
if (assertDeepEqualNested(expected[key], actual[key], strict)) {
|
||||
if (
|
||||
assertDeepEqualNested(
|
||||
expected[key],
|
||||
actual[key],
|
||||
strict,
|
||||
`Key ${key} is correct`
|
||||
)
|
||||
) {
|
||||
ok++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
Message-ID: <sample.eml@mime.sample>
|
||||
Date: Fri, 20 May 2000 00:29:55 -0400
|
||||
To: Alice Lovelace <alice@openpgp.example>
|
||||
From: Batman <bruce@wayne-enterprises.com>
|
||||
Subject: Encrypted, attached message with attachments
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/encrypted;
|
||||
protocol="application/pgp-encrypted";
|
||||
boundary="------------M20GNGI1rLZhtbYD7WFekIXJ"
|
||||
|
||||
This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)
|
||||
--------------M20GNGI1rLZhtbYD7WFekIXJ
|
||||
Content-Type: application/pgp-encrypted
|
||||
Content-Description: PGP/MIME version identification
|
||||
|
||||
Version: 1
|
||||
|
||||
--------------M20GNGI1rLZhtbYD7WFekIXJ
|
||||
Content-Type: application/octet-stream; name="encrypted.asc"
|
||||
Content-Description: OpenPGP encrypted message
|
||||
Content-Disposition: inline; filename="encrypted.asc"
|
||||
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hF4DR2b2udXyHrYSAQdAkHA/pErV3hMoJphrF/glWHFydVs+PeGud6VzdyG6rF4w
|
||||
s0EzVZ9peVVd0+XewFpTTasMWEB9WcC1s/bVMTY2cz2TbHLufxp8XDUwyOwCoSvn
|
||||
0ukBxBk5ZqNqYNGI/LZ/9zBltAWmrxTt00BKzNuigQyhWTMFZx1SMbTamro0+ej0
|
||||
9U61CaCfLT31b+DsMyOj+FQ+0DPq4rEZ5Oek9atkaRQ1N9kbvaLmgJB+Ya+kJTnQ
|
||||
jPZEPrtHAVkSZSciPJxwkluacZMrRKWExq1HHoSoLI5NG0gIkT7+lqGX3e2HOFm8
|
||||
NuKvOyOk6Pza0v15vKf8NlXjwfgzR8ZuaNaMjO6q5ismCfm6qpLFG+YGRw7KydOQ
|
||||
ZiQ2pAWhBQEaDJuDTGM9KT2onQjkFl4okIkMRU7dapjBAZpM01t3g1YDss6UHMil
|
||||
8zRT1dlEdeoCIQiRLJykCHsSVAAujWLGLdMQt9oYekbiTC0U56t9tbQrO8P7ZB2F
|
||||
JEHeNcKRAxGod7WSl8Nbxfor8mQ8zuxUMjEdhmrBzsKTcfteTYLeMbrcXslguxxD
|
||||
LDrbM7MevUTjfPJGAF9B+OMOMnyw1g5El/tK+wEFE3zv03EBEtEHjl4RPDPIzfZ3
|
||||
ozKVPkzEmLkZPHMN2yKJzT2nsKI8RSqpoTxfk3QlKSrVHTaZhQDSTcorzFXLDL8Y
|
||||
vdXQoozFyTfPVd3PHBp/L2tfnYZDpwqraicPK4eX0yQ+eoN1W5qFUXHFHcZFFyPo
|
||||
InJsYtEBABGWtRWcZY58BX34/Fi8mHyrAWV6gRnAKVO3ecElfvgHgNdoufJzHLEY
|
||||
b/B+I1UfRxKX37vrlPtszHpEJLk6+EYPHcPA5kjmDi4tMm3NkJJI6FBnybulzNRC
|
||||
bgHnVKlJgJLoiRbKC7fbuOtM523+krkWlKPZhEXs+qY9PjIzaEpmAIUE64gPnCiT
|
||||
OcyWQjG3hX2lo9E9CyBlI0SvyYkdHnbKAWIeZNd/k7STK99actjPg2Wn0XloYpx4
|
||||
/ldupx5oYAhcQW7lKHrczsEqXp4yi+f7KFEXVeerVxNuaSaBSpDIqTSQ82GVotB1
|
||||
3iGJFzqcpykeYVJZtYylMxRE5gKyU4wBkzPO7Thsxo8DVFcRkFAslnknEk2kqNf6
|
||||
fKiWh7k0cqYvldLTVhbNkn/Tk7XXWlFFIFlqpOB8cXqSgcUp09PxQHHQB8nlftJK
|
||||
627u7FBhrH6J01YbuLpHP+aO8pykNrS+JgvOvYxa9aGDmWSz70lDmp27hPGPvpWF
|
||||
UU74y4xTcBtPB1xM580zvDOZULDQHmTmNyGzcOlWvGXpCbcDzeYyJRKb2+arZ7CM
|
||||
uQj5Kyari1l6fDttXtuVVvoaHpCk8h5+IqwVTWi2qqoK0C6VgMQnBYs2EnfjbU/I
|
||||
ywL4O+JDUGkxFBjkSrwyQAUY3LoA5CqaxApOwCPbP/veHpLYOuMFIkw=
|
||||
=fK7D
|
||||
-----END PGP MESSAGE-----
|
||||
|
||||
--------------M20GNGI1rLZhtbYD7WFekIXJ--
|
|
@ -0,0 +1,598 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var { FileUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/FileUtils.sys.mjs"
|
||||
);
|
||||
var { ExtensionTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/ExtensionXPCShellUtils.sys.mjs"
|
||||
);
|
||||
var { OpenPGPTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/mail/OpenPGPTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
const OPENPGP_TEST_DIR = do_get_file("../../../../test/browser/openpgp");
|
||||
const OPENPGP_KEY_PATH = PathUtils.join(
|
||||
OPENPGP_TEST_DIR.path,
|
||||
"data",
|
||||
"keys",
|
||||
"alice@openpgp.example-0xf231550c4f47e38e-secret.asc"
|
||||
);
|
||||
|
||||
add_setup(async () => {
|
||||
await OpenPGPTestUtils.initOpenPGP();
|
||||
|
||||
const _account = createAccount();
|
||||
const _identity = addIdentity(_account);
|
||||
const _folder = await createSubfolder(
|
||||
_account.incomingServer.rootFolder,
|
||||
"test1"
|
||||
);
|
||||
|
||||
const [id] = await OpenPGPTestUtils.importPrivateKey(
|
||||
null,
|
||||
new FileUtils.File(OPENPGP_KEY_PATH)
|
||||
);
|
||||
_identity.setUnicharAttribute("openpgp_key_id", id);
|
||||
|
||||
await createMessageFromFile(
|
||||
_folder,
|
||||
do_get_file("messages/encryptedNestedMessages.eml").path
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_messages_encrypted_attachment() {
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
files: {
|
||||
"background.js": async () => {
|
||||
const [folder] = await browser.folders.query({ name: "test1" });
|
||||
const { accountId } = folder;
|
||||
const { type } = await browser.accounts.get(accountId);
|
||||
|
||||
const { messages } = await browser.messages.list(folder.id);
|
||||
browser.test.assertEq(1, messages.length);
|
||||
browser.test.assertEq(1, messages[0].id);
|
||||
|
||||
// Get the raw decrypted content of the message (id: 1) via getRaw().
|
||||
const raw1file = await browser.messages.getRaw(1, { decrypt: true });
|
||||
// eslint-disable-next-line mozilla/use-isInstance
|
||||
browser.test.assertTrue(raw1file instanceof File);
|
||||
browser.test.assertEq("message-1.eml", raw1file.name);
|
||||
browser.test.assertEq(type == "imap" ? 4024 : 3971, raw1file.size);
|
||||
const raw1content = await raw1file.text();
|
||||
browser.test.assertTrue(
|
||||
!raw1content.includes("-----BEGIN PGP MESSAGE-----"),
|
||||
"getRaw() of the outer message should be decrypted"
|
||||
);
|
||||
browser.test.assertTrue(
|
||||
raw1content.includes("<sample.eml@mime.sample>"),
|
||||
"getRaw() of the outer message should include the message ID of the outer message"
|
||||
);
|
||||
browser.test.assertTrue(
|
||||
raw1content.includes("<sample-attached.eml@mime.sample>"),
|
||||
"getRaw() of the outer message should include the message ID of the nested message"
|
||||
);
|
||||
browser.test.assertTrue(
|
||||
raw1content.includes("<sample-nested-attached.eml@mime.sample>"),
|
||||
"getRaw() of the outer message should include the message ID of the inner nested message"
|
||||
);
|
||||
|
||||
// Get the full decrypted content of the message (id: 1) via getFull().
|
||||
const full1 = await browser.messages.getFull(1, { decrypt: true });
|
||||
window.assertDeepEqual(
|
||||
{
|
||||
contentType: "message/rfc822",
|
||||
partName: "",
|
||||
size: 2884,
|
||||
decryptionStatus: "success",
|
||||
headers: {
|
||||
"message-id": ["<sample.eml@mime.sample>"],
|
||||
date: ["Fri, 20 May 2000 00:29:55 -0400"],
|
||||
to: ["Alice Lovelace <alice@openpgp.example>"],
|
||||
from: ["Batman <bruce@wayne-enterprises.com>"],
|
||||
subject: ["Encrypted, attached message with attachments"],
|
||||
"mime-version": ["1.0"],
|
||||
"content-type": ["message/rfc822"],
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
contentType: "multipart/mixed",
|
||||
headers: {
|
||||
"content-type": [
|
||||
'multipart/mixed; boundary="------------M20GNGI1rLZhtbYD7WFekIXJ"',
|
||||
],
|
||||
},
|
||||
size: 2884,
|
||||
partName: "1",
|
||||
parts: [
|
||||
{
|
||||
contentType: "multipart/mixed",
|
||||
headers: {
|
||||
"content-type": [
|
||||
'multipart/mixed; boundary="------------49CVLb1N6p6Spdka4qq7Naeg"',
|
||||
],
|
||||
},
|
||||
size: 2884,
|
||||
partName: "1.1",
|
||||
parts: [
|
||||
{
|
||||
contentType: "text/html",
|
||||
headers: {
|
||||
"content-type": ["text/html; charset=UTF-8"],
|
||||
"content-transfer-encoding": ["7bit"],
|
||||
},
|
||||
size: 248,
|
||||
partName: "1.1.1",
|
||||
body: '<html>\n <head>\n\n <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n </head>\n <body>\n <p>This message has one normal attachment and one email attachment,\n which itself has 3 attachments.<br>\n </p>\n </body>\n</html>',
|
||||
},
|
||||
{
|
||||
contentType: "message/rfc822",
|
||||
headers: {
|
||||
"content-type": [
|
||||
'message/rfc822; charset=UTF-8; name="message1.eml"',
|
||||
],
|
||||
"content-disposition": [
|
||||
'attachment; filename="message1.eml"',
|
||||
],
|
||||
"content-transfer-encoding": ["7bit"],
|
||||
},
|
||||
size: 2517,
|
||||
partName: "1.1.2",
|
||||
name: "message1.eml",
|
||||
},
|
||||
{
|
||||
contentType: "image/png",
|
||||
headers: {
|
||||
"content-type": ["image/png;"],
|
||||
"content-transfer-encoding": ["base64"],
|
||||
"content-disposition": [
|
||||
'attachment; filename="yellowPixel.png"',
|
||||
],
|
||||
},
|
||||
size: 119,
|
||||
partName: "1.1.3",
|
||||
name: "yellowPixel.png",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
full1,
|
||||
"getFull() for the outer message should be correct"
|
||||
);
|
||||
|
||||
// List the attachments from the decrypted outer message.
|
||||
// Note: listAttachments() is always acting on the decrypted message.
|
||||
const attachments1 = await browser.messages.listAttachments(1);
|
||||
window.assertDeepEqual(
|
||||
[
|
||||
{
|
||||
contentType: "message/rfc822",
|
||||
name: "message1.eml",
|
||||
size: 442,
|
||||
partName: "1.1.2",
|
||||
message: {
|
||||
id: 2,
|
||||
date: new Date("2000-05-17T23:32:47.000Z"),
|
||||
author: "Superman <clark.kent@dailyplanet.com>",
|
||||
recipients: ["Jimmy <jimmy.olsen@dailyplanet.com>"],
|
||||
ccList: [],
|
||||
bccList: [],
|
||||
subject: "Test message 1",
|
||||
read: false,
|
||||
new: false,
|
||||
headersOnly: false,
|
||||
flagged: false,
|
||||
junk: false,
|
||||
junkScore: 0,
|
||||
headerMessageId: "sample-attached.eml@mime.sample",
|
||||
size: 442,
|
||||
tags: [],
|
||||
external: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
contentType: "image/png",
|
||||
name: "yellowPixel.png",
|
||||
size: 119,
|
||||
partName: "1.1.3",
|
||||
},
|
||||
],
|
||||
attachments1,
|
||||
"Attachments of the outer message should be correct",
|
||||
{
|
||||
strict: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Get the actual attachments of the outer message as File objects.
|
||||
// Note: getAttachmentFile() is always acting on the decrypted message.
|
||||
const file112 = await browser.messages.getAttachmentFile(1, "1.1.2");
|
||||
// eslint-disable-next-line mozilla/use-isInstance
|
||||
browser.test.assertTrue(file112 instanceof File);
|
||||
browser.test.assertEq("message1.eml", file112.name);
|
||||
browser.test.assertEq(2517, file112.size);
|
||||
const file112content = await file112.text();
|
||||
browser.test.assertTrue(
|
||||
!file112content.includes("<sample.eml@mime.sample>"),
|
||||
"file112content should not include the message ID of the outer message"
|
||||
);
|
||||
browser.test.assertTrue(
|
||||
file112content.includes("<sample-attached.eml@mime.sample>"),
|
||||
"file112content should include the message ID of the nested message"
|
||||
);
|
||||
browser.test.assertTrue(
|
||||
file112content.includes("<sample-nested-attached.eml@mime.sample>"),
|
||||
"file112content should include the message ID of the inner nested message"
|
||||
);
|
||||
|
||||
const file113 = await browser.messages.getAttachmentFile(1, "1.1.3");
|
||||
// eslint-disable-next-line mozilla/use-isInstance
|
||||
browser.test.assertTrue(file113 instanceof File);
|
||||
browser.test.assertEq("yellowPixel.png", file113.name);
|
||||
browser.test.assertEq(119, file113.size);
|
||||
|
||||
// Get the raw content of the nested message (id: 2) via getRaw().
|
||||
const raw2file = await browser.messages.getRaw(2);
|
||||
// eslint-disable-next-line mozilla/use-isInstance
|
||||
browser.test.assertTrue(raw2file instanceof File);
|
||||
browser.test.assertEq("message-2.eml", raw2file.name);
|
||||
browser.test.assertEq(2517, raw2file.size);
|
||||
const raw2content = await raw2file.text();
|
||||
browser.test.assertEq(
|
||||
raw2content,
|
||||
file112content,
|
||||
"getRaw() of the attached message and getAttachmentFile() of the attached message should be identical"
|
||||
);
|
||||
|
||||
// Get the full content of the nested message via getFull().
|
||||
const full2 = await browser.messages.getFull(2);
|
||||
window.assertDeepEqual(
|
||||
{
|
||||
contentType: "message/rfc822",
|
||||
partName: "",
|
||||
size: 1180,
|
||||
decryptionStatus: "none",
|
||||
headers: {
|
||||
"message-id": ["<sample-attached.eml@mime.sample>"],
|
||||
from: ["Superman <clark.kent@dailyplanet.com>"],
|
||||
to: ["Jimmy <jimmy.olsen@dailyplanet.com>"],
|
||||
subject: ["Test message 1"],
|
||||
date: ["Wed, 17 May 2000 19:32:47 -0400"],
|
||||
"mime-version": ["1.0"],
|
||||
"content-type": ["message/rfc822"],
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
contentType: "multipart/mixed",
|
||||
headers: {
|
||||
"content-type": [
|
||||
'multipart/mixed;\tboundary="----=_NextPart_000_0002_01BFC036.AE309650"',
|
||||
],
|
||||
},
|
||||
size: 1180,
|
||||
partName: "1",
|
||||
parts: [
|
||||
{
|
||||
contentType: "text/plain",
|
||||
headers: {
|
||||
"content-type": ['text/plain;\tcharset="iso-8859-1"'],
|
||||
"content-transfer-encoding": ["7bit"],
|
||||
},
|
||||
size: 35,
|
||||
partName: "1.1",
|
||||
body: "Message with multiple attachments.\n",
|
||||
},
|
||||
{
|
||||
contentType: "image/png",
|
||||
headers: {
|
||||
"content-type": ['image/png;\tname="whitePixel.png"'],
|
||||
"content-transfer-encoding": ["base64"],
|
||||
"content-disposition": [
|
||||
'attachment;\tfilename="whitePixel.png"',
|
||||
],
|
||||
},
|
||||
size: 69,
|
||||
partName: "1.2",
|
||||
name: "whitePixel.png",
|
||||
},
|
||||
{
|
||||
contentType: "image/png",
|
||||
headers: {
|
||||
"content-type": ['image/png;\tname="greenPixel.png"'],
|
||||
"content-transfer-encoding": ["base64"],
|
||||
"content-disposition": ["attachment"],
|
||||
},
|
||||
size: 119,
|
||||
partName: "1.3",
|
||||
name: "greenPixel.png",
|
||||
},
|
||||
{
|
||||
contentType: "image/png",
|
||||
headers: {
|
||||
"content-type": ["image/png"],
|
||||
"content-transfer-encoding": ["base64"],
|
||||
"content-disposition": [
|
||||
'attachment;\tfilename="redPixel.png"',
|
||||
],
|
||||
},
|
||||
size: 119,
|
||||
partName: "1.4",
|
||||
name: "redPixel.png",
|
||||
},
|
||||
{
|
||||
contentType: "message/rfc822",
|
||||
headers: {
|
||||
"content-type": [
|
||||
'message/rfc822; charset=UTF-8; name="message2.eml"',
|
||||
],
|
||||
"content-disposition": [
|
||||
'attachment; filename="message2.eml"',
|
||||
],
|
||||
"content-transfer-encoding": ["7bit"],
|
||||
},
|
||||
size: 838,
|
||||
partName: "1.5",
|
||||
name: "message2.eml",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
full2,
|
||||
"getFull() of the nested message should be correct"
|
||||
);
|
||||
|
||||
// List the attachments from the nested message.
|
||||
const attachments2 = await browser.messages.listAttachments(2);
|
||||
window.assertDeepEqual(
|
||||
[
|
||||
{
|
||||
contentType: "image/png",
|
||||
name: "whitePixel.png",
|
||||
size: 69,
|
||||
partName: "1.2",
|
||||
},
|
||||
{
|
||||
contentType: "image/png",
|
||||
name: "greenPixel.png",
|
||||
size: 119,
|
||||
partName: "1.3",
|
||||
},
|
||||
{
|
||||
contentType: "image/png",
|
||||
name: "redPixel.png",
|
||||
size: 119,
|
||||
partName: "1.4",
|
||||
},
|
||||
{
|
||||
contentType: "message/rfc822",
|
||||
name: "message2.eml",
|
||||
size: 100,
|
||||
partName: "1.5",
|
||||
message: {
|
||||
id: 3,
|
||||
date: new Date("2000-05-16T23:32:47.000Z"),
|
||||
author: "Jimmy <jimmy.olsen@dailyplanet.com>",
|
||||
recipients: ["Superman <clark.kent@dailyplanet.com>"],
|
||||
ccList: [],
|
||||
bccList: [],
|
||||
subject: "Test message 2",
|
||||
read: false,
|
||||
new: false,
|
||||
headersOnly: false,
|
||||
flagged: false,
|
||||
junk: false,
|
||||
junkScore: 0,
|
||||
headerMessageId: "sample-nested-attached.eml@mime.sample",
|
||||
size: 100,
|
||||
tags: [],
|
||||
external: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
attachments2,
|
||||
"Attachments of the nested message should be correct",
|
||||
{
|
||||
strict: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Get the actual attachments of the nested message as File objects.
|
||||
const files = new Map();
|
||||
const expectedAttachments2 = [
|
||||
{
|
||||
name: "whitePixel.png",
|
||||
size: 69,
|
||||
partName: "1.2",
|
||||
},
|
||||
{
|
||||
name: "greenPixel.png",
|
||||
size: 119,
|
||||
partName: "1.3",
|
||||
},
|
||||
{
|
||||
name: "redPixel.png",
|
||||
size: 119,
|
||||
partName: "1.4",
|
||||
},
|
||||
{
|
||||
name: "message2.eml",
|
||||
size: 838,
|
||||
partName: "1.5",
|
||||
},
|
||||
];
|
||||
for (const expectedAttachment2 of expectedAttachments2) {
|
||||
const f = await browser.messages.getAttachmentFile(
|
||||
2,
|
||||
expectedAttachment2.partName
|
||||
);
|
||||
files.set(expectedAttachment2.partName, f);
|
||||
// eslint-disable-next-line mozilla/use-isInstance
|
||||
browser.test.assertTrue(f instanceof File);
|
||||
browser.test.assertEq(
|
||||
expectedAttachment2.name,
|
||||
f.name,
|
||||
`Name of part ${expectedAttachment2.partName} should be correct`
|
||||
);
|
||||
browser.test.assertEq(
|
||||
expectedAttachment2.size,
|
||||
f.size,
|
||||
`Size of part ${expectedAttachment2.partName} should be correct`
|
||||
);
|
||||
}
|
||||
|
||||
// Check content of the inner nested message (part 1.5, id: 3).
|
||||
const file15content = await files.get("1.5").text();
|
||||
browser.test.assertTrue(
|
||||
!file15content.includes("<sample.eml@mime.sample>"),
|
||||
"file15content should not include the message ID of the outer message"
|
||||
);
|
||||
browser.test.assertTrue(
|
||||
!file15content.includes("<sample-attached.eml@mime.sample>"),
|
||||
"file15content should not include the message ID of the nested message"
|
||||
);
|
||||
browser.test.assertTrue(
|
||||
file15content.includes("<sample-nested-attached.eml@mime.sample>"),
|
||||
"file15content should include the message ID of the inner nested message"
|
||||
);
|
||||
|
||||
// Get the raw content of the inner nested message (part 1.5, id: 3) via
|
||||
// getRaw().
|
||||
const raw3file = await browser.messages.getRaw(3);
|
||||
// eslint-disable-next-line mozilla/use-isInstance
|
||||
browser.test.assertTrue(raw3file instanceof File);
|
||||
browser.test.assertEq("message-3.eml", raw3file.name);
|
||||
browser.test.assertEq(838, raw3file.size);
|
||||
const raw3content = await raw3file.text();
|
||||
browser.test.assertEq(
|
||||
raw3content,
|
||||
file15content,
|
||||
"getRaw() of the inner attached message and getAttachmentFile() of the inner attached message should be identical"
|
||||
);
|
||||
|
||||
// Get the full content of the inner nested message via getFull().
|
||||
const full3 = await browser.messages.getFull(3);
|
||||
window.assertDeepEqual(
|
||||
{
|
||||
contentType: "message/rfc822",
|
||||
partName: "",
|
||||
size: 100,
|
||||
decryptionStatus: "none",
|
||||
headers: {
|
||||
"message-id": ["<sample-nested-attached.eml@mime.sample>"],
|
||||
from: ["Jimmy <jimmy.olsen@dailyplanet.com>"],
|
||||
to: ["Superman <clark.kent@dailyplanet.com>"],
|
||||
subject: ["Test message 2"],
|
||||
date: ["Wed, 16 May 2000 19:32:47 -0400"],
|
||||
"mime-version": ["1.0"],
|
||||
"content-type": ["message/rfc822"],
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
contentType: "multipart/mixed",
|
||||
headers: {
|
||||
"content-type": [
|
||||
'multipart/mixed; boundary="----=_NextPart_000_0003_01BFC036.AE309650"',
|
||||
],
|
||||
},
|
||||
size: 100,
|
||||
partName: "1",
|
||||
parts: [
|
||||
{
|
||||
contentType: "text/plain",
|
||||
headers: {
|
||||
"content-type": ['text/plain; charset="iso-8859-1"'],
|
||||
"content-transfer-encoding": ["7bit"],
|
||||
},
|
||||
size: 31,
|
||||
partName: "1.1",
|
||||
body: "This message has an attachment\n",
|
||||
},
|
||||
{
|
||||
contentType: "image/png",
|
||||
headers: {
|
||||
"content-type": ['image/png; name="whitePixel.png"'],
|
||||
"content-transfer-encoding": ["base64"],
|
||||
"content-disposition": [
|
||||
'attachment; filename="whitePixel.png"',
|
||||
],
|
||||
},
|
||||
size: 69,
|
||||
partName: "1.2",
|
||||
name: "whitePixel.png",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
full3,
|
||||
"getFull() of the inner nested message should be correct"
|
||||
);
|
||||
|
||||
// List the attachments from the inner nested message.
|
||||
const attachments3 = await browser.messages.listAttachments(3);
|
||||
window.assertDeepEqual(
|
||||
[
|
||||
{
|
||||
contentType: "image/png",
|
||||
name: "whitePixel.png",
|
||||
size: 69,
|
||||
partName: "1.2",
|
||||
},
|
||||
],
|
||||
attachments3,
|
||||
"Attachments of the inner nested message should be correct",
|
||||
{
|
||||
strict: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Get the actual attachments of the inner nested message as File objects.
|
||||
const expectedAttachments3 = [
|
||||
{
|
||||
name: "whitePixel.png",
|
||||
size: 69,
|
||||
partName: "1.2",
|
||||
},
|
||||
];
|
||||
for (const expectedAttachment3 of expectedAttachments3) {
|
||||
const f = await browser.messages.getAttachmentFile(
|
||||
3,
|
||||
expectedAttachment3.partName
|
||||
);
|
||||
files.set(expectedAttachment3.partName, f);
|
||||
// eslint-disable-next-line mozilla/use-isInstance
|
||||
browser.test.assertTrue(f instanceof File);
|
||||
browser.test.assertEq(
|
||||
expectedAttachment3.name,
|
||||
f.name,
|
||||
`Name of part ${expectedAttachment3.partName} should be correct`
|
||||
);
|
||||
browser.test.assertEq(
|
||||
expectedAttachment3.size,
|
||||
f.size,
|
||||
`Size of part ${expectedAttachment3.partName} should be correct`
|
||||
);
|
||||
}
|
||||
|
||||
browser.test.notifyPass("finished");
|
||||
},
|
||||
"utils.js": await getUtilsJS(),
|
||||
},
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
background: { scripts: ["utils.js", "background.js"] },
|
||||
permissions: ["accountsRead", "messagesRead"],
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
await extension.awaitFinish("finished");
|
||||
await extension.unload();
|
||||
});
|
|
@ -9,6 +9,7 @@ tags = addrbook
|
|||
[test_ext_messages_attachments.js] # IMAP disabled (doesn't work with test server).
|
||||
support-files = messages/**
|
||||
[test_ext_messages_bug_1737532.js]
|
||||
[test_ext_messages_encrypted_attachment.js]
|
||||
[test_ext_messages_get.js] # PGP test disabled for NNTP.
|
||||
support-files = messages/**
|
||||
[test_ext_messages_id.js] # Disabled for NNTP (message move not supported).
|
||||
|
|
Загрузка…
Ссылка в новой задаче