From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../content/ui/attachmentItemContext.inc.xhtml | 17 + .../openpgp/content/ui/backupKeyPassword.js | 123 + .../openpgp/content/ui/backupKeyPassword.xhtml | 67 + .../openpgp/content/ui/changeExpiryDlg.js | 152 + .../openpgp/content/ui/changeExpiryDlg.xhtml | 73 + .../openpgp/content/ui/commonWorkflows.js | 194 ++ .../openpgp/content/ui/composeKeyStatus.js | 222 ++ .../openpgp/content/ui/composeKeyStatus.xhtml | 94 + .../openpgp/content/ui/confirmPubkeyImport.js | 102 + .../openpgp/content/ui/confirmPubkeyImport.xhtml | 55 + .../openpgp/content/ui/enigmailCommon.js | 69 + .../openpgp/content/ui/enigmailKeyImportInfo.js | 172 + .../openpgp/content/ui/enigmailKeyImportInfo.xhtml | 42 + .../openpgp/content/ui/enigmailKeyManager.js | 1442 ++++++++ .../openpgp/content/ui/enigmailKeyManager.xhtml | 406 +++ .../openpgp/content/ui/enigmailMessengerOverlay.js | 3460 ++++++++++++++++++++ .../openpgp/content/ui/enigmailMsgBox.js | 181 + .../openpgp/content/ui/enigmailMsgBox.xhtml | 71 + .../content/ui/enigmailMsgComposeOverlay.js | 3034 +++++++++++++++++ .../content/ui/enigmailMsgHdrViewOverlay.js | 1214 +++++++ .../openpgp/content/ui/keyAssistant.inc.xhtml | 119 + .../extensions/openpgp/content/ui/keyAssistant.js | 956 ++++++ .../extensions/openpgp/content/ui/keyDetailsDlg.js | 1119 +++++++ .../openpgp/content/ui/keyDetailsDlg.xhtml | 405 +++ .../extensions/openpgp/content/ui/keyWizard.js | 1195 +++++++ .../extensions/openpgp/content/ui/keyWizard.xhtml | 506 +++ .../openpgp/content/ui/oneRecipientStatus.js | 177 + .../openpgp/content/ui/oneRecipientStatus.xhtml | 86 + 28 files changed, 15753 insertions(+) create mode 100644 comm/mail/extensions/openpgp/content/ui/attachmentItemContext.inc.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/backupKeyPassword.js create mode 100644 comm/mail/extensions/openpgp/content/ui/backupKeyPassword.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/changeExpiryDlg.js create mode 100644 comm/mail/extensions/openpgp/content/ui/changeExpiryDlg.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/commonWorkflows.js create mode 100644 comm/mail/extensions/openpgp/content/ui/composeKeyStatus.js create mode 100644 comm/mail/extensions/openpgp/content/ui/composeKeyStatus.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/confirmPubkeyImport.js create mode 100644 comm/mail/extensions/openpgp/content/ui/confirmPubkeyImport.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/enigmailCommon.js create mode 100644 comm/mail/extensions/openpgp/content/ui/enigmailKeyImportInfo.js create mode 100644 comm/mail/extensions/openpgp/content/ui/enigmailKeyImportInfo.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/enigmailKeyManager.js create mode 100644 comm/mail/extensions/openpgp/content/ui/enigmailKeyManager.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/enigmailMessengerOverlay.js create mode 100644 comm/mail/extensions/openpgp/content/ui/enigmailMsgBox.js create mode 100644 comm/mail/extensions/openpgp/content/ui/enigmailMsgBox.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js create mode 100644 comm/mail/extensions/openpgp/content/ui/enigmailMsgHdrViewOverlay.js create mode 100644 comm/mail/extensions/openpgp/content/ui/keyAssistant.inc.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/keyAssistant.js create mode 100644 comm/mail/extensions/openpgp/content/ui/keyDetailsDlg.js create mode 100644 comm/mail/extensions/openpgp/content/ui/keyDetailsDlg.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/keyWizard.js create mode 100644 comm/mail/extensions/openpgp/content/ui/keyWizard.xhtml create mode 100644 comm/mail/extensions/openpgp/content/ui/oneRecipientStatus.js create mode 100644 comm/mail/extensions/openpgp/content/ui/oneRecipientStatus.xhtml (limited to 'comm/mail/extensions/openpgp/content/ui') diff --git a/comm/mail/extensions/openpgp/content/ui/attachmentItemContext.inc.xhtml b/comm/mail/extensions/openpgp/content/ui/attachmentItemContext.inc.xhtml new file mode 100644 index 0000000000..060752b497 --- /dev/null +++ b/comm/mail/extensions/openpgp/content/ui/attachmentItemContext.inc.xhtml @@ -0,0 +1,17 @@ +# 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/. + + + + + + diff --git a/comm/mail/extensions/openpgp/content/ui/backupKeyPassword.js b/comm/mail/extensions/openpgp/content/ui/backupKeyPassword.js new file mode 100644 index 0000000000..9916429bcb --- /dev/null +++ b/comm/mail/extensions/openpgp/content/ui/backupKeyPassword.js @@ -0,0 +1,123 @@ +/* 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"; + +/** + * @file Implements the functionality of backupKeyPassword.xhtml: + * a dialog that lets the user enter the password used to protect + * a backup of OpenPGP secret keys. + * Based on setp12password.js and setp12password.xhtml + */ + +/** + * @property {boolean} confirmedPassword + * Set to true if the user entered two matching passwords and + * confirmed the dialog. + * @property {string} password + * The password the user entered. Undefined value if + * |confirmedPassword| is not true. + */ + +let gAcceptButton; + +window.addEventListener("DOMContentLoaded", onLoad); + +/** + * onload() handler. + */ +function onLoad() { + // Ensure the first password textbox has focus. + document.getElementById("pw1").focus(); + document.addEventListener("dialogaccept", onDialogAccept); + gAcceptButton = document + .getElementById("backupKeyPassword") + .getButton("accept"); + gAcceptButton.disabled = true; +} + +/** + * ondialogaccept() handler. + */ +function onDialogAccept() { + window.arguments[0].okCallback( + document.getElementById("pw1").value, + window.arguments[0].fprArray, + window.arguments[0].file, + true + ); +} + +/** + * Calculates the strength of the given password, suitable for use in updating + * a progress bar that represents said strength. + * + * The strength of the password is calculated by checking the number of: + * - Characters + * - Numbers + * - Non-alphanumeric chars + * - Upper case characters + * + * @param {string} password + * The password to calculate the strength of. + * @returns {number} + * The strength of the password in the range [0, 100]. + */ +function getPasswordStrength(password) { + let lengthStrength = password.length; + if (lengthStrength > 5) { + lengthStrength = 5; + } + + let nonNumericChars = password.replace(/[0-9]/g, ""); + let numericStrength = password.length - nonNumericChars.length; + if (numericStrength > 3) { + numericStrength = 3; + } + + let nonSymbolChars = password.replace(/\W/g, ""); + let symbolStrength = password.length - nonSymbolChars.length; + if (symbolStrength > 3) { + symbolStrength = 3; + } + + let nonUpperAlphaChars = password.replace(/[A-Z]/g, ""); + let upperAlphaStrength = password.length - nonUpperAlphaChars.length; + if (upperAlphaStrength > 3) { + upperAlphaStrength = 3; + } + + let strength = + lengthStrength * 10 - + 20 + + numericStrength * 10 + + symbolStrength * 15 + + upperAlphaStrength * 10; + if (strength < 0) { + strength = 0; + } + if (strength > 100) { + strength = 100; + } + + return strength; +} + +/** + * oninput() handler for both password textboxes. + * + * @param {boolean} recalculatePasswordStrength + * Whether to recalculate the strength of the first password. + */ +function onPasswordInput(recalculatePasswordStrength) { + let pw1 = document.getElementById("pw1").value; + + if (recalculatePasswordStrength) { + document.getElementById("pwmeter").value = getPasswordStrength(pw1); + } + + // Disable the accept button if the two passwords don't match, and enable it + // if the passwords do match. + let pw2 = document.getElementById("pw2").value; + gAcceptButton.disabled = pw1 != pw2 || !pw1.length; +} diff --git a/comm/mail/extensions/openpgp/content/ui/backupKeyPassword.xhtml b/comm/mail/extensions/openpgp/content/ui/backupKeyPassword.xhtml new file mode 100644 index 0000000000..1fe18e1b0f --- /dev/null +++ b/comm/mail/extensions/openpgp/content/ui/backupKeyPassword.xhtml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + +
+ +

