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 {String} ASCII armor
|
||||
* @returns {String | ReadableStream<String>} ASCII armor
|
||||
*/
|
||||
CleartextMessage.prototype.armor = function() {
|
||||
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
|
||||
* @param {String} armoredText text to be parsed
|
||||
* @param {String | ReadableStream<String>} armoredText text to be parsed
|
||||
* @returns {module:cleartext.CleartextMessage} new cleartext message object
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
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 {Uint8Array} m Message to sign
|
||||
* @param {Uint8Array} d Private key used to sign the message
|
||||
* @param {Uint8Array} hashed The hashed message
|
||||
* @returns {{r: Uint8Array,
|
||||
* s: Uint8Array}} Signature of the message
|
||||
* @async
|
||||
|
@ -49,6 +50,7 @@ async function sign(oid, hash_algo, m, d, hashed) {
|
|||
s: Uint8Array}} signature Signature to verify
|
||||
* @param {Uint8Array} m Message to verify
|
||||
* @param {Uint8Array} Q Public key used to verify the message
|
||||
* @param {Uint8Array} hashed The hashed message
|
||||
* @returns {Boolean}
|
||||
* @async
|
||||
*/
|
||||
|
|
|
@ -29,6 +29,7 @@ import Curve from './curves';
|
|||
* @param {module:enums.hash} hash_algo Hash algorithm used to sign
|
||||
* @param {Uint8Array} m Message to sign
|
||||
* @param {Uint8Array} d Private key used to sign
|
||||
* @param {Uint8Array} hashed The hashed message
|
||||
* @returns {{R: Uint8Array,
|
||||
* S: Uint8Array}} Signature of the message
|
||||
* @async
|
||||
|
@ -50,6 +51,7 @@ async function sign(oid, hash_algo, m, d, hashed) {
|
|||
S: Uint8Array}} signature Signature to verify the message
|
||||
* @param {Uint8Array} m Message to verify
|
||||
* @param {Uint8Array} Q Public key used to verify the message
|
||||
* @param {Uint8Array} hashed The hashed message
|
||||
* @returns {Boolean}
|
||||
* @async
|
||||
*/
|
||||
|
|
|
@ -25,6 +25,7 @@ export default {
|
|||
* @param {Array<module:type/mpi>} msg_MPIs Algorithm-specific signature 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} hashed The hashed data
|
||||
* @returns {Boolean} True if signature is valid
|
||||
* @async
|
||||
*/
|
||||
|
@ -78,6 +79,7 @@ export default {
|
|||
* @param {module:enums.hash} hash_algo Hash algorithm
|
||||
* @param {Array<module:type/mpi>} key_params Algorithm-specific public and private key parameters
|
||||
* @param {Uint8Array} data Data to be signed
|
||||
* @param {Uint8Array} hashed The hashed data
|
||||
* @returns {Uint8Array} Signature
|
||||
* @async
|
||||
*/
|
||||
|
|
|
@ -118,19 +118,14 @@ function addheader(customComment) {
|
|||
|
||||
/**
|
||||
* Calculates a checksum over the given data and returns it base64 encoded
|
||||
* @param {String} data Data to create a CRC-24 checksum for
|
||||
* @returns {String} Base64 encoded checksum
|
||||
* @param {String | ReadableStream<String>} data Data to create a CRC-24 checksum for
|
||||
* @returns {String | ReadableStream<String>} Base64 encoded checksum
|
||||
*/
|
||||
function getCheckSum(data) {
|
||||
const crc = createcrc24(data);
|
||||
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 = [
|
||||
0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139,
|
||||
0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
|
||||
|
@ -166,6 +161,11 @@ const crc_table = [
|
|||
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) {
|
||||
let crc = 0xB704CE;
|
||||
return stream.transform(input, value => {
|
||||
|
@ -197,7 +197,8 @@ function verifyHeaders(headers) {
|
|||
* the encoded bytes
|
||||
* @param {String} text OpenPGP armored message
|
||||
* @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
|
||||
*/
|
||||
function dearmor(input) {
|
||||
|
@ -310,7 +311,7 @@ function dearmor(input) {
|
|||
* @param {Integer} partindex
|
||||
* @param {Integer} parttotal
|
||||
* @param {String} customComment (optional) additional comment to add to the armored string
|
||||
* @returns {String} Armored text
|
||||
* @returns {String | ReadableStream<String>} Armored text
|
||||
* @static
|
||||
*/
|
||||
function armor(messagetype, body, partindex, parttotal, customComment) {
|
||||
|
|
|
@ -23,9 +23,9 @@ const b64u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|||
|
||||
/**
|
||||
* 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
|
||||
* @returns {string} radix-64 version of input string
|
||||
* @returns {String | ReadableStream<String>} radix-64 version of input string
|
||||
* @static
|
||||
*/
|
||||
function s2r(t, u = false) {
|
||||
|
@ -92,9 +92,9 @@ function s2r(t, u = false) {
|
|||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Uint8Array} binary array version of input string
|
||||
* @returns {Uint8Array | ReadableStream<Uint8Array>} binary array version of input string
|
||||
* @static
|
||||
*/
|
||||
function r2s(t, u) {
|
||||
|
|
|
@ -248,7 +248,7 @@ Key.prototype.toPublic = function() {
|
|||
|
||||
/**
|
||||
* Returns ASCII armored text of key
|
||||
* @returns {String} ASCII armor
|
||||
* @returns {ReadableStream<String>} ASCII armor
|
||||
*/
|
||||
Key.prototype.armor = function() {
|
||||
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
|
||||
* @param {String} armoredText text to be parsed
|
||||
* @param {String | ReadableStream<String>} armoredText text to be parsed
|
||||
* @returns {{keys: Array<module:key.Key>,
|
||||
* err: (Array<Error>|null)}} result object with key and error arrays
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
export async function readArmored(armoredText) {
|
||||
|
|
|
@ -36,6 +36,7 @@ function Keyring(storeHandler) {
|
|||
|
||||
/**
|
||||
* Calls the storeHandler to load the keys
|
||||
* @async
|
||||
*/
|
||||
Keyring.prototype.load = async function () {
|
||||
this.publicKeys = new KeyArray(await this.storeHandler.loadPublic());
|
||||
|
@ -44,6 +45,7 @@ Keyring.prototype.load = async function () {
|
|||
|
||||
/**
|
||||
* Calls the storeHandler to save the keys
|
||||
* @async
|
||||
*/
|
||||
Keyring.prototype.store = async function () {
|
||||
await Promise.all([
|
||||
|
|
|
@ -55,6 +55,7 @@ LocalStore.prototype.privateKeysItem = 'private-keys';
|
|||
/**
|
||||
* Load the public keys from HTML5 local storage.
|
||||
* @returns {Array<module:key.Key>} array of keys retrieved from localstore
|
||||
* @async
|
||||
*/
|
||||
LocalStore.prototype.loadPublic = async function () {
|
||||
return loadKeys(this.storage, this.publicKeysItem);
|
||||
|
@ -63,6 +64,7 @@ LocalStore.prototype.loadPublic = async function () {
|
|||
/**
|
||||
* Load the private keys from HTML5 local storage.
|
||||
* @returns {Array<module:key.Key>} array of keys retrieved from localstore
|
||||
* @async
|
||||
*/
|
||||
LocalStore.prototype.loadPrivate = async function () {
|
||||
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.
|
||||
* The key array gets stringified using JSON
|
||||
* @param {Array<module:key.Key>} keys array of keys to save in localstore
|
||||
* @async
|
||||
*/
|
||||
LocalStore.prototype.storePublic = async function (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.
|
||||
* The key array gets stringified using JSON
|
||||
* @param {Array<module:key.Key>} keys array of keys to save in localstore
|
||||
* @async
|
||||
*/
|
||||
LocalStore.prototype.storePrivate = async function (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 {String} ASCII armor
|
||||
* @returns {ReadableStream<String>} ASCII armor
|
||||
*/
|
||||
Message.prototype.armor = function() {
|
||||
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
|
||||
* @param {String} armoredText text to be parsed
|
||||
* @param {String | ReadableStream<String>} armoredText text to be parsed
|
||||
* @returns {module:message.Message} new message object
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
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
|
||||
* @param {Uint8Array} input binary message
|
||||
* @param {Uint8Array | ReadableStream<Uint8Array>} input binary message
|
||||
* @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
|
||||
*/
|
||||
export async function read(input, fromStream) {
|
||||
|
@ -703,7 +705,7 @@ export async function read(input, fromStream) {
|
|||
|
||||
/**
|
||||
* creates new message object from text
|
||||
* @param {String} text
|
||||
* @param {String | ReadableStream<String>} text
|
||||
* @param {String} filename (optional)
|
||||
* @param {Date} date (optional)
|
||||
* @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
|
||||
* @param {Uint8Array} bytes
|
||||
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes
|
||||
* @param {String} filename (optional)
|
||||
* @param {Date} date (optional)
|
||||
* @param {utf8|binary|text|mime} type (optional) data packet type
|
||||
|
|
|
@ -362,27 +362,8 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
|
|||
const result = {};
|
||||
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 = 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();
|
||||
await postProcess(result, asStream, message, decrypted.packets.stream);
|
||||
return result;
|
||||
}).catch(onError.bind(null, 'Error decrypting message'));
|
||||
}
|
||||
|
@ -461,26 +442,7 @@ export function verify({ message, publicKeys, asStream=message&&message.fromStre
|
|||
const result = {};
|
||||
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 = 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(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;
|
||||
}));
|
||||
}
|
||||
await postProcess(result, asStream, message);
|
||||
return result;
|
||||
}).catch(onError.bind(null, 'Error verifying cleartext signed message'));
|
||||
}
|
||||
|
@ -633,6 +595,42 @@ async function convertStreams(obj, asStream, keys=[]) {
|
|||
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.
|
||||
|
|
|
@ -60,14 +60,14 @@ function Compressed() {
|
|||
|
||||
/**
|
||||
* Compressed packet data
|
||||
* @type {String}
|
||||
* @type {Uint8Array | ReadableStream<Uint8Array>}
|
||||
*/
|
||||
this.compressed = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
await stream.parse(bytes, async reader => {
|
||||
|
@ -85,7 +85,7 @@ Compressed.prototype.read = async function (bytes) {
|
|||
|
||||
/**
|
||||
* Return the compressed packet.
|
||||
* @returns {String} binary compressed packet
|
||||
* @returns {Uint8Array | ReadableStream<Uint8Array>} binary compressed packet
|
||||
*/
|
||||
Compressed.prototype.write = function () {
|
||||
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
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
* 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) {
|
||||
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.
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
* @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) {
|
||||
if (this.data === null) {
|
||||
|
@ -135,7 +137,7 @@ Literal.prototype.getFilename = function() {
|
|||
/**
|
||||
* 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
|
||||
*/
|
||||
Literal.prototype.read = async function(bytes) {
|
||||
|
@ -157,7 +159,7 @@ Literal.prototype.read = async function(bytes) {
|
|||
/**
|
||||
* 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() {
|
||||
const filename = util.str_to_Uint8Array(util.encode_utf8(this.filename));
|
||||
|
|
|
@ -133,7 +133,7 @@ export default {
|
|||
/**
|
||||
* 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
|
||||
* @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.
|
||||
* @param {Uint8Array} A Uint8Array of bytes.
|
||||
* @param {Uint8Array | ReadableStream<Uint8Array>} A Uint8Array of bytes.
|
||||
*/
|
||||
List.prototype.read = async function (bytes) {
|
||||
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)
|
||||
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes
|
||||
*/
|
||||
SymEncryptedAEADProtected.prototype.read = async function (bytes) {
|
||||
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)
|
||||
* @returns {Uint8Array} The encrypted payload
|
||||
* @returns {Uint8Array | ReadableStream<Uint8Array>} The encrypted payload
|
||||
*/
|
||||
SymEncryptedAEADProtected.prototype.write = function () {
|
||||
if (config.aead_protect_version === 4) {
|
||||
|
@ -90,7 +91,7 @@ SymEncryptedAEADProtected.prototype.write = function () {
|
|||
* Decrypt the encrypted payload.
|
||||
* @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128'
|
||||
* @param {Uint8Array} key The session key used to encrypt the payload
|
||||
* @returns {Promise<Boolean>}
|
||||
* @returns {Boolean}
|
||||
* @async
|
||||
*/
|
||||
SymEncryptedAEADProtected.prototype.decrypt = async function (sessionKeyAlgorithm, key) {
|
||||
|
@ -105,7 +106,6 @@ SymEncryptedAEADProtected.prototype.decrypt = async function (sessionKeyAlgorith
|
|||
* Encrypt the packet list payload.
|
||||
* @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128'
|
||||
* @param {Uint8Array} key The session key used to encrypt the payload
|
||||
* @returns {Promise<Boolean>}
|
||||
* @async
|
||||
*/
|
||||
SymEncryptedAEADProtected.prototype.encrypt = async function (sessionKeyAlgorithm, key) {
|
||||
|
@ -122,8 +122,8 @@ SymEncryptedAEADProtected.prototype.encrypt = async function (sessionKeyAlgorith
|
|||
* En/decrypt the payload.
|
||||
* @param {encrypt|decrypt} fn Whether to encrypt or decrypt
|
||||
* @param {Uint8Array} key The session key used to en/decrypt the payload
|
||||
* @param {Uint8Array} data The data to en/decrypt
|
||||
* @returns {Promise<Uint8Array>}
|
||||
* @param {Uint8Array | ReadableStream<Uint8Array>} data The data to en/decrypt
|
||||
* @returns {Uint8Array | ReadableStream<Uint8Array>}
|
||||
* @async
|
||||
*/
|
||||
SymEncryptedAEADProtected.prototype.crypt = async function (fn, key, data) {
|
||||
|
|
|
@ -87,6 +87,7 @@ SymEncryptedIntegrityProtected.prototype.write = function () {
|
|||
* Encrypt the payload in the packet.
|
||||
* @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 {Boolean} asStream Whether to set this.encrypted to a stream
|
||||
* @returns {Promise<Boolean>}
|
||||
* @async
|
||||
*/
|
||||
|
@ -116,6 +117,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlg
|
|||
* Decrypts the encrypted data contained in the packet.
|
||||
* @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 {Boolean} asStream Whether to read this.encrypted as a stream
|
||||
* @returns {Promise<Boolean>}
|
||||
* @async
|
||||
*/
|
||||
|
|
|
@ -41,7 +41,7 @@ export function Signature(packetlist) {
|
|||
|
||||
/**
|
||||
* Returns ASCII armored text of signature
|
||||
* @returns {String} ASCII armor
|
||||
* @returns {ReadableStream<String>} ASCII armor
|
||||
*/
|
||||
Signature.prototype.armor = function() {
|
||||
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
|
||||
* @param {String} armoredText text to be parsed
|
||||
* @param {String | ReadableStream<String>} armoredText text to be parsed
|
||||
* @returns {Signature} new signature object
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
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
|
||||
* @param {Uint8Array} input binary signature
|
||||
* @param {Uint8Array | ReadableStream<Uint8Array>} input binary signature
|
||||
* @returns {Signature} new signature object
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
export async function read(input) {
|
||||
|
|
208
src/stream.js
208
src/stream.js
|
@ -1,7 +1,12 @@
|
|||
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) {
|
||||
if (util.isStream(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) {
|
||||
await Promise.all(transforms.map(array => cancel(array, reason)));
|
||||
});
|
||||
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, {
|
||||
preventClose: i !== arrays.length - 1
|
||||
preventClose: i !== list.length - 1
|
||||
}));
|
||||
return prev;
|
||||
}));
|
||||
return transform.readable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Reader
|
||||
* @param {ReadableStream|Uint8array|String} input
|
||||
* @returns {Reader}
|
||||
*/
|
||||
function getReader(input) {
|
||||
return new Reader(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Writer
|
||||
* @param {WritableStream} input
|
||||
* @returns {WritableStreamDefaultWriter}
|
||||
*/
|
||||
function getWriter(input) {
|
||||
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) {
|
||||
if (!util.isStream(input)) {
|
||||
input = toStream(input);
|
||||
}
|
||||
try {
|
||||
if (input.externalBuffer) {
|
||||
if (input[externalBuffer]) {
|
||||
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.write(input.externalBuffer[i]);
|
||||
await writer.write(input[externalBuffer][i]);
|
||||
}
|
||||
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) {
|
||||
const transformStream = new TransformStream(options);
|
||||
pipe(input, transformStream.writable);
|
||||
return transformStream.readable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cancelable TransformStream.
|
||||
* @param {Function} cancel
|
||||
* @returns {TransformStream}
|
||||
*/
|
||||
function transformWithCancel(cancel) {
|
||||
let backpressureChangePromiseResolve = function() {};
|
||||
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) {
|
||||
if (util.isStream(input)) {
|
||||
return transformRaw(input, {
|
||||
|
@ -117,6 +162,15 @@ function transform(input, process = () => undefined, finish = () => undefined) {
|
|||
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) {
|
||||
let incomingTransformController;
|
||||
const incoming = new TransformStream({
|
||||
|
@ -136,6 +190,15 @@ function transformPair(input, fn) {
|
|||
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) {
|
||||
let returnValue;
|
||||
const transformed = transformPair(input, (readable, writable) => {
|
||||
|
@ -150,15 +213,29 @@ function parse(input, fn) {
|
|||
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) {
|
||||
if (util.isStream(input)) {
|
||||
const teed = input.tee();
|
||||
teed[0].externalBuffer = teed[1].externalBuffer = input.externalBuffer;
|
||||
teed[0][externalBuffer] = teed[1][externalBuffer] = input[externalBuffer];
|
||||
return teed;
|
||||
}
|
||||
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) {
|
||||
if (util.isStream(input)) {
|
||||
const teed = tee(input);
|
||||
|
@ -168,6 +245,14 @@ function clone(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) {
|
||||
if (util.isStream(input)) {
|
||||
return new ReadableStream({
|
||||
|
@ -199,6 +284,12 @@ function passiveClone(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) {
|
||||
// Overwrite input.getReader, input.locked, etc to point to clone
|
||||
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) {
|
||||
if (util.isStream(input)) {
|
||||
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.`);
|
||||
return fromAsync(async () => slice(await readToEnd(input), begin, end));
|
||||
}
|
||||
if (input.externalBuffer) {
|
||||
input = util.concat(input.externalBuffer.concat([input]));
|
||||
if (input[externalBuffer]) {
|
||||
input = util.concat(input[externalBuffer].concat([input]));
|
||||
}
|
||||
if (util.isUint8Array(input)) {
|
||||
return input.subarray(begin, end);
|
||||
|
@ -263,19 +359,36 @@ function slice(input, begin=0, end=Infinity) {
|
|||
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)) {
|
||||
return getReader(input).readToEnd(join);
|
||||
return getReader(input).readToEnd(concat);
|
||||
}
|
||||
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) {
|
||||
if (util.isStream(input)) {
|
||||
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) {
|
||||
return new ReadableStream({
|
||||
pull: async controller => {
|
||||
|
@ -298,8 +411,13 @@ function fromAsync(fn) {
|
|||
let nodeToWeb;
|
||||
let webToNode;
|
||||
|
||||
if (nodeStream) {
|
||||
if (NodeReadableStream) {
|
||||
|
||||
/**
|
||||
* Convert a Node Readable Stream to a Web ReadableStream
|
||||
* @param {Readable} nodeStream
|
||||
* @returns {ReadableStream}
|
||||
*/
|
||||
nodeToWeb = function(nodeStream) {
|
||||
return new ReadableStream({
|
||||
start(controller) {
|
||||
|
@ -321,7 +439,7 @@ if (nodeStream) {
|
|||
};
|
||||
|
||||
|
||||
class NodeReadable extends nodeStream.Readable {
|
||||
class NodeReadable extends NodeReadableStream {
|
||||
constructor(webStream, options) {
|
||||
super(options);
|
||||
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) {
|
||||
return new NodeReadable(webStream);
|
||||
};
|
||||
|
@ -363,10 +486,11 @@ export default { toStream, concat, getReader, getWriter, pipe, transformRaw, tra
|
|||
|
||||
|
||||
const doneReadingSet = new WeakSet();
|
||||
const externalBuffer = Symbol('externalBuffer');
|
||||
function Reader(input) {
|
||||
this.stream = input;
|
||||
if (input.externalBuffer) {
|
||||
this.externalBuffer = input.externalBuffer.slice();
|
||||
if (input[externalBuffer]) {
|
||||
this[externalBuffer] = input[externalBuffer].slice();
|
||||
}
|
||||
if (util.isStream(input)) {
|
||||
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() {
|
||||
if (this.externalBuffer && this.externalBuffer.length) {
|
||||
const value = this.externalBuffer.shift();
|
||||
if (this[externalBuffer] && this[externalBuffer].length) {
|
||||
const value = this[externalBuffer].shift();
|
||||
return { done: false, value };
|
||||
}
|
||||
return this._read();
|
||||
};
|
||||
|
||||
/**
|
||||
* Allow others to read the stream.
|
||||
*/
|
||||
Reader.prototype.releaseLock = function() {
|
||||
if (this.externalBuffer) {
|
||||
this.stream.externalBuffer = this.externalBuffer;
|
||||
if (this[externalBuffer]) {
|
||||
this.stream[externalBuffer] = this[externalBuffer];
|
||||
}
|
||||
this._releaseLock();
|
||||
};
|
||||
|
||||
/**
|
||||
* Read up to and including the first \n character.
|
||||
* @returns {String|Undefined}
|
||||
*/
|
||||
Reader.prototype.readLine = async function() {
|
||||
let buffer = [];
|
||||
let returnVal;
|
||||
|
@ -428,6 +563,10 @@ Reader.prototype.readLine = async function() {
|
|||
return returnVal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read a single byte/character.
|
||||
* @returns {Number|String|Undefined}
|
||||
*/
|
||||
Reader.prototype.readByte = async function() {
|
||||
const { done, value } = await this.read();
|
||||
if (done) return;
|
||||
|
@ -436,6 +575,10 @@ Reader.prototype.readByte = async function() {
|
|||
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) {
|
||||
const buffer = [];
|
||||
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) {
|
||||
const bytes = await this.readBytes(length);
|
||||
this.unshift(bytes);
|
||||
return bytes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Push data to the front of the stream.
|
||||
* @param {Uint8Array|String|Undefined} ...values
|
||||
*/
|
||||
Reader.prototype.unshift = function(...values) {
|
||||
if (!this.externalBuffer) {
|
||||
this.externalBuffer = [];
|
||||
if (!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 = [];
|
||||
while (true) {
|
||||
const { done, value } = await this.read();
|
||||
if (done) break;
|
||||
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++)
|
||||
* 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
|
||||
* @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) {
|
||||
if (Object.prototype.isPrototypeOf(obj)) {
|
||||
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 => {
|
||||
console.log(str + ': ', fn(result));
|
||||
/**
|
||||
* Read a stream to the end and print it to the console when it's closed.
|
||||
* @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) {
|
||||
const rest = bitcount % 8;
|
||||
if (rest === 0) {
|
||||
|
@ -622,17 +629,41 @@ export default {
|
|||
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
|
||||
* the api when available. But it can also be deactivated with config.use_native
|
||||
* @returns {Object} The crypto module or 'undefined'
|
||||
*/
|
||||
getNodeCrypto: function() {
|
||||
if (!util.detectNode() || !config.use_native) {
|
||||
if (!config.use_native) {
|
||||
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'
|
||||
*/
|
||||
getNodeBuffer: function() {
|
||||
if (!util.detectNode()) {
|
||||
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');
|
||||
return (util.nodeRequire('buffer') || {}).Buffer;
|
||||
},
|
||||
|
||||
getNodeStream: function() {
|
||||
if (!util.detectNode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-useless-concat, import/no-dynamic-require
|
||||
return require('stream'+'');
|
||||
return (util.nodeRequire('stream') || {}).Readable;
|
||||
},
|
||||
|
||||
getNodeTextDecoder: function() {
|
||||
if (!util.detectNode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-useless-concat, import/no-dynamic-require
|
||||
return require('util'+'').TextDecoder;
|
||||
return (util.nodeRequire('util') || {}).TextDecoder;
|
||||
},
|
||||
|
||||
isEmailAddress: function(data) {
|
||||
|
|
|
@ -182,15 +182,15 @@ describe('Streaming', function() {
|
|||
canceled = true;
|
||||
}
|
||||
});
|
||||
const encrypted = await openpgp.sign({
|
||||
const signed = await openpgp.sign({
|
||||
message: openpgp.message.fromBinary(data),
|
||||
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/);
|
||||
if (i > 10) throw new Error('Data did not arrive early.');
|
||||
reader.releaseLock();
|
||||
await openpgp.stream.cancel(encrypted.data);
|
||||
await openpgp.stream.cancel(signed.data);
|
||||
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),
|
||||
privateKeys: privKey
|
||||
});
|
||||
|
||||
const msgAsciiArmored = encrypted.data;
|
||||
const msgAsciiArmored = signed.data;
|
||||
const message = await openpgp.message.readArmored(openpgp.stream.transform(msgAsciiArmored, value => {
|
||||
if (value.length > 1000) return value.slice(0, 499) + 'a' + value.slice(500);
|
||||
return value;
|
||||
}));
|
||||
const decrypted = await openpgp.verify({
|
||||
const verified = await openpgp.verify({
|
||||
publicKeys: pubKey,
|
||||
message
|
||||
});
|
||||
expect(util.isStream(decrypted.data)).to.be.true;
|
||||
expect(await openpgp.stream.getReader(openpgp.stream.clone(decrypted.data)).readBytes(10)).not.to.deep.equal(plaintext[0]);
|
||||
expect(util.isStream(verified.data)).to.be.true;
|
||||
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.');
|
||||
await expect(openpgp.stream.readToEnd(decrypted.data)).to.be.rejectedWith('Ascii armor integrity check on message failed');
|
||||
expect(decrypted.signatures).to.exist.and.have.length(1);
|
||||
await expect(openpgp.stream.readToEnd(verified.data)).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;
|
||||
}
|
||||
|
@ -702,26 +702,26 @@ describe('Streaming', function() {
|
|||
canceled = true;
|
||||
}
|
||||
});
|
||||
const encrypted = await openpgp.sign({
|
||||
const signed = await openpgp.sign({
|
||||
message: openpgp.message.fromBinary(data),
|
||||
privateKeys: privKey
|
||||
});
|
||||
|
||||
const msgAsciiArmored = encrypted.data;
|
||||
const msgAsciiArmored = signed.data;
|
||||
const message = await openpgp.message.readArmored(msgAsciiArmored);
|
||||
const decrypted = await openpgp.verify({
|
||||
const verified = await openpgp.verify({
|
||||
publicKeys: pubKey,
|
||||
message
|
||||
});
|
||||
expect(util.isStream(decrypted.data)).to.be.true;
|
||||
const reader = openpgp.stream.getReader(decrypted.data);
|
||||
expect(util.isStream(verified.data)).to.be.true;
|
||||
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(decrypted.data, new Error('canceled by test'));
|
||||
await openpgp.stream.cancel(verified.data, new Error('canceled by test'));
|
||||
expect(canceled).to.be.true;
|
||||
expect(decrypted.signatures).to.exist.and.have.length(1);
|
||||
expect(await decrypted.signatures[0].verified).to.be.undefined;
|
||||
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;
|
||||
|
@ -773,11 +773,11 @@ describe('Streaming', function() {
|
|||
await new Promise(setTimeout);
|
||||
}
|
||||
});
|
||||
const encrypted = await openpgp.sign({
|
||||
const signed = await openpgp.sign({
|
||||
message: openpgp.message.fromBinary(data),
|
||||
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/);
|
||||
if (i > 10) throw new Error('Data did not arrive early.');
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
|
@ -851,18 +851,18 @@ describe('Streaming', function() {
|
|||
await new Promise(setTimeout);
|
||||
}
|
||||
});
|
||||
const encrypted = await openpgp.sign({
|
||||
const signed = await openpgp.sign({
|
||||
message: openpgp.message.fromBinary(data),
|
||||
privateKeys: privKey
|
||||
});
|
||||
const msgAsciiArmored = encrypted.data;
|
||||
const msgAsciiArmored = signed.data;
|
||||
const message = await openpgp.message.readArmored(msgAsciiArmored);
|
||||
const decrypted = await openpgp.verify({
|
||||
const verified = await openpgp.verify({
|
||||
publicKeys: pubKey,
|
||||
message
|
||||
});
|
||||
expect(util.isStream(decrypted.data)).to.be.true;
|
||||
const reader = openpgp.stream.getReader(decrypted.data);
|
||||
expect(util.isStream(verified.data)).to.be.true;
|
||||
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));
|
||||
|
|
Loading…
Reference in New Issue
Block a user