/* * 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 https://mozilla.org/MPL/2.0/. */ "use strict"; var EXPORTED_SYMBOLS = ["EnigmailMsgRead"]; /** * Message-reading related functions */ const { XPCOMUtils } = ChromeUtils.importESModule( "resource://gre/modules/XPCOMUtils.sys.mjs" ); const lazy = {}; XPCOMUtils.defineLazyModuleGetters(lazy, { EnigmailFuncs: "chrome://openpgp/content/modules/funcs.jsm", EnigmailKeyRing: "chrome://openpgp/content/modules/keyRing.jsm", }); var EnigmailMsgRead = { /** * Ensure that Thunderbird prepares certain headers during message reading */ ensureExtraAddonHeaders() { let hdr = Services.prefs.getCharPref("mailnews.headers.extraAddonHeaders"); if (hdr !== "*") { // do nothing if extraAddonHeaders is "*" (all headers) for (let h of ["autocrypt", "openpgp"]) { if (hdr.search(h) < 0) { if (hdr.length > 0) { hdr += " "; } hdr += h; } } Services.prefs.setCharPref("mailnews.headers.extraAddonHeaders", hdr); } }, /** * Get a mail URL from a uriSpec * * @param uriSpec: String - URI of the desired message * * @returns Object: nsIURL or nsIMsgMailNewsUrl object */ getUrlFromUriSpec(uriSpec) { return lazy.EnigmailFuncs.getUrlFromUriSpec(uriSpec); }, /** * Determine if an attachment is possibly signed */ checkSignedAttachment(attachmentObj, index, currentAttachments) { function escapeRegex(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string } var attachmentList; if (index !== null) { attachmentList = attachmentObj; } else { attachmentList = currentAttachments; for (let i = 0; i < attachmentList.length; i++) { if (attachmentList[i].url == attachmentObj.url) { index = i; break; } } if (index === null) { return false; } } var signed = false; var findFile; var attName = this.getAttachmentName(attachmentList[index]) .toLowerCase() .replace(/\+/g, "\\+"); // check if filename is a signature if ( this.getAttachmentName(attachmentList[index]).search(/\.(sig|asc)$/i) > 0 || attachmentList[index].contentType.match(/^application\/pgp-signature/i) ) { findFile = new RegExp(escapeRegex(attName.replace(/\.(sig|asc)$/, ""))); } else if (attName.search(/\.pgp$/i) > 0) { findFile = new RegExp( escapeRegex(attName.replace(/\.pgp$/, "")) + "(\\.pgp)?\\.(sig|asc)$" ); } else { findFile = new RegExp(escapeRegex(attName) + "\\.(sig|asc)$"); } for (let i in attachmentList) { if ( i != index && this.getAttachmentName(attachmentList[i]) .toLowerCase() .search(findFile) === 0 ) { signed = true; } } return signed; }, /** * Get the name of an attachment from the attachment object */ getAttachmentName(attachment) { return attachment.name; }, /** * Escape text such that it can be used as HTML text */ escapeTextForHTML(text, hyperlink) { // Escape special characters if (text.indexOf("&") > -1) { text = text.replace(/&/g, "&"); } if (text.indexOf("<") > -1) { text = text.replace(/") > -1) { text = text.replace(/>/g, ">"); } if (text.indexOf('"') > -1) { text = text.replace(/"/g, """); } if (!hyperlink) { return text; } // Hyperlink email addresses (we accept at most 1024 characters before and after the @) var addrs = text.match( /\b[A-Za-z0-9_+.-]{1,1024}@[A-Za-z0-9.-]{1,1024}\b/g ); var newText, offset, loc; if (addrs && addrs.length) { newText = ""; offset = 0; for (var j = 0; j < addrs.length; j++) { var addr = addrs[j]; loc = text.indexOf(addr, offset); if (loc < offset) { break; } if (loc > offset) { newText += text.substr(offset, loc - offset); } // Strip any period off the end of address addr = addr.replace(/[.]$/, ""); if (!addr.length) { continue; } newText += '' + addr + ""; offset = loc + addr.length; } newText += text.substr(offset, text.length - offset); text = newText; } // Hyperlink URLs (we don't accept URLS or more than 1024 characters length) var urls = text.match(/\b(http|https|ftp):\S{1,1024}\s/g); if (urls && urls.length) { newText = ""; offset = 0; for (var k = 0; k < urls.length; k++) { var url = urls[k]; loc = text.indexOf(url, offset); if (loc < offset) { break; } if (loc > offset) { newText += text.substr(offset, loc - offset); } // Strip delimiters off the end of URL url = url.replace(/\s$/, ""); url = url.replace(/([),.']|>|")$/, ""); if (!url.length) { continue; } newText += '' + url + ""; offset = loc + url.length; } newText += text.substr(offset, text.length - offset); text = newText; } return text; }, /** * Match the key to the sender's from address * * @param {string} keyId: signing key ID * @param {string} fromAddr: sender's email address * * @returns Promise: matching email address */ matchUidToSender(keyId, fromAddr) { if (!fromAddr || !keyId) { return null; } try { fromAddr = lazy.EnigmailFuncs.stripEmail(fromAddr).toLowerCase(); } catch (ex) { console.debug(ex); } let keyObj = lazy.EnigmailKeyRing.getKeyById(keyId); if (!keyObj) { return null; } let userIdList = keyObj.userIds; try { for (let i = 0; i < userIdList.length; i++) { if ( fromAddr == lazy.EnigmailFuncs.stripEmail(userIdList[i].userId).toLowerCase() ) { let result = lazy.EnigmailFuncs.stripEmail(userIdList[i].userId); return result; } } } catch (ex) { console.debug(ex); } return null; }, searchQuotedPgp(node) { if ( node.nodeName.toLowerCase() === "blockquote" && node.textContent.includes("-----BEGIN PGP ") ) { return true; } if (node.firstChild && this.searchQuotedPgp(node.firstChild)) { return true; } if (node.nextSibling && this.searchQuotedPgp(node.nextSibling)) { return true; } return false; }, };