Refactor web worker async proxy to use promises.

This commit is contained in:
Tankred Hase 2014-10-01 21:18:05 +02:00
parent 7f2573c77d
commit f08fc0a4f7
5 changed files with 264 additions and 273 deletions

View File

@ -239,8 +239,8 @@ function generateKeyPair(options) {
/** /**
* Are we in a browser and do we support worker? * Are we in a browser and do we support worker?
*/ */
function useWorker(callback) { function useWorker() {
if (typeof window === 'undefined' || !window.Worker || typeof callback !== 'function') { if (typeof window === 'undefined' || !window.Worker) {
return false; return false;
} }

View File

@ -24,11 +24,12 @@
* @module async_proxy * @module async_proxy
*/ */
'use strict';
var crypto = require('../crypto'), var crypto = require('../crypto'),
packet = require('../packet'), packet = require('../packet'),
key = require('../key.js'), key = require('../key.js'),
type_keyid = require('../type/keyid.js'), type_keyid = require('../type/keyid.js');
enums = require('../enums.js');
var INITIAL_RANDOM_SEED = 50000, // random bytes seeded to worker var INITIAL_RANDOM_SEED = 50000, // random bytes seeded to worker
RANDOM_SEED_REQUEST = 20000; // random bytes seeded after worker request RANDOM_SEED_REQUEST = 20000; // random bytes seeded after worker request
@ -49,6 +50,24 @@ function AsyncProxy(path) {
this.tasks = []; this.tasks = [];
} }
/**
* Command pattern that wraps synchronous code into a promise
* @param {Object} self The current this
* @param {function} cmd The synchronous function with a return value
* to be wrapped in a promise
* @return {Promise} The promise wrapped around cmd
*/
AsyncProxy.prototype.execute = function(cmd) {
var self = this;
var promise = new Promise(function(resolve, reject) {
cmd();
self.tasks.push({ resolve:resolve, reject:reject });
});
return promise;
};
/** /**
* Message handling * Message handling
*/ */
@ -56,7 +75,13 @@ AsyncProxy.prototype.onMessage = function(event) {
var msg = event.data; var msg = event.data;
switch (msg.event) { switch (msg.event) {
case 'method-return': case 'method-return':
this.tasks.shift()(msg.err ? new Error(msg.err) : null, msg.data); if (msg.err) {
// fail
this.tasks.shift().reject(new Error(msg.err));
} else {
// success
this.tasks.shift().resolve(msg.data);
}
break; break;
case 'request-seed': case 'request-seed':
this.seedRandom(RANDOM_SEED_REQUEST); this.seedRandom(RANDOM_SEED_REQUEST);
@ -98,21 +123,23 @@ AsyncProxy.prototype.terminate = function() {
* Encrypts message text with keys * Encrypts message text with keys
* @param {(Array<module:key~Key>|module:key~Key)} keys array of keys or single key, used to encrypt the message * @param {(Array<module:key~Key>|module:key~Key)} keys array of keys or single key, used to encrypt the message
* @param {String} text message as native JavaScript string * @param {String} text message as native JavaScript string
* @param {Function} callback receives encrypted ASCII armored message
*/ */
AsyncProxy.prototype.encryptMessage = function(keys, text, callback) { AsyncProxy.prototype.encryptMessage = function(keys, text) {
if (!keys.length) { var self = this;
keys = [keys];
} return self.execute(function() {
keys = keys.map(function(key) { if (!keys.length) {
return key.toPacketlist(); keys = [keys];
}
keys = keys.map(function(key) {
return key.toPacketlist();
});
self.worker.postMessage({
event: 'encrypt-message',
keys: keys,
text: text
});
}); });
this.worker.postMessage({
event: 'encrypt-message',
keys: keys,
text: text
});
this.tasks.push(callback);
}; };
/** /**
@ -120,40 +147,43 @@ AsyncProxy.prototype.encryptMessage = function(keys, text, callback) {
* @param {(Array<module:key~Key>|module:key~Key)} publicKeys array of keys or single key, used to encrypt the message * @param {(Array<module:key~Key>|module:key~Key)} publicKeys array of keys or single key, used to encrypt the message
* @param {module:key~Key} privateKey private key with decrypted secret key data for signing * @param {module:key~Key} privateKey private key with decrypted secret key data for signing
* @param {String} text message as native JavaScript string * @param {String} text message as native JavaScript string
* @param {Function} callback receives encrypted ASCII armored message
*/ */
AsyncProxy.prototype.signAndEncryptMessage = function(publicKeys, privateKey, text, callback) { AsyncProxy.prototype.signAndEncryptMessage = function(publicKeys, privateKey, text) {
if (!publicKeys.length) { var self = this;
publicKeys = [publicKeys];
} return self.execute(function() {
publicKeys = publicKeys.map(function(key) { if (!publicKeys.length) {
return key.toPacketlist(); publicKeys = [publicKeys];
}
publicKeys = publicKeys.map(function(key) {
return key.toPacketlist();
});
privateKey = privateKey.toPacketlist();
self.worker.postMessage({
event: 'sign-and-encrypt-message',
publicKeys: publicKeys,
privateKey: privateKey,
text: text
});
}); });
privateKey = privateKey.toPacketlist();
this.worker.postMessage({
event: 'sign-and-encrypt-message',
publicKeys: publicKeys,
privateKey: privateKey,
text: text
});
this.tasks.push(callback);
}; };
/** /**
* Decrypts message * Decrypts message
* @param {module:key~Key} privateKey private key with decrypted secret key data * @param {module:key~Key} privateKey private key with decrypted secret key data
* @param {module:message~Message} message the message object with the encrypted data * @param {module:message~Message} message the message object with the encrypted data
* @param {Function} callback receives decrypted message as as native JavaScript string
* or null if no literal data found
*/ */
AsyncProxy.prototype.decryptMessage = function(privateKey, message, callback) { AsyncProxy.prototype.decryptMessage = function(privateKey, message) {
privateKey = privateKey.toPacketlist(); var self = this;
this.worker.postMessage({
event: 'decrypt-message', return self.execute(function() {
privateKey: privateKey, privateKey = privateKey.toPacketlist();
message: message self.worker.postMessage({
event: 'decrypt-message',
privateKey: privateKey,
message: message
});
}); });
this.tasks.push(callback);
}; };
/** /**
@ -161,82 +191,91 @@ AsyncProxy.prototype.decryptMessage = function(privateKey, message, callback) {
* @param {module:key~Key} privateKey private key with decrypted secret key data * @param {module:key~Key} privateKey private key with decrypted secret key data
* @param {(Array<module:key~Key>|module:key~Key)} publicKeys array of keys or single key to verify signatures * @param {(Array<module:key~Key>|module:key~Key)} publicKeys array of keys or single key to verify signatures
* @param {module:message~Message} message the message object with signed and encrypted data * @param {module:message~Message} message the message object with signed and encrypted data
* @param {Function} callback receives decrypted message as as native JavaScript string
* with verified signatures or null if no literal data found
*/ */
AsyncProxy.prototype.decryptAndVerifyMessage = function(privateKey, publicKeys, message, callback) { AsyncProxy.prototype.decryptAndVerifyMessage = function(privateKey, publicKeys, message) {
privateKey = privateKey.toPacketlist(); var self = this;
if (!publicKeys.length) {
publicKeys = [publicKeys]; var promise = new Promise(function(resolve, reject) {
} privateKey = privateKey.toPacketlist();
publicKeys = publicKeys.map(function(key) { if (!publicKeys.length) {
return key.toPacketlist(); publicKeys = [publicKeys];
}); }
this.worker.postMessage({ publicKeys = publicKeys.map(function(key) {
event: 'decrypt-and-verify-message', return key.toPacketlist();
privateKey: privateKey, });
publicKeys: publicKeys, self.worker.postMessage({
message: message event: 'decrypt-and-verify-message',
}); privateKey: privateKey,
this.tasks.push(function(err, data) { publicKeys: publicKeys,
if (data) { message: message
});
self.tasks.push({ resolve:function(data) {
data.signatures = data.signatures.map(function(sig) { data.signatures = data.signatures.map(function(sig) {
sig.keyid = type_keyid.fromClone(sig.keyid); sig.keyid = type_keyid.fromClone(sig.keyid);
return sig; return sig;
}); });
} resolve(data);
callback(err, data); }, reject:reject });
}); });
return promise;
}; };
/** /**
* Signs a cleartext message * Signs a cleartext message
* @param {(Array<module:key~Key>|module:key~Key)} privateKeys array of keys or single key, with decrypted secret key data to sign cleartext * @param {(Array<module:key~Key>|module:key~Key)} privateKeys array of keys or single key, with decrypted secret key data to sign cleartext
* @param {String} text cleartext * @param {String} text cleartext
* @param {Function} callback receives ASCII armored message
*/ */
AsyncProxy.prototype.signClearMessage = function(privateKeys, text, callback) { AsyncProxy.prototype.signClearMessage = function(privateKeys, text) {
if (!privateKeys.length) { var self = this;
privateKeys = [privateKeys];
} return self.execute(function() {
privateKeys = privateKeys.map(function(key) { if (!privateKeys.length) {
return key.toPacketlist(); privateKeys = [privateKeys];
}
privateKeys = privateKeys.map(function(key) {
return key.toPacketlist();
});
self.worker.postMessage({
event: 'sign-clear-message',
privateKeys: privateKeys,
text: text
});
}); });
this.worker.postMessage({
event: 'sign-clear-message',
privateKeys: privateKeys,
text: text
});
this.tasks.push(callback);
}; };
/** /**
* Verifies signatures of cleartext signed message * Verifies signatures of cleartext signed message
* @param {(Array<module:key~Key>|module:key~Key)} publicKeys array of keys or single key, to verify signatures * @param {(Array<module:key~Key>|module:key~Key)} publicKeys array of keys or single key, to verify signatures
* @param {module:cleartext~CleartextMessage} message cleartext message object with signatures * @param {module:cleartext~CleartextMessage} message cleartext message object with signatures
* @param {Function} callback receives cleartext with status of verified signatures
*/ */
AsyncProxy.prototype.verifyClearSignedMessage = function(publicKeys, message, callback) { AsyncProxy.prototype.verifyClearSignedMessage = function(publicKeys, message) {
if (!publicKeys.length) { var self = this;
publicKeys = [publicKeys];
} var promise = new Promise(function(resolve, reject) {
publicKeys = publicKeys.map(function(key) { if (!publicKeys.length) {
return key.toPacketlist(); publicKeys = [publicKeys];
}); }
this.worker.postMessage({ publicKeys = publicKeys.map(function(key) {
event: 'verify-clear-signed-message', return key.toPacketlist();
publicKeys: publicKeys, });
message: message self.worker.postMessage({
}); event: 'verify-clear-signed-message',
this.tasks.push(function(err, data) { publicKeys: publicKeys,
if (data) { message: message
});
self.tasks.push({ resolve:function(data) {
data.signatures = data.signatures.map(function(sig) { data.signatures = data.signatures.map(function(sig) {
sig.keyid = type_keyid.fromClone(sig.keyid); sig.keyid = type_keyid.fromClone(sig.keyid);
return sig; return sig;
}); });
} resolve(data);
callback(err, data); }, reject:reject });
}); });
return promise;
}; };
/** /**
@ -247,42 +286,50 @@ AsyncProxy.prototype.verifyClearSignedMessage = function(publicKeys, message, ca
* @param {Integer} numBits number of bits for the key creation. (should be 1024+, generally) * @param {Integer} numBits number of bits for the key creation. (should be 1024+, generally)
* @param {String} userId assumes already in form of "User Name <username@email.com>" * @param {String} userId assumes already in form of "User Name <username@email.com>"
* @param {String} passphrase The passphrase used to encrypt the resulting private key * @param {String} passphrase The passphrase used to encrypt the resulting private key
* @param {Function} callback receives object with key and public and private armored texts
*/ */
AsyncProxy.prototype.generateKeyPair = function(options, callback) { AsyncProxy.prototype.generateKeyPair = function(options) {
this.worker.postMessage({ var self = this;
event: 'generate-key-pair',
options: options var promise = new Promise(function(resolve, reject) {
}); self.worker.postMessage({
this.tasks.push(function(err, data) { event: 'generate-key-pair',
if (data) { options: options
});
self.tasks.push({ resolve:function(data) {
var packetlist = packet.List.fromStructuredClone(data.key); var packetlist = packet.List.fromStructuredClone(data.key);
data.key = new key.Key(packetlist); data.key = new key.Key(packetlist);
} resolve(data);
callback(err, data); }, reject:reject });
}); });
return promise;
}; };
/** /**
* Decrypts secret part of all secret key packets of key. * Decrypts secret part of all secret key packets of key.
* @param {module:key~Key} privateKey private key with encrypted secret key data * @param {module:key~Key} privateKey private key with encrypted secret key data
* @param {String} password password to unlock the key * @param {String} password password to unlock the key
* @param {Function} callback receives decrypted key
*/ */
AsyncProxy.prototype.decryptKey = function(privateKey, password, callback) { AsyncProxy.prototype.decryptKey = function(privateKey, password) {
privateKey = privateKey.toPacketlist(); var self = this;
this.worker.postMessage({
event: 'decrypt-key', var promise = new Promise(function(resolve, reject) {
privateKey: privateKey, privateKey = privateKey.toPacketlist();
password: password self.worker.postMessage({
}); event: 'decrypt-key',
this.tasks.push(function(err, data) { privateKey: privateKey,
if (data) { password: password
});
self.tasks.push({ resolve:function(data) {
var packetlist = packet.List.fromStructuredClone(data); var packetlist = packet.List.fromStructuredClone(data);
data = new key.Key(packetlist); data = new key.Key(packetlist);
} resolve(data);
callback(err, data); }, reject:reject });
}); });
return promise;
}; };
/** /**
@ -290,23 +337,27 @@ AsyncProxy.prototype.decryptKey = function(privateKey, password, callback) {
* @param {module:key~Key} privateKey private key with encrypted secret key data * @param {module:key~Key} privateKey private key with encrypted secret key data
* @param {Array<module:type/keyid>} keyIds * @param {Array<module:type/keyid>} keyIds
* @param {String} password password to unlock the key * @param {String} password password to unlock the key
* @param {Function} callback receives decrypted key
*/ */
AsyncProxy.prototype.decryptKeyPacket = function(privateKey, keyIds, password, callback) { AsyncProxy.prototype.decryptKeyPacket = function(privateKey, keyIds, password) {
privateKey = privateKey.toPacketlist(); var self = this;
this.worker.postMessage({
event: 'decrypt-key-packet', var promise = new Promise(function(resolve, reject) {
privateKey: privateKey, privateKey = privateKey.toPacketlist();
keyIds: keyIds, self.worker.postMessage({
password: password event: 'decrypt-key-packet',
}); privateKey: privateKey,
this.tasks.push(function(err, data) { keyIds: keyIds,
if (data) { password: password
});
self.tasks.push({ resolve:function(data) {
var packetlist = packet.List.fromStructuredClone(data); var packetlist = packet.List.fromStructuredClone(data);
data = new key.Key(packetlist); data = new key.Key(packetlist);
} resolve(data);
callback(err, data); }, reject:reject });
}); });
return promise;
}; };
module.exports = AsyncProxy; module.exports = AsyncProxy;

View File

@ -24,11 +24,12 @@ var MAX_SIZE_RANDOM_BUFFER = 60000;
window.openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER); window.openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER);
onmessage = function (event) { self.onmessage = function (event) {
var data = null, var data = null,
err = null, err = null,
msg = event.data, msg = event.data,
correct = false; correct = false;
switch (msg.event) { switch (msg.event) {
case 'seed-random': case 'seed-random':
if (!(msg.buf instanceof Uint8Array)) { if (!(msg.buf instanceof Uint8Array)) {
@ -37,93 +38,78 @@ onmessage = function (event) {
window.openpgp.crypto.random.randomBuffer.set(msg.buf); window.openpgp.crypto.random.randomBuffer.set(msg.buf);
break; break;
case 'encrypt-message': case 'encrypt-message':
try { if (!msg.keys.length) {
if (!msg.keys.length) { msg.keys = [msg.keys];
msg.keys = [msg.keys];
}
msg.keys = msg.keys.map(packetlistCloneToKey);
data = window.openpgp.encryptMessage(msg.keys, msg.text);
} catch (e) {
err = e.message;
} }
response({event: 'method-return', data: data, err: err}); msg.keys = msg.keys.map(packetlistCloneToKey);
window.openpgp.encryptMessage(msg.keys, msg.text).then(function(data) {
response({event: 'method-return', data: data});
}).catch(function(e) {
response({event: 'method-return', err: e.message});
});
break; break;
case 'sign-and-encrypt-message': case 'sign-and-encrypt-message':
try { if (!msg.publicKeys.length) {
if (!msg.publicKeys.length) { msg.publicKeys = [msg.publicKeys];
msg.publicKeys = [msg.publicKeys];
}
msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey);
msg.privateKey = packetlistCloneToKey(msg.privateKey);
data = window.openpgp.signAndEncryptMessage(msg.publicKeys, msg.privateKey, msg.text);
} catch (e) {
err = e.message;
} }
response({event: 'method-return', data: data, err: err}); msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey);
msg.privateKey = packetlistCloneToKey(msg.privateKey);
window.openpgp.signAndEncryptMessage(msg.publicKeys, msg.privateKey, msg.text).then(function(data) {
response({event: 'method-return', data: data});
}).catch(function(e) {
response({event: 'method-return', err: e.message});
});
break; break;
case 'decrypt-message': case 'decrypt-message':
try { msg.privateKey = packetlistCloneToKey(msg.privateKey);
msg.privateKey = packetlistCloneToKey(msg.privateKey); msg.message = packetlistCloneToMessage(msg.message.packets);
msg.message = packetlistCloneToMessage(msg.message.packets); window.openpgp.decryptMessage(msg.privateKey, msg.message).then(function(data) {
data = window.openpgp.decryptMessage(msg.privateKey, msg.message); response({event: 'method-return', data: data});
} catch (e) { }).catch(function(e) {
err = e.message; response({event: 'method-return', err: e.message});
} });
response({event: 'method-return', data: data, err: err});
break; break;
case 'decrypt-and-verify-message': case 'decrypt-and-verify-message':
try { msg.privateKey = packetlistCloneToKey(msg.privateKey);
msg.privateKey = packetlistCloneToKey(msg.privateKey); if (!msg.publicKeys.length) {
if (!msg.publicKeys.length) { msg.publicKeys = [msg.publicKeys];
msg.publicKeys = [msg.publicKeys];
}
msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey);
msg.message = packetlistCloneToMessage(msg.message.packets);
data = window.openpgp.decryptAndVerifyMessage(msg.privateKey, msg.publicKeys, msg.message);
} catch (e) {
err = e.message;
} }
response({event: 'method-return', data: data, err: err}); msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey);
msg.message = packetlistCloneToMessage(msg.message.packets);
window.openpgp.decryptAndVerifyMessage(msg.privateKey, msg.publicKeys, msg.message).then(function(data) {
response({event: 'method-return', data: data});
}).catch(function(e) {
response({event: 'method-return', err: e.message});
});
break; break;
case 'sign-clear-message': case 'sign-clear-message':
try { msg.privateKeys = msg.privateKeys.map(packetlistCloneToKey);
msg.privateKeys = msg.privateKeys.map(packetlistCloneToKey); window.openpgp.signClearMessage(msg.privateKeys, msg.text).then(function(data) {
data = window.openpgp.signClearMessage(msg.privateKeys, msg.text); response({event: 'method-return', data: data});
} catch (e) { }).catch(function(e) {
err = e.message; response({event: 'method-return', err: e.message});
} });
response({event: 'method-return', data: data, err: err});
break; break;
case 'verify-clear-signed-message': case 'verify-clear-signed-message':
try { if (!msg.publicKeys.length) {
if (!msg.publicKeys.length) { msg.publicKeys = [msg.publicKeys];
msg.publicKeys = [msg.publicKeys];
}
msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey);
var packetlist = window.openpgp.packet.List.fromStructuredClone(msg.message.packets);
msg.message = new window.openpgp.cleartext.CleartextMessage(msg.message.text, packetlist);
data = window.openpgp.verifyClearSignedMessage(msg.publicKeys, msg.message);
} catch (e) {
err = e.message;
} }
response({event: 'method-return', data: data, err: err}); msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey);
var packetlist = window.openpgp.packet.List.fromStructuredClone(msg.message.packets);
msg.message = new window.openpgp.cleartext.CleartextMessage(msg.message.text, packetlist);
window.openpgp.verifyClearSignedMessage(msg.publicKeys, msg.message).then(function(data) {
response({event: 'method-return', data: data});
}).catch(function(e) {
response({event: 'method-return', err: e.message});
});
break; break;
case 'generate-key-pair': case 'generate-key-pair':
try { window.openpgp.generateKeyPair(msg.options).then(function(data) {
window.openpgp.generateKeyPair(msg.options, function(error, data) { data.key = data.key.toPacketlist();
if (error) { response({event: 'method-return', data: data});
err = error.message; }).catch(function(e) {
response({event: 'method-return', data: data, err: err}); response({event: 'method-return', err: e.message});
return; });
}
data.key = data.key.toPacketlist();
response({event: 'method-return', data: data, err: err});
});
} catch (e) {
err = e.message;
response({event: 'method-return', data: data, err: err});
}
break; break;
case 'decrypt-key': case 'decrypt-key':
try { try {

View File

@ -18,6 +18,7 @@
<script src="lib/mocha.js"></script> <script src="lib/mocha.js"></script>
<script> <script>
mocha.setup('bdd'); mocha.setup('bdd');
mocha.timeout(20000);
</script> </script>
<script src="lib/unittests-bundle.js"></script> <script src="lib/unittests-bundle.js"></script>
<script> <script>

View File

@ -184,8 +184,7 @@ describe('High level API', function() {
describe('Encryption', function() { describe('Encryption', function() {
it('RSA: encryptMessage async', function (done) { it('RSA: encryptMessage async', function (done) {
openpgp.encryptMessage([pubKeyRSA], plaintext, function(err, data) { openpgp.encryptMessage([pubKeyRSA], plaintext).then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
expect(data).to.match(/^-----BEGIN PGP MESSAGE/); expect(data).to.match(/^-----BEGIN PGP MESSAGE/);
var msg = openpgp.message.readArmored(data); var msg = openpgp.message.readArmored(data);
@ -195,8 +194,7 @@ describe('High level API', function() {
}); });
it('RSA: encryptMessage one key async', function (done) { it('RSA: encryptMessage one key async', function (done) {
openpgp.encryptMessage(pubKeyRSA, plaintext, function(err, data) { openpgp.encryptMessage(pubKeyRSA, plaintext).then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
expect(data).to.match(/^-----BEGIN PGP MESSAGE/); expect(data).to.match(/^-----BEGIN PGP MESSAGE/);
var msg = openpgp.message.readArmored(data); var msg = openpgp.message.readArmored(data);
@ -205,25 +203,8 @@ describe('High level API', function() {
}); });
}); });
it('RSA: encryptMessage sync', function () {
var msg = openpgp.encryptMessage([pubKeyRSA], plaintext);
expect(msg).to.exist;
expect(msg).to.match(/^-----BEGIN PGP MESSAGE/);
msg = openpgp.message.readArmored(msg);
expect(msg).to.be.an.instanceof(openpgp.message.Message);
});
it('RSA: encryptMessage one key sync', function () {
var msg = openpgp.encryptMessage(pubKeyRSA, plaintext);
expect(msg).to.exist;
expect(msg).to.match(/^-----BEGIN PGP MESSAGE/);
msg = openpgp.message.readArmored(msg);
expect(msg).to.be.an.instanceof(openpgp.message.Message);
});
it('ELG: encryptMessage async', function (done) { it('ELG: encryptMessage async', function (done) {
openpgp.encryptMessage([pubKeyDE], plaintext, function(err, data) { openpgp.encryptMessage([pubKeyDE], plaintext).then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
expect(data).to.match(/^-----BEGIN PGP MESSAGE/); expect(data).to.match(/^-----BEGIN PGP MESSAGE/);
var msg = openpgp.message.readArmored(data); var msg = openpgp.message.readArmored(data);
@ -232,14 +213,6 @@ describe('High level API', function() {
}); });
}); });
it('ELG: encryptMessage sync', function () {
var msg = openpgp.encryptMessage([pubKeyDE], plaintext);
expect(msg).to.exist;
expect(msg).to.match(/^-----BEGIN PGP MESSAGE/);
msg = openpgp.message.readArmored(msg);
expect(msg).to.be.an.instanceof(openpgp.message.Message);
});
}); });
describe('Decryption', function() { describe('Decryption', function() {
@ -254,35 +227,21 @@ describe('High level API', function() {
}); });
it('RSA: decryptMessage async', function (done) { it('RSA: decryptMessage async', function (done) {
openpgp.decryptMessage(privKeyRSA, msgRSA, function(err, data) { openpgp.decryptMessage(privKeyRSA, msgRSA).then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
expect(data).to.equal(plaintext); expect(data).to.equal(plaintext);
done(); done();
}); });
}); });
it('RSA: decryptMessage sync', function () {
var text = openpgp.decryptMessage(privKeyRSA, msgRSA);
expect(text).to.exist;
expect(text).to.equal(plaintext);
});
it('ELG: decryptMessage async', function (done) { it('ELG: decryptMessage async', function (done) {
openpgp.decryptMessage(privKeyDE, msgDE, function(err, data) { openpgp.decryptMessage(privKeyDE, msgDE).then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
expect(data).to.equal(plaintext); expect(data).to.equal(plaintext);
done(); done();
}); });
}); });
it('ELG: decryptMessage sync', function () {
var text = openpgp.decryptMessage(privKeyDE, msgDE);
expect(text).to.exist;
expect(text).to.equal(plaintext);
});
}); });
function verifySignature(data, privKey) { function verifySignature(data, privKey) {
@ -304,8 +263,7 @@ describe('High level API', function() {
}); });
it('RSA: decryptAndVerifyMessage async', function (done) { it('RSA: decryptAndVerifyMessage async', function (done) {
openpgp.decryptAndVerifyMessage(privKeyRSA, [pubKeyRSA], msgRSA, function(err, data) { openpgp.decryptAndVerifyMessage(privKeyRSA, [pubKeyRSA], msgRSA).then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
verifySignature(data, privKeyRSA); verifySignature(data, privKeyRSA);
done(); done();
@ -313,8 +271,7 @@ describe('High level API', function() {
}); });
it('ELG: decryptAndVerifyMessage async', function (done) { it('ELG: decryptAndVerifyMessage async', function (done) {
openpgp.decryptAndVerifyMessage(privKeyDE, [pubKeyDE], msgDE, function(err, data) { openpgp.decryptAndVerifyMessage(privKeyDE, [pubKeyDE], msgDE).then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
verifySignature(data, privKeyDE); verifySignature(data, privKeyDE);
done(); done();
@ -330,13 +287,13 @@ describe('High level API', function() {
}); });
it('RSA: signAndEncryptMessage async', function (done) { it('RSA: signAndEncryptMessage async', function (done) {
openpgp.signAndEncryptMessage([pubKeyRSA], privKeyRSA, plaintext, function(err, data) { openpgp.signAndEncryptMessage([pubKeyRSA], privKeyRSA, plaintext).then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
expect(data).to.match(/^-----BEGIN PGP MESSAGE/); expect(data).to.match(/^-----BEGIN PGP MESSAGE/);
var msg = openpgp.message.readArmored(data); var msg = openpgp.message.readArmored(data);
expect(msg).to.be.an.instanceof(openpgp.message.Message); expect(msg).to.be.an.instanceof(openpgp.message.Message);
var decrypted = openpgp.decryptAndVerifyMessage(privKeyRSA, [pubKeyRSA], msg); return openpgp.decryptAndVerifyMessage(privKeyRSA, [pubKeyRSA], msg);
}).then(function(decrypted) {
verifySignature(decrypted, privKeyRSA); verifySignature(decrypted, privKeyRSA);
done(); done();
}); });
@ -352,8 +309,7 @@ describe('High level API', function() {
}); });
it('RSA: signClearMessage async', function (done) { it('RSA: signClearMessage async', function (done) {
openpgp.signClearMessage([privKeyRSA], plaintext, function(err, data) { openpgp.signClearMessage([privKeyRSA], plaintext).then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
expect(data).to.match(/-----BEGIN PGP SIGNED MESSAGE-----/); expect(data).to.match(/-----BEGIN PGP SIGNED MESSAGE-----/);
var msg = openpgp.message.readArmored(data); var msg = openpgp.message.readArmored(data);
@ -363,8 +319,7 @@ describe('High level API', function() {
}); });
it('DSA: signClearMessage async', function (done) { it('DSA: signClearMessage async', function (done) {
openpgp.signClearMessage([privKeyDE], plaintext, function(err, data) { openpgp.signClearMessage([privKeyDE], plaintext).then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
expect(data).to.match(/-----BEGIN PGP SIGNED MESSAGE-----/); expect(data).to.match(/-----BEGIN PGP SIGNED MESSAGE-----/);
var msg = openpgp.message.readArmored(data); var msg = openpgp.message.readArmored(data);
@ -374,10 +329,10 @@ describe('High level API', function() {
}); });
it('RSA: verifyClearSignedMessage async', function (done) { it('RSA: verifyClearSignedMessage async', function (done) {
var signed = openpgp.signClearMessage([privKeyRSA], plaintext); openpgp.signClearMessage([privKeyRSA], plaintext).then(function(signed) {
signed = openpgp.cleartext.readArmored(signed); signed = openpgp.cleartext.readArmored(signed);
openpgp.verifyClearSignedMessage([pubKeyRSA], signed, function(err, data) { return openpgp.verifyClearSignedMessage([pubKeyRSA], signed);
expect(err).to.not.exist; }).then(function(data) {
expect(data).to.exist; expect(data).to.exist;
verifySignature(data, privKeyRSA); verifySignature(data, privKeyRSA);
done(); done();
@ -391,8 +346,7 @@ describe('High level API', function() {
before(initKeys); before(initKeys);
it('Signing with not decrypted key gives error', function (done) { it('Signing with not decrypted key gives error', function (done) {
openpgp.signClearMessage([privKeyRSA], plaintext, function(err, data) { openpgp.signClearMessage([privKeyRSA], plaintext).catch(function(err) {
expect(data).to.not.exist;
expect(err).to.exist; expect(err).to.exist;
expect(err.message).to.equal('Private key is not decrypted.'); expect(err.message).to.equal('Private key is not decrypted.');
done(); done();
@ -404,8 +358,7 @@ describe('High level API', function() {
wProxy.worker = new Worker('../dist/openpgp.worker.js'); wProxy.worker = new Worker('../dist/openpgp.worker.js');
wProxy.worker.onmessage = wProxy.onMessage.bind(wProxy); wProxy.worker.onmessage = wProxy.onMessage.bind(wProxy);
wProxy.seedRandom(10); wProxy.seedRandom(10);
wProxy.encryptMessage([pubKeyRSA], plaintext, function(err, data) { wProxy.encryptMessage([pubKeyRSA], plaintext).catch(function(err) {
expect(data).to.not.exist;
expect(err).to.exist; expect(err).to.exist;
expect(err).to.eql(new Error('Random number buffer depleted')); expect(err).to.eql(new Error('Random number buffer depleted'));
done(); done();
@ -442,13 +395,13 @@ describe('High level API', function() {
it('Decrypt key', function (done) { it('Decrypt key', function (done) {
expect(privKeyRSA.primaryKey.isDecrypted).to.be.false; expect(privKeyRSA.primaryKey.isDecrypted).to.be.false;
expect(privKeyRSA.subKeys[0].subKey.isDecrypted).to.be.false; expect(privKeyRSA.subKeys[0].subKey.isDecrypted).to.be.false;
proxy.decryptKey(privKeyRSA, 'hello world', function(err, data) { proxy.decryptKey(privKeyRSA, 'hello world').then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
expect(data).to.be.an.instanceof(openpgp.key.Key); expect(data).to.be.an.instanceof(openpgp.key.Key);
expect(data.primaryKey.isDecrypted).to.be.true; expect(data.primaryKey.isDecrypted).to.be.true;
expect(data.subKeys[0].subKey.isDecrypted).to.be.true; expect(data.subKeys[0].subKey.isDecrypted).to.be.true;
var text = openpgp.decryptMessage(data, msg); return openpgp.decryptMessage(data, msg);
}).then(function(text) {
expect(text).to.equal(plaintext); expect(text).to.equal(plaintext);
done(); done();
}); });
@ -458,20 +411,20 @@ describe('High level API', function() {
expect(privKeyRSA.primaryKey.isDecrypted).to.be.false; expect(privKeyRSA.primaryKey.isDecrypted).to.be.false;
expect(privKeyRSA.subKeys[0].subKey.isDecrypted).to.be.false; expect(privKeyRSA.subKeys[0].subKey.isDecrypted).to.be.false;
var keyid = privKeyRSA.subKeys[0].subKey.getKeyId(); var keyid = privKeyRSA.subKeys[0].subKey.getKeyId();
proxy.decryptKeyPacket(privKeyRSA, [keyid], 'hello world', function(err, data) { proxy.decryptKeyPacket(privKeyRSA, [keyid], 'hello world').then(function(data) {
expect(err).to.not.exist;
expect(data).to.exist; expect(data).to.exist;
expect(data).to.be.an.instanceof(openpgp.key.Key); expect(data).to.be.an.instanceof(openpgp.key.Key);
expect(data.primaryKey.isDecrypted).to.be.false; expect(data.primaryKey.isDecrypted).to.be.false;
expect(data.subKeys[0].subKey.isDecrypted).to.be.true; expect(data.subKeys[0].subKey.isDecrypted).to.be.true;
var text = openpgp.decryptMessage(data, msg); return openpgp.decryptMessage(data, msg);
}).then(function(text) {
expect(text).to.equal(plaintext); expect(text).to.equal(plaintext);
done(); done();
}); });
}); });
it('Error on wrong password decryptKey', function (done) { it('Error on wrong password decryptKey', function (done) {
proxy.decryptKey(privKeyRSA, 'what?', function(err, data) { proxy.decryptKey(privKeyRSA, 'what?').catch(function(err) {
expect(err).to.eql(new Error('Wrong password')); expect(err).to.eql(new Error('Wrong password'));
done(); done();
}); });
@ -479,7 +432,7 @@ describe('High level API', function() {
it('Error on wrong password decryptKeyPacket', function (done) { it('Error on wrong password decryptKeyPacket', function (done) {
var keyid = privKeyRSA.subKeys[0].subKey.getKeyId(); var keyid = privKeyRSA.subKeys[0].subKey.getKeyId();
proxy.decryptKeyPacket(privKeyRSA, [keyid], 'what?', function(err, data) { proxy.decryptKeyPacket(privKeyRSA, [keyid], 'what?').catch(function(err) {
expect(err).to.eql(new Error('Wrong password')); expect(err).to.eql(new Error('Wrong password'));
done(); done();
}); });