Skip to content

Commit

Permalink
Return strings in Node streams where appropriate
Browse files Browse the repository at this point in the history
  • Loading branch information
twiss committed Feb 9, 2021
1 parent 95eb43a commit 37d30c5
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 33 deletions.
19 changes: 11 additions & 8 deletions src/openpgp.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKe
if (returnSessionKey) {
result.sessionKey = encrypted.sessionKey;
}
return convertStreams(result, streaming, ['signature', 'data']);
return convertStreams(result, streaming, armor ? 'utf8' : 'binary', ['signature', 'data']);
}).catch(onError.bind(null, 'Error encrypting message'));
}

Expand Down Expand Up @@ -388,7 +388,7 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
result.data = format === 'binary' ? decrypted.getLiteralData() : decrypted.getText();
result.filename = decrypted.getFilename();
if (streaming) linkStreams(result, message);
result.data = await convertStream(result.data, streaming);
result.data = await convertStream(result.data, streaming, format);
if (!streaming) await prepareSignatures(result.signatures);
return result;
}).catch(onError.bind(null, 'Error decrypting message'));
Expand Down Expand Up @@ -453,7 +453,7 @@ export function sign({ message, privateKeys, armor = true, streaming = message &
message = await message.sign(privateKeys, undefined, date, fromUserIds, message.fromStream);
result.data = armor ? message.armor() : message.write();
}
return convertStreams(result, streaming, ['signature', 'data']);
return convertStreams(result, streaming, armor ? 'utf8' : 'binary', ['signature', 'data']);
}).catch(onError.bind(null, 'Error signing message'));
}

Expand Down Expand Up @@ -495,7 +495,7 @@ export function verify({ message, publicKeys, format = 'utf8', streaming = messa
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date, streaming) : await message.verify(publicKeys, date, streaming);
result.data = format === 'binary' ? message.getLiteralData() : message.getText();
if (streaming) linkStreams(result, message);
result.data = await convertStream(result.data, streaming);
result.data = await convertStream(result.data, streaming, format);
if (!streaming) await prepareSignatures(result.signatures);
return result;
}).catch(onError.bind(null, 'Error verifying signed message'));
Expand Down Expand Up @@ -616,9 +616,10 @@ function toArray(param) {
* Convert data to or from Stream
* @param {Object} data the data to convert
* @param {'web'|'node'|false} streaming (optional) whether to return a ReadableStream
* @param {'utf8'|'binary'} encoding (optional) how to return data in Node Readable streams
* @returns {Object} the data in the respective format
*/
async function convertStream(data, streaming) {
async function convertStream(data, streaming, encoding = 'utf8') {
if (!streaming && util.isStream(data)) {
return stream.readToEnd(data);
}
Expand All @@ -632,6 +633,7 @@ async function convertStream(data, streaming) {
}
if (streaming === 'node') {
data = stream.webToNode(data);
if (encoding !== 'binary') data.setEncoding(encoding);
}
return data;
}
Expand All @@ -640,16 +642,17 @@ async function convertStream(data, streaming) {
* Convert object properties from Stream
* @param {Object} obj the data to convert
* @param {'web'|'node'|false} streaming (optional) whether to return ReadableStreams
* @param {'utf8'|'binary'} encoding (optional) how to return data in Node Readable streams
* @param {Array<String>} keys (optional) which keys to return as streams, if possible
* @returns {Object} the data in the respective format
*/
async function convertStreams(obj, streaming, keys = []) {
async function convertStreams(obj, streaming, encoding = 'utf8', keys = []) {
if (Object.prototype.isPrototypeOf(obj) && !Uint8Array.prototype.isPrototypeOf(obj)) {
await Promise.all(Object.entries(obj).map(async ([key, value]) => { // recursively search all children
if (util.isStream(value) || keys.includes(key)) {
obj[key] = await convertStream(value, streaming);
obj[key] = await convertStream(value, streaming, encoding);
} else {
await convertStreams(obj[key], streaming);
await convertStreams(obj[key], streaming, encoding);
}
}));
}
Expand Down
69 changes: 44 additions & 25 deletions test/general/streaming.js
Original file line number Diff line number Diff line change
Expand Up @@ -892,31 +892,6 @@ function tests() {
await openpgp.stream.cancel(signed.signature, new Error('canceled by test'));
expect(canceled).to.be.true;
});

if (openpgp.util.detectNode()) {
const fs = util.nodeRequire('fs');

it('Node: Encrypt and decrypt binary message roundtrip', async function() {
dataArrived(); // Do not wait until data arrived.
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() {
Expand Down Expand Up @@ -969,4 +944,48 @@ describe('Streaming', function() {
expectedType = 'node';
}
});

if (openpgp.util.detectNode()) {
const fs = util.nodeRequire('fs');

it('Node: Encrypt and decrypt text message roundtrip', async function() {
dataArrived(); // Do not wait until data arrived.
const plaintext = fs.readFileSync(__filename.replace('streaming.js', 'openpgp.js'), 'utf8');
const data = fs.createReadStream(__filename.replace('streaming.js', 'openpgp.js'), { encoding: 'utf8' });
const encrypted = await openpgp.encrypt({
message: openpgp.message.fromText(data),
passwords: ['test']
});
expect(util.isStream(encrypted.data)).to.equal('node');

const message = await openpgp.message.readArmored(encrypted.data);
const decrypted = await openpgp.decrypt({
passwords: ['test'],
message
});
expect(util.isStream(decrypted.data)).to.equal('node');
expect(await openpgp.stream.readToEnd(decrypted.data)).to.equal(plaintext);
});

it('Node: Encrypt and decrypt binary message roundtrip', async function() {
dataArrived(); // Do not wait until data arrived.
const plaintext = fs.readFileSync(__filename.replace('streaming.js', 'openpgp.js'));
const data = fs.createReadStream(__filename.replace('streaming.js', 'openpgp.js'));
const encrypted = await openpgp.encrypt({
message: openpgp.message.fromBinary(data),
passwords: ['test'],
armor: false
});
expect(util.isStream(encrypted.data)).to.equal('node');

const message = await openpgp.message.read(encrypted.data);
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);
});
}
});

0 comments on commit 37d30c5

Please sign in to comment.