mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-04 23:17:02 +03:00
OpenPGP improvements (first step)
openpgpjs: 0.7.2 -> 0.10.1 additional fixes
This commit is contained in:
parent
09334159c2
commit
34a9b8cbc5
28 changed files with 1363 additions and 644 deletions
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
AppStore = require('Stores/User/App'),
|
||||
FolderStore = require('Stores/User/Folder'),
|
||||
PgpStore = require('Stores/User/Pgp'),
|
||||
SettingsStore = require('Stores/User/Settings'),
|
||||
|
||||
Remote = require('Remote/User/Ajax'),
|
||||
|
|
@ -502,6 +503,19 @@
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} oMessageTextBody
|
||||
*/
|
||||
MessageUserStore.prototype.initOpenPgpControls = function (oMessageTextBody)
|
||||
{
|
||||
if (oMessageTextBody && oMessageTextBody.find)
|
||||
{
|
||||
oMessageTextBody.find('.b-plain-openpgp:not(.inited)').each(function () {
|
||||
PgpStore.initMessageBodyControls($(this));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
MessageUserStore.prototype.setMessage = function (oData, bCached)
|
||||
{
|
||||
var
|
||||
|
|
@ -512,6 +526,7 @@
|
|||
oBody = null,
|
||||
oTextBody = null,
|
||||
sId = '',
|
||||
sPlain = '',
|
||||
sResultHtml = '',
|
||||
bPgpSigned = false,
|
||||
bPgpEncrypted = false,
|
||||
|
|
@ -579,13 +594,13 @@
|
|||
|
||||
if ((oMessage.isPgpSigned() || oMessage.isPgpEncrypted()) && require('Stores/User/Pgp').capaOpenPGP())
|
||||
{
|
||||
oMessage.plainRaw = Utils.pString(oData.Result.Plain);
|
||||
sPlain = Utils.pString(oData.Result.Plain);
|
||||
|
||||
bPgpEncrypted = /---BEGIN PGP MESSAGE---/.test(oMessage.plainRaw);
|
||||
bPgpEncrypted = /---BEGIN PGP MESSAGE---/.test(sPlain);
|
||||
if (!bPgpEncrypted)
|
||||
{
|
||||
bPgpSigned = /-----BEGIN PGP SIGNED MESSAGE-----/.test(oMessage.plainRaw) &&
|
||||
/-----BEGIN PGP SIGNATURE-----/.test(oMessage.plainRaw);
|
||||
bPgpSigned = /-----BEGIN PGP SIGNED MESSAGE-----/.test(sPlain) &&
|
||||
/-----BEGIN PGP SIGNATURE-----/.test(sPlain);
|
||||
}
|
||||
|
||||
Globals.$div.empty();
|
||||
|
|
@ -593,7 +608,7 @@
|
|||
{
|
||||
sResultHtml =
|
||||
Globals.$div.append(
|
||||
$('<pre class="b-plain-openpgp signed"></pre>').text(oMessage.plainRaw)
|
||||
$('<pre class="b-plain-openpgp signed"></pre>').text(sPlain)
|
||||
).html()
|
||||
;
|
||||
}
|
||||
|
|
@ -601,11 +616,13 @@
|
|||
{
|
||||
sResultHtml =
|
||||
Globals.$div.append(
|
||||
$('<pre class="b-plain-openpgp encrypted"></pre>').text(oMessage.plainRaw)
|
||||
$('<pre class="b-plain-openpgp encrypted"></pre>').text(sPlain)
|
||||
).html()
|
||||
;
|
||||
}
|
||||
|
||||
sPlain = '';
|
||||
|
||||
Globals.$div.empty();
|
||||
|
||||
oMessage.isPgpSigned(bPgpSigned);
|
||||
|
|
@ -624,8 +641,6 @@
|
|||
|
||||
oMessage.isHtml(!!bIsHtml);
|
||||
oMessage.hasImages(!!bHasExternals);
|
||||
oMessage.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None);
|
||||
oMessage.pgpSignedVerifyUser('');
|
||||
|
||||
oMessage.body = oBody;
|
||||
if (oMessage.body)
|
||||
|
|
@ -663,6 +678,8 @@
|
|||
|
||||
if (oBody)
|
||||
{
|
||||
this.initOpenPgpControls(oBody);
|
||||
|
||||
this.initBlockquoteSwitcher(oBody);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@
|
|||
var
|
||||
_ = require('_'),
|
||||
ko = require('ko'),
|
||||
$ = require('$'),
|
||||
kn = require('Knoin/Knoin'),
|
||||
|
||||
Translator = require('Common/Translator'),
|
||||
|
||||
Utils = require('Common/Utils')
|
||||
;
|
||||
|
|
@ -41,32 +45,41 @@
|
|||
PgpUserStore.prototype.findPublicKeyByHex = function (sHash)
|
||||
{
|
||||
return _.find(this.openpgpkeysPublic(), function (oItem) {
|
||||
return oItem && sHash === oItem.id;
|
||||
return sHash && oItem && sHash === oItem.id;
|
||||
});
|
||||
};
|
||||
|
||||
PgpUserStore.prototype.findPrivateKeyByHex = function (sHash)
|
||||
{
|
||||
return _.find(this.openpgpkeysPrivate(), function (oItem) {
|
||||
return sHash && oItem && sHash === oItem.id;
|
||||
});
|
||||
};
|
||||
|
||||
PgpUserStore.prototype.findPublicKeysByEmail = function (sEmail)
|
||||
{
|
||||
return _.compact(_.flatten(_.map(this.openpgpkeysPublic(), function (oItem) {
|
||||
var oKey = oItem && sEmail === oItem.email ? oItem : null;
|
||||
return oKey ? oKey.getNativeKeys() : [null];
|
||||
}), true));
|
||||
};
|
||||
|
||||
PgpUserStore.prototype.findPublicKeysBySigningKeyIds = function (aSigningKeyIds)
|
||||
{
|
||||
var self = this;
|
||||
return _.compact(_.map(this.openpgpkeysPublic(), function (oItem) {
|
||||
return _.compact(_.flatten(_.map(aSigningKeyIds, function (oId) {
|
||||
var oKey = oId && oId.toHex ? self.findPublicKeyByHex(oId.toHex()) : null;
|
||||
return oKey ? oKey.getNativeKeys() : [null];
|
||||
}), true));
|
||||
};
|
||||
|
||||
var oKey = null;
|
||||
if (oItem && sEmail === oItem.email)
|
||||
{
|
||||
try
|
||||
{
|
||||
oKey = self.openpgp.key.readArmored(oItem.armor);
|
||||
if (oKey && !oKey.err && oKey.keys && oKey.keys[0])
|
||||
{
|
||||
return oKey.keys[0];
|
||||
}
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}));
|
||||
PgpUserStore.prototype.findPrivateKeysByEncryptionKeyIds = function (aEncryptionKeyIds, bReturnWrapKeys)
|
||||
{
|
||||
var self = this;
|
||||
return _.compact(_.flatten(_.map(aEncryptionKeyIds, function (oId) {
|
||||
var oKey = oId && oId.toHex ? self.findPrivateKeyByHex(oId.toHex()) : null;
|
||||
return oKey ? (bReturnWrapKeys ? [oKey] : oKey.getNativeKeys()) : [null];
|
||||
}), true));
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -77,6 +90,7 @@
|
|||
PgpUserStore.prototype.findPrivateKeyByEmail = function (sEmail, sPassword)
|
||||
{
|
||||
var
|
||||
oPrivateKeys = [],
|
||||
oPrivateKey = null,
|
||||
oKey = _.find(this.openpgpkeysPrivate(), function (oItem) {
|
||||
return oItem && sEmail === oItem.email;
|
||||
|
|
@ -85,18 +99,15 @@
|
|||
|
||||
if (oKey)
|
||||
{
|
||||
oPrivateKeys = oKey.getNativeKeys();
|
||||
oPrivateKey = oPrivateKeys[0] || null;
|
||||
|
||||
try
|
||||
{
|
||||
oPrivateKey = this.openpgp.key.readArmored(oKey.armor);
|
||||
if (oPrivateKey && !oPrivateKey.err && oPrivateKey.keys && oPrivateKey.keys[0])
|
||||
if (oPrivateKey)
|
||||
{
|
||||
oPrivateKey = oPrivateKey.keys[0];
|
||||
oPrivateKey.decrypt(Utils.pString(sPassword));
|
||||
}
|
||||
else
|
||||
{
|
||||
oPrivateKey = null;
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
|
|
@ -116,6 +127,259 @@
|
|||
return this.findPrivateKeyByEmail(require('Stores/User/Account').email(), sPassword);
|
||||
};
|
||||
|
||||
PgpUserStore.prototype.decryptMessage = function (oMessage, fCallback)
|
||||
{
|
||||
var self = this, aPrivateKeys = [], aEncryptionKeyIds = [];
|
||||
if (oMessage && oMessage.getSigningKeyIds)
|
||||
{
|
||||
aEncryptionKeyIds = oMessage.getEncryptionKeyIds();
|
||||
if (aEncryptionKeyIds)
|
||||
{
|
||||
aPrivateKeys = this.findPrivateKeysByEncryptionKeyIds(aEncryptionKeyIds, true);
|
||||
if (aPrivateKeys && 0 < aPrivateKeys.length)
|
||||
{
|
||||
kn.showScreenPopup(require('View/Popup/MessageOpenPgp'), [function (oDecriptedKey) {
|
||||
|
||||
if (oDecriptedKey)
|
||||
{
|
||||
var oPrivateKey = null, oDecryptedMessage = null;
|
||||
try
|
||||
{
|
||||
oDecryptedMessage = oMessage.decrypt(oDecriptedKey);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
oDecryptedMessage = null;
|
||||
}
|
||||
|
||||
if (oDecryptedMessage)
|
||||
{
|
||||
oPrivateKey = self.findPrivateKeyByHex(oDecriptedKey.primaryKey.keyid.toHex());
|
||||
if (oPrivateKey)
|
||||
{
|
||||
self.verifyMessage(oDecryptedMessage, function (oValidKey, aSigningKeyIds) {
|
||||
fCallback(oPrivateKey, oDecryptedMessage, oValidKey || null, aSigningKeyIds || null);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
fCallback(oPrivateKey, oDecryptedMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fCallback(oPrivateKey, oDecryptedMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fCallback(null, null);
|
||||
}
|
||||
|
||||
}, aPrivateKeys]);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fCallback(null, null);
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
PgpUserStore.prototype.verifyMessage = function (oMessage, fCallback)
|
||||
{
|
||||
var oValid = null, aResult = [], aPublicKeys = [], aSigningKeyIds = [];
|
||||
if (oMessage && oMessage.getSigningKeyIds)
|
||||
{
|
||||
aSigningKeyIds = oMessage.getSigningKeyIds();
|
||||
if (aSigningKeyIds && 0 < aSigningKeyIds.length)
|
||||
{
|
||||
aPublicKeys = this.findPublicKeysBySigningKeyIds(aSigningKeyIds);
|
||||
if (aPublicKeys && 0 < aPublicKeys.length)
|
||||
{
|
||||
try
|
||||
{
|
||||
aResult = oMessage.verify(aPublicKeys);
|
||||
oValid = _.find(_.isArray(aResult) ? aResult : [], function (oItem) {
|
||||
return oItem && oItem.valid && oItem.keyid;
|
||||
});
|
||||
|
||||
if (oValid && oValid.keyid && oValid.keyid && oValid.keyid.toHex)
|
||||
{
|
||||
fCallback(this.findPublicKeyByHex(oValid.keyid.toHex()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
|
||||
fCallback(null, aSigningKeyIds);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fCallback(null);
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} mDom
|
||||
*/
|
||||
PgpUserStore.prototype.controlsHelper = function (mDom, oVerControl, bSuccess, sTitle, sText)
|
||||
{
|
||||
if (bSuccess)
|
||||
{
|
||||
mDom.removeClass('error').addClass('success').attr('title', sTitle);
|
||||
oVerControl.removeClass('error').addClass('success').attr('title', sTitle);
|
||||
}
|
||||
else
|
||||
{
|
||||
mDom.removeClass('success').addClass('error').attr('title', sTitle);
|
||||
oVerControl.removeClass('success').addClass('error').attr('title', sTitle);
|
||||
}
|
||||
|
||||
if (undefined !== sText)
|
||||
{
|
||||
mDom.text(Utils.trim(sText.replace(/(\u200C|\u0002)/g, '')));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} mDom
|
||||
*/
|
||||
PgpUserStore.prototype.initMessageBodyControls = function (mDom)
|
||||
{
|
||||
if (mDom && !mDom.hasClass('inited'))
|
||||
{
|
||||
mDom.addClass('inited');
|
||||
|
||||
var
|
||||
self = this,
|
||||
bEncrypted = mDom.hasClass('encrypted'),
|
||||
bSigned = mDom.hasClass('signed'),
|
||||
oVerControl = null,
|
||||
sData = ''
|
||||
;
|
||||
|
||||
if (bEncrypted || bSigned)
|
||||
{
|
||||
sData = mDom.text();
|
||||
mDom.data('openpgp-original', sData);
|
||||
|
||||
if (bEncrypted)
|
||||
{
|
||||
oVerControl = $('<div class="b-openpgp-control"><i class="icon-lock"></i></div>')
|
||||
.attr('title', Translator.i18n('MESSAGE/PGP_ENCRYPTED_MESSAGE_DESC'));
|
||||
|
||||
oVerControl.on('click', function () {
|
||||
if ($(this).hasClass('success'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var oMessage = self.openpgp.message.readArmored(sData);
|
||||
if (oMessage && oMessage.getText && oMessage.verify && oMessage.decrypt)
|
||||
{
|
||||
self.decryptMessage(oMessage, function (oValidPrivateKey, oDecriptedMessage, oValidPublicKey, aSigningKeyIds) {
|
||||
|
||||
if (oDecriptedMessage)
|
||||
{
|
||||
if (oValidPublicKey)
|
||||
{
|
||||
self.controlsHelper(mDom, oVerControl, true, Translator.i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
|
||||
'USER': oValidPublicKey.user + ' (' + oValidPublicKey.id + ')'
|
||||
}), oDecriptedMessage.getText());
|
||||
}
|
||||
else if (oValidPrivateKey)
|
||||
{
|
||||
var
|
||||
aKeyIds = Utils.isNonEmptyArray(aSigningKeyIds) ? aSigningKeyIds : null,
|
||||
sAdditional = aKeyIds ? _.compact(_.map(aKeyIds, function (oItem) {
|
||||
return oItem && oItem.toHex ? oItem.toHex() : null;
|
||||
})).join(', ') : ''
|
||||
;
|
||||
|
||||
self.controlsHelper(mDom, oVerControl, false,
|
||||
Translator.i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') +
|
||||
(sAdditional ? ' (' + sAdditional + ')' : ''),
|
||||
oDecriptedMessage.getText());
|
||||
}
|
||||
else
|
||||
{
|
||||
self.controlsHelper(mDom, oVerControl, false,
|
||||
Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.controlsHelper(mDom, oVerControl, false,
|
||||
Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
self.controlsHelper(mDom, oVerControl, false, Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
|
||||
return false;
|
||||
|
||||
});
|
||||
}
|
||||
else if (bSigned)
|
||||
{
|
||||
oVerControl = $('<div class="b-openpgp-control"><i class="icon-lock"></i></div>')
|
||||
.attr('title', Translator.i18n('MESSAGE/PGP_SIGNED_MESSAGE_DESC'));
|
||||
|
||||
oVerControl.on('click', function () {
|
||||
|
||||
if ($(this).hasClass('success') || $(this).hasClass('error'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var oMessage = self.openpgp.cleartext.readArmored(sData);
|
||||
if (oMessage && oMessage.getText && oMessage.verify)
|
||||
{
|
||||
self.verifyMessage(oMessage, function (oValidKey, aSigningKeyIds) {
|
||||
if (oValidKey)
|
||||
{
|
||||
self.controlsHelper(mDom, oVerControl, true, Translator.i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
|
||||
'USER': oValidKey.user + ' (' + oValidKey.id + ')'
|
||||
}), oMessage.getText());
|
||||
}
|
||||
else
|
||||
{
|
||||
var
|
||||
aKeyIds = Utils.isNonEmptyArray(aSigningKeyIds) ? aSigningKeyIds : null,
|
||||
sAdditional = aKeyIds ? _.compact(_.map(aKeyIds, function (oItem) {
|
||||
return oItem && oItem.toHex ? oItem.toHex() : null;
|
||||
})).join(', ') : ''
|
||||
;
|
||||
|
||||
self.controlsHelper(mDom, oVerControl, false,
|
||||
Translator.i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') +
|
||||
(sAdditional ? ' (' + sAdditional + ')' : ''));
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
self.controlsHelper(mDom, oVerControl, false, Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (oVerControl)
|
||||
{
|
||||
mDom.before(oVerControl).before('<div></div>');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = new PgpUserStore();
|
||||
|
||||
}());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue