From f5375ef7009af2f149358245f9578b2782282ae7 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Tue, 9 Feb 2016 08:46:18 +0700 Subject: [PATCH] Drastically simplify async_proxy with generic delegate function --- src/openpgp.js | 8 ++-- src/worker/async_proxy.js | 80 +++++++++++++++++---------------------- src/worker/worker.js | 61 ++++++++++++++--------------- test/general/openpgp.js | 4 +- 4 files changed, 69 insertions(+), 84 deletions(-) diff --git a/src/openpgp.js b/src/openpgp.js index c3fe7cdd..1e533488 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -94,7 +94,7 @@ export function generateKey({ userIds=[], passphrase, numBits=2048, unlocked=fal formatUserIds(options); if (!util.getWebCrypto() && asyncProxy) { // use web worker if web crypto apis are not supported - return asyncProxy.generateKey(options); + return asyncProxy.delegate('generateKey', options); } return key.generate(options).then(newKey => ({ @@ -112,7 +112,7 @@ export function generateKey({ userIds=[], passphrase, numBits=2048, unlocked=fal } // fall back to js keygen in a worker if (config.debug) { console.log('Error generating keypair using native WebCrypto... falling back back to js'); } - return asyncProxy.generateKey(options); + return asyncProxy.delegate('generateKey', options); }).catch(onError.bind(null, 'Error generating keypair')); } @@ -141,7 +141,7 @@ export function encrypt({ data, publicKeys, privateKeys, passwords, filename, pa checkData(data); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); if (asyncProxy) { // use web worker if available - return asyncProxy.encrypt({ data, publicKeys, privateKeys, passwords, filename, packets }); + return asyncProxy.delegate('encrypt', { data, publicKeys, privateKeys, passwords, filename, packets }); } return execute(() => { @@ -178,7 +178,7 @@ export function decrypt({ message, privateKey, publicKeys, sessionKey, password, checkMessage(message); publicKeys = toArray(publicKeys); if (asyncProxy) { // use web worker if available - return asyncProxy.decrypt({ message, privateKey, publicKeys, sessionKey, password, format }); + return asyncProxy.delegate('decrypt', { message, privateKey, publicKeys, sessionKey, password, format }); } return execute(() => { diff --git a/src/worker/async_proxy.js b/src/worker/async_proxy.js index eadc56f0..b068554c 100644 --- a/src/worker/async_proxy.js +++ b/src/worker/async_proxy.js @@ -130,54 +130,42 @@ AsyncProxy.prototype.terminate = function() { ////////////////////////////////////////////////////////////////////////////////////////////////// -AsyncProxy.prototype.generateKey = function(options) { +AsyncProxy.prototype.delegate = function(method, options) { return new Promise((resolve, reject) => { - this.worker.postMessage({ - event: 'generate-key', - options: options + // clone packets (for web worker structured cloning algorithm) + this.worker.postMessage({ event:method, options:clonePackets(options) }); + + // remember to handle parsing cloned packets from worker + this.tasks.push({ resolve: data => resolve(parseClonedPackets(data)), reject }); + }); +}; + +function clonePackets(options) { + if(options.publicKeys) { + options.publicKeys = options.publicKeys.map(key => key.toPacketlist()); + } + if(options.privateKeys) { + options.privateKeys = options.privateKeys.map(key => key.toPacketlist()); + } + if(options.privateKey) { + options.privateKey = options.privateKey.toPacketlist(); + } + return options; +} + +function parseClonedPackets(data) { + if (data.key) { // parse cloned generated key + const packetlist = packet.List.fromStructuredClone(data.key); + data.key = new key.Key(packetlist); + } + if (data.signatures) { // parse cloned signatures + data.signatures = data.signatures.map(sig => { + sig.keyid = type_keyid.fromClone(sig.keyid); + return sig; }); - - this.tasks.push({ resolve: data => { - const packetlist = packet.List.fromStructuredClone(data.key); - data.key = new key.Key(packetlist); - resolve(data); - }, reject }); - }); -}; - -AsyncProxy.prototype.encrypt = function(options) { - return this.execute(() => { - if(options.publicKeys) { - options.publicKeys = options.publicKeys.map(key => key.toPacketlist()); - } - if(options.privateKeys) { - options.privateKeys = options.privateKeys.map(key => key.toPacketlist()); - } - this.worker.postMessage({ event:'encrypt', options }); - }); -}; - -AsyncProxy.prototype.decrypt = function(options) { - return new Promise((resolve, reject) => { - if(options.publicKeys) { - options.publicKeys = options.publicKeys.map(key => key.toPacketlist()); - } - if(options.privateKey) { - options.privateKey = options.privateKey.toPacketlist(); - } - this.worker.postMessage({ event:'decrypt', options }); - - this.tasks.push({ resolve: data => { - if (data.signatures) { - data.signatures = data.signatures.map(sig => { - sig.keyid = type_keyid.fromClone(sig.keyid); - return sig; - }); - } - resolve(data); - }, reject }); - }); -}; + } + return data; +} AsyncProxy.prototype.encryptSessionKey = function({ sessionKey, algo, keys, passwords }) { return this.execute(() => { diff --git a/src/worker/worker.js b/src/worker/worker.js index 87781724..54db7c58 100644 --- a/src/worker/worker.js +++ b/src/worker/worker.js @@ -69,40 +69,14 @@ self.onmessage = function (event) { window.openpgp.crypto.random.randomBuffer.set(msg.buf); break; - case 'generate-key': - window.openpgp.generateKey(opt).then(data => { - data.key = data.key.toPacketlist(); - response({ event:'method-return', data }); - }).catch(e => { - response({ event:'method-return', err:e.message }); - }); - break; - + case 'generateKey': case 'encrypt': - if(opt.publicKeys) { - opt.publicKeys = opt.publicKeys.map(packetlistCloneToKey); - } - if(opt.privateKeys) { - opt.privateKeys = opt.privateKeys.map(packetlistCloneToKey); - } - window.openpgp.encrypt(opt).then(data => { - response({ event:'method-return', data }); - }).catch(e => { - response({ event:'method-return', err:e.message }); - }); - break; - case 'decrypt': - if(opt.publicKeys) { - opt.publicKeys = opt.publicKeys.map(packetlistCloneToKey); - } - if(opt.privateKey) { - opt.privateKey = packetlistCloneToKey(opt.privateKey); - } - opt.message = packetlistCloneToMessage(opt.message.packets); - window.openpgp.decrypt(opt).then(data => { - response({ event:'method-return', data }); - }).catch(e => { + // parse cloned packets + window.openpgp[msg.event](parseClonedPackets(opt)).then(function(data) { + // clone packets (for web worker structured cloning algorithm) + response({ event:'method-return', data:clonePackets(data) }); + }).catch(function(e) { response({ event:'method-return', err:e.message }); }); break; @@ -189,6 +163,29 @@ self.onmessage = function (event) { } }; +function parseClonedPackets(options) { + if(options.publicKeys) { + options.publicKeys = options.publicKeys.map(packetlistCloneToKey); + } + if(options.privateKeys) { + options.privateKeys = options.privateKeys.map(packetlistCloneToKey); + } + if(options.privateKey) { + options.privateKey = packetlistCloneToKey(options.privateKey); + } + if (options.message) { + options.message = packetlistCloneToMessage(options.message.packets); + } + return options; +} + +function clonePackets(data) { + if (data.key) { + data.key = data.key.toPacketlist(); + } + return data; +} + function response(event) { if (window.openpgp.crypto.random.randomBuffer.size < MIN_SIZE_RANDOM_BUFFER) { postMessage({event: 'request-seed'}); diff --git a/test/general/openpgp.js b/test/general/openpgp.js index d3aad488..427a97dd 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -175,7 +175,7 @@ describe('OpenPGP.js public api tests', function() { openpgp.initWorker({ worker: workerStub }); - var proxyGenStub = sinon.stub(openpgp.getWorker(), 'generateKey'); + var proxyGenStub = sinon.stub(openpgp.getWorker(), 'delegate'); getWebCryptoStub.returns(); openpgp.generateKey(); @@ -190,7 +190,7 @@ describe('OpenPGP.js public api tests', function() { openpgp.initWorker({ worker: workerStub }); - var proxyGenStub = sinon.stub(openpgp.getWorker(), 'generateKey').returns(resolves('proxy_key')); + var proxyGenStub = sinon.stub(openpgp.getWorker(), 'delegate').returns(resolves('proxy_key')); getWebCryptoStub.returns({}); keyGenStub.returns(rejects(new Error('Native webcrypto keygen failed on purpose :)')));