Don't mutate prototypes of Uint8Array, ReadableStream and ReadableStreamDefaultWriter
This commit is contained in:
parent
70f0e1d2f5
commit
4ada3fa590
|
@ -7,6 +7,7 @@
|
||||||
* @requires asmcrypto.js
|
* @requires asmcrypto.js
|
||||||
* @requires hash.js
|
* @requires hash.js
|
||||||
* @requires crypto/hash/md5
|
* @requires crypto/hash/md5
|
||||||
|
* @requires stream
|
||||||
* @requires util
|
* @requires util
|
||||||
* @module crypto/hash
|
* @module crypto/hash
|
||||||
*/
|
*/
|
||||||
|
@ -19,6 +20,7 @@ import sha384 from 'hash.js/lib/hash/sha/384';
|
||||||
import sha512 from 'hash.js/lib/hash/sha/512';
|
import sha512 from 'hash.js/lib/hash/sha/512';
|
||||||
import { ripemd160 } from 'hash.js/lib/hash/ripemd';
|
import { ripemd160 } from 'hash.js/lib/hash/ripemd';
|
||||||
import md5 from './md5';
|
import md5 from './md5';
|
||||||
|
import stream from '../../stream';
|
||||||
import util from '../../util';
|
import util from '../../util';
|
||||||
|
|
||||||
const rusha = new Rusha();
|
const rusha = new Rusha();
|
||||||
|
@ -36,7 +38,7 @@ function node_hash(type) {
|
||||||
function hashjs_hash(hash) {
|
function hashjs_hash(hash) {
|
||||||
return function(data) {
|
return function(data) {
|
||||||
const hashInstance = hash();
|
const hashInstance = hash();
|
||||||
return data.transform((done, value) => {
|
return stream.transform(data, (done, value) => {
|
||||||
if (!done) {
|
if (!done) {
|
||||||
hashInstance.update(value);
|
hashInstance.update(value);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* @requires crypto/public_key
|
* @requires crypto/public_key
|
||||||
* @requires crypto/pkcs1
|
* @requires crypto/pkcs1
|
||||||
* @requires enums
|
* @requires enums
|
||||||
|
* @requires stream
|
||||||
* @requires util
|
* @requires util
|
||||||
* @module crypto/signature
|
* @module crypto/signature
|
||||||
*/
|
*/
|
||||||
|
@ -12,6 +13,7 @@ import BN from 'bn.js';
|
||||||
import publicKey from './public_key';
|
import publicKey from './public_key';
|
||||||
import pkcs1 from './pkcs1';
|
import pkcs1 from './pkcs1';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
|
import stream from '../stream';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -29,7 +31,7 @@ export default {
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
verify: async function(algo, hash_algo, msg_MPIs, pub_MPIs, data) {
|
verify: async function(algo, hash_algo, msg_MPIs, pub_MPIs, data) {
|
||||||
data = await data.readToEnd();
|
data = await stream.readToEnd(data);
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case enums.publicKey.rsa_encrypt_sign:
|
case enums.publicKey.rsa_encrypt_sign:
|
||||||
case enums.publicKey.rsa_encrypt:
|
case enums.publicKey.rsa_encrypt:
|
||||||
|
@ -83,7 +85,7 @@ export default {
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
sign: async function(algo, hash_algo, key_params, data) {
|
sign: async function(algo, hash_algo, key_params, data) {
|
||||||
data = await data.readToEnd();
|
data = await stream.readToEnd(data);
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case enums.publicKey.rsa_encrypt_sign:
|
case enums.publicKey.rsa_encrypt_sign:
|
||||||
case enums.publicKey.rsa_encrypt:
|
case enums.publicKey.rsa_encrypt:
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
* @requires encoding/base64
|
* @requires encoding/base64
|
||||||
* @requires enums
|
* @requires enums
|
||||||
* @requires config
|
* @requires config
|
||||||
|
* @requires stream
|
||||||
* @requires util
|
* @requires util
|
||||||
* @module encoding/armor
|
* @module encoding/armor
|
||||||
*/
|
*/
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
import base64 from './base64.js';
|
import base64 from './base64.js';
|
||||||
import enums from '../enums.js';
|
import enums from '../enums.js';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
import stream from '../stream';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -166,7 +168,7 @@ const crc_table = [
|
||||||
|
|
||||||
function createcrc24(input) {
|
function createcrc24(input) {
|
||||||
let crc = 0xB704CE;
|
let crc = 0xB704CE;
|
||||||
return input.transform((done, value) => {
|
return stream.transform(input, (done, value) => {
|
||||||
if (!done) {
|
if (!done) {
|
||||||
for (let index = 0; index < value.length; index++) {
|
for (let index = 0; index < value.length; index++) {
|
||||||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ value[index]) & 0xff];
|
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ value[index]) & 0xff];
|
||||||
|
@ -311,7 +313,7 @@ function armor(messagetype, body, partindex, parttotal, customComment) {
|
||||||
body = body.data;
|
body = body.data;
|
||||||
}
|
}
|
||||||
let bodyClone;
|
let bodyClone;
|
||||||
[body, bodyClone] = body.tee();
|
[body, bodyClone] = stream.tee(body);
|
||||||
const result = [];
|
const result = [];
|
||||||
switch (messagetype) {
|
switch (messagetype) {
|
||||||
case enums.armor.multipart_section:
|
case enums.armor.multipart_section:
|
||||||
|
|
|
@ -12,10 +12,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @requires stream
|
||||||
* @requires util
|
* @requires util
|
||||||
* @module encoding/base64
|
* @module encoding/base64
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import stream from '../stream';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
const b64s = util.str_to_Uint8Array('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'); // Standard radix-64
|
const b64s = util.str_to_Uint8Array('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'); // Standard radix-64
|
||||||
|
@ -37,7 +39,7 @@ function s2r(t, u = false) {
|
||||||
let l = 0;
|
let l = 0;
|
||||||
let s = 0;
|
let s = 0;
|
||||||
|
|
||||||
return t.transform((done, value) => {
|
return stream.transform(t, (done, value) => {
|
||||||
const r = [];
|
const r = [];
|
||||||
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
|
@ -106,7 +108,7 @@ function r2s(t, u) {
|
||||||
let s = 0;
|
let s = 0;
|
||||||
let a = 0;
|
let a = 0;
|
||||||
|
|
||||||
return t.transform((done, value) => {
|
return stream.transform(t, (done, value) => {
|
||||||
if (!done) {
|
if (!done) {
|
||||||
const r = [];
|
const r = [];
|
||||||
const tl = value.length;
|
const tl = value.length;
|
||||||
|
|
|
@ -101,10 +101,10 @@ export { default as KDFParams } from './type/kdf_params';
|
||||||
export { default as OID } from './type/oid';
|
export { default as OID } from './type/oid';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see module:type/oid
|
* @see module:stream
|
||||||
* @name module:openpgp.OID
|
* @name module:openpgp.stream
|
||||||
*/
|
*/
|
||||||
export { default as Stream } from './type/stream';
|
export { default as stream } from './stream';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see module:encoding/armor
|
* @see module:encoding/armor
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
* @requires key
|
* @requires key
|
||||||
* @requires config
|
* @requires config
|
||||||
* @requires enums
|
* @requires enums
|
||||||
|
* @requires stream
|
||||||
* @requires util
|
* @requires util
|
||||||
* @requires polyfills
|
* @requires polyfills
|
||||||
* @requires worker/async_proxy
|
* @requires worker/async_proxy
|
||||||
|
@ -43,6 +44,7 @@ import { CleartextMessage } from './cleartext';
|
||||||
import { generate, reformat } from './key';
|
import { generate, reformat } from './key';
|
||||||
import config from './config/config';
|
import config from './config/config';
|
||||||
import enums from './enums';
|
import enums from './enums';
|
||||||
|
import stream from './stream';
|
||||||
import util from './util';
|
import util from './util';
|
||||||
import AsyncProxy from './worker/async_proxy';
|
import AsyncProxy from './worker/async_proxy';
|
||||||
|
|
||||||
|
@ -596,12 +598,12 @@ async function parseMessage(message, format, asStream) {
|
||||||
if (format === 'binary') {
|
if (format === 'binary') {
|
||||||
data = message.getLiteralData();
|
data = message.getLiteralData();
|
||||||
if (!asStream && util.isStream(data)) {
|
if (!asStream && util.isStream(data)) {
|
||||||
data = await data.readToEnd();
|
data = await stream.readToEnd(data);
|
||||||
}
|
}
|
||||||
} else if (format === 'utf8') {
|
} else if (format === 'utf8') {
|
||||||
data = message.getText();
|
data = message.getText();
|
||||||
if (!asStream && util.isStream(data)) {
|
if (!asStream && util.isStream(data)) {
|
||||||
data = await data.readToEnd(chunks => chunks.join(''));
|
data = await stream.readToEnd(data, chunks => chunks.join(''));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid format');
|
throw new Error('Invalid format');
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @requires enums
|
* @requires enums
|
||||||
|
* @requires stream
|
||||||
* @requires util
|
* @requires util
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
|
import stream from '../stream';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,7 +69,7 @@ Literal.prototype.getText = function() {
|
||||||
let text;
|
let text;
|
||||||
if (this.text === null) {
|
if (this.text === null) {
|
||||||
let lastChar = '';
|
let lastChar = '';
|
||||||
[this.data, this.text] = this.data.tee();
|
[this.data, this.text] = stream.tee(this.data);
|
||||||
this.text = stream.transform(this.text, value => {
|
this.text = stream.transform(this.text, value => {
|
||||||
const text = lastChar + util.Uint8Array_to_str(value);
|
const text = lastChar + util.Uint8Array_to_str(value);
|
||||||
// decode UTF8 and normalize EOL to \n
|
// decode UTF8 and normalize EOL to \n
|
||||||
|
@ -82,7 +84,7 @@ Literal.prototype.getText = function() {
|
||||||
return normalized.slice(0, -1);
|
return normalized.slice(0, -1);
|
||||||
}, () => lastChar);
|
}, () => lastChar);
|
||||||
}
|
}
|
||||||
[text, this.text] = this.text.tee();
|
[text, this.text] = stream.tee(this.text);
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,7 +142,7 @@ Literal.prototype.getFilename = function() {
|
||||||
* @returns {module:packet.Literal} object representation
|
* @returns {module:packet.Literal} object representation
|
||||||
*/
|
*/
|
||||||
Literal.prototype.read = async function(bytes) {
|
Literal.prototype.read = async function(bytes) {
|
||||||
const reader = bytes.getReader();
|
const reader = stream.getReader(bytes);
|
||||||
// - A one-octet field that describes how the data is formatted.
|
// - A one-octet field that describes how the data is formatted.
|
||||||
const format = enums.read(enums.literal, await reader.readByte());
|
const format = enums.read(enums.literal, await reader.readByte());
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* @requires packet/packet
|
* @requires packet/packet
|
||||||
* @requires config
|
* @requires config
|
||||||
* @requires enums
|
* @requires enums
|
||||||
|
* @requires stream
|
||||||
* @requires util
|
* @requires util
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -11,6 +12,7 @@ import * as packets from './all_packets';
|
||||||
import packetParser from './packet';
|
import packetParser from './packet';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
|
import stream from '../stream';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,7 +36,7 @@ function List() {
|
||||||
* @param {Uint8Array} A Uint8Array of bytes.
|
* @param {Uint8Array} A Uint8Array of bytes.
|
||||||
*/
|
*/
|
||||||
List.prototype.read = async function (bytes) {
|
List.prototype.read = async function (bytes) {
|
||||||
const reader = bytes.getReader();
|
const reader = stream.getReader(bytes);
|
||||||
while (true) {
|
while (true) {
|
||||||
const parsed = await packetParser.read(reader);
|
const parsed = await packetParser.read(reader);
|
||||||
|
|
||||||
|
@ -78,7 +80,7 @@ List.prototype.write = function () {
|
||||||
let bufferLength = 0;
|
let bufferLength = 0;
|
||||||
const minLength = 512;
|
const minLength = 512;
|
||||||
arr.push(packetParser.writeTag(this[i].tag));
|
arr.push(packetParser.writeTag(this[i].tag));
|
||||||
arr.push(packetbytes.transform((done, value) => {
|
arr.push(stream.transform(packetbytes, (done, value) => {
|
||||||
if (!done) {
|
if (!done) {
|
||||||
buffer.push(value);
|
buffer.push(value);
|
||||||
bufferLength += value.length;
|
bufferLength += value.length;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
* @requires asmcrypto.js
|
* @requires asmcrypto.js
|
||||||
* @requires crypto
|
* @requires crypto
|
||||||
* @requires enums
|
* @requires enums
|
||||||
|
* @requires stream
|
||||||
* @requires util
|
* @requires util
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ import { AES_CFB_Decrypt, AES_CFB_Encrypt } from 'asmcrypto.js/src/aes/cfb/expor
|
||||||
|
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
|
import stream from '../stream';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
const nodeCrypto = util.getNodeCrypto();
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
|
@ -61,7 +63,7 @@ function SymEncryptedIntegrityProtected() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SymEncryptedIntegrityProtected.prototype.read = async function (bytes) {
|
SymEncryptedIntegrityProtected.prototype.read = async function (bytes) {
|
||||||
const reader = bytes.getReader();
|
const reader = stream.getReader(bytes);
|
||||||
|
|
||||||
// - A one-octet version number. The only currently defined value is 1.
|
// - A one-octet version number. The only currently defined value is 1.
|
||||||
if (await reader.readByte() !== VERSION) {
|
if (await reader.readByte() !== VERSION) {
|
||||||
|
@ -92,7 +94,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlg
|
||||||
const prefix = util.concatUint8Array([prefixrandom, repeat]);
|
const prefix = util.concatUint8Array([prefixrandom, repeat]);
|
||||||
const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet
|
const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet
|
||||||
|
|
||||||
let [tohash, tohashClone] = util.concatUint8Array([bytes, mdc]).tee();
|
let [tohash, tohashClone] = stream.tee(util.concatUint8Array([bytes, mdc]));
|
||||||
const hash = crypto.hash.sha1(util.concatUint8Array([prefix, tohashClone]));
|
const hash = crypto.hash.sha1(util.concatUint8Array([prefix, tohashClone]));
|
||||||
tohash = util.concatUint8Array([tohash, hash]);
|
tohash = util.concatUint8Array([tohash, hash]);
|
||||||
|
|
||||||
|
@ -100,7 +102,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlg
|
||||||
this.encrypted = aesEncrypt(sessionKeyAlgorithm, util.concatUint8Array([prefix, tohash]), key);
|
this.encrypted = aesEncrypt(sessionKeyAlgorithm, util.concatUint8Array([prefix, tohash]), key);
|
||||||
} else {
|
} else {
|
||||||
this.encrypted = crypto.cfb.encrypt(prefixrandom, sessionKeyAlgorithm, tohash, key, false);
|
this.encrypted = crypto.cfb.encrypt(prefixrandom, sessionKeyAlgorithm, tohash, key, false);
|
||||||
this.encrypted = this.encrypted.subarray(0, prefix.length + tohash.length);
|
this.encrypted = stream.subarray(this.encrypted, 0, prefix.length + tohash.length);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -113,7 +115,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlg
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
SymEncryptedIntegrityProtected.prototype.decrypt = async function (sessionKeyAlgorithm, key) {
|
SymEncryptedIntegrityProtected.prototype.decrypt = async function (sessionKeyAlgorithm, key) {
|
||||||
const [encrypted, encryptedClone] = this.encrypted.tee();
|
const [encrypted, encryptedClone] = stream.tee(this.encrypted);
|
||||||
let decrypted;
|
let decrypted;
|
||||||
if (sessionKeyAlgorithm.substr(0, 3) === 'aes') { // AES optimizations. Native code for node, asmCrypto for browser.
|
if (sessionKeyAlgorithm.substr(0, 3) === 'aes') { // AES optimizations. Native code for node, asmCrypto for browser.
|
||||||
decrypted = aesDecrypt(sessionKeyAlgorithm, encrypted, key);
|
decrypted = aesDecrypt(sessionKeyAlgorithm, encrypted, key);
|
||||||
|
@ -122,20 +124,20 @@ SymEncryptedIntegrityProtected.prototype.decrypt = async function (sessionKeyAlg
|
||||||
}
|
}
|
||||||
|
|
||||||
let decryptedClone;
|
let decryptedClone;
|
||||||
[decrypted, decryptedClone] = decrypted.tee();
|
[decrypted, decryptedClone] = stream.tee(decrypted);
|
||||||
// there must be a modification detection code packet as the
|
// there must be a modification detection code packet as the
|
||||||
// last packet and everything gets hashed except the hash itself
|
// last packet and everything gets hashed except the hash itself
|
||||||
const encryptedPrefix = await encryptedClone.subarray(0, crypto.cipher[sessionKeyAlgorithm].blockSize + 2).readToEnd();
|
const encryptedPrefix = await stream.readToEnd(stream.subarray(encryptedClone, 0, crypto.cipher[sessionKeyAlgorithm].blockSize + 2));
|
||||||
const prefix = crypto.cfb.mdc(sessionKeyAlgorithm, key, encryptedPrefix);
|
const prefix = crypto.cfb.mdc(sessionKeyAlgorithm, key, encryptedPrefix);
|
||||||
let [bytes, bytesClone] = decrypted.subarray(0, -20).tee();
|
let [bytes, bytesClone] = stream.tee(stream.subarray(decrypted, 0, -20));
|
||||||
const tohash = util.concatUint8Array([prefix, bytes]);
|
const tohash = util.concatUint8Array([prefix, bytes]);
|
||||||
this.hash = util.Uint8Array_to_str(await crypto.hash.sha1(tohash).readToEnd());
|
this.hash = util.Uint8Array_to_str(await stream.readToEnd(crypto.hash.sha1(tohash)));
|
||||||
const mdc = util.Uint8Array_to_str(await decryptedClone.subarray(-20).readToEnd());
|
const mdc = util.Uint8Array_to_str(await stream.readToEnd(stream.subarray(decryptedClone, -20)));
|
||||||
|
|
||||||
if (this.hash !== mdc) {
|
if (this.hash !== mdc) {
|
||||||
throw new Error('Modification detected.');
|
throw new Error('Modification detected.');
|
||||||
} else {
|
} else {
|
||||||
await this.packets.read(bytesClone.subarray(0, -2));
|
await this.packets.read(stream.subarray(bytesClone, 0, -2));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -156,7 +158,7 @@ function aesEncrypt(algo, pt, key) {
|
||||||
return nodeEncrypt(algo, pt, key);
|
return nodeEncrypt(algo, pt, key);
|
||||||
} // asm.js fallback
|
} // asm.js fallback
|
||||||
const cfb = new AES_CFB_Encrypt(key);
|
const cfb = new AES_CFB_Encrypt(key);
|
||||||
return pt.transform((done, value) => {
|
return stream.transform(pt, (done, value) => {
|
||||||
if (!done) {
|
if (!done) {
|
||||||
return cfb.process(value).result;
|
return cfb.process(value).result;
|
||||||
}
|
}
|
||||||
|
@ -170,14 +172,14 @@ function aesDecrypt(algo, ct, key) {
|
||||||
pt = nodeDecrypt(algo, ct, key);
|
pt = nodeDecrypt(algo, ct, key);
|
||||||
} else { // asm.js fallback
|
} else { // asm.js fallback
|
||||||
const cfb = new AES_CFB_Decrypt(key);
|
const cfb = new AES_CFB_Decrypt(key);
|
||||||
pt = ct.transform((done, value) => {
|
pt = stream.transform(ct, (done, value) => {
|
||||||
if (!done) {
|
if (!done) {
|
||||||
return cfb.process(value).result;
|
return cfb.process(value).result;
|
||||||
}
|
}
|
||||||
return cfb.finish().result;
|
return cfb.finish().result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return pt.subarray(crypto.cipher[algo].blockSize + 2); // Remove random prefix
|
return stream.subarray(pt, crypto.cipher[algo].blockSize + 2); // Remove random prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
function nodeEncrypt(algo, prefix, pt, key) {
|
function nodeEncrypt(algo, prefix, pt, key) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import util from '../util';
|
import util from './util';
|
||||||
|
|
||||||
function concat(arrays) {
|
function concat(arrays) {
|
||||||
const readers = arrays.map(entry => entry.getReader());
|
const readers = arrays.map(getReader);
|
||||||
let current = 0;
|
let current = 0;
|
||||||
return new ReadableStream({
|
return new ReadableStream({
|
||||||
async pull(controller) {
|
async pull(controller) {
|
||||||
|
@ -17,7 +17,80 @@ function concat(arrays) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { concat };
|
function getReader(input) {
|
||||||
|
return new Reader(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transform(input, fn) {
|
||||||
|
if (util.isStream(input)) {
|
||||||
|
const reader = getReader(input);
|
||||||
|
return new ReadableStream({
|
||||||
|
async pull(controller) {
|
||||||
|
try {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
const result = await fn(done, value);
|
||||||
|
if (result) controller.enqueue(result);
|
||||||
|
else if (!done) await this.pull(controller); // ??? Chrome bug?
|
||||||
|
if (done) controller.close();
|
||||||
|
} catch(e) {
|
||||||
|
controller.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const result1 = fn(false, input);
|
||||||
|
const result2 = fn(true, undefined);
|
||||||
|
if (result1 && result2) return util.concatUint8Array([result1, result2]);
|
||||||
|
return result1 || result2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tee(input) {
|
||||||
|
if (util.isStream(input)) {
|
||||||
|
return input.tee();
|
||||||
|
}
|
||||||
|
return [input, input];
|
||||||
|
}
|
||||||
|
|
||||||
|
function subarray(input, begin=0, end=Infinity) {
|
||||||
|
if (util.isStream(input)) {
|
||||||
|
if (begin >= 0 && end >= 0) {
|
||||||
|
const reader = getReader(input);
|
||||||
|
let bytesRead = 0;
|
||||||
|
return new ReadableStream({
|
||||||
|
async pull (controller) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (!done && bytesRead < end) {
|
||||||
|
if (bytesRead + value.length >= begin) {
|
||||||
|
controller.enqueue(value.subarray(Math.max(begin - bytesRead, 0), end - bytesRead));
|
||||||
|
}
|
||||||
|
bytesRead += value.length;
|
||||||
|
await this.pull(controller); // Only necessary if the above call to enqueue() didn't happen
|
||||||
|
} else {
|
||||||
|
controller.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return new ReadableStream({
|
||||||
|
pull: async controller => {
|
||||||
|
// TODO: Don't read entire stream into memory here.
|
||||||
|
controller.enqueue((await readToEnd(input)).subarray(begin, end));
|
||||||
|
controller.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return input.subarray(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readToEnd(input, join) {
|
||||||
|
if (util.isStream(input)) {
|
||||||
|
return getReader(input).readToEnd(join);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default { concat, getReader, transform, tee, subarray, readToEnd };
|
||||||
|
|
||||||
|
|
||||||
/*const readerAcquiredMap = new Map();
|
/*const readerAcquiredMap = new Map();
|
||||||
|
@ -33,60 +106,23 @@ ReadableStream.prototype.getReader = function() {
|
||||||
};*/
|
};*/
|
||||||
|
|
||||||
|
|
||||||
ReadableStream.prototype.transform = function(fn) {
|
function Reader(input) {
|
||||||
const reader = this.getReader();
|
if (util.isStream(input)) {
|
||||||
return new ReadableStream({
|
const reader = input.getReader();
|
||||||
async pull(controller) {
|
this._read = reader.read.bind(reader);
|
||||||
try {
|
return;
|
||||||
const { done, value } = await reader.read();
|
|
||||||
const result = await fn(done, value);
|
|
||||||
if (result) controller.enqueue(result);
|
|
||||||
else if (!done) await this.pull(controller); // ??? Chrome bug?
|
|
||||||
if (done) controller.close();
|
|
||||||
} catch(e) {
|
|
||||||
controller.error(e);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
ReadableStream.prototype.readToEnd = async function(join) {
|
|
||||||
return this.getReader().readToEnd(join);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Uint8Array.prototype.getReader = function() {
|
|
||||||
let doneReading = false;
|
let doneReading = false;
|
||||||
const reader = Object.create(ReadableStreamDefaultReader.prototype);
|
this._read = async () => {
|
||||||
reader._read = async () => {
|
|
||||||
if (doneReading) {
|
if (doneReading) {
|
||||||
return { value: undefined, done: true };
|
return { value: undefined, done: true };
|
||||||
}
|
}
|
||||||
doneReading = true;
|
doneReading = true;
|
||||||
return { value: this, done: false };
|
return { value: input, done: false };
|
||||||
};
|
|
||||||
return reader;
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Uint8Array.prototype.transform = function(fn) {
|
Reader.prototype.read = async function() {
|
||||||
const result1 = fn(false, this);
|
|
||||||
const result2 = fn(true, undefined);
|
|
||||||
if (result1 && result2) return util.concatUint8Array([result1, result2]);
|
|
||||||
return result1 || result2;
|
|
||||||
};
|
|
||||||
|
|
||||||
Uint8Array.prototype.tee = function() {
|
|
||||||
return [this, this];
|
|
||||||
};
|
|
||||||
|
|
||||||
Uint8Array.prototype.readToEnd = async function() {
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ReadableStreamDefaultReader = new ReadableStream().getReader().constructor;
|
|
||||||
|
|
||||||
ReadableStreamDefaultReader.prototype._read = ReadableStreamDefaultReader.prototype.read;
|
|
||||||
ReadableStreamDefaultReader.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 };
|
||||||
|
@ -94,7 +130,7 @@ ReadableStreamDefaultReader.prototype.read = async function() {
|
||||||
return this._read();
|
return this._read();
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadableStreamDefaultReader.prototype.readLine = async function() {
|
Reader.prototype.readLine = async function() {
|
||||||
let buffer = [];
|
let buffer = [];
|
||||||
let returnVal;
|
let returnVal;
|
||||||
while (!returnVal) {
|
while (!returnVal) {
|
||||||
|
@ -116,7 +152,7 @@ ReadableStreamDefaultReader.prototype.readLine = async function() {
|
||||||
return returnVal;
|
return returnVal;
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadableStreamDefaultReader.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;
|
||||||
const byte = value[0];
|
const byte = value[0];
|
||||||
|
@ -124,7 +160,7 @@ ReadableStreamDefaultReader.prototype.readByte = async function() {
|
||||||
return byte;
|
return byte;
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadableStreamDefaultReader.prototype.readBytes = async function(length) {
|
Reader.prototype.readBytes = async function(length) {
|
||||||
const buffer = [];
|
const buffer = [];
|
||||||
let bufferLength = 0;
|
let bufferLength = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -143,20 +179,20 @@ ReadableStreamDefaultReader.prototype.readBytes = async function(length) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadableStreamDefaultReader.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;
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadableStreamDefaultReader.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));
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadableStreamDefaultReader.prototype.substream = function() {
|
Reader.prototype.substream = function() {
|
||||||
return new ReadableStream({ pull: pullFrom(this) });
|
return new ReadableStream({ pull: pullFrom(this) });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -171,35 +207,7 @@ function pullFrom(reader) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadableStream.prototype.subarray = function(begin=0, end=Infinity) {
|
Reader.prototype.readToEnd = async function(join=util.concatUint8Array) {
|
||||||
if (begin >= 0 && end >= 0) {
|
|
||||||
const reader = this.getReader();
|
|
||||||
let bytesRead = 0;
|
|
||||||
return new ReadableStream({
|
|
||||||
async pull (controller) {
|
|
||||||
const { done, value } = await reader.read();
|
|
||||||
if (!done && bytesRead < end) {
|
|
||||||
if (bytesRead + value.length >= begin) {
|
|
||||||
controller.enqueue(value.subarray(Math.max(begin - bytesRead, 0), end - bytesRead));
|
|
||||||
}
|
|
||||||
bytesRead += value.length;
|
|
||||||
await this.pull(controller); // Only necessary if the above call to enqueue() didn't happen
|
|
||||||
} else {
|
|
||||||
controller.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return new ReadableStream({
|
|
||||||
pull: async controller => {
|
|
||||||
// TODO: Don't read entire stream into memory here.
|
|
||||||
controller.enqueue((await this.readToEnd()).subarray(begin, end));
|
|
||||||
controller.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
ReadableStreamDefaultReader.prototype.readToEnd = async function(join=util.concatUint8Array) {
|
|
||||||
const result = [];
|
const result = [];
|
||||||
while (true) {
|
while (true) {
|
||||||
const { done, value } = await this.read();
|
const { done, value } = await this.read();
|
|
@ -29,7 +29,7 @@ import rfc2822 from 'address-rfc2822';
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import util from './util'; // re-import module to access util functions
|
import util from './util'; // re-import module to access util functions
|
||||||
import b64 from './encoding/base64';
|
import b64 from './encoding/base64';
|
||||||
import Stream from './type/stream';
|
import Stream from './stream';
|
||||||
|
|
||||||
const isIE11 = typeof navigator !== 'undefined' && !!navigator.userAgent.match(/Trident\/7\.0.*rv:([0-9.]+).*\).*Gecko$/);
|
const isIE11 = typeof navigator !== 'undefined' && !!navigator.userAgent.match(/Trident\/7\.0.*rv:([0-9.]+).*\).*Gecko$/);
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@ export default {
|
||||||
|
|
||||||
print_entire_stream: function (str, stream, fn = result => result) {
|
print_entire_stream: function (str, stream, fn = result => result) {
|
||||||
const teed = stream.tee();
|
const teed = stream.tee();
|
||||||
teed[1].readToEnd().then(result => {
|
stream.readToEnd(teed[1]).then(result => {
|
||||||
console.log(str + ': ', fn(result));
|
console.log(str + ': ', fn(result));
|
||||||
});
|
});
|
||||||
return teed[0];
|
return teed[0];
|
||||||
|
|
|
@ -9,7 +9,7 @@ const input = require('./testInputs.js');
|
||||||
|
|
||||||
function stringify(array) {
|
function stringify(array) {
|
||||||
if (openpgp.util.isStream(array)) {
|
if (openpgp.util.isStream(array)) {
|
||||||
return array.readToEnd().then(stringify);
|
return openpgp.stream.readToEnd(array).then(stringify);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!openpgp.util.isUint8Array(array)) {
|
if (!openpgp.util.isUint8Array(array)) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ describe('Streaming', function() {
|
||||||
data,
|
data,
|
||||||
passwords: ['test'],
|
passwords: ['test'],
|
||||||
});
|
});
|
||||||
const msgAsciiArmored = util.Uint8Array_to_str(await encrypted.data.readToEnd());
|
const msgAsciiArmored = util.Uint8Array_to_str(await openpgp.stream.readToEnd(encrypted.data));
|
||||||
const message = await openpgp.message.readArmored(msgAsciiArmored);
|
const message = await openpgp.message.readArmored(msgAsciiArmored);
|
||||||
const decrypted = await openpgp.decrypt({
|
const decrypted = await openpgp.decrypt({
|
||||||
passwords: ['test'],
|
passwords: ['test'],
|
||||||
|
@ -48,7 +48,7 @@ describe('Streaming', function() {
|
||||||
data,
|
data,
|
||||||
passwords: ['test'],
|
passwords: ['test'],
|
||||||
});
|
});
|
||||||
const msgAsciiArmored = util.Uint8Array_to_str(await encrypted.data.readToEnd());
|
const msgAsciiArmored = util.Uint8Array_to_str(await openpgp.stream.readToEnd(encrypted.data));
|
||||||
const message = await openpgp.message.readArmored(msgAsciiArmored);
|
const message = await openpgp.message.readArmored(msgAsciiArmored);
|
||||||
const decrypted = await openpgp.decrypt({
|
const decrypted = await openpgp.decrypt({
|
||||||
passwords: ['test'],
|
passwords: ['test'],
|
||||||
|
@ -85,6 +85,6 @@ describe('Streaming', function() {
|
||||||
format: 'binary'
|
format: 'binary'
|
||||||
});
|
});
|
||||||
expect(util.isStream(decrypted.data)).to.be.true;
|
expect(util.isStream(decrypted.data)).to.be.true;
|
||||||
expect(await decrypted.data.readToEnd()).to.deep.equal(util.concatUint8Array(plaintext));
|
expect(await openpgp.stream.readToEnd(decrypted.data)).to.deep.equal(util.concatUint8Array(plaintext));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user