Allow simultaneously reading data and waiting for signature verification

This makes openpgp.{decrypt,verify}().signatures a Promise when passing a
stream or when asStream=true
This commit is contained in:
Daniel Huigens 2018-06-01 12:19:16 +02:00
parent 4bbbdaee9f
commit 1effe19c1d
5 changed files with 28 additions and 7 deletions

View File

@ -370,7 +370,8 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
}
const result = {};
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date) : await message.verify(publicKeys, date);
result.signatures = signature ? message.verifyDetached(signature, publicKeys, date) : message.verify(publicKeys, date);
if (!asStream) result.signatures = await result.signatures;
result.data = format === 'binary' ? message.getLiteralData() : message.getText();
result.data = await convertStream(result.data, asStream);
result.filename = message.getFilename();
@ -456,9 +457,8 @@ export function verify({ message, publicKeys, asStream, signature=null, date=new
return Promise.resolve().then(async function() {
const result = {};
result.signatures = signature ?
await message.verifyDetached(signature, publicKeys, date) :
await message.verify(publicKeys, date);
result.signatures = signature ? message.verifyDetached(signature, publicKeys, date) : message.verify(publicKeys, date);
if (!asStream) result.signatures = await result.signatures;
result.data = message instanceof CleartextMessage ? message.getText() : message.getLiteralData();
result.data = await convertStream(result.data, asStream);
return result;

View File

@ -28,6 +28,7 @@ import { CleartextMessage } from '../cleartext';
import { Signature } from '../signature';
import List from './packetlist';
import type_keyid from '../type/keyid';
import stream from '../stream';
import util from '../util';
@ -68,7 +69,12 @@ export function clonePackets(options) {
options.signature = options.signature.packets;
}
if (options.signatures) {
options.signatures = options.signatures.map(sig => verificationObjectToClone(sig));
if (options.signatures instanceof Promise) {
const signatures = options.signatures;
options.signatures = stream.fromAsync(async () => (await signatures).map(verificationObjectToClone));
} else {
options.signatures.forEach(verificationObjectToClone);
}
}
return options;
}
@ -110,7 +116,13 @@ export function parseClonedPackets(options) {
options.message = packetlistCloneToMessage(options.message);
}
if (options.signatures) {
options.signatures = options.signatures.map(packetlistCloneToSignatures);
if (util.isStream(options.signatures)) {
options.signatures = stream.readToEnd(options.signatures, arr => arr).then(([signatures]) => {
return signatures.map(packetlistCloneToSignatures);
});
} else {
options.signatures = options.signatures.map(packetlistCloneToSignatures);
}
}
if (options.signature) {
options.signature = packetlistCloneToSignature(options.signature);

View File

@ -149,7 +149,7 @@ AsyncProxy.prototype.delegate = function(method, options) {
this.workers[workerId].requests++;
// remember to handle parsing cloned packets from worker
this.tasks[id] = { resolve: data => resolve(util.restoreStreams(packet.clone.parseClonedPackets(data, method))), reject };
this.tasks[id] = { resolve: data => resolve(packet.clone.parseClonedPackets(util.restoreStreams(data), method)), reject };
});
};

View File

@ -680,6 +680,7 @@ yYDnCgA=
return openpgp.verify({ publicKeys:[pubKey], message:sMsg }).then(async function(cleartextSig) {
expect(cleartextSig).to.exist;
expect(openpgp.util.nativeEOL(openpgp.util.Uint8Array_to_str(await openpgp.stream.readToEnd(cleartextSig.data)))).to.equal(plaintext);
cleartextSig.signatures = await cleartextSig.signatures;
expect(cleartextSig.signatures).to.have.length(1);
expect(cleartextSig.signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);

View File

@ -48,6 +48,8 @@ describe('Streaming', function() {
data,
passwords: ['test'],
});
await openpgp.stream.getReader(openpgp.stream.clone(encrypted.data)).readBytes(1000);
if (i > 10) throw new Error('Data did not arrive early.');
const msgAsciiArmored = await openpgp.stream.readToEnd(encrypted.data);
const message = await openpgp.message.readArmored(msgAsciiArmored);
const decrypted = await openpgp.decrypt({
@ -90,12 +92,15 @@ describe('Streaming', function() {
it('Encrypt and decrypt larger message roundtrip (draft04)', async function() {
let aead_protectValue = openpgp.config.aead_protect;
let aead_chunk_size_byteValue = openpgp.config.aead_chunk_size_byte;
openpgp.config.aead_protect = true;
openpgp.config.aead_chunk_size_byte = 4;
try {
let plaintext = [];
let i = 0;
const data = new ReadableStream({
async pull(controller) {
await new Promise(setTimeout);
if (i++ < 10) {
let randomBytes = await openpgp.crypto.random.getRandomBytes(1024);
controller.enqueue(randomBytes);
@ -118,9 +123,12 @@ describe('Streaming', function() {
format: 'binary'
});
expect(util.isStream(decrypted.data)).to.be.true;
await openpgp.stream.getReader(openpgp.stream.clone(decrypted.data)).readBytes(1000);
if (i > 10) throw new Error('Data did not arrive early.');
expect(await openpgp.stream.readToEnd(decrypted.data)).to.deep.equal(util.concatUint8Array(plaintext));
} finally {
openpgp.config.aead_protect = aead_protectValue;
openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteValue;
}
});
});