/home/ivoiecob/email.hirewise-va.com/modules/OpenPgpFilesWebclient/js/OpenPgpEncryptor_unused.js
'use strict';
let
_ = require('underscore'),
$ = require('jquery'),
ko = require('knockout'),
Types = require('%PathToCoreWebclientModule%/js/utils/Types.js'),
App = require('%PathToCoreWebclientModule%/js/App.js'),
openpgp = require('%PathToCoreWebclientModule%/js/vendors/openpgp.js'),
COpenPgpKey = require('modules/%ModuleName%/js/COpenPgpKey.js'),
COpenPgpResult = require('modules/%ModuleName%/js/COpenPgpResult.js'),
Screens = require('%PathToCoreWebclientModule%/js/Screens.js'),
TextUtils = require('%PathToCoreWebclientModule%/js/utils/Text.js')
;
/**
* @constructor
*/
function OpenPgpEncryptor()
{
const sPrefix = 'user_' + (App.getUserId() || '0') + '_';
this.iPasswordLength = 15;
this.oKeyring = new openpgp.Keyring(new openpgp.Keyring.localstore(sPrefix));
this.keys = ko.observableArray([]);
}
OpenPgpEncryptor.prototype.oKeyring = null;
OpenPgpEncryptor.prototype.keys = [];
OpenPgpEncryptor.prototype.initKeys = async function ()
{
await this.oKeyring.load();
this.reloadKeysFromStorage();
};
/**
* @return {Array}
*/
OpenPgpEncryptor.prototype.getKeys = function ()
{
return this.keys();
};
/**
* @return {Array}
*/
OpenPgpEncryptor.prototype.getPublicKeys = function ()
{
return _.filter(this.keys(), oKey => {
return oKey && oKey.isPublic() === true;
});
};
/**
* @return {mixed}
*/
OpenPgpEncryptor.prototype.getKeysObservable = function ()
{
return this.keys;
};
/**
* @private
*/
OpenPgpEncryptor.prototype.reloadKeysFromStorage = function ()
{
let
aKeys = [],
oOpenpgpKeys = this.oKeyring.getAllKeys()
;
_.each(oOpenpgpKeys, oItem => {
if (oItem && oItem.primaryKey)
{
aKeys.push(new COpenPgpKey(oItem));
}
});
this.keys(aKeys);
};
/**
* @private
* @param {Array} aKeys
* @return {Array}
*/
OpenPgpEncryptor.prototype.convertToNativeKeys = function (aKeys)
{
return _.map(aKeys, oItem => {
return (oItem && oItem.pgpKey) ? oItem.pgpKey : oItem;
});
};
/**
* @private
* @param {Object} oKey
*/
OpenPgpEncryptor.prototype.cloneKey = async function (oKey)
{
let oPrivateKey = null;
if (oKey)
{
oPrivateKey = await openpgp.key.readArmored(oKey.armor());
if (oPrivateKey && !oPrivateKey.err && oPrivateKey.keys && oPrivateKey.keys[0])
{
oPrivateKey = oPrivateKey.keys[0];
if (!oPrivateKey || !oPrivateKey.primaryKey)
{
oPrivateKey = null;
}
}
else
{
oPrivateKey = null;
}
}
return oPrivateKey;
};
/**
* @private
* @param {Object} oResult
* @param {Object} oKey
* @param {string} sPassphrase
* @param {string} sKeyEmail
*/
OpenPgpEncryptor.prototype.decryptKeyHelper = async function (oResult, oKey, sPassphrase, sKeyEmail)
{
if (oKey && oKey.primaryKey && oKey.primaryKey.isDecrypted() && sPassphrase === '')
{
//key is encoded with an empty passphrase
}
else if(oKey)
{
try
{
await oKey.decrypt(Types.pString(sPassphrase));
if (!oKey || !oKey.primaryKey || !oKey.primaryKey.isDecrypted())
{
oResult.addError(Enums.OpenPgpErrors.KeyIsNotDecodedError, sKeyEmail || '');
}
}
catch (e)
{
oResult.addExceptionMessage(e, Enums.OpenPgpErrors.KeyIsNotDecodedError, sKeyEmail || '');
}
}
else
{
oResult.addError(Enums.OpenPgpErrors.KeyIsNotDecodedError, sKeyEmail || '');
}
};
/**
* @private
* @param {string} sArmor
* @return {Array}
*/
OpenPgpEncryptor.prototype.splitKeys = function (sArmor)
{
let
aResult = [],
iCount = 0,
iLimit = 30,
aMatch = null,
sKey = $.trim(sArmor),
oReg = /[\-]{3,6}BEGIN[\s]PGP[\s](PRIVATE|PUBLIC)[\s]KEY[\s]BLOCK[\-]{3,6}[\s\S]+?[\-]{3,6}END[\s]PGP[\s](PRIVATE|PUBLIC)[\s]KEY[\s]BLOCK[\-]{3,6}/gi
;
// If the key doesn't have any additional fields (for example "Version: 1.1"), this transformation corrupts the key.
// Seems like it is unnecessary transformation. Everything works fine without it.
// sKey = sKey.replace(/[\r\n]([a-zA-Z0-9]{2,}:[^\r\n]+)[\r\n]+([a-zA-Z0-9\/\\+=]{10,})/g, '\n$1---xyx---$2')
// .replace(/[\n\r]+/g, '\n').replace(/---xyx---/g, '\n\n');
do
{
aMatch = oReg.exec(sKey);
if (!aMatch || 0 > iLimit)
{
break;
}
if (aMatch[0] && aMatch[1] && aMatch[2] && aMatch[1] === aMatch[2])
{
if ('PRIVATE' === aMatch[1] || 'PUBLIC' === aMatch[1])
{
aResult.push([aMatch[1], aMatch[0]]);
iCount++;
}
}
iLimit--;
}
while (true);
return aResult;
};
/**
* @param {string} sArmor
* @return {Array|boolean}
*/
OpenPgpEncryptor.prototype.getArmorInfo = async function (sArmor)
{
sArmor = $.trim(sArmor);
let
iIndex = 0,
iCount = 0,
oKey = null,
aResult = [],
aData = null,
aKeys = []
;
if (!sArmor)
{
return false;
}
aKeys = this.splitKeys(sArmor);
for (iIndex = 0; iIndex < aKeys.length; iIndex++)
{
aData = aKeys[iIndex];
if ('PRIVATE' === aData[0])
{
try
{
oKey = await openpgp.key.readArmored(aData[1]);
if (oKey && !oKey.err && oKey.keys && oKey.keys[0])
{
aResult.push(new COpenPgpKey(oKey.keys[0]));
}
iCount++;
}
catch (e)
{
aResult.push(null);
}
}
else if ('PUBLIC' === aData[0])
{
try
{
oKey = await openpgp.key.readArmored(aData[1]);
if (oKey && !oKey.err && oKey.keys && oKey.keys[0])
{
aResult.push(new COpenPgpKey(oKey.keys[0]));
}
iCount++;
}
catch (e)
{
aResult.push(null);
}
}
}
return aResult;
};
/**
* @param {string} sID
* @param {boolean} bPublic
* @return {COpenPgpKey|null}
*/
OpenPgpEncryptor.prototype.findKeyByID = function (sID, bPublic)
{
bPublic = !!bPublic;
sID = sID.toLowerCase();
let oKey = _.find(this.keys(), oKey => {
let
oResult = false,
aKeys = null
;
if (oKey && bPublic === oKey.isPublic())
{
aKeys = oKey.pgpKey.getKeyIds();
if (aKeys)
{
oResult = _.find(aKeys, oKey => {
return oKey && oKey.toHex && sID === oKey.toHex().toLowerCase();
});
}
}
return !!oResult;
});
return oKey ? oKey : null;
};
/**
* @param {Array} aEmail
* @param {boolean} bIsPublic
* @param {COpenPgpResult=} oResult
* @return {Array}
*/
OpenPgpEncryptor.prototype.findKeysByEmails = function (aEmail, bIsPublic, oResult)
{
bIsPublic = !!bIsPublic;
let
aResult = [],
aKeys = this.keys()
;
_.each(aEmail, sEmail => {
let oKey = _.find(aKeys, oKey => {
return oKey && bIsPublic === oKey.isPublic() && sEmail === oKey.getEmail();
});
if (oKey)
{
aResult.push(oKey);
}
else
{
if (oResult)
{
oResult.addError(bIsPublic ?
Enums.OpenPgpErrors.PublicKeyNotFoundError : Enums.OpenPgpErrors.PrivateKeyNotFoundError, sEmail);
}
}
});
return aResult;
};
/**
* @param {type} aEmail
* @returns {Array}
*/
OpenPgpEncryptor.prototype.getPublicKeysIfExistsByEmail = function (sEmail)
{
let
aResult = [],
aKeys = this.keys(),
oKey = _.find(aKeys, oKey => {
return oKey && oKey.isPublic() === true && sEmail === oKey.getEmail();
})
;
if (oKey)
{
aResult.push(oKey);
}
return aResult;
};
/**
* @param {blob|string} Data
* @param {string} sPrincipalsEmail
* @param {boolean} bPasswordBasedEncryption
* @return {COpenPgpResult}
*/
OpenPgpEncryptor.prototype.encryptData = async function (Data, sPrincipalsEmail, bPasswordBasedEncryption, bSign, sPassphrase, sFromEmail)
{
let
oResult = new COpenPgpResult(),
aPublicKeys = [],
sPassword = '',
bIsBlob = Data instanceof Blob,
buffer = null,
aEmailForEncrypt = this.findKeysByEmails([sFromEmail], true).length > 0 ? [sPrincipalsEmail, sFromEmail] : [sPrincipalsEmail],
aPrivateKeys = this.findKeysByEmails([sFromEmail], false),
oOptions = {}
;
oResult.result = false;
if (!oResult.hasErrors())
{
if (bIsBlob)
{
buffer = await new Response(Data).arrayBuffer();
oOptions.message = openpgp.message.fromBinary(new Uint8Array(buffer));
oOptions.armor = false;
Data = null;
buffer = null;
}
else
{
oOptions.message = openpgp.message.fromText(Data);
}
if (bPasswordBasedEncryption)
{
sPassword = this.generatePassword();
oOptions.passwords = [sPassword];
}
else
{
aPublicKeys = this.findKeysByEmails(aEmailForEncrypt, true, oResult);
oOptions.publicKeys = this.convertToNativeKeys(aPublicKeys);
}
if (bSign && aPrivateKeys && aPrivateKeys.length > 0 && !bPasswordBasedEncryption)
{
let
oPrivateKey = this.convertToNativeKeys(aPrivateKeys)[0],
oPrivateKeyClone = await this.cloneKey(oPrivateKey)
;
await this.decryptKeyHelper(oResult, oPrivateKeyClone, sPassphrase, sFromEmail);
oOptions.privateKeys = [oPrivateKeyClone];
}
if (!oResult.hasErrors())
{
try
{
let oPgpResult = await openpgp.encrypt(oOptions);
oResult.result = {
data: bIsBlob ? oPgpResult.message.packets.write() : oPgpResult.data,
password: sPassword
};
}
catch (e)
{
oResult.addExceptionMessage(e, Enums.OpenPgpErrors.EncryptError);
}
}
}
return oResult;
};
/**
* @param {blob|string} Data
* @param {string} sAccountEmail
* @param {string} sPassword
* @param {boolean} sPassword
* @return {string}
*/
OpenPgpEncryptor.prototype.decryptData = async function (Data, sAccountEmail, sPassword, bPasswordBasedEncryption)
{
let
oResult = new COpenPgpResult(),
bIsBlob = Data instanceof Blob,
buffer = null,
aPrivateKeys = [],
aPublicKeys = this.getPublicKeys(),
oOptions = {
publicKeys: this.convertToNativeKeys(aPublicKeys) // for verification
}
;
if (bIsBlob)
{
buffer = await new Response(Data).arrayBuffer();
oOptions.message = await openpgp.message.read(new Uint8Array(buffer));
oOptions.format = 'binary';
}
else
{
oOptions.message = await openpgp.message.readArmored(Data);
}
oResult.result = false;
if (bPasswordBasedEncryption)
{
oOptions.passwords = [sPassword];
}
else
{
aPrivateKeys = this.findKeysByEmails([sAccountEmail], false, oResult);
if (aPrivateKeys && aPrivateKeys.length > 0)
{
let
oPrivateKey = this.convertToNativeKeys(aPrivateKeys)[0],
oPrivateKeyClone = await this.cloneKey(oPrivateKey)
;
await this.decryptKeyHelper(oResult, oPrivateKeyClone, sPassword, sAccountEmail);
oOptions.privateKeys = oPrivateKeyClone;
}
}
if (!oResult.hasErrors())
{
try
{
let oPgpResult = await openpgp.decrypt(oOptions);
oResult.result = await openpgp.stream.readToEnd(oPgpResult.data);
//if result contains invalid signatures
let aValidityPromises = [];
for (let oSignature of oPgpResult.signatures)
{
aValidityPromises.push(
oSignature.verified
.then(validity => {
oSignature.is_valid = validity;
return oSignature;
})
);
}
await Promise.all(aValidityPromises)
.then(aSignatures => {
const aInvalidSignatures = _.filter(aSignatures, oSignature => {
return oSignature !== null && oSignature.is_valid !== true;
});
const aValidSignatures = _.filter(aSignatures, oSignature => {
return oSignature !== null && oSignature.is_valid === true;
});
if (oPgpResult.signatures.length && aInvalidSignatures.length > 0)
{
Screens.showError(TextUtils.i18n('%MODULENAME%/ERROR_SIGNATURE_VERIFICATION'));
}
else if (aValidSignatures.length > 0)
{
const aKeyNames = _.map(aValidSignatures, oSignature => {
const sKeyID = oSignature.keyid.toHex();
const oKey = this.findKeyByID(sKeyID, true);
return oKey.getUser();
});
let sReportText = TextUtils.i18n('%MODULENAME%/REPORT_SUCCESSFULL_SIGNATURE_VERIFICATION');
sReportText = sReportText + ' ' + aKeyNames.join(', ').replace(/</g, "<").replace(/>/g, ">");
Screens.showReport(sReportText);
}
});
}
catch (e)
{
if (bPasswordBasedEncryption)
{
oResult.addExceptionMessage(e, Enums.OpenPgpErrors.PasswordDecryptError);
}
else
{
oResult.addExceptionMessage(e, Enums.OpenPgpErrors.VerifyAndDecryptError);
}
}
}
return oResult;
};
/**
* @param {Blob} oBlob
* @return {boolean}
*/
OpenPgpEncryptor.prototype.isDataEncryptedWithPassword = async function (oBlob)
{
let buffer = await new Response(oBlob).arrayBuffer();
let message = await openpgp.message.read(new Uint8Array(buffer));
return !!message.packets.findPacket(openpgp.enums.packet.symEncryptedSessionKey);
};
/**
* @param {string} sMessage
* @param {string} aPrincipalsEmail
* @param {boolean} bPasswordBasedEncryption
* @return {COpenPgpResult}
*/
OpenPgpEncryptor.prototype.encryptMessage = async function (sMessage, sPrincipalsEmail, bSign, sPassphrase, sFromEmail)
{
let oEncryptionResult = await this.encryptData(sMessage, sPrincipalsEmail, /*bPasswordBasedEncryption*/false, bSign, sPassphrase, sFromEmail);
if (oEncryptionResult.result)
{
let {data, password} = oEncryptionResult.result;
oEncryptionResult.result = data;
}
return oEncryptionResult;
};
OpenPgpEncryptor.prototype.generatePassword = function ()
{
let sPassword = "";
if (window.crypto)
{
let password = window.crypto.getRandomValues(new Uint8Array(10));
sPassword = btoa(String.fromCharCode.apply(null, password));
sPassword = sPassword.replace(/[^A-Za-z0-9]/g, "");
}
else
{
const sSymbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!;%:?*()_+=";
for (let i = 0; i < this.iPasswordLength; i++)
{
sPassword += sSymbols.charAt(Math.floor(Math.random() * sSymbols.length));
}
}
return sPassword;
};
OpenPgpEncryptor.prototype.getEncryptionKeyFromArmoredMessage = async function (sArmoredMessage)
{
let oMessage = await openpgp.message.readArmored(sArmoredMessage);
let aEncryptionKeys = oMessage.getEncryptionKeyIds();
let oEncryptionKey = null;
if (aEncryptionKeys.length > 0)
{
for (let key of aEncryptionKeys)
{
let oKey = this.findKeyByID(key.toHex(), false);
if (oKey)
{
oEncryptionKey = oKey;
break;
}
}
}
return oEncryptionKey;
};
module.exports = new OpenPgpEncryptor();