/* 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 for the display of OpenPGP signed/encrypted state in opened messages. */ "use strict"; requestLongerTimeout(2); const { get_about_message, open_message_from_file, wait_for_message_display_completion, } = ChromeUtils.importESModule( "resource://testing-common/mail/FolderDisplayHelpers.sys.mjs" ); const { promise_new_window, wait_for_window_focused } = ChromeUtils.importESModule( "resource://testing-common/mail/WindowHelpers.sys.mjs" ); const { OpenPGPTestUtils } = ChromeUtils.importESModule( "resource://testing-common/mail/OpenPGPTestUtils.sys.mjs" ); const { MailServices } = ChromeUtils.importESModule( "resource:///modules/MailServices.sys.mjs" ); var { MailConsts } = ChromeUtils.importESModule( "resource:///modules/MailConsts.sys.mjs" ); const MSG_TEXT = "Sundays are nothing without callaloo."; function getMsgBodyTxt(msgc) { const msgPane = get_about_message(msgc).getMessagePaneBrowser(); return msgPane.contentDocument.documentElement.textContent; } /** * When testing a scenario that should automatically process the OpenPGP * contents (it's not suppressed e.g. because of a partial content), * then we need to wait for the automatic processing to complete. */ async function openpgpProcessed() { const [subject] = await TestUtils.topicObserved( "document-element-inserted", document => { return document.ownerGlobal?.location == "about:message"; } ); return BrowserTestUtils.waitForEvent(subject, "openpgpprocessed"); } var aliceAcct; /** * Set up the base account, identity and keys needed for the tests. */ add_setup(async function () { // This test assumes the standalone message window. Services.prefs.setIntPref( "mail.openMessageBehavior", MailConsts.OpenMessageBehavior.NEW_WINDOW ); registerCleanupFunction(() => { Services.prefs.clearUserPref("mail.openMessageBehavior"); }); aliceAcct = MailServices.accounts.createAccount(); aliceAcct.incomingServer = MailServices.accounts.createIncomingServer( "alice", "openpgp.example", "pop3" ); const aliceIdentity = MailServices.accounts.createIdentity(); aliceIdentity.email = "alice@openpgp.example"; aliceAcct.addIdentity(aliceIdentity); // Set up the alice's private key. const [id] = await OpenPGPTestUtils.importPrivateKey( window, new FileUtils.File( getTestFilePath( "data/keys/alice@openpgp.example-0xf231550c4f47e38e-secret.asc" ) ) ); aliceIdentity.setUnicharAttribute("openpgp_key_id", id); // Import and accept the public key for Bob, our verified sender. await OpenPGPTestUtils.importPublicKey( window, new FileUtils.File( getTestFilePath( "data/keys/bob@openpgp.example-0xfbfcc82a015e7330-pub.asc" ) ) ); }); /** * Test that an unsigned unencrypted message do not show as signed nor encrypted. */ add_task(async function testOpenNoPGPSecurity() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/unsigned-unencrypted-from-bob-to-alice.eml") ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage.document), "signed icon is not displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that a signed (only) message, signed by a verified key, shows as such. */ add_task(async function testOpenSignedByVerifiedUnencrypted() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath( "data/eml/signed-by-0xfbfcc82a015e7330-to-0xf231550c4f47e38e-unencrypted.eml" ) ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "verified"), "signed verified icon is displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that a signed (only) message, signed by a verified key, * but with an mismatching email date, is shown with invalid signature. */ add_task(async function testOpenSignedDateMismatch() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/signed-mismatch-email-date.eml") ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "mismatch"), "signed unknown icon is displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that opening an unsigned encrypted message shows as such. */ add_task(async function testOpenVerifiedUnsignedEncrypted() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath( "data/eml/unsigned-encrypted-to-0xf231550c4f47e38e-from-0xfbfcc82a015e7330.eml" ) ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage.document), "signed icon is not displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that opening an attached encrypted message has no effect * on security status icons of the parent message window. */ add_task(async function testOpenForwardedEncrypted() { const msgc = await open_message_from_file( new FileUtils.File(getTestFilePath("data/eml/fwd-unsigned-encrypted.eml")) ); const aboutMessage = get_about_message(msgc); Assert.ok( getMsgBodyTxt(msgc).includes("wrapper message with plain text"), "wrapper message text should be shown" ); Assert.ok( !getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text should not be shown" ); Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage.document), "signed icon is not displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is not displayed" ); // Delete should not work. EventUtils.synthesizeMouseAtCenter( aboutMessage.document.getElementById("attachmentBar"), { clickCount: 1 }, aboutMessage ); EventUtils.synthesizeKey("VK_DELETE", {}, aboutMessage); await TestUtils.waitForTick(); const newWindowPromise = promise_new_window("mail:messageWindow"); EventUtils.synthesizeMouseAtCenter( aboutMessage.document.getElementById("attachmentName"), { clickCount: 1 }, aboutMessage ); const mc2 = await newWindowPromise; await wait_for_message_display_completion(mc2, true); await wait_for_window_focused(mc2); const aboutMessage2 = get_about_message(mc2); // Check properties of the opened attachment window. Assert.ok( getMsgBodyTxt(mc2).includes(MSG_TEXT), "message text should be shown" ); Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage2.document), "signed icon is not displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage2.document, "ok"), "encrypted icon is displayed" ); await BrowserTestUtils.closeWindow(mc2); await wait_for_window_focused(msgc); // Ensure there were no side effects for the primary window. Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage.document), "signed icon is still not displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is still not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that opening an attached signed message has no effect * on security status icons of the parent message window, and that the * opened attachment displays the text of the signed message. */ add_task(async function testOpenForwardedSigned() { const msgc = await open_message_from_file( new FileUtils.File(getTestFilePath("data/eml/fwd-signed.eml")) ); const aboutMessage = get_about_message(msgc); const SIGNED_TEXT = "signed message"; Assert.ok( getMsgBodyTxt(msgc).includes("outer text"), "wrapper message text should be shown" ); Assert.ok( getMsgBodyTxt(msgc).includes(SIGNED_TEXT), "message text should be shown, because inline viewing of attachments" ); Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage.document), "signed icon is not displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is not displayed" ); const newWindowPromise = promise_new_window("mail:messageWindow"); EventUtils.synthesizeMouseAtCenter( aboutMessage.document.getElementById("attachmentName"), { clickCount: 1 }, aboutMessage ); const mc2 = await newWindowPromise; await wait_for_message_display_completion(mc2, true); await wait_for_window_focused(mc2); const aboutMessage2 = get_about_message(mc2); // Check properties of the opened attachment window. Assert.ok( getMsgBodyTxt(mc2).includes(SIGNED_TEXT), "message text should be shown" ); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage2.document, "unknown"), "signed icon is displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage2.document, "ok"), "encrypted icon is not displayed" ); await BrowserTestUtils.closeWindow(mc2); await wait_for_window_focused(msgc); // Ensure there were no side effects for the primary window. Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage.document), "signed icon is still not displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is still not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); // TODO: the above tests that an encrypted .eml can be opened from an unencrypted message. // We should also test/handle: // - other attachment (like .doc) in an encrypted message // - unencrypted .eml attachment in encrypted message (currently broken - bug 1926607) // - encrypted .eml in an encrypted message (currently broken - bug 1926608) /** * Test that opening a message that is signed by a verified key shows as such. */ add_task(async function testOpenSignedByVerifiedEncrypted() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath( "data/eml/signed-by-0xfbfcc82a015e7330-encrypted-to-0xf231550c4f47e38e.eml" ) ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "verified"), "signed verified icon is displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that opening a message that is signed by a verified key, but the From * is not what it should be due to multiple From headers, will show mismatch. * Here it's signed by Bob, but Eve inserted an From: Eve * header first. Only first From is used. The second From should not * be used for verification. */ add_task(async function testOpenSignedEncryptedMultiFrom() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath( "data/eml/signed-by-0xfbfcc82a015e7330-encrypted-to-0xf231550c4f47e38e-multi-from.eml" ) ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "mismatch"), "mismatch icon should be displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon should be displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that opening a message signed (only) by an unverified key shows as such. */ add_task(async function testOpenSignedByUnverifiedUnencrypted() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath( "data/eml/signed-by-0x3099ff1238852b9f-to-0xf231550c4f47e38e-unencrypted.eml" ) ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "unknown"), "signed unknown icon is displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that opening a message signed (only) with extra outer layer * doesn't show signature state. */ add_task(async function testOpenSignedWithOuterLayer() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/signed-with-mailman-footer.eml") ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage.document), "signed icon is not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that opening a message encrypted (only) shows as such. */ add_task(async function testOpenUnverifiedUnsignedEncrypted() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath( "data/eml/unsigned-encrypted-to-0xf231550c4f47e38e-from-0x3099ff1238852b9f.eml" ) ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage.document), "signed icon is not displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that we decrypt a nested OpenPGP encrypted message * (with outer S/MIME signature that is ignored). */ add_task(async function testOuterSmimeSigInnerPgpUnverifiedUnsignedEncrypted() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/outer-smime-bad-sig-inner-pgp-enc.eml") ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage.document), "signed icon is not displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that we decrypt a nested OpenPGP encrypted message * (with outer OpenPGP signature that is ignored). */ add_task(async function testOuterPgpSigInnerPgpUnverifiedUnsignedEncrypted() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/outer-pgp-sig-inner-pgp-enc.eml") ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasNoSignedIconState(aboutMessage.document), "signed icon is not displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that we DO NOT decrypt a nested OpenPGP encrypted message * at MIME level 3, with an outer signature layer (level 1) and a * multipart/mixed in between (level 2). * We should not ignore the outer signature in this scenario. */ add_task(async function testOuterPgpSigInnerPgpEncryptedInsideMixed() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/outer-pgp-sig-inner-pgp-enc-with-mixed.eml") ) ); const aboutMessage = get_about_message(msgc); Assert.ok(!getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "unknown"), "signed unknown icon is displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that opening an encrypted message signed by an unverified key is shown * as it should. */ add_task(async function testOpenSignedByUnverifiedEncrypted() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath( "data/eml/signed-by-0x3099ff1238852b9f-encrypted-to-0xf231550c4f47e38e.eml" ) ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "unknown"), "signed unknown icon is displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that we decrypt a nested OpenPGP encrypted+signed message * (with outer S/MIME signature that is ignored). */ add_task(async function testOuterSmimeSigInnerPgpSignedByUnverifiedEncrypted() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/outer-smime-bad-sig-inner-pgp-enc-sig.eml") ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "unknown"), "signed unknown icon is displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that we DO NOT decrypt a nested OpenPGP encrypted message * at MIME level 3, with an outer signature layer (level 1) and a * multipart/mixed in between (level 2). * We should not ignore the outer signature in this scenario. */ add_task(async function testOuterSmimeSigInnerPgpEncryptedInsideMixed() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath( "data/eml/outer-smime-bad-sig-inner-pgp-enc-sig-with-mixed.eml" ) ) ); const aboutMessage = get_about_message(msgc); Assert.ok(!getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); // Note this is an S/MIME signature status, at the time of writing // this test, string "mismatch" is used for status "notok". Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "mismatch"), "signed icon with a mismatch status is displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that processing a nested OpenPGP signed message with an outer S/MIME * signature does not result in an endless reload loop, if the content type * parameters are ordered in an unusual way. */ add_task(async function testUncommonContentType() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/dual-signed-uncommon-content-type.eml") ) ); const aboutMessage = get_about_message(msgc); Assert.ok( getMsgBodyTxt(msgc).includes( "The order of the content type parameters is unusual" ), "message text is in body" ); // Note this is an S/MIME signature status, at the time of writing // this test, string "mismatch" is used for status "notok". Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "mismatch"), "signed icon with a mismatch status is displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that we decrypt a nested OpenPGP encrypted+signed message * (with outer OpenPGP signature that is ignored). */ add_task(async function testOuterPgpSigOpenSignedByUnverifiedEncrypted() { const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/outer-pgp-sig-inner-pgp-enc-sig.eml") ) ); const aboutMessage = get_about_message(msgc); Assert.ok(getMsgBodyTxt(msgc).includes(MSG_TEXT), "message text is in body"); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "unknown"), "signed unknown icon is displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that the message is properly reloaded and the message security icon is * updated if the user changes the signature acceptance level. */ add_task(async function testUpdateMessageSignature() { // Setup the message. const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath( "data/eml/signed-by-0xfbfcc82a015e7330-to-0xf231550c4f47e38e-unencrypted.eml" ) ) ); const aboutMessage = get_about_message(msgc); // Verify current signature acceptance. Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "verified"), "signed verified icon is displayed" ); const popupshown = BrowserTestUtils.waitForEvent( aboutMessage.document.getElementById("messageSecurityPanel"), "popupshown" ); EventUtils.synthesizeMouseAtCenter( aboutMessage.document.getElementById("encryptionTechBtn"), { clickCount: 1 }, aboutMessage ); // Wait for the popup panel and signature button to become visible otherwise // we can't click on it. await popupshown; // Open the Key Properties dialog and change the signature acceptance. const dialogPromise = BrowserTestUtils.domWindowOpened(null, async win => { await BrowserTestUtils.waitForEvent(win, "load"); if ( win.document.documentURI != "chrome://openpgp/content/ui/keyDetailsDlg.xhtml" ) { return false; } if (Services.focus.activeWindow != win) { await BrowserTestUtils.waitForEvent(win, "focus"); } EventUtils.synthesizeMouseAtCenter( win.document.querySelector("#acceptUnverified"), {}, win ); const closedPromise = BrowserTestUtils.domWindowClosed(win); win.document.documentElement.querySelector("dialog").acceptDialog(); await closedPromise; return true; }); // This will open the key details, the domWindowOpened handler // will catch it and execute the changes. EventUtils.synthesizeMouseAtCenter( aboutMessage.document.getElementById("viewSignatureKey"), { clickCount: 1 }, aboutMessage ); // Wait until we are done with keyDetailsDlg. await dialogPromise; // Wait for the signedHdrIcon state to change. // Verify the new acceptance level is correct. await TestUtils.waitForCondition( () => OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "unverified"), "signed unverified icon should be displayed" ); await BrowserTestUtils.closeWindow(msgc); }); // After test testUpdateMessageSignature acceptance of Bob's key // has changed from verified to unverified. /** * Test that a signed (only) inline PGP message with UTF-8 characters * can be correctly verified. */ add_task(async function testOpenSignedInlineWithUTF8() { const opengpgprocessed = openpgpProcessed(); const msgc = await open_message_from_file( new FileUtils.File(getTestFilePath("data/eml/alice-utf.eml")) ); const aboutMessage = get_about_message(msgc); await opengpgprocessed; Assert.ok( getMsgBodyTxt(msgc).includes("£35.00"), "UTF-8 £35.00 should be found in message" ); await TestUtils.waitForCondition( () => OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "unverified"), "signed unverified icon is displayed" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon is not displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that a signed (only) inline PGP message with leading whitespace * can be correctly verified. */ add_task(async function testOpenSignedInlineWithLeadingWS() { const opengpgprocessed = openpgpProcessed(); const msgc = await open_message_from_file( new FileUtils.File(getTestFilePath("data/eml/signed-inline-indented.eml")) ); const aboutMessage = get_about_message(msgc); await opengpgprocessed; Assert.ok( getMsgBodyTxt(msgc).includes("indent test with £"), "expected text 'indent test with £' should be found in message" ); await TestUtils.waitForCondition( () => OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "unverified"), "signed unverified icon should display" ); Assert.ok( !OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon should not display" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that an encrypted inline message, with nbsp encoded as qp * in the PGP separator line, is trimmed and decrypted. */ add_task(async function testDecryptInlineWithNBSPasQP() { const opengpgprocessed = openpgpProcessed(); const msgc = await open_message_from_file( new FileUtils.File(getTestFilePath("data/eml/bob-enc-inline-nbsp-qp.eml")) ); const aboutMessage = get_about_message(msgc); await opengpgprocessed; Assert.ok( getMsgBodyTxt(msgc).includes("My real name is not Bob."), "Secret text should be contained in message" ); await TestUtils.waitForCondition( () => OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "Encrypted icon should be displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that an inline message, encoded as html message, with nbsp * encoded as qp in the PGP separator line, is trimmed and decrypted. */ add_task(async function testDecryptHtmlWithNBSP() { const opengpgprocessed = openpgpProcessed(); const msgc = await open_message_from_file( new FileUtils.File(getTestFilePath("data/eml/bob-enc-html-nbsp.eml")) ); const aboutMessage = get_about_message(msgc); await opengpgprocessed; Assert.ok( getMsgBodyTxt(msgc).includes("My real name is not Bob."), "Secret text should be contained in message" ); await TestUtils.waitForCondition( () => OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "Encrypted icon should be displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that opening an encrypted (and signed) message with non-ascii subject * and body works. */ add_task(async function testOpenAliceToBobEncryptedNonASCII() { const opengpgprocessed = openpgpProcessed(); const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/encrypted-and-signed-alice-to-bob-nonascii.eml") ) ); const aboutMessage = get_about_message(msgc); await opengpgprocessed; // Check the subject was properly updated (from ...) in the message header. Assert.equal( aboutMessage.document.getElementById("expandedsubjectBox").textContent, "Subject:Re: kod blå", "Non-ascii subject should correct" ); Assert.ok(getMsgBodyTxt(msgc).includes("Detta är krypterat!")); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "ok"), "signed verified icon should be displayed" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon should be displayed" ); await BrowserTestUtils.closeWindow(msgc); }); /** * Test that it's possible to decrypt an OpenPGP encrypted message * using a revoked key. (Also signed, unknown signer key.) */ add_task(async function testOpenEncryptedForRevokedKey() { await OpenPGPTestUtils.importPrivateKey( window, new FileUtils.File( getTestFilePath( "data/keys/carol@pgp.icu-0xEF2FD01608AFD744-revoked-secret.asc" ) ) ); const opengpgprocessed = openpgpProcessed(); const msgc = await open_message_from_file( new FileUtils.File( getTestFilePath("data/eml/enc-to-carol@pgp.icu-revoked.eml") ) ); const aboutMessage = get_about_message(msgc); await opengpgprocessed; Assert.ok( getMsgBodyTxt(msgc).includes("billie-jean"), "message text is in body" ); Assert.ok( OpenPGPTestUtils.hasEncryptedIconState(aboutMessage.document, "ok"), "encrypted icon should be displayed" ); await BrowserTestUtils.closeWindow(msgc); await OpenPGPTestUtils.removeKeyById("0xEF2FD01608AFD744", true); }); /** * Test that a git commit isn't confusing signed/encrypted states. * The MIME content type headers claim that we have an encrypted OpenPGP * message, while in fact we have a signed message. * The important part is to test that the message isn't incorrectly shown as * being encrypted. */ add_task(async function testGitCommitSpoof() { await OpenPGPTestUtils.importPublicKey( window, new FileUtils.File( getTestFilePath("data/keys/benny-hashwell-0xc55ccd9c5ab482b2-pub.asc") ) ); const opengpgprocessed = openpgpProcessed(); const msgc = await open_message_from_file( new FileUtils.File(getTestFilePath("data/eml/sigspoof-git-commit.eml")) ); const aboutMessage = get_about_message(msgc); await opengpgprocessed; // This (text#1) should be visible, and not confused with mail headers. Assert.ok( getMsgBodyTxt(msgc).includes( "tree 870fc0aaa5383d845fa9431c9d08cfd486e11a65" ), "message text#1 should be in body" ); // This (text#2), the normal text should be visible too. Assert.ok( getMsgBodyTxt(msgc).includes("Hope you find something good elsewhere!"), "message text#2 should be in body" ); // The signing status is currently "mismatch" though it's debatable // whether that is correct. // See bug https://bugzilla.mozilla.org/show_bug.cgi?id=1953402#c5 // Assert.ok( // OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "mismatch"), // "should say signed mismatch" // ); Assert.ok( OpenPGPTestUtils.hasNoEncryptedIconState(aboutMessage.document), "should not be say encrypted" ); await BrowserTestUtils.closeWindow(msgc); await OpenPGPTestUtils.removeKeyById("0xc55ccd9c5ab482b2", false); }); /** * Test that a missing signature is treated as bad signature. */ add_task(async function testStrippedSig() { const opengpgprocessed = openpgpProcessed(); const msgc = await open_message_from_file( new FileUtils.File(getTestFilePath("data/eml/openpgp__stripped_sig.eml")) ); const aboutMessage = get_about_message(msgc); await opengpgprocessed; // This (text#1) should be visible, and not confused with mail headers. Assert.ok( getMsgBodyTxt(msgc).includes("This is a test"), "message text should be in body" ); Assert.ok( OpenPGPTestUtils.hasSignedIconState(aboutMessage.document, "mismatch"), "should say signed mismatch" ); Assert.ok( OpenPGPTestUtils.hasNoEncryptedIconState(aboutMessage.document), "should not be say encrypted" ); await BrowserTestUtils.closeWindow(msgc); }); registerCleanupFunction(async function tearDown() { MailServices.accounts.removeAccount(aliceAcct, true); await OpenPGPTestUtils.removeKeyById("0xf231550c4f47e38e", true); });