Drastically simplify async_proxy with generic delegate function

This commit is contained in:
Tankred Hase 2016-02-09 08:46:18 +07:00
parent 227a412ca0
commit f5375ef700
4 changed files with 69 additions and 84 deletions

View File

@ -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(() => {

View File

@ -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(() => {

View File

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

View File

@ -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 :)')));