+
+ +

+ +

+ +
+
+ +
+ +
+ +
+ +
+ +
+
+
+ + diff --git a/comm/mail/extensions/openpgp/content/ui/commonWorkflows.js b/comm/mail/extensions/openpgp/content/ui/commonWorkflows.js new file mode 100644 index 0000000000..ac6c054e2f --- /dev/null +++ b/comm/mail/extensions/openpgp/content/ui/commonWorkflows.js @@ -0,0 +1,194 @@ +/* + * 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 { EnigmailDialog } = ChromeUtils.import( + "chrome://openpgp/content/modules/dialog.jsm" +); +var { EnigmailKey } = ChromeUtils.import( + "chrome://openpgp/content/modules/key.jsm" +); +var { EnigmailKeyRing } = ChromeUtils.import( + "chrome://openpgp/content/modules/keyRing.jsm" +); +var { EnigmailArmor } = ChromeUtils.import( + "chrome://openpgp/content/modules/armor.jsm" +); +var { MailStringUtils } = ChromeUtils.import( + "resource:///modules/MailStringUtils.jsm" +); + +var l10n = new Localization(["messenger/openpgp/openpgp.ftl"], true); + +/** + * opens a prompt, asking the user to enter passphrase for given key id + * returns: the passphrase if entered (empty string is allowed) + * resultFlags.canceled is set to true if the user clicked cancel + */ +function passphrasePromptCallback(win, promptString, resultFlags) { + let password = { value: "" }; + if (!Services.prompt.promptPassword(win, "", promptString, password)) { + resultFlags.canceled = true; + return ""; + } + + resultFlags.canceled = false; + return password.value; +} + +/** + * @param {nsIFile} file + * @returns {string} The first block of the wanted type, or empty string. + * Skip blocks of wrong type. + */ +async function getKeyBlockFromFile(file, wantSecret) { + let contents = await IOUtils.readUTF8(file.path).catch(() => ""); + let searchOffset = 0; + + while (searchOffset < contents.length) { + const beginIndexObj = {}; + const endIndexObj = {}; + const blockType = EnigmailArmor.locateArmoredBlock( + contents, + searchOffset, + "", + beginIndexObj, + endIndexObj, + {} + ); + if (!blockType) { + return ""; + } + + if ( + (wantSecret && blockType.search(/^PRIVATE KEY BLOCK$/) !== 0) || + (!wantSecret && blockType.search(/^PUBLIC KEY BLOCK$/) !== 0) + ) { + searchOffset = endIndexObj.value; + continue; + } + + return contents.substr( + beginIndexObj.value, + endIndexObj.value - beginIndexObj.value + 1 + ); + } + return ""; +} + +/** + * import OpenPGP keys from file + * + * @param {string} what - "rev" for revocation, "pub" for public keys + */ +async function EnigmailCommon_importObjectFromFile(what) { + if (what != "rev" && what != "pub") { + throw new Error(`Can't import. Invalid argument: ${what}`); + } + + let importingRevocation = what == "rev"; + let promptStr = importingRevocation ? "import-rev-file" : "import-key-file"; + + let files = EnigmailDialog.filePicker( + window, + l10n.formatValueSync(promptStr), + "", + false, + true, + "*.asc", + "", + [l10n.formatValueSync("gnupg-file"), "*.asc;*.gpg;*.pgp"] + ); + + if (!files.length) { + return; + } + + for (let file of files) { + if (file.fileSize > 5000000) { + document.l10n.formatValue("file-to-big-to-import").then(value => { + EnigmailDialog.alert(window, value); + }); + continue; + } + + let errorMsgObj = {}; + + if (importingRevocation) { + await EnigmailKeyRing.importRevFromFile(file); + continue; + } + + let importBinary = false; + let keyBlock = await getKeyBlockFromFile(file, false); + + // if we don't find an ASCII block, try to import as binary. + if (!keyBlock) { + importBinary = true; + let data = await IOUtils.read(file.path); + keyBlock = MailStringUtils.uint8ArrayToByteString(data); + } + + // Generate a preview of the imported key. + let preview = await EnigmailKey.getKeyListFromKeyBlock( + keyBlock, + errorMsgObj, + true, // interactive + true, + false // not secret + ); + + if (!preview || !preview.length || errorMsgObj.value) { + document.l10n.formatValue("import-keys-failed").then(value => { + EnigmailDialog.alert(window, value + "\n\n" + errorMsgObj.value); + }); + continue; + } + + if (preview.length > 0) { + let confirmImport = false; + let autoAcceptance = null; + let outParam = {}; + confirmImport = EnigmailDialog.confirmPubkeyImport( + window, + preview, + outParam + ); + if (confirmImport) { + autoAcceptance = outParam.acceptance; + } + + if (confirmImport) { + // import + let resultKeys = {}; + + let importExitCode = EnigmailKeyRing.importKey( + window, + false, // interactive, we already asked for confirmation + keyBlock, + importBinary, + null, // expected keyId, ignored + errorMsgObj, + resultKeys, + false, // minimize + [], // filter + true, // allow prompt for permissive + autoAcceptance + ); + + if (importExitCode !== 0) { + document.l10n.formatValue("import-keys-failed").then(value => { + EnigmailDialog.alert(window, value + "\n\n" + errorMsgObj.value); + }); + continue; + } + + EnigmailDialog.keyImportDlg(window, resultKeys.value); + } + } + } +} diff --git a/comm/mail/extensions/openpgp/content/ui/composeKeyStatus.js b/comm/mail/extensions/openpgp/content/ui/composeKeyStatus.js new file mode 100644 index 0000000000..a6320072ab --- /dev/null +++ b/comm/mail/extensions/openpgp/content/ui/composeKeyStatus.js @@ -0,0 +1,222 @@ +/* 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/. */ + +var { EnigmailFuncs } = ChromeUtils.import( + "chrome://openpgp/content/modules/funcs.jsm" +); +var EnigmailKeyRing = ChromeUtils.import( + "chrome://openpgp/content/modules/keyRing.jsm" +).EnigmailKeyRing; +var { EnigmailWindows } = ChromeUtils.import( + "chrome://openpgp/content/modules/windows.jsm" +); +var { EnigmailKey } = ChromeUtils.import( + "chrome://openpgp/content/modules/key.jsm" +); +const { OpenPGPAlias } = ChromeUtils.import( + "chrome://openpgp/content/modules/OpenPGPAlias.jsm" +); +const { PgpSqliteDb2 } = ChromeUtils.import( + "chrome://openpgp/content/modules/sqliteDb.jsm" +); + +var gListBox; +var gViewButton; + +var gEmailAddresses = []; +var gRowToEmail = []; + +// One boolean entry per row. True means it is an alias row. +// This allows us to use different dialog behavior for alias entries. +var gAliasRows = []; + +var gMapAddressToKeyObjs = null; + +function addRecipients(toAddrList, recList) { + for (var i = 0; i < recList.length; i++) { + try { + let entry = EnigmailFuncs.stripEmail(recList[i].replace(/[",]/g, "")); + toAddrList.push(entry); + } catch (ex) { + console.debug(ex); + } + } +} + +async function setListEntries() { + gMapAddressToKeyObjs = new Map(); + + for (let addr of gEmailAddresses) { + addr = addr.toLowerCase(); + + let statusStringID = null; + let statusStringDirect = ""; + + let aliasKeyList = EnigmailKeyRing.getAliasKeyList(addr); + let isAlias = !!aliasKeyList; + + if (isAlias) { + let aliasKeys = EnigmailKeyRing.getAliasKeys(aliasKeyList); + if (!aliasKeys.length) { + // failure, at least one alias key is unusable/unavailable + statusStringDirect = await document.l10n.formatValue( + "openpgp-compose-alias-status-error" + ); + } else { + statusStringDirect = await document.l10n.formatValue( + "openpgp-compose-alias-status-direct", + { + count: aliasKeys.length, + } + ); + } + } else { + // We ask to include keys which are expired, because that's what + // our sub dialog oneRecipientStatus needs. This is for + // efficiency - because otherwise the sub dialog would have to + // query all keys again. + // The consequence is, we need to later call isValidForEncryption + // for the keys we have obtained, to confirm they are really valid. + let foundKeys = await EnigmailKeyRing.getMultValidKeysForOneRecipient( + addr, + true + ); + if (!foundKeys || !foundKeys.length) { + statusStringID = "openpgp-recip-missing"; + } else { + gMapAddressToKeyObjs.set(addr, foundKeys); + for (let keyObj of foundKeys) { + let goodPersonal = false; + if (keyObj.secretAvailable) { + goodPersonal = await PgpSqliteDb2.isAcceptedAsPersonalKey( + keyObj.fpr + ); + } + if ( + goodPersonal || + (EnigmailKeyRing.isValidForEncryption(keyObj) && + (keyObj.acceptance == "verified" || + keyObj.acceptance == "unverified")) + ) { + statusStringID = "openpgp-recip-good"; + break; + } + } + if (!statusStringID) { + statusStringID = "openpgp-recip-none-accepted"; + } + } + } + + let listitem = document.createXULElement("richlistitem"); + + let emailItem = document.createXULElement("label"); + emailItem.setAttribute("value", addr); + emailItem.setAttribute("crop", "end"); + emailItem.setAttribute("style", "width: var(--recipientWidth)"); + listitem.appendChild(emailItem); + + let status = document.createXULElement("label"); + + if (statusStringID) { + document.l10n.setAttributes(status, statusStringID); + } else { + status.setAttribute("value", statusStringDirect); + } + + status.setAttribute("crop", "end"); + status.setAttribute("style", "width: var(--statusWidth)"); + listitem.appendChild(status); + + gListBox.appendChild(listitem); + + gRowToEmail.push(addr); + gAliasRows.push(isAlias); + } +} + +async function onLoad() { + let params = window.arguments[0]; + if (!params) { + return; + } + + try { + await OpenPGPAlias.load(); + } catch (ex) { + console.log("failed to load OpenPGP alias file: " + ex); + } + + gListBox = document.getElementById("infolist"); + gViewButton = document.getElementById("detailsButton"); + + var arrLen = {}; + var recList; + + if (params.compFields.to) { + recList = params.compFields.splitRecipients( + params.compFields.to, + true, + arrLen + ); + addRecipients(gEmailAddresses, recList); + } + if (params.compFields.cc) { + recList = params.compFields.splitRecipients( + params.compFields.cc, + true, + arrLen + ); + addRecipients(gEmailAddresses, recList); + } + if (params.compFields.bcc) { + recList = params.compFields.splitRecipients( + params.compFields.bcc, + true, + arrLen + ); + addRecipients(gEmailAddresses, recList); + } + + await setListEntries(); +} + +async function reloadAndReselect(selIndex = -1) { + while (true) { + let child = gListBox.lastChild; + // keep first child, which is the header + if (child == gListBox.firstChild) { + break; + } + gListBox.removeChild(child); + } + gRowToEmail = []; + await setListEntries(); + gListBox.selectedIndex = selIndex; +} + +function onSelectionChange(event) { + // We don't offer detail management/discovery for email addresses + // that match an alias rule. + gViewButton.disabled = + !gListBox.selectedItems.length || gAliasRows[gListBox.selectedIndex]; +} + +function viewSelectedEmail() { + let selIndex = gListBox.selectedIndex; + if (gViewButton.disabled || selIndex == -1) { + return; + } + let email = gRowToEmail[selIndex]; + window.openDialog( + "chrome://openpgp/content/ui/oneRecipientStatus.xhtml", + "", + "chrome,modal,resizable,centerscreen", + { + email, + keys: gMapAddressToKeyObjs.get(email), + } + ); + reloadAndReselect(selIndex); +} diff --git a/comm/mail/extensions/openpgp/content/ui/composeKeyStatus.xhtml b/comm/mail/extensions/openpgp/content/ui/composeKeyStatus.xhtml new file mode 100644 index 0000000000..fc0192a8a6 --- /dev/null +++ b/comm/mail/extensions/openpgp/content/ui/composeKeyStatus.xhtml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3