Merge comm-central to ash
--HG-- rename : mail/base/content/mainPopupSet.inc.xhtml => mail/base/content/widgets/browserPopups.inc.xhtml
This commit is contained in:
Коммит
a5e68baacf
|
@ -79,7 +79,6 @@ module.exports = {
|
|||
"import/named": "error",
|
||||
"import/namespace": "error",
|
||||
"import/newline-after-import": "error",
|
||||
"import/no-anonymous-default-export": "error",
|
||||
"import/no-duplicates": "error",
|
||||
"import/no-absolute-path": "error",
|
||||
"import/no-named-default": "error",
|
||||
|
@ -96,6 +95,12 @@ module.exports = {
|
|||
"import/no-useless-path-segments": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["mail/components/storybook/**"],
|
||||
rules: {
|
||||
"import/no-unresolved": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
...removeOverrides(xpcshellTestConfig),
|
||||
files: xpcshellTestPaths.map(path => `${path}**`),
|
||||
|
|
|
@ -2,4 +2,5 @@ pth:comm/testing/marionette
|
|||
pth:comm/python/l10n
|
||||
pth:comm/python/mach
|
||||
pth:comm/taskcluster
|
||||
pth:comm/python/rocbuild
|
||||
pth:comm/python/thirdroc
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
pref("mailnews.start_page.url", "https://live.thunderbird.net/%APP%/start?locale=%LOCALE%&version=%VERSION%&channel=%CHANNEL%&os=%OS%&buildid=%APPBUILDID%");
|
||||
|
||||
// start page override to load after an update
|
||||
pref("mailnews.start_page.override_url", "https://live.thunderbird.net/%APP%/whatsnew?locale=%LOCALE%&version=%VERSION%&channel=%CHANNEL%&os=%OS%&buildid=%APPBUILDID%&oldversion=%OLD_VERSION%");
|
||||
// pref("mailnews.start_page.override_url", "https://live.thunderbird.net/%APP%/whatsnew?locale=%LOCALE%&version=%VERSION%&channel=%CHANNEL%&os=%OS%&buildid=%APPBUILDID%&oldversion=%OLD_VERSION%");
|
||||
// Leave blank per bug 1695529 until the website has a proper "Thunderbird Daily" landing page
|
||||
pref("mailnews.start_page.override_url", "");
|
||||
|
||||
// There's no Thunderbird Daily specific page or release notes
|
||||
// URL user can browse to manually if for some reason all update installation
|
||||
|
|
|
@ -176,10 +176,10 @@
|
|||
<vbox id="contextPaneFlexibleBox" flex="1">
|
||||
<vbox flex="1" class="conv-chat" width="150">
|
||||
<hbox align="baseline" class="conv-nicklist-header input-container">
|
||||
<label id="participantLabel"
|
||||
class="conv-nicklist-header-label"
|
||||
<label class="conv-nicklist-header-label conv-header-label"
|
||||
control="participantCount"
|
||||
value="&chat.participants;"/>
|
||||
value="&chat.participants;"
|
||||
crop="end"/>
|
||||
<html:input id="participantCount" readonly="readonly" class="plain"/>
|
||||
</hbox>
|
||||
<richlistbox id="nicklist" class="conv-nicklist"
|
||||
|
@ -191,8 +191,8 @@
|
|||
</vbox>
|
||||
<splitter id="logsSplitter" class="conv-chat" collapse="after" orient="vertical"/>
|
||||
<vbox flex="1" id="previousConversations" style="min-height: 200px;">
|
||||
<label class="conv-logs-header-label"
|
||||
id="participantLabel"
|
||||
<label class="conv-logs-header-label conv-header-label"
|
||||
crop="end"
|
||||
value="&chat.previousConversations;"/>
|
||||
<tree id="logTree" flex="1" hidecolumnpicker="true" seltype="single"
|
||||
context="logTreeContext" onselect="chatHandler.onLogSelect();">
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
/* 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/. */
|
||||
module.exports = {
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
},
|
||||
};
|
|
@ -11,7 +11,7 @@ const path = require("path");
|
|||
module.exports = {
|
||||
stories: [
|
||||
"../stories/**/*.stories.mdx",
|
||||
"../stories/**/*.stories.@(js|jsx|ts|tsx)",
|
||||
"../stories/**/*.stories.@(mjs|jsx|ts|tsx)",
|
||||
],
|
||||
addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
|
||||
framework: "@storybook/web-components",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import { html } from "lit";
|
||||
import "mail/themes/shared/mail/colors.css";
|
||||
import "mail/themes/shared/mail/colors.css"; //eslint-disable-line import/no-unassigned-import
|
||||
|
||||
const FORMATTER = new Intl.NumberFormat("en", {
|
||||
numberingSystem: "latn",
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import { html } from "lit";
|
||||
import "mail/base/content/widgets/pane-splitter.js";
|
||||
import "mail/base/content/widgets/pane-splitter.js"; //eslint-disable-line import/no-unassigned-import
|
||||
|
||||
export default {
|
||||
title: "Widgets/Pane Splitter",
|
|
@ -106,11 +106,9 @@ pref("temp.openpgp.inlineSigAttachExt", ".sig");
|
|||
// debug log directory (if set, also enabled debugging)
|
||||
pref("temp.openpgp.logDirectory", "");
|
||||
|
||||
// list of key servers to use (comma separated list)
|
||||
pref("temp.openpgp.keyserver", "vks://keys.openpgp.org");
|
||||
|
||||
// auto select the first keyserver in the key server list
|
||||
pref("temp.openpgp.autoKeyServerSelection", true);
|
||||
// List of key servers to use (comma separated list), ordered by priority.
|
||||
// Only the first supported keyserver will be used for uploading keys.
|
||||
pref("mail.openpgp.keyserver_list", "vks://keys.openpgp.org, hkps://keys.mailvelope.com");
|
||||
|
||||
// keep passphrase for ... minutes
|
||||
pref("temp.openpgp.maxIdleMinutes", 5);
|
||||
|
@ -194,9 +192,6 @@ pref("temp.openpgp.warnDeprecatedGnuPG", true);
|
|||
// warn if gpg-agent is found and "remember passphrase for X minutes is active"
|
||||
pref("temp.openpgp.warnGpgAgentAndIdleTime", true);
|
||||
|
||||
// display a warning when all keys are to be refreshed
|
||||
pref("temp.openpgp.warnRefreshAll", true);
|
||||
|
||||
// display a warning when the keys for all contacts are downloaded
|
||||
pref("temp.openpgp.warnDownloadContactKeys", true);
|
||||
|
||||
|
@ -218,21 +213,6 @@ pref("temp.openpgp.searchKeyWithTor", false);
|
|||
pref("temp.openpgp.searchKeyRequireTor", false);
|
||||
pref("temp.openpgp.uploadKeyWithTor", false);
|
||||
pref("temp.openpgp.uploadKeyRequireTor", false);
|
||||
pref("temp.openpgp.refreshAllKeysWithTor", false);
|
||||
pref("temp.openpgp.refreshAllKeysRequireTor", false);
|
||||
|
||||
// Hours per week that Enigmail is available for refreshing keys
|
||||
// The smaller the hours available, the more often the refresh
|
||||
// will happen to accommodate.
|
||||
pref("temp.openpgp.hoursPerWeekEnigmailIsOn", 40);
|
||||
|
||||
// The minimum number of seconds to wait between refreshing keys.
|
||||
// Applied if the refresh frequence from hoursPerWeekEnigmailIsOn
|
||||
// goes too low
|
||||
pref("temp.openpgp.refreshMinDelaySeconds", 300);
|
||||
|
||||
// Toggle to have user keys continuously refreshed
|
||||
pref("temp.openpgp.keyRefreshOn", false);
|
||||
|
||||
// enable experimental features.
|
||||
// WARNING: such features may unfinished functions or tests that can break
|
||||
|
|
|
@ -129,8 +129,6 @@ Enigmail.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
//getEnigmailKeyRefreshService().start(getEnigmailKeyServer());
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
lazy.EnigmailLog.DEBUG("core.jsm: Enigmail.initialize: END\n");
|
||||
|
|
|
@ -241,12 +241,13 @@ var EnigmailEncryption = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Determine if the sender key ID or user ID can be used for signing and/or encryption
|
||||
* Determine if the sender key ID or user ID can be used for signing and/or
|
||||
* encryption
|
||||
*
|
||||
* @param sendFlags: Number - the send Flags; need to contain SEND_SIGNED and/or SEND_ENCRYPTED
|
||||
* @param fromKeyId: String - the sender key ID
|
||||
* @param {integer} sendFlags - The send Flags; need to contain SEND_SIGNED and/or SEND_ENCRYPTED
|
||||
* @param {string} fromKeyId - The sender key ID
|
||||
*
|
||||
* @returns Object:
|
||||
* @returns {object} object
|
||||
* - keyId: String - the found key ID, or null if fromMailAddr is not valid
|
||||
* - errorMsg: String - the error message if key not valid, or null if key is valid
|
||||
*/
|
||||
|
|
|
@ -48,92 +48,119 @@ var KeyLookupHelper = {
|
|||
* @returns {boolean} flags.foundUnchanged - All found keys are identical to already existing local keys.
|
||||
* @returns {boolean} flags.collectedForLater - At least one key was added to CollectedKeysDB.
|
||||
*/
|
||||
|
||||
isExpiredOrRevoked(keyTrust) {
|
||||
return keyTrust.match(/e/i) || keyTrust.match(/r/i);
|
||||
},
|
||||
|
||||
async _lookupAndImportOnKeyserver(mode, window, identifier) {
|
||||
let keyImported = false;
|
||||
let foundUpdated = false;
|
||||
let foundUnchanged = false;
|
||||
let collectedForLater = false;
|
||||
|
||||
let defKs = lazy.EnigmailKeyserverURIs.getDefaultKeyServer();
|
||||
if (!defKs) {
|
||||
let ksArray = lazy.EnigmailKeyserverURIs.getKeyServers();
|
||||
if (!ksArray.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let vks = await lazy.EnigmailKeyServer.downloadNoImport(identifier, defKs);
|
||||
if (vks && "keyData" in vks) {
|
||||
let errorInfo = {};
|
||||
let keyList = await lazy.EnigmailKey.getKeyListFromKeyBlock(
|
||||
vks.keyData,
|
||||
errorInfo,
|
||||
false,
|
||||
true,
|
||||
false
|
||||
);
|
||||
// We might get a zero length keyList, if we refuse to use the key
|
||||
// that we received because of its properties.
|
||||
if (keyList && keyList.length == 1) {
|
||||
let oldKey = lazy.EnigmailKeyRing.getKeyById(keyList[0].fpr);
|
||||
if (oldKey) {
|
||||
await lazy.EnigmailKeyRing.importKeyDataSilent(
|
||||
window,
|
||||
vks.keyData,
|
||||
true,
|
||||
"0x" + keyList[0].fpr
|
||||
);
|
||||
|
||||
let updatedKey = lazy.EnigmailKeyRing.getKeyById(keyList[0].fpr);
|
||||
// If new imported/merged key is equal to old key,
|
||||
// don't notify about new keys details.
|
||||
if (JSON.stringify(oldKey) !== JSON.stringify(updatedKey)) {
|
||||
foundUpdated = true;
|
||||
keyImported = true;
|
||||
if (mode == "interactive-import") {
|
||||
lazy.EnigmailDialog.keyImportDlg(
|
||||
window,
|
||||
keyList.map(a => a.id)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
foundUnchanged = true;
|
||||
}
|
||||
} else {
|
||||
keyList = keyList.filter(k => k.userIds.length);
|
||||
if (keyList.length && mode == "interactive-import") {
|
||||
keyImported = await lazy.EnigmailKeyRing.importKeyDataWithConfirmation(
|
||||
window,
|
||||
keyList,
|
||||
vks.keyData,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (!keyImported) {
|
||||
collectedForLater = true;
|
||||
let db = await lazy.CollectedKeysDB.getInstance();
|
||||
for (let newKey of keyList) {
|
||||
// If key is known in the db: merge + update.
|
||||
let key = await db.mergeExisting(newKey, vks.keyData, {
|
||||
uri: lazy.EnigmailKeyServer.serverReqURL(
|
||||
`0x${newKey.fpr}`,
|
||||
defKs
|
||||
),
|
||||
type: "keyserver",
|
||||
});
|
||||
await db.storeKey(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (keyList.length > 1) {
|
||||
throw new Error(
|
||||
"Unexpected multiple results from verifying keyserver."
|
||||
);
|
||||
}
|
||||
console.debug(
|
||||
"failed to process data retrieved from keyserver: " + errorInfo.value
|
||||
let continueSearching = true;
|
||||
for (let ks of ksArray) {
|
||||
let foundKey;
|
||||
if (ks.startsWith("vks://")) {
|
||||
foundKey = await lazy.EnigmailKeyServer.downloadNoImport(
|
||||
identifier,
|
||||
ks
|
||||
);
|
||||
} else if (ks.startsWith("hkp://") || ks.startsWith("hkps://")) {
|
||||
foundKey = await lazy.EnigmailKeyServer.searchAndDownloadSingleResultNoImport(
|
||||
identifier,
|
||||
ks
|
||||
);
|
||||
}
|
||||
} else {
|
||||
console.debug("searchKeysOnInternet no data found on keyserver");
|
||||
if (foundKey && "keyData" in foundKey) {
|
||||
let errorInfo = {};
|
||||
let keyList = await lazy.EnigmailKey.getKeyListFromKeyBlock(
|
||||
foundKey.keyData,
|
||||
errorInfo,
|
||||
false,
|
||||
true,
|
||||
false
|
||||
);
|
||||
// We might get a zero length keyList, if we refuse to use the key
|
||||
// that we received because of its properties.
|
||||
if (keyList && keyList.length == 1) {
|
||||
let oldKey = lazy.EnigmailKeyRing.getKeyById(keyList[0].fpr);
|
||||
if (oldKey) {
|
||||
await lazy.EnigmailKeyRing.importKeyDataSilent(
|
||||
window,
|
||||
foundKey.keyData,
|
||||
true,
|
||||
"0x" + keyList[0].fpr
|
||||
);
|
||||
|
||||
let updatedKey = lazy.EnigmailKeyRing.getKeyById(keyList[0].fpr);
|
||||
// If new imported/merged key is equal to old key,
|
||||
// don't notify about new keys details.
|
||||
if (JSON.stringify(oldKey) !== JSON.stringify(updatedKey)) {
|
||||
foundUpdated = true;
|
||||
keyImported = true;
|
||||
if (mode == "interactive-import") {
|
||||
lazy.EnigmailDialog.keyImportDlg(
|
||||
window,
|
||||
keyList.map(a => a.id)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
foundUnchanged = true;
|
||||
}
|
||||
} else {
|
||||
keyList = keyList.filter(k => k.userIds.length);
|
||||
keyList = keyList.filter(k => !this.isExpiredOrRevoked(k.keyTrust));
|
||||
if (keyList.length && mode == "interactive-import") {
|
||||
keyImported = await lazy.EnigmailKeyRing.importKeyDataWithConfirmation(
|
||||
window,
|
||||
keyList,
|
||||
foundKey.keyData,
|
||||
true
|
||||
);
|
||||
if (keyImported) {
|
||||
// In interactive mode, don't offer the user to import keys multiple times.
|
||||
// When silently collecting keys, it's fine to discover everything we can.
|
||||
continueSearching = false;
|
||||
}
|
||||
}
|
||||
if (!keyImported) {
|
||||
collectedForLater = true;
|
||||
let db = await lazy.CollectedKeysDB.getInstance();
|
||||
for (let newKey of keyList) {
|
||||
// If key is known in the db: merge + update.
|
||||
let key = await db.mergeExisting(newKey, foundKey.keyData, {
|
||||
uri: lazy.EnigmailKeyServer.serverReqURL(
|
||||
`0x${newKey.fpr}`,
|
||||
ks
|
||||
),
|
||||
type: "keyserver",
|
||||
});
|
||||
await db.storeKey(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (keyList && keyList.length > 1) {
|
||||
throw new Error("Unexpected multiple results from keyserver " + ks);
|
||||
}
|
||||
console.log(
|
||||
"failed to process data retrieved from keyserver " +
|
||||
ks +
|
||||
": " +
|
||||
errorInfo.value
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!continueSearching) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return { keyImported, foundUpdated, foundUnchanged, collectedForLater };
|
||||
|
@ -269,6 +296,7 @@ var KeyLookupHelper = {
|
|||
wkdKeyImported = true;
|
||||
}
|
||||
|
||||
newKeys = newKeys.filter(k => !this.isExpiredOrRevoked(k.keyTrust));
|
||||
if (newKeys.length && mode == "interactive-import") {
|
||||
wkdKeyImported =
|
||||
wkdKeyImported ||
|
||||
|
|
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
* 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";
|
||||
|
||||
const EXPORTED_SYMBOLS = ["EnigmailKeyRefreshService"];
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/XPCOMUtils.sys.mjs"
|
||||
);
|
||||
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
EnigmailKeyRing: "chrome://openpgp/content/modules/keyRing.jsm",
|
||||
EnigmailKeyServer: "chrome://openpgp/content/modules/keyserver.jsm",
|
||||
EnigmailKeyserverURIs: "chrome://openpgp/content/modules/keyserverUris.jsm",
|
||||
EnigmailLog: "chrome://openpgp/content/modules/log.jsm",
|
||||
});
|
||||
|
||||
const ONE_HOUR_IN_MILLISEC = 60 * 60 * 1000;
|
||||
|
||||
let gTimer = null;
|
||||
|
||||
function getTimer() {
|
||||
if (gTimer === null) {
|
||||
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
}
|
||||
return gTimer;
|
||||
}
|
||||
|
||||
function calculateMaxTimeForRefreshInMilliseconds(totalPublicKeys) {
|
||||
const millisecondsAvailableForRefresh =
|
||||
Services.prefs.getIntPref("temp.openpgp.hoursPerWeekEnigmailIsOn") *
|
||||
ONE_HOUR_IN_MILLISEC;
|
||||
return Math.floor(millisecondsAvailableForRefresh / totalPublicKeys);
|
||||
}
|
||||
|
||||
function calculateWaitTimeInMilliseconds(totalPublicKeys) {
|
||||
const randomNumber = crypto.getRandomValues(new Uint32Array(1));
|
||||
const maxTimeForRefresh = calculateMaxTimeForRefreshInMilliseconds(
|
||||
totalPublicKeys
|
||||
);
|
||||
const minDelay =
|
||||
Services.prefs.getIntPref("temp.openpgp.refreshMinDelaySeconds") * 1000;
|
||||
|
||||
lazy.EnigmailLog.DEBUG(
|
||||
"keyRefreshService.jsm: Wait time = random number: " +
|
||||
randomNumber +
|
||||
" % max time for refresh: " +
|
||||
maxTimeForRefresh +
|
||||
"\n"
|
||||
);
|
||||
|
||||
let millisec = randomNumber % maxTimeForRefresh;
|
||||
if (millisec < minDelay) {
|
||||
millisec += minDelay;
|
||||
}
|
||||
|
||||
lazy.EnigmailLog.DEBUG(
|
||||
"keyRefreshService.jsm: Time until next refresh in milliseconds: " +
|
||||
millisec +
|
||||
"\n"
|
||||
);
|
||||
|
||||
return millisec;
|
||||
}
|
||||
|
||||
function refreshKey() {
|
||||
const timer = getTimer();
|
||||
refreshWith(lazy.EnigmailKeyServer, timer, true);
|
||||
}
|
||||
|
||||
function restartTimerInOneHour(timer) {
|
||||
timer.initWithCallback(
|
||||
refreshKey,
|
||||
ONE_HOUR_IN_MILLISEC,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT
|
||||
);
|
||||
}
|
||||
|
||||
function setupNextRefresh(timer, waitTime) {
|
||||
timer.initWithCallback(refreshKey, waitTime, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
function logMissingInformation(keyIdsExist, validKeyserversExist) {
|
||||
if (!keyIdsExist) {
|
||||
lazy.EnigmailLog.DEBUG(
|
||||
"keyRefreshService.jsm: No keys available to refresh yet. Will recheck in an hour.\n"
|
||||
);
|
||||
}
|
||||
if (!validKeyserversExist) {
|
||||
lazy.EnigmailLog.DEBUG(
|
||||
"keyRefreshService.jsm: Either no keyservers exist or the protocols specified are invalid. Will recheck in an hour.\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomKeyId(randomNumber) {
|
||||
const keyRingLength = lazy.EnigmailKeyRing.getAllKeys().keyList.length;
|
||||
|
||||
if (keyRingLength === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return lazy.EnigmailKeyRing.getAllKeys().keyList[randomNumber % keyRingLength]
|
||||
.keyId;
|
||||
}
|
||||
|
||||
function refreshKeyIfReady(keyserver, readyToRefresh, keyId) {
|
||||
if (readyToRefresh) {
|
||||
lazy.EnigmailLog.DEBUG(
|
||||
"keyRefreshService.jsm: refreshing key ID " + keyId + "\n"
|
||||
);
|
||||
return keyserver.download(keyId);
|
||||
}
|
||||
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
async function refreshWith(keyserver, timer, readyToRefresh) {
|
||||
const keyId = getRandomKeyId(crypto.getRandomValues(new Uint32Array(1)));
|
||||
const keyIdsExist = keyId !== null;
|
||||
const validKeyserversExist = lazy.EnigmailKeyserverURIs.validKeyserversExist();
|
||||
const ioService = Services.io;
|
||||
|
||||
if (keyIdsExist && validKeyserversExist) {
|
||||
if (ioService && !ioService.offline) {
|
||||
// don't try to refresh if we are offline
|
||||
await refreshKeyIfReady(keyserver, readyToRefresh, keyId);
|
||||
} else {
|
||||
lazy.EnigmailLog.DEBUG(
|
||||
"keyRefreshService.jsm: offline - not refreshing any key\n"
|
||||
);
|
||||
}
|
||||
const waitTime = calculateWaitTimeInMilliseconds(
|
||||
lazy.EnigmailKeyRing.getAllKeys().keyList.length
|
||||
);
|
||||
setupNextRefresh(timer, waitTime);
|
||||
} else {
|
||||
logMissingInformation(keyIdsExist, validKeyserversExist);
|
||||
restartTimerInOneHour(timer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a process to continuously refresh keys on a random time interval and in random order.
|
||||
*
|
||||
* The default time period for all keys to be refreshed is one week, although the user can specifically set this in their preferences
|
||||
* The wait time to refresh the next key is selected at random, from a range of zero milliseconds to the maximum time to refresh a key
|
||||
*
|
||||
* The maximum time to refresh a single key is calculated by averaging the total refresh time by the total number of public keys to refresh
|
||||
* For example, if a user has 12 public keys to refresh, the maximum time to refresh a single key (by default) will be: milliseconds per week divided by 12
|
||||
*
|
||||
* This service does not keep state, it will restart each time Enigmail is initialized.
|
||||
*
|
||||
* @param keyserver | dependency injected for testability
|
||||
*/
|
||||
function start(keyserver) {
|
||||
if (Services.prefs.getBoolPref("temp.openpgp.keyRefreshOn")) {
|
||||
lazy.EnigmailLog.DEBUG("keyRefreshService.jsm: Started\n");
|
||||
const timer = getTimer();
|
||||
refreshWith(keyserver, timer, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This module initializes the continuous key refresh functionality. This includes randomly selecting th key to refresh and the timing to wait between each refresh
|
||||
*/
|
||||
|
||||
var EnigmailKeyRefreshService = {
|
||||
start,
|
||||
};
|
|
@ -141,22 +141,20 @@ const accessHkpInternal = {
|
|||
*/
|
||||
async buildHkpPayload(actionFlag, searchTerms) {
|
||||
switch (actionFlag) {
|
||||
/*
|
||||
case EnigmailConstants.UPLOAD_KEY:
|
||||
let keyData = await EnigmailKeyRing.extractPublicKeys(
|
||||
searchTerms, // TODO: confirm input is ID or fingerprint
|
||||
case lazy.EnigmailConstants.UPLOAD_KEY:
|
||||
let exitCodeObj = {};
|
||||
let keyData = await lazy.EnigmailKeyRing.extractPublicKeys(
|
||||
["0x" + searchTerms], // TODO: confirm input is ID or fingerprint
|
||||
null,
|
||||
null,
|
||||
{},
|
||||
null,
|
||||
exitCodeObj,
|
||||
{}
|
||||
);
|
||||
if (keyData.length === 0) {
|
||||
if (exitCodeObj.value !== 0 || keyData.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let payLoad = "keytext=" + encodeURIComponent(keyData);
|
||||
return payLoad;
|
||||
*/
|
||||
return 'keytext="' + encodeURIComponent(keyData) + '"';
|
||||
|
||||
case lazy.EnigmailConstants.DOWNLOAD_KEY:
|
||||
case lazy.EnigmailConstants.DOWNLOAD_KEY_NO_IMPORT:
|
||||
|
@ -205,7 +203,7 @@ const accessHkpInternal = {
|
|||
url +=
|
||||
"/pks/lookup?search=" +
|
||||
escape(searchTerm) +
|
||||
"&fingerprint=on&op=index&options=mr";
|
||||
"&fingerprint=on&op=index&options=mr&exact=on";
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -312,23 +310,31 @@ const accessHkpInternal = {
|
|||
} else {
|
||||
let errorMsgObj = {},
|
||||
importedKeysObj = {};
|
||||
let importMinimal = false;
|
||||
let r = lazy.EnigmailKeyRing.importKey(
|
||||
null,
|
||||
false,
|
||||
xmlReq.responseText,
|
||||
false,
|
||||
"",
|
||||
errorMsgObj,
|
||||
importedKeysObj,
|
||||
importMinimal
|
||||
);
|
||||
if (r === 0) {
|
||||
resolve(importedKeysObj.value);
|
||||
} else {
|
||||
reject(
|
||||
createError(lazy.EnigmailConstants.KEYSERVER_ERR_IMPORT_ERROR)
|
||||
|
||||
if (actionFlag === lazy.EnigmailConstants.DOWNLOAD_KEY) {
|
||||
let importMinimal = false;
|
||||
let r = lazy.EnigmailKeyRing.importKey(
|
||||
null,
|
||||
false,
|
||||
xmlReq.responseText,
|
||||
false,
|
||||
"",
|
||||
errorMsgObj,
|
||||
importedKeysObj,
|
||||
importMinimal
|
||||
);
|
||||
if (r === 0) {
|
||||
resolve(importedKeysObj.value);
|
||||
} else {
|
||||
reject(
|
||||
createError(
|
||||
lazy.EnigmailConstants.KEYSERVER_ERR_IMPORT_ERROR
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// DOWNLOAD_KEY_NO_IMPORT
|
||||
resolve(xmlReq.responseText);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -415,8 +421,14 @@ const accessHkpInternal = {
|
|||
keyIdArr[i],
|
||||
listener
|
||||
);
|
||||
if (Array.isArray(r)) {
|
||||
retObj.keyList = retObj.keyList.concat(r);
|
||||
if (autoImport) {
|
||||
if (Array.isArray(r)) {
|
||||
retObj.keyList = retObj.keyList.concat(r);
|
||||
}
|
||||
} else if (typeof r == "string") {
|
||||
retObj.keyData = r;
|
||||
} else {
|
||||
retObj.result = r;
|
||||
}
|
||||
} catch (ex) {
|
||||
retObj.result = ex.result;
|
||||
|
@ -449,18 +461,14 @@ const accessHkpInternal = {
|
|||
* @param keyserver: String - keyserver URL (optionally incl. protocol)
|
||||
* @param listener: optional Object implementing the KeySrvListener API (above)
|
||||
*
|
||||
* @return: Promise<...>
|
||||
* @return {boolean} - Returns true if the key was sent successfully
|
||||
*/
|
||||
async upload(keyIDs, keyserver, listener = null) {
|
||||
lazy.EnigmailLog.DEBUG(
|
||||
`keyserver.jsm: accessHkpInternal.upload(${keyIDs})\n`
|
||||
);
|
||||
let keyIdArr = keyIDs.split(/ +/);
|
||||
let retObj = {
|
||||
result: 0,
|
||||
errorDetails: "",
|
||||
keyList: [],
|
||||
};
|
||||
let rv = false;
|
||||
|
||||
for (let i = 0; i < keyIdArr.length; i++) {
|
||||
try {
|
||||
|
@ -471,14 +479,15 @@ const accessHkpInternal = {
|
|||
listener
|
||||
);
|
||||
if (r === 0) {
|
||||
retObj.keyList.push(keyIdArr[i]);
|
||||
rv = true;
|
||||
} else {
|
||||
retObj.result = r;
|
||||
rv = false;
|
||||
break;
|
||||
}
|
||||
} catch (ex) {
|
||||
retObj.result = ex.result;
|
||||
retObj.errorDetails = ex.errorDetails;
|
||||
throw retObj;
|
||||
console.log(ex.errorDetails);
|
||||
rv = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (listener && "onProgress" in listener) {
|
||||
|
@ -486,7 +495,7 @@ const accessHkpInternal = {
|
|||
}
|
||||
}
|
||||
|
||||
return retObj;
|
||||
return rv;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -626,7 +635,7 @@ const accessKeyBase = {
|
|||
*
|
||||
* @return: Promise<Number (Status-ID)>
|
||||
*/
|
||||
accessKeyServer(actionFlag, keyId, listener) {
|
||||
async accessKeyServer(actionFlag, keyId, listener) {
|
||||
lazy.EnigmailLog.DEBUG(`keyserver.jsm: accessKeyBase: accessKeyServer()\n`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -668,7 +677,7 @@ const accessKeyBase = {
|
|||
case lazy.EnigmailConstants.DOWNLOAD_KEY_NO_IMPORT:
|
||||
if (xmlReq.status >= 400 && xmlReq.status < 500) {
|
||||
// key not found
|
||||
resolve([]);
|
||||
resolve(1);
|
||||
} else if (xmlReq.status >= 500) {
|
||||
lazy.EnigmailLog.DEBUG(
|
||||
"keyserver.jsm: onload: " + xmlReq.responseText + "\n"
|
||||
|
@ -679,8 +688,6 @@ const accessKeyBase = {
|
|||
} else {
|
||||
try {
|
||||
let resp = JSON.parse(xmlReq.responseText);
|
||||
let imported = [];
|
||||
|
||||
if (resp.status.code === 0) {
|
||||
for (let hit in resp.them) {
|
||||
lazy.EnigmailLog.DEBUG(
|
||||
|
@ -690,22 +697,33 @@ const accessKeyBase = {
|
|||
if (resp.them[hit] !== null) {
|
||||
let errorMsgObj = {},
|
||||
importedKeysObj = {};
|
||||
let r = lazy.EnigmailKeyRing.importKey(
|
||||
null,
|
||||
false,
|
||||
resp.them[hit].public_keys.primary.bundle,
|
||||
false,
|
||||
"",
|
||||
errorMsgObj,
|
||||
importedKeysObj
|
||||
);
|
||||
if (r === 0) {
|
||||
imported.push(importedKeysObj.value);
|
||||
|
||||
if (actionFlag === lazy.EnigmailConstants.DOWNLOAD_KEY) {
|
||||
let r = lazy.EnigmailKeyRing.importKey(
|
||||
null,
|
||||
false,
|
||||
resp.them[hit].public_keys.primary.bundle,
|
||||
false,
|
||||
"",
|
||||
errorMsgObj,
|
||||
importedKeysObj
|
||||
);
|
||||
if (r === 0) {
|
||||
resolve(importedKeysObj.value);
|
||||
} else {
|
||||
reject(
|
||||
createError(
|
||||
lazy.EnigmailConstants.KEYSERVER_ERR_IMPORT_ERROR
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// DOWNLOAD_KEY_NO_IMPORT
|
||||
resolve(resp.them[hit].public_keys.primary.bundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
resolve(imported);
|
||||
} catch (ex) {
|
||||
reject(
|
||||
createError(lazy.EnigmailConstants.KEYSERVER_ERR_UNKNOWN)
|
||||
|
@ -924,32 +942,30 @@ const accessVksServer = {
|
|||
*/
|
||||
async buildJsonPayload(actionFlag, searchTerms, locale) {
|
||||
switch (actionFlag) {
|
||||
/*
|
||||
case EnigmailConstants.UPLOAD_KEY:
|
||||
let keyData = await EnigmailKeyRing.extractPublicKeys(
|
||||
searchTerms, // must be id or fingerprint
|
||||
case lazy.EnigmailConstants.UPLOAD_KEY:
|
||||
let exitCodeObj = {};
|
||||
let keyData = await lazy.EnigmailKeyRing.extractPublicKeys(
|
||||
["0x" + searchTerms], // must be id or fingerprint
|
||||
null,
|
||||
null,
|
||||
{},
|
||||
null,
|
||||
exitCodeObj,
|
||||
{}
|
||||
);
|
||||
if (keyData.length === 0) {
|
||||
if (exitCodeObj.value !== 0 || keyData.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let payLoad = JSON.stringify({
|
||||
return JSON.stringify({
|
||||
keytext: keyData,
|
||||
});
|
||||
return payLoad;
|
||||
*/
|
||||
|
||||
case lazy.EnigmailConstants.GET_CONFIRMATION_LINK:
|
||||
let payLoad = JSON.stringify({
|
||||
return JSON.stringify({
|
||||
token: searchTerms.token,
|
||||
addresses: searchTerms.addresses,
|
||||
locale: [locale],
|
||||
});
|
||||
return payLoad;
|
||||
|
||||
case lazy.EnigmailConstants.DOWNLOAD_KEY:
|
||||
case lazy.EnigmailConstants.DOWNLOAD_KEY_NO_IMPORT:
|
||||
|
@ -1301,27 +1317,22 @@ const accessVksServer = {
|
|||
* @param keyserver: String - keyserver URL (optionally incl. protocol)
|
||||
* @param listener: optional Object implementing the KeySrvListener API (above)
|
||||
*
|
||||
* @return: Promise<...>
|
||||
* @return {boolean} - Returns true if the key was sent successfully
|
||||
*/
|
||||
async upload(keyIDs, keyserver, listener = null) {
|
||||
lazy.EnigmailLog.DEBUG(
|
||||
`keyserver.jsm: accessVksServer.upload(${keyIDs})\n`
|
||||
);
|
||||
let keyIdArr = keyIDs.split(/ +/);
|
||||
let retObj = {
|
||||
result: 0,
|
||||
errorDetails: "",
|
||||
keyList: [],
|
||||
};
|
||||
let rv = false;
|
||||
|
||||
for (let i = 0; i < keyIdArr.length; i++) {
|
||||
let keyObj = lazy.EnigmailKeyRing.getKeyById(keyIdArr[i]);
|
||||
|
||||
if (!keyObj.secretAvailable) {
|
||||
// VKS keyservers only accept uploading own keys
|
||||
retObj.result = 1;
|
||||
retObj.errorDetails = "NO_SECRET_KEY_AVAILABLE";
|
||||
throw retObj;
|
||||
throw new Error(
|
||||
"public keyserver uploading supported only for user's own keys"
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -1332,20 +1343,18 @@ const accessVksServer = {
|
|||
listener
|
||||
);
|
||||
if (typeof r === "string") {
|
||||
retObj.keyList.push(keyIdArr[i]);
|
||||
let req = await this.requestConfirmationLink(keyserver, r);
|
||||
|
||||
if (req >= 0) {
|
||||
retObj.result = 0;
|
||||
retObj.numEmails = req;
|
||||
rv = true;
|
||||
}
|
||||
} else {
|
||||
retObj.result = r;
|
||||
rv = false;
|
||||
break;
|
||||
}
|
||||
} catch (ex) {
|
||||
retObj.result = ex.result;
|
||||
retObj.errorDetails = ex.errorDetails;
|
||||
throw retObj;
|
||||
console.log(ex.errorDetails);
|
||||
rv = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (listener && "onProgress" in listener) {
|
||||
|
@ -1353,7 +1362,7 @@ const accessVksServer = {
|
|||
}
|
||||
}
|
||||
|
||||
return retObj;
|
||||
return rv;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1449,12 +1458,12 @@ var EnigmailKeyServer = {
|
|||
* Object: - result: Number - result Code (0 = OK),
|
||||
* - keyList: Array of String - imported key FPR
|
||||
*/
|
||||
download(keyIDs, keyserver = null, listener) {
|
||||
async download(keyIDs, keyserver = null, listener) {
|
||||
let acc = getAccessType(keyserver);
|
||||
return acc.download(true, keyIDs, keyserver, listener);
|
||||
},
|
||||
|
||||
downloadNoImport(keyIDs, keyserver = null, listener) {
|
||||
async downloadNoImport(keyIDs, keyserver = null, listener) {
|
||||
let acc = getAccessType(keyserver);
|
||||
return acc.download(false, keyIDs, keyserver, listener);
|
||||
},
|
||||
|
@ -1476,12 +1485,10 @@ var EnigmailKeyServer = {
|
|||
* @param keyserver: String - keyserver URL (optionally incl. protocol)
|
||||
* @param listener: optional Object implementing the KeySrvListener API (above)
|
||||
*
|
||||
* @return: Promise<Object>
|
||||
* Object: - result: Number - result Code (0 = OK),
|
||||
* - keyList: Array of String - imported key FPR
|
||||
* @return {boolean} - Returns true if the key was sent successfully
|
||||
*/
|
||||
|
||||
upload(keyIDs, keyserver = null, listener) {
|
||||
async upload(keyIDs, keyserver = null, listener) {
|
||||
let acc = getAccessType(keyserver);
|
||||
return acc.upload(keyIDs, keyserver, listener);
|
||||
},
|
||||
|
@ -1504,11 +1511,32 @@ var EnigmailKeyServer = {
|
|||
* - status: String: one of ''=valid, r=revoked, e=expired
|
||||
* - uid: Array of Strings with UIDs
|
||||
*/
|
||||
searchKeyserver(searchString, keyserver = null, listener) {
|
||||
async searchKeyserver(searchString, keyserver = null, listener) {
|
||||
let acc = getAccessType(keyserver);
|
||||
return acc.search(searchString, keyserver, listener);
|
||||
},
|
||||
|
||||
async searchAndDownloadSingleResultNoImport(
|
||||
searchString,
|
||||
keyserver = null,
|
||||
listener
|
||||
) {
|
||||
let acc = getAccessType(keyserver);
|
||||
let searchResult = await acc.searchKeyserver(
|
||||
searchString,
|
||||
keyserver,
|
||||
listener
|
||||
);
|
||||
if (searchResult.result != 0 || searchResult.pubKeys.length != 1) {
|
||||
return null;
|
||||
}
|
||||
return this.downloadNoImport(
|
||||
searchResult.pubKeys[0].keyId,
|
||||
keyserver,
|
||||
listener
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh all keys
|
||||
*
|
||||
|
|
|
@ -8,137 +8,36 @@
|
|||
|
||||
const EXPORTED_SYMBOLS = ["EnigmailKeyserverURIs"];
|
||||
|
||||
const supportedProtocols = {
|
||||
hkps: "443",
|
||||
hkp: "11371",
|
||||
ldap: "389",
|
||||
};
|
||||
|
||||
function buildUriFor(protocol, keyserver) {
|
||||
return {
|
||||
protocol,
|
||||
domain: keyserver,
|
||||
port: supportedProtocols[protocol],
|
||||
};
|
||||
}
|
||||
|
||||
function addUriOptionsForPoolKeyservers(keyserver, uris) {
|
||||
if (keyserver === "hkps.pool.sks-keyservers.net") {
|
||||
uris.push(buildUriFor("hkps", keyserver));
|
||||
}
|
||||
if (keyserver === "pool.sks-keyservers.net") {
|
||||
uris.push(buildUriFor("hkps", "hkps.pool.sks-keyservers.net"));
|
||||
uris.push(buildUriFor("hkp", keyserver));
|
||||
}
|
||||
}
|
||||
|
||||
function buildUriOptionsFor(keyserver) {
|
||||
const uris = [];
|
||||
const keyserverProtocolAndDomain = keyserver.split("://");
|
||||
const protocolIncluded = keyserverProtocolAndDomain.length === 2;
|
||||
const isPoolKeyserver =
|
||||
["hkps.pool.sks-keyservers.net", "pool.sks-keyservers.net"].indexOf(
|
||||
keyserver
|
||||
) > -1;
|
||||
|
||||
if (isPoolKeyserver) {
|
||||
addUriOptionsForPoolKeyservers(keyserver, uris);
|
||||
} else if (protocolIncluded) {
|
||||
uris.push(
|
||||
buildUriFor(
|
||||
keyserverProtocolAndDomain[0].toLowerCase(),
|
||||
keyserverProtocolAndDomain[1]
|
||||
)
|
||||
);
|
||||
} else {
|
||||
uris.push(buildUriFor("hkps", keyserver));
|
||||
uris.push(buildUriFor("hkp", keyserver));
|
||||
}
|
||||
|
||||
return uris;
|
||||
}
|
||||
|
||||
function getDefaultKeyServer() {
|
||||
function getKeyServers() {
|
||||
let keyservers = Services.prefs
|
||||
.getCharPref("temp.openpgp.keyserver")
|
||||
.getCharPref("mail.openpgp.keyserver_list")
|
||||
.split(/\s*[,;]\s*/g);
|
||||
let defKs = keyservers[0];
|
||||
// We don't have great code yet to handle multiple results,
|
||||
// or poisoned results. So avoid SKS.
|
||||
// Let's start with verifying keyservers, only, which return only
|
||||
// one result.
|
||||
if (!defKs.startsWith("vks://")) {
|
||||
console.debug("Not using " + defKs + " in getDefaultKeyServer");
|
||||
return null;
|
||||
return keyservers.filter(
|
||||
ks =>
|
||||
ks.startsWith("vks://") ||
|
||||
ks.startsWith("hkp://") ||
|
||||
ks.startsWith("hkps://")
|
||||
);
|
||||
}
|
||||
|
||||
function getUploadKeyServer() {
|
||||
let keyservers = Services.prefs
|
||||
.getCharPref("mail.openpgp.keyserver_list")
|
||||
.split(/\s*[,;]\s*/g);
|
||||
for (let ks of keyservers) {
|
||||
if (
|
||||
!ks.startsWith("vks://") &&
|
||||
!ks.startsWith("hkp://") &&
|
||||
!ks.startsWith("hkps://")
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
return ks;
|
||||
}
|
||||
return defKs;
|
||||
}
|
||||
|
||||
function getUserDefinedKeyserverURIs() {
|
||||
const keyservers = Services.prefs
|
||||
.getCharPref("temp.openpgp.keyserver")
|
||||
.split(/\s*[,;]\s*/g);
|
||||
return Services.prefs.getCharPref("temp.openpgp.autoKeyServerSelection")
|
||||
? [keyservers[0]]
|
||||
: keyservers;
|
||||
}
|
||||
|
||||
function combineIntoURI(protocol, domain, port) {
|
||||
return protocol + "://" + domain + ":" + port;
|
||||
}
|
||||
|
||||
function isValidProtocol(uri) {
|
||||
return uri.match(/:\/\//) === null || /^(hkps|hkp|ldap):\/\//i.test(uri);
|
||||
}
|
||||
|
||||
function validProtocolsExist() {
|
||||
const validKeyserverUris = getUserDefinedKeyserverURIs().filter(
|
||||
isValidProtocol
|
||||
);
|
||||
return validKeyserverUris.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the full URIs for making gpg requests.
|
||||
* This takes the specified keyservers and adds the relevant protocol and port.
|
||||
* When no specific protocol is defined by the user, 2 URIs will be built, for hkps and hkp.
|
||||
*
|
||||
* @returns array of all URIs to try refreshing keys over
|
||||
*/
|
||||
function buildKeyserverUris() {
|
||||
const uris = getUserDefinedKeyserverURIs()
|
||||
.filter(isValidProtocol)
|
||||
.map(function(keyserver) {
|
||||
return buildUriOptionsFor(keyserver);
|
||||
})
|
||||
.reduce(function(a, b) {
|
||||
return a.concat(b);
|
||||
});
|
||||
|
||||
return uris.map(function(uri) {
|
||||
return combineIntoURI(uri.protocol, uri.domain, uri.port);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the keyservers specified are valid.
|
||||
* Key refreshes will not be attempted without valid keyservers.
|
||||
* A valid keyserver is one that is non-empty and consists of
|
||||
* - the keyserverDomain
|
||||
* - may include a protocol from hkps, hkp or ldap
|
||||
* - may include the port
|
||||
*
|
||||
* @returns true if keyservers exist and are valid, false otherwise.
|
||||
*/
|
||||
function validKeyserversExist() {
|
||||
return (
|
||||
Services.prefs.getCharPref("temp.openpgp.keyserver").trim() !== "" &&
|
||||
validProtocolsExist()
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
var EnigmailKeyserverURIs = {
|
||||
getDefaultKeyServer,
|
||||
buildKeyserverUris,
|
||||
validKeyserversExist,
|
||||
getKeyServers,
|
||||
getUploadKeyServer,
|
||||
};
|
||||
|
|
|
@ -57,6 +57,9 @@ var { EnigmailConstants } = ChromeUtils.import(
|
|||
var { EnigmailDialog } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/dialog.jsm"
|
||||
);
|
||||
var { EnigmailKeyserverURIs } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/keyserverUris.jsm"
|
||||
);
|
||||
|
||||
const ENIG_KEY_EXPIRED = "e";
|
||||
const ENIG_KEY_REVOKED = "r";
|
||||
|
@ -117,8 +120,7 @@ function enigmailKeyManagerLoad() {
|
|||
});
|
||||
|
||||
gUserList.addEventListener("click", onListClick, true);
|
||||
document.l10n.setAttributes(
|
||||
document.getElementById("statusText"),
|
||||
document.getElementById("statusText").value = l10n.formatValueSync(
|
||||
"key-man-loading-keys"
|
||||
);
|
||||
document.getElementById("progressBar").style.visibility = "visible";
|
||||
|
@ -152,7 +154,7 @@ function loadkeyList() {
|
|||
sortTree();
|
||||
gKeyListView.applyFilter(0);
|
||||
document.getElementById("pleaseWait").hidePopup();
|
||||
document.getElementById("statusText").value = " ";
|
||||
document.getElementById("statusText").value = "";
|
||||
document.getElementById("progressBar").style.visibility = "collapse";
|
||||
}
|
||||
|
||||
|
@ -261,6 +263,8 @@ function enigmailKeyMenu() {
|
|||
}
|
||||
}
|
||||
|
||||
let singleSecretSelected = keyList.length == 1 && haveSecretForAll;
|
||||
|
||||
// Make the selected key count available to translations.
|
||||
for (let el of document.querySelectorAll(".enigmail-bulk-key-operation")) {
|
||||
el.setAttribute(
|
||||
|
@ -270,6 +274,7 @@ function enigmailKeyMenu() {
|
|||
}
|
||||
|
||||
document.getElementById("backupSecretKey").disabled = !haveSecretForAll;
|
||||
document.getElementById("uploadToServer").disabled = !singleSecretSelected;
|
||||
|
||||
document.getElementById("revokeKey").disabled =
|
||||
keyList.length != 1 || !gKeyList[keyList[0]].secretAvailable;
|
||||
|
@ -701,22 +706,27 @@ async function enigmailSearchKey() {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function enigmailUploadKeys() {
|
||||
accessKeyServer(EnigmailConstants.UPLOAD_KEY, enigmailUploadKeysCb);
|
||||
}
|
||||
|
||||
function enigmailUploadKeysCb(exitCode, errorMsg, msgBox) {
|
||||
if (msgBox) {
|
||||
if (exitCode !== 0) {
|
||||
EnigmailDialog.alert(window, "Sending of keys failed" + "\n" + errorMsg);
|
||||
}
|
||||
} else {
|
||||
return exitCode === 0 ? "Key(s) sent successfully" : "Sending of keys failed";
|
||||
async function enigmailUploadKey() {
|
||||
/* Always upload to the first configured keyserver with a supported protocol */
|
||||
let selKeyList = getSelectedKeys();
|
||||
if (selKeyList.length != 1) {
|
||||
return;
|
||||
}
|
||||
return "";
|
||||
|
||||
let keyId = gKeyList[selKeyList[0]].keyId;
|
||||
let ks = EnigmailKeyserverURIs.getUploadKeyServer();
|
||||
|
||||
let ok = await EnigmailKeyServer.upload(keyId, ks);
|
||||
document.l10n
|
||||
.formatValue(ok ? "openpgp-key-publish-ok" : "openpgp-key-publish-fail", {
|
||||
keyserver: ks,
|
||||
})
|
||||
.then(value => {
|
||||
EnigmailDialog.alert(window, value);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
function enigmailUploadToWkd() {
|
||||
let selKeyList = getSelectedKeys();
|
||||
let keyList = [];
|
||||
|
@ -871,123 +881,6 @@ function determineHiddenKeys(keyObj, showInvalidKeys, showOthersKeys) {
|
|||
return show;
|
||||
}
|
||||
|
||||
//
|
||||
// ----- keyserver related functionality ----
|
||||
//
|
||||
function accessKeyServer(accessType, callbackFunc) {
|
||||
const ioService = Services.io;
|
||||
if (ioService && ioService.offline) {
|
||||
document.l10n.formatValue("need-online").then(value => {
|
||||
EnigmailDialog.alert(window, value);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let inputObj = {};
|
||||
let resultObj = {};
|
||||
let selKeyList = getSelectedKeys();
|
||||
let keyList = [];
|
||||
for (let i = 0; i < selKeyList.length; i++) {
|
||||
keyList.push(gKeyList[selKeyList[i]]);
|
||||
}
|
||||
|
||||
if (accessType !== EnigmailConstants.REFRESH_KEY && selKeyList.length === 0) {
|
||||
if (
|
||||
EnigmailDialog.confirmDlg(
|
||||
window,
|
||||
l10n.formatValueSync("refresh-all-question"),
|
||||
l10n.formatValueSync("key-man-button-refresh-all")
|
||||
)
|
||||
) {
|
||||
accessType = EnigmailConstants.DOWNLOAD_KEY;
|
||||
EnigmailDialog.alertPref(
|
||||
window,
|
||||
l10n.formatValueSync("refresh-key-warn"),
|
||||
"warnRefreshAll"
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let keyServer = Services.prefs.getBoolPref(
|
||||
"temp.openpgp.autoKeyServerSelection"
|
||||
)
|
||||
? Services.prefs.getCharPref("temp.openpgp.keyserver").split(/[ ,;]/g)[0]
|
||||
: null;
|
||||
if (!keyServer) {
|
||||
switch (accessType) {
|
||||
case EnigmailConstants.REFRESH_KEY:
|
||||
inputObj.upload = false;
|
||||
inputObj.keyId = "All keys";
|
||||
break;
|
||||
case EnigmailConstants.DOWNLOAD_KEY:
|
||||
inputObj.upload = false;
|
||||
inputObj.keyId = keyList
|
||||
.map(k => {
|
||||
try {
|
||||
return EnigmailFuncs.stripEmail(k.userId);
|
||||
} catch (x) {
|
||||
return "0x" + k.fpr;
|
||||
}
|
||||
})
|
||||
.join(", ");
|
||||
break;
|
||||
/*
|
||||
case EnigmailConstants.UPLOAD_KEY:
|
||||
inputObj.upload = true;
|
||||
inputObj.keyId = keyList
|
||||
.map(k => {
|
||||
try {
|
||||
return EnigmailFuncs.stripEmail(k.userId);
|
||||
} catch (x) {
|
||||
return "0x" + k.fpr;
|
||||
}
|
||||
})
|
||||
.join(", ");
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
inputObj.upload = true;
|
||||
inputObj.keyId = "";
|
||||
}
|
||||
|
||||
window.openDialog(
|
||||
"chrome://openpgp/content/ui/enigmailKeyserverDlg.xhtml",
|
||||
"",
|
||||
"dialog,modal,centerscreen",
|
||||
inputObj,
|
||||
resultObj
|
||||
);
|
||||
keyServer = resultObj.value;
|
||||
}
|
||||
|
||||
if (keyServer.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (accessType !== EnigmailConstants.REFRESH_KEY) {
|
||||
inputObj.keyServer = keyServer;
|
||||
inputObj.accessType = accessType;
|
||||
inputObj.keyId = keyList.map(k => {
|
||||
return "0x" + k.fpr;
|
||||
});
|
||||
window.openDialog(
|
||||
"chrome://openpgp/content/ui/enigRetrieveProgress.xhtml",
|
||||
"",
|
||||
"dialog,modal,centerscreen",
|
||||
inputObj,
|
||||
resultObj
|
||||
);
|
||||
|
||||
if (resultObj.result) {
|
||||
callbackFunc(resultObj.exitCode, resultObj.errorMsg, false);
|
||||
}
|
||||
} else {
|
||||
EnigmailKeyServer.refresh(keyServer);
|
||||
}
|
||||
}
|
||||
|
||||
function getSortDirection() {
|
||||
return gUserList.getAttribute("sortDirection") == "ascending" ? 1 : -1;
|
||||
}
|
||||
|
|
|
@ -159,10 +159,13 @@
|
|||
|
||||
<menu id="keyserverMenu"
|
||||
data-l10n-id="openpgp-key-man-keyserver-menu">
|
||||
<menupopup>
|
||||
<menupopup onpopupshowing="enigmailKeyMenu()">
|
||||
<menuitem id="importFromServer"
|
||||
data-l10n-id="openpgp-key-man-discover-cmd"
|
||||
oncommand="enigmailSearchKey()"/>
|
||||
<menuitem id="uploadToServer"
|
||||
data-l10n-id="openpgp-key-man-publish-cmd"
|
||||
oncommand="enigmailUploadKey()"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
||||
|
|
|
@ -2684,28 +2684,6 @@ Enigmail.msg = {
|
|||
);
|
||||
},
|
||||
|
||||
importKeyFromKeyserver() {
|
||||
var pubKeyId = "0x" + Enigmail.msg.securityInfo.keyId;
|
||||
var inputObj = {
|
||||
searchList: [pubKeyId],
|
||||
autoKeyServer: Services.prefs.getBoolPref(
|
||||
"temp.openpgp.autoKeyServerSelection"
|
||||
)
|
||||
? Services.prefs
|
||||
.getCharPref("temp.openpgp.keyserver")
|
||||
.split(/[ ,;]/g)[0]
|
||||
: null,
|
||||
};
|
||||
var resultObj = {};
|
||||
EnigmailWindows.downloadKeys(window, inputObj, resultObj);
|
||||
|
||||
if (resultObj.importedKeys > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
onUnloadEnigmail() {
|
||||
window.removeEventListener("unload", Enigmail.msg.messengerClose);
|
||||
window.removeEventListener(
|
||||
|
|
|
@ -44,6 +44,12 @@ include $(moztopsrcdir)/config/rules.mk
|
|||
|
||||
include $(moztopsrcdir)/toolkit/locales/l10n.mk
|
||||
|
||||
ifeq ($(VCS_CHECKOUT_TYPE),hg)
|
||||
L10N_CO = $(PYTHON3) $(moztopsrcdir)/comm/python/l10n/l10n_clone/l10n_clone.py $(AB_CD) $(L10NBASEDIR)
|
||||
else
|
||||
L10N_CO = $(error You need to use hg)
|
||||
endif
|
||||
|
||||
l10n-%: AB_CD=$*
|
||||
l10n-%:
|
||||
# merge if we're not en-US. Conditional function because
|
||||
|
|
|
@ -126,8 +126,13 @@ openpgp-key-man-backup-secret-keys =
|
|||
openpgp-key-man-discover-cmd =
|
||||
.label = Discover Keys Online
|
||||
.accesskey = D
|
||||
openpgp-key-man-publish-cmd =
|
||||
.label = Publish
|
||||
.accesskey = P
|
||||
openpgp-key-man-discover-prompt = To discover OpenPGP keys online, on keyservers or using the WKD protocol, enter either an email address or a key ID.
|
||||
openpgp-key-man-discover-progress = Searching…
|
||||
openpgp-key-publish-ok = The request to publish your public key was sent to "{ $keyserver }". The keyserver might send email that asks for confirmation.
|
||||
openpgp-key-publish-fail = Failed to send your public key to "{ $keyserver }".
|
||||
|
||||
openpgp-key-copy-key =
|
||||
.label = Copy Public Key
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
@import url("chrome://messenger/skin/icons.css");
|
||||
@import url("chrome://messenger/skin/icons.css");
|
||||
@import url("chrome://messenger/skin/colors.css");
|
||||
|
||||
body {
|
||||
/* Override the absolute (px) font-size value in common-shared.css. */
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
font: message-box;
|
||||
background-color: var(--color-white);
|
||||
|
||||
--address-book-book-label-color: var(--color-white);
|
||||
--address-book-book-label-background: var(--color-gray-50);
|
||||
--address-book-card-min-height: 140px;
|
||||
|
||||
--ab-card-line-height: 1.3em;
|
||||
|
@ -34,13 +32,8 @@
|
|||
background-color: transparent;
|
||||
color: currentColor;
|
||||
|
||||
--address-book-books-list-bg: transparent;
|
||||
--address-book-cards-list-bg: transparent;
|
||||
|
||||
--address-book-icons-color: currentColor;
|
||||
|
||||
--address-book-section-border-color: currentColor;
|
||||
--address-book-section-bg: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,18 +41,8 @@
|
|||
:root {
|
||||
color: var(--color-gray-80);
|
||||
|
||||
--address-book-books-list-bg: var(--color-gray-10);
|
||||
--address-book-cards-list-bg: var(--color-gray-05);
|
||||
|
||||
--address-book-icons-color: var(--color-ink-80);
|
||||
|
||||
--in-content-button-background-active: var(--grey-90-a30);
|
||||
--in-content-categories-background: #ebebef;
|
||||
--in-content-item-selected-unfocused: var(--grey-20);
|
||||
--splitter-color: var(--in-content-border-color);
|
||||
|
||||
--address-book-section-border-color: var(--color-gray-30);
|
||||
--address-book-section-bg: var(--color-gray-05);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
@ -67,24 +50,8 @@
|
|||
background: var(--color-gray-90);
|
||||
color: var(--color-gray-05);
|
||||
|
||||
--address-book-books-list-bg: var(--color-gray-80);
|
||||
--address-book-cards-list-bg: var(--color-gray-80);
|
||||
|
||||
--address-book-icons-color: var(--color-gray-30);
|
||||
|
||||
--in-content-categories-background: rgba(249, 249, 250, 0.1);
|
||||
--in-content-item-selected-unfocused: rgba(249, 249, 250, 0.05);
|
||||
--in-content-button-background-active: rgba(249, 249, 250, 0.2);
|
||||
--in-content-primary-button-background: #45a1ff;
|
||||
--in-content-primary-button-background-hover: #65c1ff;
|
||||
--in-content-primary-button-background-active: #85e1ff;
|
||||
--in-content-focus-outline-color: #45a1ff;
|
||||
|
||||
--address-book-book-label-color: var(--color-white);
|
||||
--address-book-book-label-background: var(--color-gray-50);
|
||||
|
||||
--address-book-section-border-color: transparent;
|
||||
--address-book-section-bg: var(--color-gray-80);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +135,7 @@ body.layout-table {
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
background-color: var(--address-book-books-list-bg);
|
||||
background-color: var(--in-content-categories-background);
|
||||
}
|
||||
|
||||
#booksSplitter {
|
||||
|
@ -863,8 +830,8 @@ body:not(.is-editing) #editContactForm {
|
|||
#detailsBody section {
|
||||
padding: 15px;
|
||||
border-radius: var(--in-content-button-border-radius);
|
||||
border: 1px solid var(--address-book-section-border-color);
|
||||
background-color: var(--address-book-section-bg);
|
||||
border: 1px solid var(--in-content-box-info-border);
|
||||
background-color: var(--in-content-box-info-background);
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
@ -1199,7 +1166,7 @@ input[type="number"]::-moz-number-spin-down {
|
|||
#cardCount {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
background-color: var(--address-book-books-list-bg);
|
||||
background-color: var(--in-content-categories-background);
|
||||
border-top: 1px solid var(--splitter-color);
|
||||
color: color-mix(in srgb, currentColor 75%, transparent);
|
||||
padding: 9px;
|
||||
|
|
|
@ -218,6 +218,13 @@ richlistitem[is="chat-imconv-richlistitem"]:not(:hover) > .closeConversationButt
|
|||
color: GrayText;
|
||||
}
|
||||
|
||||
.convDisplayName,
|
||||
.blistDisplayName,
|
||||
.contactDisplayName,
|
||||
richlistitem[is="chat-group-richlistitem"] > label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.convUnreadCount,
|
||||
.contactDisplayName,
|
||||
.convDisplayName,
|
||||
|
@ -455,12 +462,17 @@ richlistitem:not([selected]) .protoIconDimmed {
|
|||
|
||||
.displayName {
|
||||
font-size: larger;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nameAndStatusGrid > .displayName:empty + hr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.statusMessage {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.statusMessage[noTopic] {
|
||||
font-style: italic;
|
||||
}
|
||||
|
@ -617,6 +629,7 @@ richlistitem:not([selected]) .protoIconDimmed {
|
|||
pointer-events: none;
|
||||
font-weight: bold;
|
||||
padding-inline-start: 1px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.conv-nicklist-image {
|
||||
|
@ -788,8 +801,13 @@ toolbar[mode="text"] #statusTypeIcon > .toolbarbutton-icon {
|
|||
border-bottom-color: var(--sidebar-border-color, rgba(249,249,250,.2));
|
||||
}
|
||||
|
||||
.conv-header-label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#participantCount {
|
||||
background: transparent;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
:root[lwt-tree] #participantCount {
|
||||
|
@ -894,6 +912,11 @@ toolbar[mode="text"] .badgeButton-badge {
|
|||
|
||||
.encryption-label {
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.encryption-not-private > image {
|
||||
|
|
|
@ -21,20 +21,25 @@
|
|||
@media not (prefers-contrast) {
|
||||
:host,
|
||||
:root {
|
||||
--in-content-box-info-background: var(--color-gray-05);
|
||||
--in-content-box-info-border: var(--color-gray-30);
|
||||
--in-content-button-background: var(--grey-90-a10);
|
||||
--in-content-button-background-hover: var(--grey-90-a20);
|
||||
--in-content-button-background-active: var(--grey-90-a30);
|
||||
--in-content-categories-background: #ebebef;
|
||||
--in-content-categories-background: var(--color-gray-10);
|
||||
--in-content-item-selected-unfocused: var(--grey-20);
|
||||
--in-content-item-hover: color-mix(in srgb, currentColor 12%, transparent);
|
||||
--in-content-item-selected: color-mix(in srgb, currentColor 20%, transparent);
|
||||
--in-content-item-selected-text: var(--in-content-page-color);
|
||||
--splitter-color: var(--in-content-border-color);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:host,
|
||||
:root {
|
||||
--in-content-categories-background: rgba(249, 249, 250, 0.1);
|
||||
--in-content-box-info-background: var(--color-gray-80);
|
||||
--in-content-box-info-border: transparent;
|
||||
--in-content-categories-background: var(--color-gray-80);
|
||||
--in-content-item-selected-unfocused: rgba(249, 249, 250, 0.05);
|
||||
--in-content-button-background: rgba(249, 249, 250, 0.1);
|
||||
--in-content-button-background-hover: rgba(249, 249, 250, 0.15);
|
||||
|
@ -49,6 +54,8 @@
|
|||
|
||||
@media (prefers-contrast) {
|
||||
:root {
|
||||
--in-content-box-info-background: transparent;
|
||||
--in-content-box-info-border: currentColor;
|
||||
--in-content-categories-background: transparent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
@import url("chrome://messenger/skin/shared/contextMenu.css");
|
||||
@import url("chrome://messenger/skin/colors.css");
|
||||
|
||||
:host {
|
||||
--icon-size: 16px;
|
||||
|
@ -20,6 +21,7 @@
|
|||
|
||||
@media (prefers-contrast) {
|
||||
:host {
|
||||
--in-content-box-info-background: -moz-Dialog;
|
||||
--in-content-button-color: ButtonText;
|
||||
--in-content-button-border: ThreeDLightShadow;
|
||||
--in-content-button-background: ButtonFace;
|
||||
|
@ -52,6 +54,10 @@
|
|||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:host {
|
||||
--in-content-box-info-background: var(--color-gray-60);
|
||||
}
|
||||
|
||||
:host([type=warning]) {
|
||||
--message-bar-background-color: #ffe900;
|
||||
}
|
||||
|
|
|
@ -452,6 +452,7 @@ checkbox {
|
|||
|
||||
.updateSettingCrossUserWarningContainer {
|
||||
background: var(--in-content-box-info-background);
|
||||
border: 1px solid var(--in-content-box-info-border);
|
||||
border-radius: 5px;
|
||||
padding: 2px 8px 8px;
|
||||
margin-block-end: 17px;
|
||||
|
|
|
@ -12,15 +12,9 @@ menuitem[disabled="true"]:not(.menuitem-iconic) {
|
|||
}
|
||||
|
||||
menupopup:not([type="arrow"]) {
|
||||
--windows-panel-box-shadow: 0 0 4px hsla(0, 0%, 0%, 0.2);
|
||||
margin: -4px;
|
||||
}
|
||||
|
||||
menupopup:not([type="arrow"])::part(content) {
|
||||
margin: 4px;
|
||||
box-shadow: var(--windows-panel-box-shadow);
|
||||
}
|
||||
|
||||
@media (prefers-contrast) {
|
||||
menupopup > :is(menu, menuitem):not([disabled="true"])[_moz-menuactive] {
|
||||
color: SelectedItemText;
|
||||
|
@ -52,6 +46,11 @@ menupopup:not([type="arrow"])::part(content) {
|
|||
border-radius: calc(2 * var(--arrowpanel-border-radius));
|
||||
}
|
||||
|
||||
menupopup:not([type="arrow"])::part(content) {
|
||||
--panel-shadow-margin: 4px;
|
||||
--panel-shadow: 0 0 4px hsla(0, 0%, 0%, 0.2);
|
||||
}
|
||||
|
||||
/* Override popup.css */
|
||||
menulist > menupopup {
|
||||
--panel-background: var(--arrowpanel-background);
|
||||
|
|
|
@ -511,8 +511,3 @@ treechildren::-moz-tree-row(dummy, selected, focus) {
|
|||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#notification-popup::part(content) {
|
||||
margin: 4px;
|
||||
box-shadow: var(--windows-panel-box-shadow);
|
||||
}
|
||||
|
|
|
@ -369,14 +369,14 @@ class ImapClient {
|
|||
}
|
||||
|
||||
if (folder.onlineName) {
|
||||
return folder.onlineName;
|
||||
return folder.onlineName.replaceAll('"', '\\"');
|
||||
}
|
||||
let delimiter =
|
||||
folder.QueryInterface(Ci.nsIMsgImapMailFolder).hierarchyDelimiter || "/";
|
||||
let names = this._getAncestorFolderNames(folder);
|
||||
return this._charsetManager.unicodeToMutf7(
|
||||
[...names, folder.name].join(delimiter)
|
||||
);
|
||||
return this._charsetManager
|
||||
.unicodeToMutf7([...names, folder.name].join(delimiter))
|
||||
.replaceAll('"', '\\"');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -669,11 +669,7 @@ class ImapClient {
|
|||
* @param {Function} nextAction - Callback function after IDLE is ended.
|
||||
*/
|
||||
endIdle(nextAction) {
|
||||
this._nextAction = res => {
|
||||
if (res.status == "OK") {
|
||||
nextAction();
|
||||
}
|
||||
};
|
||||
this._nextAction = nextAction;
|
||||
this._send("DONE");
|
||||
this._idling = false;
|
||||
}
|
||||
|
@ -717,7 +713,6 @@ class ImapClient {
|
|||
this._response = new ImapResponse();
|
||||
}
|
||||
this._response.parse(stringPayload);
|
||||
this._logger.debug("Parsed:", this._response);
|
||||
if (
|
||||
!this._authenticating &&
|
||||
this._response.done &&
|
||||
|
@ -1335,7 +1330,9 @@ class ImapClient {
|
|||
this._folderSink.setFolderQuotaData(VALIDATE_QUOTA, "", 0, 0);
|
||||
this._actionAfterSelectFolder();
|
||||
};
|
||||
this._sendTagged(`GETQUOTAROOT ${this._getServerFolderName(this.folder)}`);
|
||||
this._sendTagged(
|
||||
`GETQUOTAROOT "${this._getServerFolderName(this.folder)}"`
|
||||
);
|
||||
this._folderSink.folderQuotaCommandIssued = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -473,6 +473,16 @@ class ImapIncomingServer extends MsgIncomingServer {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if INBOX folder is selected in a connection.
|
||||
*
|
||||
* @param {ImapClient} client - The client to check.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isInboxConnection(client) {
|
||||
return client.folder?.onlineName.toUpperCase() == "INBOX";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a free connection that can be used.
|
||||
*
|
||||
|
@ -509,16 +519,18 @@ class ImapIncomingServer extends MsgIncomingServer {
|
|||
return this._waitForNextClient(folder);
|
||||
}
|
||||
|
||||
// Reuse any free connection available.
|
||||
if (this.maximumConnectionsNumber <= 1) {
|
||||
// Reuse any free connection if only have one connection or IDLE not used.
|
||||
if (
|
||||
this.maximumConnectionsNumber <= 1 ||
|
||||
!this.useIdle ||
|
||||
!this._capabilities.includes("IDLE")
|
||||
) {
|
||||
freeConnections[0].busy = true;
|
||||
return freeConnections[0];
|
||||
}
|
||||
|
||||
// Reuse non-inbox free connection.
|
||||
client = freeConnections.find(
|
||||
c => c.folder?.onlineName.toUpperCase() != "INBOX"
|
||||
);
|
||||
client = freeConnections.find(c => !this._isInboxConnection(c));
|
||||
if (client) {
|
||||
client.busy = true;
|
||||
return client;
|
||||
|
@ -539,27 +551,32 @@ class ImapIncomingServer extends MsgIncomingServer {
|
|||
return;
|
||||
}
|
||||
client.onFree = async () => {
|
||||
let alreadyIdling =
|
||||
client.folder &&
|
||||
this._connections.find(
|
||||
c => c != client && !c.busy && c.folder == client.folder
|
||||
);
|
||||
if (
|
||||
this.useIdle &&
|
||||
this._capabilities.includes("IDLE") &&
|
||||
client.folder &&
|
||||
!alreadyIdling
|
||||
) {
|
||||
// IDLE is configed and supported, use IDLE to receive server pushes.
|
||||
client.idle();
|
||||
} else if (alreadyIdling) {
|
||||
client.folder = null;
|
||||
}
|
||||
client.busy = false;
|
||||
let resolve = this._connectionWaitingQueue.shift();
|
||||
if (resolve) {
|
||||
// Resovle the first waiting in queue.
|
||||
// Resolve the first waiting in queue.
|
||||
resolve(true);
|
||||
} else {
|
||||
let hasInboxConnection = this._connections.some(c =>
|
||||
this._isInboxConnection(c)
|
||||
);
|
||||
let alreadyIdling =
|
||||
client.folder &&
|
||||
this._connections.find(
|
||||
c => c != client && !c.busy && c.folder == client.folder
|
||||
);
|
||||
if (this.useIdle && this._capabilities.includes("IDLE")) {
|
||||
// IDLE is configed and supported, use IDLE to receive server pushes.
|
||||
if (!hasInboxConnection) {
|
||||
client.selectFolder(
|
||||
this.rootFolder.getFolderWithFlags(Ci.nsMsgFolderFlags.Inbox)
|
||||
);
|
||||
} else if (client.folder && !alreadyIdling) {
|
||||
client.idle();
|
||||
} else if (alreadyIdling) {
|
||||
client.folder = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
handler(client);
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
# 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/.
|
||||
"""
|
||||
Download and combine translations from l10n-central and comm-l10n for
|
||||
use by mach build installers-$AB_CD and mach build langpack-$AB_CD.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from mozpack.copier import FileCopier
|
||||
from mozpack.files import FileFinder
|
||||
from mozversioncontrol.repoupdate import update_mercurial_repo
|
||||
|
||||
COMM_PATH = (Path(__file__).parent / "../../..").resolve()
|
||||
COMM_PYTHON_L10N = os.path.join(COMM_PATH, "python/l10n")
|
||||
sys.path.insert(1, COMM_PYTHON_L10N)
|
||||
|
||||
from tbxchannel.l10n_merge import (
|
||||
COMM_L10N,
|
||||
L10N_CENTRAL,
|
||||
COMM_STRINGS_PATTERNS,
|
||||
GECKO_STRINGS_PATTERNS,
|
||||
)
|
||||
|
||||
ALL_LOCALES = [
|
||||
l.rstrip() for l in (COMM_PATH / "mail/locales/all-locales").open().readlines()
|
||||
]
|
||||
|
||||
|
||||
def tb_locale(locale):
|
||||
if locale in ALL_LOCALES:
|
||||
return locale
|
||||
raise argparse.ArgumentTypeError("Locale {} invalid.".format(locale))
|
||||
|
||||
|
||||
def get_strings_repos(locale, destination):
|
||||
with tempfile.TemporaryDirectory() as tmproot:
|
||||
central_url = "{}/{}".format(L10N_CENTRAL, locale)
|
||||
l10n_central = Path(tmproot) / "l10n-central"
|
||||
l10n_central.mkdir()
|
||||
central_path = l10n_central / locale
|
||||
update_mercurial_repo("hg", central_url, central_path)
|
||||
|
||||
comm_l10n = Path(tmproot) / "comm-l10n"
|
||||
update_mercurial_repo("hg", COMM_L10N, comm_l10n)
|
||||
|
||||
file_copier = FileCopier()
|
||||
|
||||
def add_to_registry(base_path, patterns):
|
||||
finder = FileFinder(base_path)
|
||||
for pattern in patterns:
|
||||
for _filepath, _fileobj in finder.find(pattern.format(lang=locale)):
|
||||
# _filepath = os.path.join("l10n-central", _filepath)
|
||||
file_copier.add(_filepath, _fileobj)
|
||||
|
||||
add_to_registry(l10n_central, GECKO_STRINGS_PATTERNS)
|
||||
add_to_registry(comm_l10n, COMM_STRINGS_PATTERNS)
|
||||
|
||||
file_copier.copy(destination / locale)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Download translated strings from comm-l10n"
|
||||
)
|
||||
parser.add_argument("locale", help="The locale to download", type=tb_locale)
|
||||
parser.add_argument(
|
||||
"dest_path", help="Path where locale will be downloaded to.", type=Path
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
get_strings_repos(args.locale, args.dest_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -22,6 +22,38 @@ def _positive_int(value):
|
|||
return value
|
||||
|
||||
|
||||
def _retry_run_process(command_context, *args, error_msg=None, **kwargs):
|
||||
try:
|
||||
return command_context.run_process(*args, **kwargs)
|
||||
except Exception as exc:
|
||||
raise Exception(error_msg or str(exc)) from exc
|
||||
|
||||
|
||||
def _get_rev(command_context, strings_path):
|
||||
result = []
|
||||
|
||||
def save_output(line):
|
||||
result.append(line)
|
||||
|
||||
status = _retry_run_process(
|
||||
command_context,
|
||||
[
|
||||
"hg",
|
||||
"--cwd",
|
||||
str(strings_path),
|
||||
"log",
|
||||
"-r",
|
||||
".",
|
||||
"--template",
|
||||
"'{node}\n'",
|
||||
],
|
||||
line_handler=save_output,
|
||||
)
|
||||
if status == 0:
|
||||
return "\n".join(result)
|
||||
raise Exception(f"Failed to get head revision: {status}")
|
||||
|
||||
|
||||
@Command(
|
||||
"tb-l10n-x-channel",
|
||||
category="thunderbird",
|
||||
|
@ -75,7 +107,9 @@ def tb_cross_channel(
|
|||
**kwargs,
|
||||
):
|
||||
"""Run Thunderbird's l10n cross-channel content generation."""
|
||||
from tbxchannel import get_thunderbird_xc_config
|
||||
from tbxchannel import get_thunderbird_xc_config, TB_XC_NOTIFICATION_TMPL
|
||||
from tbxchannel.l10n_merge import COMM_STRINGS_QUARANTINE
|
||||
from rocbuild.notify import email_notification
|
||||
|
||||
kwargs.update(
|
||||
{
|
||||
|
@ -90,6 +124,14 @@ def tb_cross_channel(
|
|||
command_context._mach_context.commands.dispatch(
|
||||
"l10n-cross-channel", command_context._mach_context, **kwargs
|
||||
)
|
||||
if os.path.exists(outgoing_path):
|
||||
head_rev = _get_rev(command_context, strings_path)
|
||||
rev_url = f"{COMM_STRINGS_QUARANTINE}/rev/{head_rev}"
|
||||
|
||||
notification_body = TB_XC_NOTIFICATION_TMPL.format(rev_url=rev_url)
|
||||
email_notification(
|
||||
"X-channel comm-strings-quarantine updated", notification_body
|
||||
)
|
||||
|
||||
|
||||
@Command(
|
||||
|
|
|
@ -7,6 +7,13 @@ from pathlib import Path
|
|||
from .l10n_merge import COMM_STRINGS_QUARANTINE, COMM_STRINGS_QUARANTINE_PUSH
|
||||
|
||||
|
||||
TB_XC_NOTIFICATION_TMPL = """\
|
||||
**Thunderbird L10n Cross Channel**
|
||||
|
||||
Changes pushed to `comm-strings-quarantine`: {rev_url}
|
||||
"""
|
||||
|
||||
|
||||
def get_thunderbird_xc_config(topsrcdir, strings_path):
|
||||
assert isinstance(topsrcdir, Path)
|
||||
assert isinstance(strings_path, Path)
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
# 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/.
|
||||
|
||||
"""
|
||||
Notification utility functions
|
||||
"""
|
||||
|
||||
import os
|
||||
from taskcluster import Notify
|
||||
from taskcluster import optionsFromEnvironment
|
||||
|
||||
|
||||
TB_BUILD_ADDR = "tb-builds@thunderbird.net"
|
||||
|
||||
|
||||
def email_notification(subject, content, recipients=None):
|
||||
# use proxy if configured, otherwise local credentials from env vars
|
||||
if recipients is None:
|
||||
recipients = [TB_BUILD_ADDR]
|
||||
|
||||
if "TASKCLUSTER_PROXY_URL" in os.environ:
|
||||
notify_options = {"rootUrl": os.environ["TASKCLUSTER_PROXY_URL"]}
|
||||
else:
|
||||
notify_options = optionsFromEnvironment()
|
||||
|
||||
notify = Notify(notify_options)
|
||||
for address in recipients:
|
||||
notify.email(
|
||||
{
|
||||
"address": address,
|
||||
"subject": subject,
|
||||
"content": content,
|
||||
}
|
||||
)
|
|
@ -13,7 +13,7 @@ jobs:
|
|||
quarantine:
|
||||
description: Push strings from all shipping trains to comm-strings-quarantine
|
||||
run-on-projects: []
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
ssh-key-secret:
|
||||
by-level:
|
||||
"3": project/comm/thunderbird/releng/build/level-3/l10n-cross-channel-quarantine-ssh
|
||||
|
|
|
@ -18,7 +18,7 @@ job-defaults:
|
|||
description: bouncer check
|
||||
run-on-projects: [] # to make sure this never runs as part of CI
|
||||
shipping-phase: push
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
worker:
|
||||
max-run-time: 1800
|
||||
docker-image: {in-tree: "update-verify"}
|
||||
|
|
|
@ -17,7 +17,7 @@ transforms:
|
|||
job-defaults:
|
||||
name: final-verify
|
||||
run-on-projects: [] # to make sure this never runs as part of CI
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
worker:
|
||||
docker-image:
|
||||
in-tree: "update-verify"
|
||||
|
|
|
@ -20,7 +20,7 @@ job-defaults:
|
|||
description: generates checksums
|
||||
run-on-projects: [] # to make sure this never runs as part of CI
|
||||
shipping-phase: promote
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
worker:
|
||||
max-run-time: 1200
|
||||
artifacts:
|
||||
|
|
|
@ -18,7 +18,7 @@ job-defaults:
|
|||
shipping-phase: promote
|
||||
treeherder:
|
||||
symbol: Src
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
worker:
|
||||
max-run-time: 3600
|
||||
env:
|
||||
|
|
|
@ -15,7 +15,7 @@ job-defaults:
|
|||
run-on-projects: [] # to make sure this never runs as part of CI
|
||||
run-on-releases: [release]
|
||||
shipping-phase: promote
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
worker:
|
||||
docker-image:
|
||||
in-tree: "update-verify"
|
||||
|
|
|
@ -13,7 +13,7 @@ job-defaults:
|
|||
name: update-verify-config
|
||||
run-on-projects: [] # to make sure this never runs as part of CI
|
||||
shipping-phase: promote
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
worker:
|
||||
docker-image:
|
||||
in-tree: "update-verify"
|
||||
|
|
|
@ -22,7 +22,7 @@ job-defaults:
|
|||
run-on-projects: [] # to make sure this never runs as part of CI
|
||||
run-on-releases: [release]
|
||||
shipping-phase: promote
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
worker:
|
||||
artifacts:
|
||||
- name: 'public/build/diff-summary.log'
|
||||
|
|
|
@ -20,7 +20,7 @@ job-defaults:
|
|||
name: update-verify
|
||||
run-on-projects: [] # to make sure this never runs as part of CI
|
||||
shipping-phase: promote
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
worker:
|
||||
artifacts:
|
||||
- name: 'public/build/diff-summary.log'
|
||||
|
|
|
@ -26,7 +26,7 @@ job-template:
|
|||
attributes:
|
||||
shipping_phase: promote
|
||||
run-time: 900
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
docker-image: {in-tree: debian11-amd64-build}
|
||||
treeherder:
|
||||
symbol: L10n-pre
|
||||
|
|
|
@ -27,7 +27,7 @@ only-for-build-platforms:
|
|||
|
||||
job-template:
|
||||
description: Upload Symbols
|
||||
worker-type: b-linux
|
||||
worker-type: b-linux-gcp
|
||||
worker:
|
||||
docker-image: {in-tree: "debian11-base"}
|
||||
max-run-time: 900
|
||||
|
|
|
@ -10,6 +10,8 @@ from shlex import quote as shell_quote
|
|||
from taskgraph.transforms.base import TransformSequence
|
||||
from taskgraph.util.schema import resolve_keyed_by
|
||||
|
||||
from rocbuild.notify import TB_BUILD_ADDR
|
||||
|
||||
transforms = TransformSequence()
|
||||
|
||||
|
||||
|
@ -35,6 +37,7 @@ def build_command(config, jobs):
|
|||
if ssh_key_secret:
|
||||
command.extend(["--ssh-secret", ssh_key_secret])
|
||||
job.setdefault("scopes", []).append(f"secrets:get:{ssh_key_secret}")
|
||||
job["scopes"].append(f"notify:email:{TB_BUILD_ADDR}")
|
||||
|
||||
command.extend(job["run"].pop("actions", []))
|
||||
job.setdefault("run", {}).update(
|
||||
|
|
Загрузка…
Ссылка в новой задаче