OpenPGP improvements (first step)

openpgpjs: 0.7.2 -> 0.10.1
additional fixes
This commit is contained in:
RainLoop Team 2015-06-23 01:33:27 +04:00
parent 09334159c2
commit 34a9b8cbc5
28 changed files with 1363 additions and 644 deletions

View file

@ -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);
}

View file

@ -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();
}());