const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp'); const stub = require('sinon/lib/sinon/stub'); const chai = require('chai'); chai.use(require('chai-as-promised')); const input = require('./testInputs.js'); const { expect } = chai; const { stream, util } = openpgp; const pub_key = ['-----BEGIN PGP PUBLIC KEY BLOCK-----', 'Version: GnuPG v2.0.19 (GNU/Linux)', '', 'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+', 'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5', 'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0', 'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS', 'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6', 'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki', 'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf', '9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa', 'JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag', 'Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr', 'woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb', 'LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA', 'SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP', 'GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2', 'bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X', 'W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD', 'AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY', 'hz3tYjKhoFTKEIq3y3Pp', '=h/aX', '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); const priv_key = ['-----BEGIN PGP PRIVATE KEY BLOCK-----', 'Version: GnuPG v2.0.19 (GNU/Linux)', '', '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', '=lw5e', '-----END PGP PRIVATE KEY BLOCK-----'].join('\n'); const passphrase = 'hello world'; let plaintext, data, i, canceled, expectedType; function tests() { it('Encrypt small message', async function() { const data = new ReadableStream({ async start(controller) { controller.enqueue(util.str_to_Uint8Array('hello ')); controller.enqueue(util.str_to_Uint8Array('world')); controller.close(); } }); const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const msgAsciiArmored = await openpgp.stream.readToEnd(encrypted.data); const message = await openpgp.message.readArmored(msgAsciiArmored); const decrypted = await openpgp.decrypt({ passwords: ['test'], message }); expect(decrypted.data).to.equal('hello world'); }); it('Encrypt larger message', async function() { const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const reader = openpgp.stream.getReader(encrypted.data); expect(await reader.peekBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\r\n/); if (i > 10) throw new Error('Data did not arrive early.'); reader.releaseLock(); const msgAsciiArmored = await openpgp.stream.readToEnd(encrypted.data); const message = await openpgp.message.readArmored(msgAsciiArmored); const decrypted = await openpgp.decrypt({ passwords: ['test'], message, format: 'binary' }); expect(decrypted.data).to.deep.equal(util.concatUint8Array(plaintext)); }); it('Input stream should be canceled when canceling encrypted stream', async function() { const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const reader = openpgp.stream.getReader(encrypted.data); expect(await reader.readBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\r\n/); if (i > 10) throw new Error('Data did not arrive early.'); reader.releaseLock(); await openpgp.stream.cancel(encrypted.data); expect(canceled).to.be.true; }); it('Sign: Input stream should be canceled when canceling encrypted stream', async function() { const privKey = (await openpgp.key.readArmored(priv_key)).keys[0]; await privKey.decrypt(passphrase); const signed = await openpgp.sign({ message: openpgp.message.fromBinary(data), privateKeys: privKey }); const reader = openpgp.stream.getReader(signed.data); expect(await reader.readBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\r\n/); if (i > 10) throw new Error('Data did not arrive early.'); reader.releaseLock(); await openpgp.stream.cancel(signed.data); expect(canceled).to.be.true; }); it('Encrypt and decrypt larger message roundtrip', async function() { const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(msgAsciiArmored); const decrypted = await openpgp.decrypt({ passwords: ['test'], message, format: 'binary' }); expect(util.isStream(decrypted.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(decrypted.data); expect(await reader.peekBytes(1024)).to.deep.equal(plaintext[0]); if (i <= 10) throw new Error('Data arrived early.'); expect(await reader.readToEnd()).to.deep.equal(util.concatUint8Array(plaintext)); }); it('Encrypt and decrypt larger message roundtrip (allow_unauthenticated_stream=true)', async function() { let allow_unauthenticated_streamValue = openpgp.config.allow_unauthenticated_stream; openpgp.config.allow_unauthenticated_stream = true; try { const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(msgAsciiArmored); const decrypted = await openpgp.decrypt({ passwords: ['test'], message, format: 'binary' }); expect(util.isStream(decrypted.data)).to.equal(expectedType); expect(util.isStream(decrypted.signatures)).to.be.false; const reader = openpgp.stream.getReader(decrypted.data); expect(await reader.peekBytes(1024)).to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); expect(await reader.readToEnd()).to.deep.equal(util.concatUint8Array(plaintext)); expect(decrypted.signatures).to.exist.and.have.length(0); } finally { openpgp.config.allow_unauthenticated_stream = allow_unauthenticated_streamValue; } }); it('Encrypt and decrypt larger message roundtrip using public keys (allow_unauthenticated_stream=true)', async function() { let allow_unauthenticated_streamValue = openpgp.config.allow_unauthenticated_stream; openpgp.config.allow_unauthenticated_stream = true; try { const pubKey = (await openpgp.key.readArmored(pub_key)).keys[0]; const privKey = (await openpgp.key.readArmored(priv_key)).keys[0]; await privKey.decrypt(passphrase); const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), publicKeys: pubKey, privateKeys: privKey }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(msgAsciiArmored); const decrypted = await openpgp.decrypt({ publicKeys: pubKey, privateKeys: privKey, message, format: 'binary' }); expect(util.isStream(decrypted.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(decrypted.data); expect(await reader.peekBytes(1024)).to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); expect(await reader.readToEnd()).to.deep.equal(util.concatUint8Array(plaintext)); } finally { openpgp.config.allow_unauthenticated_stream = allow_unauthenticated_streamValue; } }); it('Detect MDC modifications (allow_unauthenticated_stream=true)', async function() { let allow_unauthenticated_streamValue = openpgp.config.allow_unauthenticated_stream; openpgp.config.allow_unauthenticated_stream = true; try { const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(openpgp.stream.transform(msgAsciiArmored, value => { value += ''; if (value === '\n=' || value.length === 4) return; // Remove checksum if (value.length > 1000) return value.slice(0, 499) + (value[499] === 'a' ? 'b' : 'a') + value.slice(500); return value; })); const decrypted = await openpgp.decrypt({ passwords: ['test'], message, streaming: expectedType, format: 'binary' }); expect(util.isStream(decrypted.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(decrypted.data); expect(await reader.peekBytes(1024)).not.to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); await expect(reader.readToEnd()).to.be.rejectedWith('Modification detected.'); expect(decrypted.signatures).to.exist.and.have.length(0); } finally { openpgp.config.allow_unauthenticated_stream = allow_unauthenticated_streamValue; } }); it('Detect armor checksum error (allow_unauthenticated_stream=true)', async function() { let allow_unauthenticated_streamValue = openpgp.config.allow_unauthenticated_stream; openpgp.config.allow_unauthenticated_stream = true; try { const pubKey = (await openpgp.key.readArmored(pub_key)).keys[0]; const privKey = (await openpgp.key.readArmored(priv_key)).keys[0]; await privKey.decrypt(passphrase); const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), publicKeys: pubKey, privateKeys: privKey }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(openpgp.stream.transform(msgAsciiArmored, value => { value += ''; if (value.length > 1000) return value.slice(0, 499) + (value[499] === 'a' ? 'b' : 'a') + value.slice(500); return value; })); const decrypted = await openpgp.decrypt({ publicKeys: pubKey, privateKeys: privKey, message, streaming: expectedType, format: 'binary' }); expect(util.isStream(decrypted.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(decrypted.data); expect(await reader.peekBytes(1024)).not.to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); await expect(reader.readToEnd()).to.be.rejectedWith('Ascii armor integrity check on message failed'); expect(decrypted.signatures).to.exist.and.have.length(1); } finally { openpgp.config.allow_unauthenticated_stream = allow_unauthenticated_streamValue; } }); it('Detect armor checksum error when not passing public keys (allow_unauthenticated_stream=true)', async function() { let allow_unauthenticated_streamValue = openpgp.config.allow_unauthenticated_stream; openpgp.config.allow_unauthenticated_stream = true; try { const pubKey = (await openpgp.key.readArmored(pub_key)).keys[0]; const privKey = (await openpgp.key.readArmored(priv_key)).keys[0]; await privKey.decrypt(passphrase); const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), publicKeys: pubKey, privateKeys: privKey }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(openpgp.stream.transform(msgAsciiArmored, value => { value += ''; if (value.length > 1000) return value.slice(0, 499) + (value[499] === 'a' ? 'b' : 'a') + value.slice(500); return value; })); const decrypted = await openpgp.decrypt({ privateKeys: privKey, message, streaming: expectedType, format: 'binary' }); expect(util.isStream(decrypted.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(decrypted.data); expect(await reader.peekBytes(1024)).not.to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); await expect(reader.readToEnd()).to.be.rejectedWith('Ascii armor integrity check on message failed'); expect(decrypted.signatures).to.exist.and.have.length(1); expect(await decrypted.signatures[0].verified).to.be.null; } finally { openpgp.config.allow_unauthenticated_stream = allow_unauthenticated_streamValue; } }); it('Sign/verify: Detect armor checksum error (allow_unauthenticated_stream=true)', async function() { let allow_unauthenticated_streamValue = openpgp.config.allow_unauthenticated_stream; openpgp.config.allow_unauthenticated_stream = true; try { const pubKey = (await openpgp.key.readArmored(pub_key)).keys[0]; const privKey = (await openpgp.key.readArmored(priv_key)).keys[0]; await privKey.decrypt(passphrase); const signed = await openpgp.sign({ message: openpgp.message.fromBinary(data), privateKeys: privKey }); const msgAsciiArmored = signed.data; const message = await openpgp.message.readArmored(openpgp.stream.transform(msgAsciiArmored, value => { value += ''; if (value.length > 1000) return value.slice(0, 499) + (value[499] === 'a' ? 'b' : 'a') + value.slice(500); return value; })); const verified = await openpgp.verify({ publicKeys: pubKey, message, streaming: expectedType }); expect(util.isStream(verified.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(verified.data); expect(await reader.peekBytes(1024)).not.to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); await expect(reader.readToEnd()).to.be.rejectedWith('Ascii armor integrity check on message failed'); expect(verified.signatures).to.exist.and.have.length(1); } finally { openpgp.config.allow_unauthenticated_stream = allow_unauthenticated_streamValue; } }); 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 { const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(msgAsciiArmored); const decrypted = await openpgp.decrypt({ passwords: ['test'], message, format: 'binary' }); expect(util.isStream(decrypted.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(decrypted.data); expect(await reader.peekBytes(1024)).to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); expect(await reader.readToEnd()).to.deep.equal(util.concatUint8Array(plaintext)); } finally { openpgp.config.aead_protect = aead_protectValue; openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteValue; } }); it('Encrypt and decrypt larger text 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 = 0; try { let plaintext = []; let i = 0; const data = new ReadableStream({ async pull(controller) { await new Promise(resolve => setTimeout(resolve, 10)); if (i++ < 10) { let randomData = input.createSomeMessage(); controller.enqueue(randomData); plaintext.push(randomData); } else { controller.close(); } } }); const encrypted = await openpgp.encrypt({ message: openpgp.message.fromText(data), streaming: expectedType, passwords: ['test'], }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(msgAsciiArmored); const decrypted = await openpgp.decrypt({ passwords: ['test'], message }); expect(util.isStream(decrypted.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(decrypted.data); expect((await reader.peekBytes(plaintext[0].length * 4)).toString('utf8').substr(0, plaintext[0].length)).to.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); expect((await reader.readToEnd()).toString('utf8')).to.equal(util.concat(plaintext)); } finally { openpgp.config.aead_protect = aead_protectValue; openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteValue; } }); it('stream.transformPair()', async function() { const transformed = stream.transformPair(stream.slice(data, 0, 5000), async (readable, writable) => { const reader = stream.getReader(readable); const writer = stream.getWriter(writable); try { while (true) { await writer.ready; const { done, value } = await reader.read(); if (done) { await writer.close(); break; } await writer.write(value); } } catch(e) { await writer.abort(e); } }); await new Promise(resolve => setTimeout(resolve)); await stream.cancel(transformed); expect(canceled).to.be.true; }); it('Input stream should be canceled when canceling decrypted stream (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 { const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(msgAsciiArmored); const decrypted = await openpgp.decrypt({ passwords: ['test'], message, format: 'binary' }); expect(util.isStream(decrypted.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(decrypted.data); expect(await reader.readBytes(1024)).to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); reader.releaseLock(); await openpgp.stream.cancel(decrypted.data, new Error('canceled by test')); expect(canceled).to.be.true; } finally { openpgp.config.aead_protect = aead_protectValue; openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteValue; } }); it('Sign/verify: Input stream should be canceled when canceling decrypted stream (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 { const pubKey = (await openpgp.key.readArmored(pub_key)).keys[0]; const privKey = (await openpgp.key.readArmored(priv_key)).keys[0]; await privKey.decrypt(passphrase); const signed = await openpgp.sign({ message: openpgp.message.fromBinary(data), privateKeys: privKey }); const msgAsciiArmored = signed.data; const message = await openpgp.message.readArmored(msgAsciiArmored); const verified = await openpgp.verify({ publicKeys: pubKey, message }); expect(util.isStream(verified.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(verified.data); expect(await reader.readBytes(1024)).to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); reader.releaseLock(); await openpgp.stream.cancel(verified.data, new Error('canceled by test')); expect(canceled).to.be.true; expect(verified.signatures).to.exist.and.have.length(1); expect(await verified.signatures[0].verified).to.be.undefined; } finally { openpgp.config.aead_protect = aead_protectValue; openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteValue; } }); it("Don't pull entire input stream when we're not pulling encrypted stream", async function() { const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const reader = openpgp.stream.getReader(encrypted.data); expect(await reader.readBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\r\n/); if (i > 10) throw new Error('Data did not arrive early.'); await new Promise(resolve => setTimeout(resolve, 3000)); expect(i).to.be.lessThan(50); }); it("Sign: Don't pull entire input stream when we're not pulling signed stream", async function() { const pubKey = (await openpgp.key.readArmored(pub_key)).keys[0]; const privKey = (await openpgp.key.readArmored(priv_key)).keys[0]; await privKey.decrypt(passphrase); const signed = await openpgp.sign({ message: openpgp.message.fromBinary(data), privateKeys: privKey }); const reader = openpgp.stream.getReader(signed.data); expect(await reader.readBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\r\n/); if (i > 10) throw new Error('Data did not arrive early.'); await new Promise(resolve => setTimeout(resolve, 3000)); expect(i).to.be.lessThan(50); }); it("Don't pull entire input stream when we're not pulling decrypted stream (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; let coresStub = stub(openpgp.util, 'getHardwareConcurrency'); coresStub.returns(1); try { const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(msgAsciiArmored); const decrypted = await openpgp.decrypt({ passwords: ['test'], message, format: 'binary' }); expect(util.isStream(decrypted.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(decrypted.data); expect(await reader.readBytes(1024)).to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); await new Promise(resolve => setTimeout(resolve, 3000)); expect(i).to.be.lessThan(50); } finally { openpgp.config.aead_protect = aead_protectValue; openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteValue; coresStub.restore(); } }); it("Sign/verify: Don't pull entire input stream when we're not pulling verified stream (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 { const pubKey = (await openpgp.key.readArmored(pub_key)).keys[0]; const privKey = (await openpgp.key.readArmored(priv_key)).keys[0]; await privKey.decrypt(passphrase); const signed = await openpgp.sign({ message: openpgp.message.fromBinary(data), privateKeys: privKey }); const msgAsciiArmored = signed.data; const message = await openpgp.message.readArmored(msgAsciiArmored); const verified = await openpgp.verify({ publicKeys: pubKey, message }); expect(util.isStream(verified.data)).to.equal(expectedType); const reader = openpgp.stream.getReader(verified.data); expect(await reader.readBytes(1024)).to.deep.equal(plaintext[0]); if (i > 10) throw new Error('Data did not arrive early.'); await new Promise(resolve => setTimeout(resolve, 3000)); expect(i).to.be.lessThan(50); } finally { openpgp.config.aead_protect = aead_protectValue; openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteValue; } }); if (openpgp.util.detectNode()) { const fs = util.nodeRequire('fs'); it('Node: Encrypt and decrypt binary message roundtrip', async function() { let plaintext = fs.readFileSync(__filename); const data = fs.createReadStream(__filename); const encrypted = await openpgp.encrypt({ message: openpgp.message.fromBinary(data), passwords: ['test'], }); const msgAsciiArmored = encrypted.data; const message = await openpgp.message.readArmored(msgAsciiArmored); const decrypted = await openpgp.decrypt({ passwords: ['test'], message, format: 'binary' }); expect(util.isStream(decrypted.data)).to.equal('node'); expect(await openpgp.stream.readToEnd(decrypted.data)).to.deep.equal(plaintext); }); } } describe('Streaming', function() { let currentTest = 0; beforeEach(function() { let test = ++currentTest; plaintext = []; i = 0; canceled = false; data = new ReadableStream({ async pull(controller) { await new Promise(setTimeout); if (test === currentTest && i++ < 10) { let randomBytes = await openpgp.crypto.random.getRandomBytes(1024); controller.enqueue(randomBytes); plaintext.push(randomBytes); } else { controller.close(); } }, cancel() { canceled = true; } }); }); tryTests('WhatWG Streams', tests, { if: true, beforeEach: function() { expectedType = 'web'; } }); tryTests('Node Streams', tests, { if: openpgp.util.detectNode(), beforeEach: function() { data = openpgp.stream.webToNode(data); expectedType = 'node'; } }); });