mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2026-03-16 13:25:12 +00:00
Pass more tests
- Allow leading spaces in headers (since we were already accepting leading spaces everywhere else in the armored text). - Read ReadableStreams before passing them to a Worker
This commit is contained in:
@@ -207,7 +207,6 @@ function dearmor(input) {
|
||||
const reEmptyLine = /^[ \f\r\t\u00a0\u2000-\u200a\u202f\u205f\u3000]*$/;
|
||||
|
||||
const reader = stream.getReader(input);
|
||||
let lineIndex = 0;
|
||||
let type;
|
||||
const headers = [];
|
||||
let lastHeaders = headers;
|
||||
@@ -232,13 +231,13 @@ function dearmor(input) {
|
||||
});
|
||||
while (true) {
|
||||
let line = await reader.readLine();
|
||||
if (!line) break;
|
||||
if (lineIndex++ === 0) {
|
||||
// trim string
|
||||
line = line.trim();
|
||||
if (line === undefined) {
|
||||
controller.error('Misformed armored text');
|
||||
break;
|
||||
}
|
||||
// remove trailing whitespace at end of lines
|
||||
line = line.replace(/[\t\r\n ]+$/g, '');
|
||||
// remove leading whitespace for compat with older versions of OpenPGP.js
|
||||
line = line.trim();
|
||||
if (!type) {
|
||||
if (reSplit.test(line)) {
|
||||
type = getType(line);
|
||||
@@ -257,7 +256,7 @@ function dearmor(input) {
|
||||
} else if (!textDone && type === 2) {
|
||||
if (!reSplit.test(line)) {
|
||||
// Reverse dash-escaping for msg
|
||||
text.push(line.replace(/^- /mg, ''));
|
||||
text.push(line.replace(/^- /, ''));
|
||||
} else {
|
||||
text = text.join('\r\n');
|
||||
textDone = true;
|
||||
|
||||
@@ -127,15 +127,15 @@ export function generateKey({ userIds=[], passphrase="", numBits=2048, keyExpira
|
||||
return asyncProxy.delegate('generateKey', options);
|
||||
}
|
||||
|
||||
return generate(options).then(key => {
|
||||
return generate(options).then(async key => {
|
||||
const revocationCertificate = key.getRevocationCertificate();
|
||||
key.revocationSignatures = [];
|
||||
|
||||
return {
|
||||
|
||||
key: key,
|
||||
privateKeyArmored: key.armor(),
|
||||
publicKeyArmored: key.toPublic().armor(),
|
||||
privateKeyArmored: await stream.readToEnd(key.armor()),
|
||||
publicKeyArmored: await stream.readToEnd(key.toPublic().armor())
|
||||
revocationCertificate: revocationCertificate
|
||||
|
||||
};
|
||||
@@ -453,6 +453,9 @@ export function verify({ message, publicKeys, signature=null, date=new Date() })
|
||||
return Promise.resolve().then(async function() {
|
||||
const result = {};
|
||||
result.data = message instanceof CleartextMessage ? message.getText() : message.getLiteralData();
|
||||
if (!message.fromStream) {
|
||||
result.data = await stream.readToEnd(result.data);
|
||||
}
|
||||
result.signatures = signature ?
|
||||
await message.verifyDetached(signature, publicKeys, date) :
|
||||
await message.verify(publicKeys, date);
|
||||
|
||||
@@ -235,14 +235,15 @@ export default {
|
||||
if (bodydata === null) {
|
||||
bodydata = await reader.readBytes(packet_length);
|
||||
|
||||
const peekedByte = await reader.peekBytes(1);
|
||||
resolve({
|
||||
tag: tag,
|
||||
packet: bodydata,
|
||||
done: !await reader.peekBytes(1)
|
||||
done: !(peekedByte && peekedByte.length)
|
||||
});
|
||||
} else {
|
||||
const { done } = await reader.read();
|
||||
if (!done) {
|
||||
const { done, value } = await reader.read();
|
||||
if (!done && value.length) {
|
||||
throw new Error('Packets after a packet with partial lengths are not supported');
|
||||
} else {
|
||||
controller.close();
|
||||
|
||||
@@ -165,7 +165,7 @@ SymEncryptedAEADProtected.prototype.crypt = async function (fn, key, data) {
|
||||
cryptedBytes += chunk.length - tagLengthIfDecrypting;
|
||||
queuedBytes += chunk.length - tagLengthIfDecrypting;
|
||||
latestPromise = latestPromise.then(() => cryptedPromise).then(crypted => {
|
||||
if (crypted.length) controller.enqueue(crypted);
|
||||
controller.enqueue(crypted);
|
||||
queuedBytes -= chunk.length;
|
||||
}).catch(err => controller.error(err));
|
||||
// console.log(fn, done, queuedBytes, controller.desiredSize);
|
||||
@@ -181,6 +181,6 @@ SymEncryptedAEADProtected.prototype.crypt = async function (fn, key, data) {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return modeInstance[fn](data, this.iv);
|
||||
return modeInstance[fn](await stream.readToEnd(data), this.iv);
|
||||
}
|
||||
};
|
||||
|
||||
27
src/util.js
27
src/util.js
@@ -53,33 +53,38 @@ export default {
|
||||
/**
|
||||
* Get transferable objects to pass buffers with zero copy (similar to "pass by reference" in C++)
|
||||
* See: https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage
|
||||
* Also, convert ReadableStreams to Uint8Arrays
|
||||
* @param {Object} obj the options object to be passed to the web worker
|
||||
* @returns {Array<ArrayBuffer>} an array of binary data to be passed
|
||||
*/
|
||||
getTransferables: function(obj) {
|
||||
prepareBuffers: async function(obj) {
|
||||
// Internet Explorer does not support Transferable objects.
|
||||
if (isIE11) {
|
||||
return undefined;
|
||||
}
|
||||
if (config.zero_copy && Object.prototype.isPrototypeOf(obj)) {
|
||||
const transferables = [];
|
||||
util.collectBuffers(obj, transferables);
|
||||
return transferables.length ? transferables : undefined;
|
||||
}
|
||||
const transferables = [];
|
||||
await util.collectBuffers(obj, transferables);
|
||||
return transferables.length ? transferables : undefined;
|
||||
},
|
||||
|
||||
collectBuffers: function(obj, collection) {
|
||||
collectBuffers: async function(obj, collection) {
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (util.isUint8Array(obj) && collection.indexOf(obj.buffer) === -1) {
|
||||
collection.push(obj.buffer);
|
||||
if (config.zero_copy) {
|
||||
collection.push(obj.buffer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Object.prototype.isPrototypeOf(obj)) {
|
||||
Object.values(obj).forEach(value => { // recursively search all children
|
||||
util.collectBuffers(value, collection);
|
||||
});
|
||||
await Promise.all(Object.entries(obj).map(async ([key, value]) => { // recursively search all children
|
||||
if (util.isStream(value)) {
|
||||
obj[key] = value = await stream.readToEnd(value);
|
||||
}
|
||||
await util.collectBuffers(value, collection);
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ AsyncProxy.prototype.getID = function() {
|
||||
*/
|
||||
AsyncProxy.prototype.seedRandom = async function(workerId, size) {
|
||||
const buf = await crypto.random.getRandomBytes(size);
|
||||
this.workers[workerId].postMessage({ event:'seed-random', buf }, util.getTransferables(buf));
|
||||
this.workers[workerId].postMessage({ event:'seed-random', buf }, await util.prepareBuffers(buf));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -143,9 +143,10 @@ AsyncProxy.prototype.delegate = function(method, options) {
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
// clone packets (for web worker structured cloning algorithm)
|
||||
this.workers[workerId].postMessage({ id:id, event:method, options:packet.clone.clonePackets(options) }, util.getTransferables(options));
|
||||
const transferables = await util.prepareBuffers(options);
|
||||
this.workers[workerId].postMessage({ id:id, event:method, options:packet.clone.clonePackets(options) }, transferables);
|
||||
this.workers[workerId].requests++;
|
||||
|
||||
// remember to handle parsing cloned packets from worker
|
||||
|
||||
Reference in New Issue
Block a user