Comments & code style
This commit is contained in:
parent
1101a05b10
commit
ca537e439d
|
@ -129,7 +129,7 @@ CleartextMessage.prototype.getText = function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns ASCII armored text of cleartext signed message
|
* Returns ASCII armored text of cleartext signed message
|
||||||
* @returns {String} ASCII armor
|
* @returns {String | ReadableStream<String>} ASCII armor
|
||||||
*/
|
*/
|
||||||
CleartextMessage.prototype.armor = function() {
|
CleartextMessage.prototype.armor = function() {
|
||||||
let hashes = this.signature.packets.map(function(packet) {
|
let hashes = this.signature.packets.map(function(packet) {
|
||||||
|
@ -147,8 +147,9 @@ CleartextMessage.prototype.armor = function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reads an OpenPGP cleartext signed message and returns a CleartextMessage object
|
* reads an OpenPGP cleartext signed message and returns a CleartextMessage object
|
||||||
* @param {String} armoredText text to be parsed
|
* @param {String | ReadableStream<String>} armoredText text to be parsed
|
||||||
* @returns {module:cleartext.CleartextMessage} new cleartext message object
|
* @returns {module:cleartext.CleartextMessage} new cleartext message object
|
||||||
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function readArmored(armoredText) {
|
export async function readArmored(armoredText) {
|
||||||
|
|
|
@ -29,6 +29,7 @@ import Curve from './curves';
|
||||||
* @param {module:enums.hash} hash_algo Hash algorithm used to sign
|
* @param {module:enums.hash} hash_algo Hash algorithm used to sign
|
||||||
* @param {Uint8Array} m Message to sign
|
* @param {Uint8Array} m Message to sign
|
||||||
* @param {Uint8Array} d Private key used to sign the message
|
* @param {Uint8Array} d Private key used to sign the message
|
||||||
|
* @param {Uint8Array} hashed The hashed message
|
||||||
* @returns {{r: Uint8Array,
|
* @returns {{r: Uint8Array,
|
||||||
* s: Uint8Array}} Signature of the message
|
* s: Uint8Array}} Signature of the message
|
||||||
* @async
|
* @async
|
||||||
|
@ -49,6 +50,7 @@ async function sign(oid, hash_algo, m, d, hashed) {
|
||||||
s: Uint8Array}} signature Signature to verify
|
s: Uint8Array}} signature Signature to verify
|
||||||
* @param {Uint8Array} m Message to verify
|
* @param {Uint8Array} m Message to verify
|
||||||
* @param {Uint8Array} Q Public key used to verify the message
|
* @param {Uint8Array} Q Public key used to verify the message
|
||||||
|
* @param {Uint8Array} hashed The hashed message
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -29,6 +29,7 @@ import Curve from './curves';
|
||||||
* @param {module:enums.hash} hash_algo Hash algorithm used to sign
|
* @param {module:enums.hash} hash_algo Hash algorithm used to sign
|
||||||
* @param {Uint8Array} m Message to sign
|
* @param {Uint8Array} m Message to sign
|
||||||
* @param {Uint8Array} d Private key used to sign
|
* @param {Uint8Array} d Private key used to sign
|
||||||
|
* @param {Uint8Array} hashed The hashed message
|
||||||
* @returns {{R: Uint8Array,
|
* @returns {{R: Uint8Array,
|
||||||
* S: Uint8Array}} Signature of the message
|
* S: Uint8Array}} Signature of the message
|
||||||
* @async
|
* @async
|
||||||
|
@ -50,6 +51,7 @@ async function sign(oid, hash_algo, m, d, hashed) {
|
||||||
S: Uint8Array}} signature Signature to verify the message
|
S: Uint8Array}} signature Signature to verify the message
|
||||||
* @param {Uint8Array} m Message to verify
|
* @param {Uint8Array} m Message to verify
|
||||||
* @param {Uint8Array} Q Public key used to verify the message
|
* @param {Uint8Array} Q Public key used to verify the message
|
||||||
|
* @param {Uint8Array} hashed The hashed message
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -25,6 +25,7 @@ export default {
|
||||||
* @param {Array<module:type/mpi>} msg_MPIs Algorithm-specific signature parameters
|
* @param {Array<module:type/mpi>} msg_MPIs Algorithm-specific signature parameters
|
||||||
* @param {Array<module:type/mpi>} pub_MPIs Algorithm-specific public key parameters
|
* @param {Array<module:type/mpi>} pub_MPIs Algorithm-specific public key parameters
|
||||||
* @param {Uint8Array} data Data for which the signature was created
|
* @param {Uint8Array} data Data for which the signature was created
|
||||||
|
* @param {Uint8Array} hashed The hashed data
|
||||||
* @returns {Boolean} True if signature is valid
|
* @returns {Boolean} True if signature is valid
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
|
@ -78,6 +79,7 @@ export default {
|
||||||
* @param {module:enums.hash} hash_algo Hash algorithm
|
* @param {module:enums.hash} hash_algo Hash algorithm
|
||||||
* @param {Array<module:type/mpi>} key_params Algorithm-specific public and private key parameters
|
* @param {Array<module:type/mpi>} key_params Algorithm-specific public and private key parameters
|
||||||
* @param {Uint8Array} data Data to be signed
|
* @param {Uint8Array} data Data to be signed
|
||||||
|
* @param {Uint8Array} hashed The hashed data
|
||||||
* @returns {Uint8Array} Signature
|
* @returns {Uint8Array} Signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -118,19 +118,14 @@ function addheader(customComment) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates a checksum over the given data and returns it base64 encoded
|
* Calculates a checksum over the given data and returns it base64 encoded
|
||||||
* @param {String} data Data to create a CRC-24 checksum for
|
* @param {String | ReadableStream<String>} data Data to create a CRC-24 checksum for
|
||||||
* @returns {String} Base64 encoded checksum
|
* @returns {String | ReadableStream<String>} Base64 encoded checksum
|
||||||
*/
|
*/
|
||||||
function getCheckSum(data) {
|
function getCheckSum(data) {
|
||||||
const crc = createcrc24(data);
|
const crc = createcrc24(data);
|
||||||
return base64.encode(crc);
|
return base64.encode(crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal function to calculate a CRC-24 checksum over a given string (data)
|
|
||||||
* @param {String} data Data to create a CRC-24 checksum for
|
|
||||||
* @returns {Integer} The CRC-24 checksum as number
|
|
||||||
*/
|
|
||||||
const crc_table = [
|
const crc_table = [
|
||||||
0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139,
|
0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139,
|
||||||
0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
|
0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
|
||||||
|
@ -166,6 +161,11 @@ const crc_table = [
|
||||||
0x57dd8538
|
0x57dd8538
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function to calculate a CRC-24 checksum over a given string (data)
|
||||||
|
* @param {String | ReadableStream<String>} data Data to create a CRC-24 checksum for
|
||||||
|
* @returns {Uint8Array | ReadableStream<Uint8Array>} The CRC-24 checksum
|
||||||
|
*/
|
||||||
function createcrc24(input) {
|
function createcrc24(input) {
|
||||||
let crc = 0xB704CE;
|
let crc = 0xB704CE;
|
||||||
return stream.transform(input, value => {
|
return stream.transform(input, value => {
|
||||||
|
@ -197,7 +197,8 @@ function verifyHeaders(headers) {
|
||||||
* the encoded bytes
|
* the encoded bytes
|
||||||
* @param {String} text OpenPGP armored message
|
* @param {String} text OpenPGP armored message
|
||||||
* @returns {Object} An object with attribute "text" containing the message text,
|
* @returns {Object} An object with attribute "text" containing the message text,
|
||||||
* an attribute "data" containing the bytes and "type" for the ASCII armor type
|
* an attribute "data" containing a stream of bytes and "type" for the ASCII armor type
|
||||||
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
function dearmor(input) {
|
function dearmor(input) {
|
||||||
|
@ -310,7 +311,7 @@ function dearmor(input) {
|
||||||
* @param {Integer} partindex
|
* @param {Integer} partindex
|
||||||
* @param {Integer} parttotal
|
* @param {Integer} parttotal
|
||||||
* @param {String} customComment (optional) additional comment to add to the armored string
|
* @param {String} customComment (optional) additional comment to add to the armored string
|
||||||
* @returns {String} Armored text
|
* @returns {String | ReadableStream<String>} Armored text
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
function armor(messagetype, body, partindex, parttotal, customComment) {
|
function armor(messagetype, body, partindex, parttotal, customComment) {
|
||||||
|
|
|
@ -23,9 +23,9 @@ const b64u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert binary array to radix-64
|
* Convert binary array to radix-64
|
||||||
* @param {Uint8Array} t Uint8Array to convert
|
* @param {Uint8Array | ReadableStream<Uint8Array>} t Uint8Array to convert
|
||||||
* @param {bool} u if true, output is URL-safe
|
* @param {bool} u if true, output is URL-safe
|
||||||
* @returns {string} radix-64 version of input string
|
* @returns {String | ReadableStream<String>} radix-64 version of input string
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
function s2r(t, u = false) {
|
function s2r(t, u = false) {
|
||||||
|
@ -92,9 +92,9 @@ function s2r(t, u = false) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert radix-64 to binary array
|
* Convert radix-64 to binary array
|
||||||
* @param {String} t radix-64 string to convert
|
* @param {String | ReadableStream<String>} t radix-64 string to convert
|
||||||
* @param {bool} u if true, input is interpreted as URL-safe
|
* @param {bool} u if true, input is interpreted as URL-safe
|
||||||
* @returns {Uint8Array} binary array version of input string
|
* @returns {Uint8Array | ReadableStream<Uint8Array>} binary array version of input string
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
function r2s(t, u) {
|
function r2s(t, u) {
|
||||||
|
|
|
@ -248,7 +248,7 @@ Key.prototype.toPublic = function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns ASCII armored text of key
|
* Returns ASCII armored text of key
|
||||||
* @returns {String} ASCII armor
|
* @returns {ReadableStream<String>} ASCII armor
|
||||||
*/
|
*/
|
||||||
Key.prototype.armor = function() {
|
Key.prototype.armor = function() {
|
||||||
const type = this.isPublic() ? enums.armor.public_key : enums.armor.private_key;
|
const type = this.isPublic() ? enums.armor.public_key : enums.armor.private_key;
|
||||||
|
@ -1207,9 +1207,10 @@ export async function read(data) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads an OpenPGP armored text and returns one or multiple key objects
|
* Reads an OpenPGP armored text and returns one or multiple key objects
|
||||||
* @param {String} armoredText text to be parsed
|
* @param {String | ReadableStream<String>} armoredText text to be parsed
|
||||||
* @returns {{keys: Array<module:key.Key>,
|
* @returns {{keys: Array<module:key.Key>,
|
||||||
* err: (Array<Error>|null)}} result object with key and error arrays
|
* err: (Array<Error>|null)}} result object with key and error arrays
|
||||||
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function readArmored(armoredText) {
|
export async function readArmored(armoredText) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ function Keyring(storeHandler) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls the storeHandler to load the keys
|
* Calls the storeHandler to load the keys
|
||||||
|
* @async
|
||||||
*/
|
*/
|
||||||
Keyring.prototype.load = async function () {
|
Keyring.prototype.load = async function () {
|
||||||
this.publicKeys = new KeyArray(await this.storeHandler.loadPublic());
|
this.publicKeys = new KeyArray(await this.storeHandler.loadPublic());
|
||||||
|
@ -44,6 +45,7 @@ Keyring.prototype.load = async function () {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls the storeHandler to save the keys
|
* Calls the storeHandler to save the keys
|
||||||
|
* @async
|
||||||
*/
|
*/
|
||||||
Keyring.prototype.store = async function () {
|
Keyring.prototype.store = async function () {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
|
|
@ -55,6 +55,7 @@ LocalStore.prototype.privateKeysItem = 'private-keys';
|
||||||
/**
|
/**
|
||||||
* Load the public keys from HTML5 local storage.
|
* Load the public keys from HTML5 local storage.
|
||||||
* @returns {Array<module:key.Key>} array of keys retrieved from localstore
|
* @returns {Array<module:key.Key>} array of keys retrieved from localstore
|
||||||
|
* @async
|
||||||
*/
|
*/
|
||||||
LocalStore.prototype.loadPublic = async function () {
|
LocalStore.prototype.loadPublic = async function () {
|
||||||
return loadKeys(this.storage, this.publicKeysItem);
|
return loadKeys(this.storage, this.publicKeysItem);
|
||||||
|
@ -63,6 +64,7 @@ LocalStore.prototype.loadPublic = async function () {
|
||||||
/**
|
/**
|
||||||
* Load the private keys from HTML5 local storage.
|
* Load the private keys from HTML5 local storage.
|
||||||
* @returns {Array<module:key.Key>} array of keys retrieved from localstore
|
* @returns {Array<module:key.Key>} array of keys retrieved from localstore
|
||||||
|
* @async
|
||||||
*/
|
*/
|
||||||
LocalStore.prototype.loadPrivate = async function () {
|
LocalStore.prototype.loadPrivate = async function () {
|
||||||
return loadKeys(this.storage, this.privateKeysItem);
|
return loadKeys(this.storage, this.privateKeysItem);
|
||||||
|
@ -89,6 +91,7 @@ async function loadKeys(storage, itemname) {
|
||||||
* Saves the current state of the public keys to HTML5 local storage.
|
* Saves the current state of the public keys to HTML5 local storage.
|
||||||
* The key array gets stringified using JSON
|
* The key array gets stringified using JSON
|
||||||
* @param {Array<module:key.Key>} keys array of keys to save in localstore
|
* @param {Array<module:key.Key>} keys array of keys to save in localstore
|
||||||
|
* @async
|
||||||
*/
|
*/
|
||||||
LocalStore.prototype.storePublic = async function (keys) {
|
LocalStore.prototype.storePublic = async function (keys) {
|
||||||
await storeKeys(this.storage, this.publicKeysItem, keys);
|
await storeKeys(this.storage, this.publicKeysItem, keys);
|
||||||
|
@ -98,6 +101,7 @@ LocalStore.prototype.storePublic = async function (keys) {
|
||||||
* Saves the current state of the private keys to HTML5 local storage.
|
* Saves the current state of the private keys to HTML5 local storage.
|
||||||
* The key array gets stringified using JSON
|
* The key array gets stringified using JSON
|
||||||
* @param {Array<module:key.Key>} keys array of keys to save in localstore
|
* @param {Array<module:key.Key>} keys array of keys to save in localstore
|
||||||
|
* @async
|
||||||
*/
|
*/
|
||||||
LocalStore.prototype.storePrivate = async function (keys) {
|
LocalStore.prototype.storePrivate = async function (keys) {
|
||||||
await storeKeys(this.storage, this.privateKeysItem, keys);
|
await storeKeys(this.storage, this.privateKeysItem, keys);
|
||||||
|
|
|
@ -667,7 +667,7 @@ Message.prototype.appendSignature = async function(detachedSignature) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns ASCII armored text of message
|
* Returns ASCII armored text of message
|
||||||
* @returns {String} ASCII armor
|
* @returns {ReadableStream<String>} ASCII armor
|
||||||
*/
|
*/
|
||||||
Message.prototype.armor = function() {
|
Message.prototype.armor = function() {
|
||||||
return armor.encode(enums.armor.message, this.packets.write());
|
return armor.encode(enums.armor.message, this.packets.write());
|
||||||
|
@ -675,8 +675,9 @@ Message.prototype.armor = function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reads an OpenPGP armored message and returns a message object
|
* reads an OpenPGP armored message and returns a message object
|
||||||
* @param {String} armoredText text to be parsed
|
* @param {String | ReadableStream<String>} armoredText text to be parsed
|
||||||
* @returns {module:message.Message} new message object
|
* @returns {module:message.Message} new message object
|
||||||
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function readArmored(armoredText) {
|
export async function readArmored(armoredText) {
|
||||||
|
@ -688,9 +689,10 @@ export async function readArmored(armoredText) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reads an OpenPGP message as byte array and returns a message object
|
* reads an OpenPGP message as byte array and returns a message object
|
||||||
* @param {Uint8Array} input binary message
|
* @param {Uint8Array | ReadableStream<Uint8Array>} input binary message
|
||||||
* @param {Boolean} fromStream whether the message was created from a Stream
|
* @param {Boolean} fromStream whether the message was created from a Stream
|
||||||
* @returns {Message} new message object
|
* @returns {module:message.Message} new message object
|
||||||
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function read(input, fromStream) {
|
export async function read(input, fromStream) {
|
||||||
|
@ -703,7 +705,7 @@ export async function read(input, fromStream) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates new message object from text
|
* creates new message object from text
|
||||||
* @param {String} text
|
* @param {String | ReadableStream<String>} text
|
||||||
* @param {String} filename (optional)
|
* @param {String} filename (optional)
|
||||||
* @param {Date} date (optional)
|
* @param {Date} date (optional)
|
||||||
* @param {utf8|binary|text|mime} type (optional) data packet type
|
* @param {utf8|binary|text|mime} type (optional) data packet type
|
||||||
|
@ -726,7 +728,7 @@ export function fromText(text, filename, date=new Date(), type='utf8') {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates new message object from binary data
|
* creates new message object from binary data
|
||||||
* @param {Uint8Array} bytes
|
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes
|
||||||
* @param {String} filename (optional)
|
* @param {String} filename (optional)
|
||||||
* @param {Date} date (optional)
|
* @param {Date} date (optional)
|
||||||
* @param {utf8|binary|text|mime} type (optional) data packet type
|
* @param {utf8|binary|text|mime} type (optional) data packet type
|
||||||
|
|
|
@ -362,27 +362,8 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
|
||||||
const result = {};
|
const result = {};
|
||||||
result.signatures = signature ? await decrypted.verifyDetached(signature, publicKeys, date) : await decrypted.verify(publicKeys, date, asStream);
|
result.signatures = signature ? await decrypted.verifyDetached(signature, publicKeys, date) : await decrypted.verify(publicKeys, date, asStream);
|
||||||
result.data = format === 'binary' ? decrypted.getLiteralData() : decrypted.getText();
|
result.data = format === 'binary' ? decrypted.getLiteralData() : decrypted.getText();
|
||||||
result.data = await convertStream(result.data, asStream);
|
|
||||||
if (asStream) {
|
|
||||||
result.data = stream.transformPair(message.packets.stream, async (readable, writable) => {
|
|
||||||
await stream.pipe(result.data, writable, {
|
|
||||||
preventClose: true
|
|
||||||
});
|
|
||||||
const writer = stream.getWriter(writable);
|
|
||||||
try {
|
|
||||||
await stream.readToEnd(decrypted.packets.stream, arr => arr);
|
|
||||||
await writer.close();
|
|
||||||
} catch(e) {
|
|
||||||
await writer.abort(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await Promise.all(result.signatures.map(async signature => {
|
|
||||||
signature.signature = await signature.signature;
|
|
||||||
signature.valid = await signature.verified;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
result.filename = decrypted.getFilename();
|
result.filename = decrypted.getFilename();
|
||||||
|
await postProcess(result, asStream, message, decrypted.packets.stream);
|
||||||
return result;
|
return result;
|
||||||
}).catch(onError.bind(null, 'Error decrypting message'));
|
}).catch(onError.bind(null, 'Error decrypting message'));
|
||||||
}
|
}
|
||||||
|
@ -461,26 +442,7 @@ export function verify({ message, publicKeys, asStream=message&&message.fromStre
|
||||||
const result = {};
|
const result = {};
|
||||||
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date) : await message.verify(publicKeys, date, asStream);
|
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date) : await message.verify(publicKeys, date, asStream);
|
||||||
result.data = message instanceof CleartextMessage ? message.getText() : message.getLiteralData();
|
result.data = message instanceof CleartextMessage ? message.getText() : message.getLiteralData();
|
||||||
result.data = await convertStream(result.data, asStream);
|
await postProcess(result, asStream, message);
|
||||||
if (asStream) {
|
|
||||||
result.data = stream.transformPair(message.packets.stream, async (readable, writable) => {
|
|
||||||
await stream.pipe(result.data, writable, {
|
|
||||||
preventClose: true
|
|
||||||
});
|
|
||||||
const writer = stream.getWriter(writable);
|
|
||||||
try {
|
|
||||||
await stream.readToEnd(readable, arr => arr);
|
|
||||||
await writer.close();
|
|
||||||
} catch(e) {
|
|
||||||
await writer.abort(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await Promise.all(result.signatures.map(async signature => {
|
|
||||||
signature.signature = await signature.signature;
|
|
||||||
signature.valid = await signature.verified;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}).catch(onError.bind(null, 'Error verifying cleartext signed message'));
|
}).catch(onError.bind(null, 'Error verifying cleartext signed message'));
|
||||||
}
|
}
|
||||||
|
@ -633,6 +595,42 @@ async function convertStreams(obj, asStream, keys=[]) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post process the result of decrypt() and verify() before returning.
|
||||||
|
* See comments in the function body for more details.
|
||||||
|
* @param {Object} result the data to convert
|
||||||
|
* @param {Boolean} asStream whether to return ReadableStreams
|
||||||
|
* @param {Message} message message object
|
||||||
|
* @param {ReadableStream} errorStream (optional) stream which either errors or gets closed without data
|
||||||
|
* @returns {Object} the data in the respective format
|
||||||
|
*/
|
||||||
|
async function postProcess(result, asStream, message, errorStream) {
|
||||||
|
// Convert result.data to a stream or Uint8Array depending on asStream
|
||||||
|
result.data = await convertStream(result.data, asStream);
|
||||||
|
if (asStream) {
|
||||||
|
// Link result.data to the message stream for cancellation
|
||||||
|
result.data = stream.transformPair(message.packets.stream, async (readable, writable) => {
|
||||||
|
await stream.pipe(result.data, writable, {
|
||||||
|
preventClose: true
|
||||||
|
});
|
||||||
|
const writer = stream.getWriter(writable);
|
||||||
|
try {
|
||||||
|
// Forward errors in errorStream (defaults to the message stream) to result.data
|
||||||
|
await stream.readToEnd(errorStream || readable, arr => arr);
|
||||||
|
await writer.close();
|
||||||
|
} catch(e) {
|
||||||
|
await writer.abort(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Convert signature promises to values
|
||||||
|
await Promise.all(result.signatures.map(async signature => {
|
||||||
|
signature.signature = await signature.signature;
|
||||||
|
signature.valid = await signature.verified;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global error handler that logs the stack trace and rethrows a high lvl error message.
|
* Global error handler that logs the stack trace and rethrows a high lvl error message.
|
||||||
|
|
|
@ -60,14 +60,14 @@ function Compressed() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compressed packet data
|
* Compressed packet data
|
||||||
* @type {String}
|
* @type {Uint8Array | ReadableStream<Uint8Array>}
|
||||||
*/
|
*/
|
||||||
this.compressed = null;
|
this.compressed = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parsing function for the packet.
|
* Parsing function for the packet.
|
||||||
* @param {String} bytes Payload of a tag 8 packet
|
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes Payload of a tag 8 packet
|
||||||
*/
|
*/
|
||||||
Compressed.prototype.read = async function (bytes) {
|
Compressed.prototype.read = async function (bytes) {
|
||||||
await stream.parse(bytes, async reader => {
|
await stream.parse(bytes, async reader => {
|
||||||
|
@ -85,7 +85,7 @@ Compressed.prototype.read = async function (bytes) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the compressed packet.
|
* Return the compressed packet.
|
||||||
* @returns {String} binary compressed packet
|
* @returns {Uint8Array | ReadableStream<Uint8Array>} binary compressed packet
|
||||||
*/
|
*/
|
||||||
Compressed.prototype.write = function () {
|
Compressed.prototype.write = function () {
|
||||||
if (this.compressed === null) {
|
if (this.compressed === null) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ function Literal(date=new Date()) {
|
||||||
/**
|
/**
|
||||||
* Set the packet data to a javascript native string, end of line
|
* Set the packet data to a javascript native string, end of line
|
||||||
* will be normalized to \r\n and by default text is converted to UTF8
|
* will be normalized to \r\n and by default text is converted to UTF8
|
||||||
* @param {String} text Any native javascript string
|
* @param {String | ReadableStream<String>} text Any native javascript string
|
||||||
* @param {utf8|binary|text|mime} format (optional) The format of the string of bytes
|
* @param {utf8|binary|text|mime} format (optional) The format of the string of bytes
|
||||||
*/
|
*/
|
||||||
Literal.prototype.setText = function(text, format='utf8') {
|
Literal.prototype.setText = function(text, format='utf8') {
|
||||||
|
@ -59,7 +59,8 @@ Literal.prototype.setText = function(text, format='utf8') {
|
||||||
/**
|
/**
|
||||||
* Returns literal data packets as native JavaScript string
|
* Returns literal data packets as native JavaScript string
|
||||||
* with normalized end of line to \n
|
* with normalized end of line to \n
|
||||||
* @returns {String} literal data as text
|
* @param {Boolean} clone (optional) Whether to return a clone so that getBytes/getText can be called again
|
||||||
|
* @returns {String | ReadableStream<String>} literal data as text
|
||||||
*/
|
*/
|
||||||
Literal.prototype.getText = function(clone=false) {
|
Literal.prototype.getText = function(clone=false) {
|
||||||
if (this.text === null || util.isStream(this.text)) { // Assume that this.text has been read
|
if (this.text === null || util.isStream(this.text)) { // Assume that this.text has been read
|
||||||
|
@ -86,7 +87,7 @@ Literal.prototype.getText = function(clone=false) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the packet data to value represented by the provided string of bytes.
|
* Set the packet data to value represented by the provided string of bytes.
|
||||||
* @param {Uint8Array} bytes The string of bytes
|
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes The string of bytes
|
||||||
* @param {utf8|binary|text|mime} format The format of the string of bytes
|
* @param {utf8|binary|text|mime} format The format of the string of bytes
|
||||||
*/
|
*/
|
||||||
Literal.prototype.setBytes = function(bytes, format) {
|
Literal.prototype.setBytes = function(bytes, format) {
|
||||||
|
@ -98,7 +99,8 @@ Literal.prototype.setBytes = function(bytes, format) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the byte sequence representing the literal packet data
|
* Get the byte sequence representing the literal packet data
|
||||||
* @returns {Uint8Array} A sequence of bytes
|
* @param {Boolean} clone (optional) Whether to return a clone so that getBytes/getText can be called again
|
||||||
|
* @returns {Uint8Array | ReadableStream<Uint8Array>} A sequence of bytes
|
||||||
*/
|
*/
|
||||||
Literal.prototype.getBytes = function(clone=false) {
|
Literal.prototype.getBytes = function(clone=false) {
|
||||||
if (this.data === null) {
|
if (this.data === null) {
|
||||||
|
@ -135,7 +137,7 @@ Literal.prototype.getFilename = function() {
|
||||||
/**
|
/**
|
||||||
* Parsing function for a literal data packet (tag 11).
|
* Parsing function for a literal data packet (tag 11).
|
||||||
*
|
*
|
||||||
* @param {Uint8Array} input Payload of a tag 11 packet
|
* @param {Uint8Array | ReadableStream<Uint8Array>} input Payload of a tag 11 packet
|
||||||
* @returns {module:packet.Literal} object representation
|
* @returns {module:packet.Literal} object representation
|
||||||
*/
|
*/
|
||||||
Literal.prototype.read = async function(bytes) {
|
Literal.prototype.read = async function(bytes) {
|
||||||
|
@ -157,7 +159,7 @@ Literal.prototype.read = async function(bytes) {
|
||||||
/**
|
/**
|
||||||
* Creates a string representation of the packet
|
* Creates a string representation of the packet
|
||||||
*
|
*
|
||||||
* @returns {Uint8Array} Uint8Array representation of the packet
|
* @returns {Uint8Array | ReadableStream<Uint8Array>} Uint8Array representation of the packet
|
||||||
*/
|
*/
|
||||||
Literal.prototype.write = function() {
|
Literal.prototype.write = function() {
|
||||||
const filename = util.str_to_Uint8Array(util.encode_utf8(this.filename));
|
const filename = util.str_to_Uint8Array(util.encode_utf8(this.filename));
|
||||||
|
|
|
@ -133,7 +133,7 @@ export default {
|
||||||
/**
|
/**
|
||||||
* Generic static Packet Parser function
|
* Generic static Packet Parser function
|
||||||
*
|
*
|
||||||
* @param {Uint8Array} input Input stream as string
|
* @param {Uint8Array | ReadableStream<Uint8Array>} input Input stream as string
|
||||||
* @param {Function} callback Function to call with the parsed packet
|
* @param {Function} callback Function to call with the parsed packet
|
||||||
* @returns {Boolean} Returns false if the stream was empty and parsing is done, and true otherwise.
|
* @returns {Boolean} Returns false if the stream was empty and parsing is done, and true otherwise.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -33,7 +33,7 @@ function List() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a stream of binary data and interprents it as a list of packets.
|
* Reads a stream of binary data and interprents it as a list of packets.
|
||||||
* @param {Uint8Array} A Uint8Array of bytes.
|
* @param {Uint8Array | ReadableStream<Uint8Array>} A Uint8Array of bytes.
|
||||||
*/
|
*/
|
||||||
List.prototype.read = async function (bytes) {
|
List.prototype.read = async function (bytes) {
|
||||||
this.stream = stream.transformPair(bytes, async (readable, writable) => {
|
this.stream = stream.transformPair(bytes, async (readable, writable) => {
|
||||||
|
|
|
@ -56,6 +56,7 @@ export default SymEncryptedAEADProtected;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse an encrypted payload of bytes in the order: version, IV, ciphertext (see specification)
|
* Parse an encrypted payload of bytes in the order: version, IV, ciphertext (see specification)
|
||||||
|
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes
|
||||||
*/
|
*/
|
||||||
SymEncryptedAEADProtected.prototype.read = async function (bytes) {
|
SymEncryptedAEADProtected.prototype.read = async function (bytes) {
|
||||||
await stream.parse(bytes, async reader => {
|
await stream.parse(bytes, async reader => {
|
||||||
|
@ -77,7 +78,7 @@ SymEncryptedAEADProtected.prototype.read = async function (bytes) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the encrypted payload of bytes in the order: version, IV, ciphertext (see specification)
|
* Write the encrypted payload of bytes in the order: version, IV, ciphertext (see specification)
|
||||||
* @returns {Uint8Array} The encrypted payload
|
* @returns {Uint8Array | ReadableStream<Uint8Array>} The encrypted payload
|
||||||
*/
|
*/
|
||||||
SymEncryptedAEADProtected.prototype.write = function () {
|
SymEncryptedAEADProtected.prototype.write = function () {
|
||||||
if (config.aead_protect_version === 4) {
|
if (config.aead_protect_version === 4) {
|
||||||
|
@ -90,7 +91,7 @@ SymEncryptedAEADProtected.prototype.write = function () {
|
||||||
* Decrypt the encrypted payload.
|
* Decrypt the encrypted payload.
|
||||||
* @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128'
|
* @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128'
|
||||||
* @param {Uint8Array} key The session key used to encrypt the payload
|
* @param {Uint8Array} key The session key used to encrypt the payload
|
||||||
* @returns {Promise<Boolean>}
|
* @returns {Boolean}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
SymEncryptedAEADProtected.prototype.decrypt = async function (sessionKeyAlgorithm, key) {
|
SymEncryptedAEADProtected.prototype.decrypt = async function (sessionKeyAlgorithm, key) {
|
||||||
|
@ -105,7 +106,6 @@ SymEncryptedAEADProtected.prototype.decrypt = async function (sessionKeyAlgorith
|
||||||
* Encrypt the packet list payload.
|
* Encrypt the packet list payload.
|
||||||
* @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128'
|
* @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128'
|
||||||
* @param {Uint8Array} key The session key used to encrypt the payload
|
* @param {Uint8Array} key The session key used to encrypt the payload
|
||||||
* @returns {Promise<Boolean>}
|
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
SymEncryptedAEADProtected.prototype.encrypt = async function (sessionKeyAlgorithm, key) {
|
SymEncryptedAEADProtected.prototype.encrypt = async function (sessionKeyAlgorithm, key) {
|
||||||
|
@ -122,8 +122,8 @@ SymEncryptedAEADProtected.prototype.encrypt = async function (sessionKeyAlgorith
|
||||||
* En/decrypt the payload.
|
* En/decrypt the payload.
|
||||||
* @param {encrypt|decrypt} fn Whether to encrypt or decrypt
|
* @param {encrypt|decrypt} fn Whether to encrypt or decrypt
|
||||||
* @param {Uint8Array} key The session key used to en/decrypt the payload
|
* @param {Uint8Array} key The session key used to en/decrypt the payload
|
||||||
* @param {Uint8Array} data The data to en/decrypt
|
* @param {Uint8Array | ReadableStream<Uint8Array>} data The data to en/decrypt
|
||||||
* @returns {Promise<Uint8Array>}
|
* @returns {Uint8Array | ReadableStream<Uint8Array>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
SymEncryptedAEADProtected.prototype.crypt = async function (fn, key, data) {
|
SymEncryptedAEADProtected.prototype.crypt = async function (fn, key, data) {
|
||||||
|
|
|
@ -87,6 +87,7 @@ SymEncryptedIntegrityProtected.prototype.write = function () {
|
||||||
* Encrypt the payload in the packet.
|
* Encrypt the payload in the packet.
|
||||||
* @param {String} sessionKeyAlgorithm The selected symmetric encryption algorithm to be used e.g. 'aes128'
|
* @param {String} sessionKeyAlgorithm The selected symmetric encryption algorithm to be used e.g. 'aes128'
|
||||||
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
||||||
|
* @param {Boolean} asStream Whether to set this.encrypted to a stream
|
||||||
* @returns {Promise<Boolean>}
|
* @returns {Promise<Boolean>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
|
@ -116,6 +117,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlg
|
||||||
* Decrypts the encrypted data contained in the packet.
|
* Decrypts the encrypted data contained in the packet.
|
||||||
* @param {String} sessionKeyAlgorithm The selected symmetric encryption algorithm to be used e.g. 'aes128'
|
* @param {String} sessionKeyAlgorithm The selected symmetric encryption algorithm to be used e.g. 'aes128'
|
||||||
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
||||||
|
* @param {Boolean} asStream Whether to read this.encrypted as a stream
|
||||||
* @returns {Promise<Boolean>}
|
* @returns {Promise<Boolean>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -41,7 +41,7 @@ export function Signature(packetlist) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns ASCII armored text of signature
|
* Returns ASCII armored text of signature
|
||||||
* @returns {String} ASCII armor
|
* @returns {ReadableStream<String>} ASCII armor
|
||||||
*/
|
*/
|
||||||
Signature.prototype.armor = function() {
|
Signature.prototype.armor = function() {
|
||||||
return armor.encode(enums.armor.signature, this.packets.write());
|
return armor.encode(enums.armor.signature, this.packets.write());
|
||||||
|
@ -49,8 +49,9 @@ Signature.prototype.armor = function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reads an OpenPGP armored signature and returns a signature object
|
* reads an OpenPGP armored signature and returns a signature object
|
||||||
* @param {String} armoredText text to be parsed
|
* @param {String | ReadableStream<String>} armoredText text to be parsed
|
||||||
* @returns {Signature} new signature object
|
* @returns {Signature} new signature object
|
||||||
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function readArmored(armoredText) {
|
export async function readArmored(armoredText) {
|
||||||
|
@ -60,8 +61,9 @@ export async function readArmored(armoredText) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reads an OpenPGP signature as byte array and returns a signature object
|
* reads an OpenPGP signature as byte array and returns a signature object
|
||||||
* @param {Uint8Array} input binary signature
|
* @param {Uint8Array | ReadableStream<Uint8Array>} input binary signature
|
||||||
* @returns {Signature} new signature object
|
* @returns {Signature} new signature object
|
||||||
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function read(input) {
|
export async function read(input) {
|
||||||
|
|
208
src/stream.js
208
src/stream.js
|
@ -1,7 +1,12 @@
|
||||||
import util from './util';
|
import util from './util';
|
||||||
|
|
||||||
const nodeStream = util.getNodeStream();
|
const NodeReadableStream = util.getNodeStream();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert data to Stream
|
||||||
|
* @param {ReadableStream|Uint8array|String} input data to convert
|
||||||
|
* @returns {ReadableStream} Converted data
|
||||||
|
*/
|
||||||
function toStream(input) {
|
function toStream(input) {
|
||||||
if (util.isStream(input)) {
|
if (util.isStream(input)) {
|
||||||
return input;
|
return input;
|
||||||
|
@ -14,39 +19,61 @@ function toStream(input) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function concat(arrays) {
|
/**
|
||||||
arrays = arrays.map(toStream);
|
* Concat a list of Streams
|
||||||
|
* @param {Array<ReadableStream|Uint8array|String>} list Array of Uint8Arrays/Strings/Streams to concatenate
|
||||||
|
* @returns {ReadableStream} Concatenated array
|
||||||
|
*/
|
||||||
|
function concat(list) {
|
||||||
|
list = list.map(toStream);
|
||||||
const transform = transformWithCancel(async function(reason) {
|
const transform = transformWithCancel(async function(reason) {
|
||||||
await Promise.all(transforms.map(array => cancel(array, reason)));
|
await Promise.all(transforms.map(array => cancel(array, reason)));
|
||||||
});
|
});
|
||||||
let prev = Promise.resolve();
|
let prev = Promise.resolve();
|
||||||
const transforms = arrays.map((array, i) => transformPair(array, (readable, writable) => {
|
const transforms = list.map((array, i) => transformPair(array, (readable, writable) => {
|
||||||
prev = prev.then(() => pipe(readable, transform.writable, {
|
prev = prev.then(() => pipe(readable, transform.writable, {
|
||||||
preventClose: i !== arrays.length - 1
|
preventClose: i !== list.length - 1
|
||||||
}));
|
}));
|
||||||
return prev;
|
return prev;
|
||||||
}));
|
}));
|
||||||
return transform.readable;
|
return transform.readable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a Reader
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @returns {Reader}
|
||||||
|
*/
|
||||||
function getReader(input) {
|
function getReader(input) {
|
||||||
return new Reader(input);
|
return new Reader(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a Writer
|
||||||
|
* @param {WritableStream} input
|
||||||
|
* @returns {WritableStreamDefaultWriter}
|
||||||
|
*/
|
||||||
function getWriter(input) {
|
function getWriter(input) {
|
||||||
return input.getWriter();
|
return input.getWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pipe a readable stream to a writable stream. Don't throw on input stream errors, but forward them to the output stream.
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @param {WritableStream} target
|
||||||
|
* @param {Object} (optional) options
|
||||||
|
* @returns {Promise<undefined>} Promise indicating when piping has finished (input stream closed or errored)
|
||||||
|
*/
|
||||||
async function pipe(input, target, options) {
|
async function pipe(input, target, options) {
|
||||||
if (!util.isStream(input)) {
|
if (!util.isStream(input)) {
|
||||||
input = toStream(input);
|
input = toStream(input);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (input.externalBuffer) {
|
if (input[externalBuffer]) {
|
||||||
const writer = target.getWriter();
|
const writer = target.getWriter();
|
||||||
for (let i = 0; i < input.externalBuffer.length; i++) {
|
for (let i = 0; i < input[externalBuffer].length; i++) {
|
||||||
await writer.ready;
|
await writer.ready;
|
||||||
await writer.write(input.externalBuffer[i]);
|
await writer.write(input[externalBuffer][i]);
|
||||||
}
|
}
|
||||||
writer.releaseLock();
|
writer.releaseLock();
|
||||||
}
|
}
|
||||||
|
@ -56,12 +83,23 @@ async function pipe(input, target, options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pipe a readable stream through a transform stream.
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @param {Object} (optional) options
|
||||||
|
* @returns {ReadableStream} transformed stream
|
||||||
|
*/
|
||||||
function transformRaw(input, options) {
|
function transformRaw(input, options) {
|
||||||
const transformStream = new TransformStream(options);
|
const transformStream = new TransformStream(options);
|
||||||
pipe(input, transformStream.writable);
|
pipe(input, transformStream.writable);
|
||||||
return transformStream.readable;
|
return transformStream.readable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a cancelable TransformStream.
|
||||||
|
* @param {Function} cancel
|
||||||
|
* @returns {TransformStream}
|
||||||
|
*/
|
||||||
function transformWithCancel(cancel) {
|
function transformWithCancel(cancel) {
|
||||||
let backpressureChangePromiseResolve = function() {};
|
let backpressureChangePromiseResolve = function() {};
|
||||||
let outputController;
|
let outputController;
|
||||||
|
@ -90,6 +128,13 @@ function transformWithCancel(cancel) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform a stream using helper functions which are called on each chunk, and on stream close, respectively.
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @param {Function} process
|
||||||
|
* @param {Function} finish
|
||||||
|
* @returns {ReadableStream|Uint8array|String}
|
||||||
|
*/
|
||||||
function transform(input, process = () => undefined, finish = () => undefined) {
|
function transform(input, process = () => undefined, finish = () => undefined) {
|
||||||
if (util.isStream(input)) {
|
if (util.isStream(input)) {
|
||||||
return transformRaw(input, {
|
return transformRaw(input, {
|
||||||
|
@ -117,6 +162,15 @@ function transform(input, process = () => undefined, finish = () => undefined) {
|
||||||
return result1 !== undefined ? result1 : result2;
|
return result1 !== undefined ? result1 : result2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform a stream using a helper function which is passed a readable and a writable stream.
|
||||||
|
* This function also maintains the possibility to cancel the input stream,
|
||||||
|
* and does so on cancelation of the output stream, despite cancelation
|
||||||
|
* normally being impossible when the input stream is being read from.
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @param {Function} fn
|
||||||
|
* @returns {ReadableStream}
|
||||||
|
*/
|
||||||
function transformPair(input, fn) {
|
function transformPair(input, fn) {
|
||||||
let incomingTransformController;
|
let incomingTransformController;
|
||||||
const incoming = new TransformStream({
|
const incoming = new TransformStream({
|
||||||
|
@ -136,6 +190,15 @@ function transformPair(input, fn) {
|
||||||
return outgoing.readable;
|
return outgoing.readable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a stream using a helper function which is passed a Reader.
|
||||||
|
* The reader additionally has a remainder() method which returns a
|
||||||
|
* stream pointing to the remainder of input, and is linked to input
|
||||||
|
* for cancelation.
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @param {Function} fn
|
||||||
|
* @returns {Any} the return value of fn()
|
||||||
|
*/
|
||||||
function parse(input, fn) {
|
function parse(input, fn) {
|
||||||
let returnValue;
|
let returnValue;
|
||||||
const transformed = transformPair(input, (readable, writable) => {
|
const transformed = transformPair(input, (readable, writable) => {
|
||||||
|
@ -150,15 +213,29 @@ function parse(input, fn) {
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tee a Stream for reading it twice. The input stream can no longer be read after tee()ing.
|
||||||
|
* Reading either of the two returned streams will pull from the input stream.
|
||||||
|
* The input stream will only be canceled if both of the returned streams are canceled.
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @returns {Array<ReadableStream|Uint8array|String>} array containing two copies of input
|
||||||
|
*/
|
||||||
function tee(input) {
|
function tee(input) {
|
||||||
if (util.isStream(input)) {
|
if (util.isStream(input)) {
|
||||||
const teed = input.tee();
|
const teed = input.tee();
|
||||||
teed[0].externalBuffer = teed[1].externalBuffer = input.externalBuffer;
|
teed[0][externalBuffer] = teed[1][externalBuffer] = input[externalBuffer];
|
||||||
return teed;
|
return teed;
|
||||||
}
|
}
|
||||||
return [slice(input), slice(input)];
|
return [slice(input), slice(input)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone a Stream for reading it twice. The input stream can still be read after clone()ing.
|
||||||
|
* Reading from the clone will pull from the input stream.
|
||||||
|
* The input stream will only be canceled if both the clone and the input stream are canceled.
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @returns {ReadableStream|Uint8array|String} cloned input
|
||||||
|
*/
|
||||||
function clone(input) {
|
function clone(input) {
|
||||||
if (util.isStream(input)) {
|
if (util.isStream(input)) {
|
||||||
const teed = tee(input);
|
const teed = tee(input);
|
||||||
|
@ -168,6 +245,14 @@ function clone(input) {
|
||||||
return slice(input);
|
return slice(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone a Stream for reading it twice. Data will arrive at the same rate as the input stream is being read.
|
||||||
|
* Reading from the clone will NOT pull from the input stream. Data only arrives when reading the input stream.
|
||||||
|
* The input stream will NOT be canceled if the clone is canceled, only if the input stream are canceled.
|
||||||
|
* If the input stream is canceled, the clone will be errored.
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @returns {ReadableStream|Uint8array|String} cloned input
|
||||||
|
*/
|
||||||
function passiveClone(input) {
|
function passiveClone(input) {
|
||||||
if (util.isStream(input)) {
|
if (util.isStream(input)) {
|
||||||
return new ReadableStream({
|
return new ReadableStream({
|
||||||
|
@ -199,6 +284,12 @@ function passiveClone(input) {
|
||||||
return slice(input);
|
return slice(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modify a stream object to point to a different stream object.
|
||||||
|
* This is used internally by clone() and passiveClone() to provide an abstraction over tee().
|
||||||
|
* @param {ReadableStream} input
|
||||||
|
* @param {ReadableStream} clone
|
||||||
|
*/
|
||||||
function overwrite(input, clone) {
|
function overwrite(input, clone) {
|
||||||
// Overwrite input.getReader, input.locked, etc to point to clone
|
// Overwrite input.getReader, input.locked, etc to point to clone
|
||||||
Object.entries(Object.getOwnPropertyDescriptors(ReadableStream.prototype)).forEach(([name, descriptor]) => {
|
Object.entries(Object.getOwnPropertyDescriptors(ReadableStream.prototype)).forEach(([name, descriptor]) => {
|
||||||
|
@ -214,6 +305,11 @@ function overwrite(input, clone) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a stream pointing to a part of the input stream.
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @returns {ReadableStream|Uint8array|String} clone
|
||||||
|
*/
|
||||||
function slice(input, begin=0, end=Infinity) {
|
function slice(input, begin=0, end=Infinity) {
|
||||||
if (util.isStream(input)) {
|
if (util.isStream(input)) {
|
||||||
if (begin >= 0 && end >= 0) {
|
if (begin >= 0 && end >= 0) {
|
||||||
|
@ -254,8 +350,8 @@ function slice(input, begin=0, end=Infinity) {
|
||||||
util.print_debug_error(`stream.slice(input, ${begin}, ${end}) not implemented efficiently.`);
|
util.print_debug_error(`stream.slice(input, ${begin}, ${end}) not implemented efficiently.`);
|
||||||
return fromAsync(async () => slice(await readToEnd(input), begin, end));
|
return fromAsync(async () => slice(await readToEnd(input), begin, end));
|
||||||
}
|
}
|
||||||
if (input.externalBuffer) {
|
if (input[externalBuffer]) {
|
||||||
input = util.concat(input.externalBuffer.concat([input]));
|
input = util.concat(input[externalBuffer].concat([input]));
|
||||||
}
|
}
|
||||||
if (util.isUint8Array(input)) {
|
if (util.isUint8Array(input)) {
|
||||||
return input.subarray(begin, end);
|
return input.subarray(begin, end);
|
||||||
|
@ -263,19 +359,36 @@ function slice(input, begin=0, end=Infinity) {
|
||||||
return input.slice(begin, end);
|
return input.slice(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readToEnd(input, join) {
|
/**
|
||||||
|
* Read a stream to the end and return its contents, concatenated by the concat function (defaults to util.concat).
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @param {Function} concat
|
||||||
|
* @returns {Uint8array|String|Any} the return value of concat()
|
||||||
|
*/
|
||||||
|
async function readToEnd(input, concat) {
|
||||||
if (util.isStream(input)) {
|
if (util.isStream(input)) {
|
||||||
return getReader(input).readToEnd(join);
|
return getReader(input).readToEnd(concat);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel a stream.
|
||||||
|
* @param {ReadableStream|Uint8array|String} input
|
||||||
|
* @param {Any} reason
|
||||||
|
* @returns {Promise<Any>} indicates when the stream has been canceled
|
||||||
|
*/
|
||||||
async function cancel(input, reason) {
|
async function cancel(input, reason) {
|
||||||
if (util.isStream(input)) {
|
if (util.isStream(input)) {
|
||||||
return input.cancel(reason);
|
return input.cancel(reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an async function to a Stream. When the function returns, its return value is enqueued to the stream.
|
||||||
|
* @param {Function} fn
|
||||||
|
* @returns {ReadableStream}
|
||||||
|
*/
|
||||||
function fromAsync(fn) {
|
function fromAsync(fn) {
|
||||||
return new ReadableStream({
|
return new ReadableStream({
|
||||||
pull: async controller => {
|
pull: async controller => {
|
||||||
|
@ -298,8 +411,13 @@ function fromAsync(fn) {
|
||||||
let nodeToWeb;
|
let nodeToWeb;
|
||||||
let webToNode;
|
let webToNode;
|
||||||
|
|
||||||
if (nodeStream) {
|
if (NodeReadableStream) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Node Readable Stream to a Web ReadableStream
|
||||||
|
* @param {Readable} nodeStream
|
||||||
|
* @returns {ReadableStream}
|
||||||
|
*/
|
||||||
nodeToWeb = function(nodeStream) {
|
nodeToWeb = function(nodeStream) {
|
||||||
return new ReadableStream({
|
return new ReadableStream({
|
||||||
start(controller) {
|
start(controller) {
|
||||||
|
@ -321,7 +439,7 @@ if (nodeStream) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class NodeReadable extends nodeStream.Readable {
|
class NodeReadable extends NodeReadableStream {
|
||||||
constructor(webStream, options) {
|
constructor(webStream, options) {
|
||||||
super(options);
|
super(options);
|
||||||
this._webStream = webStream;
|
this._webStream = webStream;
|
||||||
|
@ -352,6 +470,11 @@ if (nodeStream) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Web ReadableStream to a Node Readable Stream
|
||||||
|
* @param {ReadableStream} webStream
|
||||||
|
* @returns {Readable}
|
||||||
|
*/
|
||||||
webToNode = function(webStream) {
|
webToNode = function(webStream) {
|
||||||
return new NodeReadable(webStream);
|
return new NodeReadable(webStream);
|
||||||
};
|
};
|
||||||
|
@ -363,10 +486,11 @@ export default { toStream, concat, getReader, getWriter, pipe, transformRaw, tra
|
||||||
|
|
||||||
|
|
||||||
const doneReadingSet = new WeakSet();
|
const doneReadingSet = new WeakSet();
|
||||||
|
const externalBuffer = Symbol('externalBuffer');
|
||||||
function Reader(input) {
|
function Reader(input) {
|
||||||
this.stream = input;
|
this.stream = input;
|
||||||
if (input.externalBuffer) {
|
if (input[externalBuffer]) {
|
||||||
this.externalBuffer = input.externalBuffer.slice();
|
this[externalBuffer] = input[externalBuffer].slice();
|
||||||
}
|
}
|
||||||
if (util.isStream(input)) {
|
if (util.isStream(input)) {
|
||||||
const reader = input.getReader();
|
const reader = input.getReader();
|
||||||
|
@ -391,21 +515,32 @@ function Reader(input) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a chunk of data.
|
||||||
|
* @returns {Object} Either { done: false, value: Uint8Array | String } or { done: true, value: undefined }
|
||||||
|
*/
|
||||||
Reader.prototype.read = async function() {
|
Reader.prototype.read = async function() {
|
||||||
if (this.externalBuffer && this.externalBuffer.length) {
|
if (this[externalBuffer] && this[externalBuffer].length) {
|
||||||
const value = this.externalBuffer.shift();
|
const value = this[externalBuffer].shift();
|
||||||
return { done: false, value };
|
return { done: false, value };
|
||||||
}
|
}
|
||||||
return this._read();
|
return this._read();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow others to read the stream.
|
||||||
|
*/
|
||||||
Reader.prototype.releaseLock = function() {
|
Reader.prototype.releaseLock = function() {
|
||||||
if (this.externalBuffer) {
|
if (this[externalBuffer]) {
|
||||||
this.stream.externalBuffer = this.externalBuffer;
|
this.stream[externalBuffer] = this[externalBuffer];
|
||||||
}
|
}
|
||||||
this._releaseLock();
|
this._releaseLock();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read up to and including the first \n character.
|
||||||
|
* @returns {String|Undefined}
|
||||||
|
*/
|
||||||
Reader.prototype.readLine = async function() {
|
Reader.prototype.readLine = async function() {
|
||||||
let buffer = [];
|
let buffer = [];
|
||||||
let returnVal;
|
let returnVal;
|
||||||
|
@ -428,6 +563,10 @@ Reader.prototype.readLine = async function() {
|
||||||
return returnVal;
|
return returnVal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a single byte/character.
|
||||||
|
* @returns {Number|String|Undefined}
|
||||||
|
*/
|
||||||
Reader.prototype.readByte = async function() {
|
Reader.prototype.readByte = async function() {
|
||||||
const { done, value } = await this.read();
|
const { done, value } = await this.read();
|
||||||
if (done) return;
|
if (done) return;
|
||||||
|
@ -436,6 +575,10 @@ Reader.prototype.readByte = async function() {
|
||||||
return byte;
|
return byte;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a specific amount of bytes/characters, unless the stream ends before that amount.
|
||||||
|
* @returns {Uint8Array|String|Undefined}
|
||||||
|
*/
|
||||||
Reader.prototype.readBytes = async function(length) {
|
Reader.prototype.readBytes = async function(length) {
|
||||||
const buffer = [];
|
const buffer = [];
|
||||||
let bufferLength = 0;
|
let bufferLength = 0;
|
||||||
|
@ -455,25 +598,38 @@ Reader.prototype.readBytes = async function(length) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peek (look ahead) a specific amount of bytes/characters, unless the stream ends before that amount.
|
||||||
|
* @returns {Uint8Array|String|Undefined}
|
||||||
|
*/
|
||||||
Reader.prototype.peekBytes = async function(length) {
|
Reader.prototype.peekBytes = async function(length) {
|
||||||
const bytes = await this.readBytes(length);
|
const bytes = await this.readBytes(length);
|
||||||
this.unshift(bytes);
|
this.unshift(bytes);
|
||||||
return bytes;
|
return bytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push data to the front of the stream.
|
||||||
|
* @param {Uint8Array|String|Undefined} ...values
|
||||||
|
*/
|
||||||
Reader.prototype.unshift = function(...values) {
|
Reader.prototype.unshift = function(...values) {
|
||||||
if (!this.externalBuffer) {
|
if (!this[externalBuffer]) {
|
||||||
this.externalBuffer = [];
|
this[externalBuffer] = [];
|
||||||
}
|
}
|
||||||
this.externalBuffer.unshift(...values.filter(value => value && value.length));
|
this[externalBuffer].unshift(...values.filter(value => value && value.length));
|
||||||
};
|
};
|
||||||
|
|
||||||
Reader.prototype.readToEnd = async function(join=util.concat) {
|
/**
|
||||||
|
* Read the stream to the end and return its contents, concatenated by the concat function (defaults to util.concat).
|
||||||
|
* @param {Function} concat
|
||||||
|
* @returns {Uint8array|String|Any} the return value of concat()
|
||||||
|
*/
|
||||||
|
Reader.prototype.readToEnd = async function(concat=util.concat) {
|
||||||
const result = [];
|
const result = [];
|
||||||
while (true) {
|
while (true) {
|
||||||
const { done, value } = await this.read();
|
const { done, value } = await this.read();
|
||||||
if (done) break;
|
if (done) break;
|
||||||
result.push(value);
|
result.push(value);
|
||||||
}
|
}
|
||||||
return join(result);
|
return concat(result);
|
||||||
};
|
};
|
||||||
|
|
82
src/util.js
82
src/util.js
|
@ -53,7 +53,7 @@ export default {
|
||||||
/**
|
/**
|
||||||
* Get transferable objects to pass buffers with zero copy (similar to "pass by reference" in C++)
|
* 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
|
* See: https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage
|
||||||
* Also, convert ReadableStreams to Uint8Arrays
|
* Also, convert ReadableStreams to MessagePorts
|
||||||
* @param {Object} obj the options object to be passed to the web worker
|
* @param {Object} obj the options object to be passed to the web worker
|
||||||
* @returns {Array<ArrayBuffer>} an array of binary data to be passed
|
* @returns {Array<ArrayBuffer>} an array of binary data to be passed
|
||||||
*/
|
*/
|
||||||
|
@ -105,6 +105,11 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert MessagePorts back to ReadableStreams
|
||||||
|
* @param {Object} obj
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
restoreStreams: function(obj) {
|
restoreStreams: function(obj) {
|
||||||
if (Object.prototype.isPrototypeOf(obj)) {
|
if (Object.prototype.isPrototypeOf(obj)) {
|
||||||
Object.entries(obj).forEach(([key, value]) => { // recursively search all children
|
Object.entries(obj).forEach(([key, value]) => { // recursively search all children
|
||||||
|
@ -490,16 +495,18 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
print_entire_stream: function (str, input, fn = result => result) {
|
/**
|
||||||
stream.readToEnd(stream.clone(input)).then(result => {
|
* Read a stream to the end and print it to the console when it's closed.
|
||||||
console.log(str + ': ', fn(result));
|
* @param {String} str String of the debug message
|
||||||
|
* @param {ReadableStream|Uint8array|String} input Stream to print
|
||||||
|
* @param {Function} concat Function to concatenate chunks of the stream (defaults to util.concat).
|
||||||
|
*/
|
||||||
|
print_entire_stream: function (str, input, concat) {
|
||||||
|
stream.readToEnd(stream.clone(input), concat).then(result => {
|
||||||
|
console.log(str + ': ', result);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
print_entire_stream_str: function (str, stream, fn = result => result) {
|
|
||||||
util.print_entire_stream(str, stream, result => fn(util.Uint8Array_to_str(result)));
|
|
||||||
},
|
|
||||||
|
|
||||||
getLeftNBits: function (array, bitcount) {
|
getLeftNBits: function (array, bitcount) {
|
||||||
const rest = bitcount % 8;
|
const rest = bitcount % 8;
|
||||||
if (rest === 0) {
|
if (rest === 0) {
|
||||||
|
@ -622,17 +629,41 @@ export default {
|
||||||
return typeof window === 'undefined';
|
return typeof window === 'undefined';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get native Node.js module
|
||||||
|
* @param {String} The module to require
|
||||||
|
* @returns {Object} The required module or 'undefined'
|
||||||
|
*/
|
||||||
|
nodeRequire: function(module) {
|
||||||
|
if (!util.detectNode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requiring the module dynamically allows us to access the native node module.
|
||||||
|
// otherwise, it gets replaced with the browserified version
|
||||||
|
// eslint-disable-next-line import/no-dynamic-require
|
||||||
|
return require(module);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get native Node.js crypto api. The default configuration is to use
|
* Get native Node.js crypto api. The default configuration is to use
|
||||||
* the api when available. But it can also be deactivated with config.use_native
|
* the api when available. But it can also be deactivated with config.use_native
|
||||||
* @returns {Object} The crypto module or 'undefined'
|
* @returns {Object} The crypto module or 'undefined'
|
||||||
*/
|
*/
|
||||||
getNodeCrypto: function() {
|
getNodeCrypto: function() {
|
||||||
if (!util.detectNode() || !config.use_native) {
|
if (!config.use_native) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return require('crypto');
|
return util.nodeRequire('crypto');
|
||||||
|
},
|
||||||
|
|
||||||
|
getNodeZlib: function() {
|
||||||
|
if (!config.use_native) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.nodeRequire('zlib');
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -641,40 +672,15 @@ export default {
|
||||||
* @returns {Function} The Buffer constructor or 'undefined'
|
* @returns {Function} The Buffer constructor or 'undefined'
|
||||||
*/
|
*/
|
||||||
getNodeBuffer: function() {
|
getNodeBuffer: function() {
|
||||||
if (!util.detectNode()) {
|
return (util.nodeRequire('buffer') || {}).Buffer;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This "hack" allows us to access the native node buffer module.
|
|
||||||
// otherwise, it gets replaced with the browserified version
|
|
||||||
// eslint-disable-next-line no-useless-concat, import/no-dynamic-require
|
|
||||||
return require('buffer'+'').Buffer;
|
|
||||||
},
|
|
||||||
|
|
||||||
getNodeZlib: function() {
|
|
||||||
if (!util.detectNode() || !config.use_native) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return require('zlib');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getNodeStream: function() {
|
getNodeStream: function() {
|
||||||
if (!util.detectNode()) {
|
return (util.nodeRequire('stream') || {}).Readable;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-useless-concat, import/no-dynamic-require
|
|
||||||
return require('stream'+'');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getNodeTextDecoder: function() {
|
getNodeTextDecoder: function() {
|
||||||
if (!util.detectNode()) {
|
return (util.nodeRequire('util') || {}).TextDecoder;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-useless-concat, import/no-dynamic-require
|
|
||||||
return require('util'+'').TextDecoder;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
isEmailAddress: function(data) {
|
isEmailAddress: function(data) {
|
||||||
|
|
|
@ -182,15 +182,15 @@ describe('Streaming', function() {
|
||||||
canceled = true;
|
canceled = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const encrypted = await openpgp.sign({
|
const signed = await openpgp.sign({
|
||||||
message: openpgp.message.fromBinary(data),
|
message: openpgp.message.fromBinary(data),
|
||||||
privateKeys: privKey
|
privateKeys: privKey
|
||||||
});
|
});
|
||||||
const reader = openpgp.stream.getReader(encrypted.data);
|
const reader = openpgp.stream.getReader(signed.data);
|
||||||
expect(await reader.readBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\r\n/);
|
expect(await reader.readBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\r\n/);
|
||||||
if (i > 10) throw new Error('Data did not arrive early.');
|
if (i > 10) throw new Error('Data did not arrive early.');
|
||||||
reader.releaseLock();
|
reader.releaseLock();
|
||||||
await openpgp.stream.cancel(encrypted.data);
|
await openpgp.stream.cancel(signed.data);
|
||||||
expect(canceled).to.be.true;
|
expect(canceled).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -476,25 +476,25 @@ describe('Streaming', function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const encrypted = await openpgp.sign({
|
const signed = await openpgp.sign({
|
||||||
message: openpgp.message.fromBinary(data),
|
message: openpgp.message.fromBinary(data),
|
||||||
privateKeys: privKey
|
privateKeys: privKey
|
||||||
});
|
});
|
||||||
|
|
||||||
const msgAsciiArmored = encrypted.data;
|
const msgAsciiArmored = signed.data;
|
||||||
const message = await openpgp.message.readArmored(openpgp.stream.transform(msgAsciiArmored, value => {
|
const message = await openpgp.message.readArmored(openpgp.stream.transform(msgAsciiArmored, value => {
|
||||||
if (value.length > 1000) return value.slice(0, 499) + 'a' + value.slice(500);
|
if (value.length > 1000) return value.slice(0, 499) + 'a' + value.slice(500);
|
||||||
return value;
|
return value;
|
||||||
}));
|
}));
|
||||||
const decrypted = await openpgp.verify({
|
const verified = await openpgp.verify({
|
||||||
publicKeys: pubKey,
|
publicKeys: pubKey,
|
||||||
message
|
message
|
||||||
});
|
});
|
||||||
expect(util.isStream(decrypted.data)).to.be.true;
|
expect(util.isStream(verified.data)).to.be.true;
|
||||||
expect(await openpgp.stream.getReader(openpgp.stream.clone(decrypted.data)).readBytes(10)).not.to.deep.equal(plaintext[0]);
|
expect(await openpgp.stream.getReader(openpgp.stream.clone(verified.data)).readBytes(10)).not.to.deep.equal(plaintext[0]);
|
||||||
if (i > 10) throw new Error('Data did not arrive early.');
|
if (i > 10) throw new Error('Data did not arrive early.');
|
||||||
await expect(openpgp.stream.readToEnd(decrypted.data)).to.be.rejectedWith('Ascii armor integrity check on message failed');
|
await expect(openpgp.stream.readToEnd(verified.data)).to.be.rejectedWith('Ascii armor integrity check on message failed');
|
||||||
expect(decrypted.signatures).to.exist.and.have.length(1);
|
expect(verified.signatures).to.exist.and.have.length(1);
|
||||||
} finally {
|
} finally {
|
||||||
openpgp.config.allow_unauthenticated_stream = allow_unauthenticated_streamValue;
|
openpgp.config.allow_unauthenticated_stream = allow_unauthenticated_streamValue;
|
||||||
}
|
}
|
||||||
|
@ -702,26 +702,26 @@ describe('Streaming', function() {
|
||||||
canceled = true;
|
canceled = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const encrypted = await openpgp.sign({
|
const signed = await openpgp.sign({
|
||||||
message: openpgp.message.fromBinary(data),
|
message: openpgp.message.fromBinary(data),
|
||||||
privateKeys: privKey
|
privateKeys: privKey
|
||||||
});
|
});
|
||||||
|
|
||||||
const msgAsciiArmored = encrypted.data;
|
const msgAsciiArmored = signed.data;
|
||||||
const message = await openpgp.message.readArmored(msgAsciiArmored);
|
const message = await openpgp.message.readArmored(msgAsciiArmored);
|
||||||
const decrypted = await openpgp.verify({
|
const verified = await openpgp.verify({
|
||||||
publicKeys: pubKey,
|
publicKeys: pubKey,
|
||||||
message
|
message
|
||||||
});
|
});
|
||||||
expect(util.isStream(decrypted.data)).to.be.true;
|
expect(util.isStream(verified.data)).to.be.true;
|
||||||
const reader = openpgp.stream.getReader(decrypted.data);
|
const reader = openpgp.stream.getReader(verified.data);
|
||||||
expect(await reader.readBytes(1024)).to.deep.equal(plaintext[0]);
|
expect(await reader.readBytes(1024)).to.deep.equal(plaintext[0]);
|
||||||
if (i > 10) throw new Error('Data did not arrive early.');
|
if (i > 10) throw new Error('Data did not arrive early.');
|
||||||
reader.releaseLock();
|
reader.releaseLock();
|
||||||
await openpgp.stream.cancel(decrypted.data, new Error('canceled by test'));
|
await openpgp.stream.cancel(verified.data, new Error('canceled by test'));
|
||||||
expect(canceled).to.be.true;
|
expect(canceled).to.be.true;
|
||||||
expect(decrypted.signatures).to.exist.and.have.length(1);
|
expect(verified.signatures).to.exist.and.have.length(1);
|
||||||
expect(await decrypted.signatures[0].verified).to.be.undefined;
|
expect(await verified.signatures[0].verified).to.be.undefined;
|
||||||
} finally {
|
} finally {
|
||||||
openpgp.config.aead_protect = aead_protectValue;
|
openpgp.config.aead_protect = aead_protectValue;
|
||||||
openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteValue;
|
openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteValue;
|
||||||
|
@ -773,11 +773,11 @@ describe('Streaming', function() {
|
||||||
await new Promise(setTimeout);
|
await new Promise(setTimeout);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const encrypted = await openpgp.sign({
|
const signed = await openpgp.sign({
|
||||||
message: openpgp.message.fromBinary(data),
|
message: openpgp.message.fromBinary(data),
|
||||||
privateKeys: privKey
|
privateKeys: privKey
|
||||||
});
|
});
|
||||||
const reader = openpgp.stream.getReader(encrypted.data);
|
const reader = openpgp.stream.getReader(signed.data);
|
||||||
expect(await reader.readBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\r\n/);
|
expect(await reader.readBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\r\n/);
|
||||||
if (i > 10) throw new Error('Data did not arrive early.');
|
if (i > 10) throw new Error('Data did not arrive early.');
|
||||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||||
|
@ -851,18 +851,18 @@ describe('Streaming', function() {
|
||||||
await new Promise(setTimeout);
|
await new Promise(setTimeout);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const encrypted = await openpgp.sign({
|
const signed = await openpgp.sign({
|
||||||
message: openpgp.message.fromBinary(data),
|
message: openpgp.message.fromBinary(data),
|
||||||
privateKeys: privKey
|
privateKeys: privKey
|
||||||
});
|
});
|
||||||
const msgAsciiArmored = encrypted.data;
|
const msgAsciiArmored = signed.data;
|
||||||
const message = await openpgp.message.readArmored(msgAsciiArmored);
|
const message = await openpgp.message.readArmored(msgAsciiArmored);
|
||||||
const decrypted = await openpgp.verify({
|
const verified = await openpgp.verify({
|
||||||
publicKeys: pubKey,
|
publicKeys: pubKey,
|
||||||
message
|
message
|
||||||
});
|
});
|
||||||
expect(util.isStream(decrypted.data)).to.be.true;
|
expect(util.isStream(verified.data)).to.be.true;
|
||||||
const reader = openpgp.stream.getReader(decrypted.data);
|
const reader = openpgp.stream.getReader(verified.data);
|
||||||
expect(await reader.readBytes(1024)).to.deep.equal(plaintext[0]);
|
expect(await reader.readBytes(1024)).to.deep.equal(plaintext[0]);
|
||||||
if (i > 10) throw new Error('Data did not arrive early.');
|
if (i > 10) throw new Error('Data did not arrive early.');
|
||||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user