From 7130c2e7b05e43cf1a6eb0ea534982f4dff780ea Mon Sep 17 00:00:00 2001 From: Danny Coates Date: Mon, 27 Jul 2020 19:23:03 -0700 Subject: [PATCH] remove browser dependency on "buffer" --- app/crc32.js | 266 +++++++++++++++++++++++++ app/ece.js | 44 ++-- app/fxa.js | 9 +- app/utils.js | 8 + app/zip.js | 2 +- package-lock.json | 21 -- package.json | 3 +- test/frontend/tests/streaming-tests.js | 16 +- 8 files changed, 304 insertions(+), 65 deletions(-) create mode 100644 app/crc32.js diff --git a/app/crc32.js b/app/crc32.js new file mode 100644 index 00000000..f6f7f5b6 --- /dev/null +++ b/app/crc32.js @@ -0,0 +1,266 @@ +const LOOKUP = [ + 0x00000000, + 0x77073096, + 0xee0e612c, + 0x990951ba, + 0x076dc419, + 0x706af48f, + 0xe963a535, + 0x9e6495a3, + 0x0edb8832, + 0x79dcb8a4, + 0xe0d5e91e, + 0x97d2d988, + 0x09b64c2b, + 0x7eb17cbd, + 0xe7b82d07, + 0x90bf1d91, + 0x1db71064, + 0x6ab020f2, + 0xf3b97148, + 0x84be41de, + 0x1adad47d, + 0x6ddde4eb, + 0xf4d4b551, + 0x83d385c7, + 0x136c9856, + 0x646ba8c0, + 0xfd62f97a, + 0x8a65c9ec, + 0x14015c4f, + 0x63066cd9, + 0xfa0f3d63, + 0x8d080df5, + 0x3b6e20c8, + 0x4c69105e, + 0xd56041e4, + 0xa2677172, + 0x3c03e4d1, + 0x4b04d447, + 0xd20d85fd, + 0xa50ab56b, + 0x35b5a8fa, + 0x42b2986c, + 0xdbbbc9d6, + 0xacbcf940, + 0x32d86ce3, + 0x45df5c75, + 0xdcd60dcf, + 0xabd13d59, + 0x26d930ac, + 0x51de003a, + 0xc8d75180, + 0xbfd06116, + 0x21b4f4b5, + 0x56b3c423, + 0xcfba9599, + 0xb8bda50f, + 0x2802b89e, + 0x5f058808, + 0xc60cd9b2, + 0xb10be924, + 0x2f6f7c87, + 0x58684c11, + 0xc1611dab, + 0xb6662d3d, + 0x76dc4190, + 0x01db7106, + 0x98d220bc, + 0xefd5102a, + 0x71b18589, + 0x06b6b51f, + 0x9fbfe4a5, + 0xe8b8d433, + 0x7807c9a2, + 0x0f00f934, + 0x9609a88e, + 0xe10e9818, + 0x7f6a0dbb, + 0x086d3d2d, + 0x91646c97, + 0xe6635c01, + 0x6b6b51f4, + 0x1c6c6162, + 0x856530d8, + 0xf262004e, + 0x6c0695ed, + 0x1b01a57b, + 0x8208f4c1, + 0xf50fc457, + 0x65b0d9c6, + 0x12b7e950, + 0x8bbeb8ea, + 0xfcb9887c, + 0x62dd1ddf, + 0x15da2d49, + 0x8cd37cf3, + 0xfbd44c65, + 0x4db26158, + 0x3ab551ce, + 0xa3bc0074, + 0xd4bb30e2, + 0x4adfa541, + 0x3dd895d7, + 0xa4d1c46d, + 0xd3d6f4fb, + 0x4369e96a, + 0x346ed9fc, + 0xad678846, + 0xda60b8d0, + 0x44042d73, + 0x33031de5, + 0xaa0a4c5f, + 0xdd0d7cc9, + 0x5005713c, + 0x270241aa, + 0xbe0b1010, + 0xc90c2086, + 0x5768b525, + 0x206f85b3, + 0xb966d409, + 0xce61e49f, + 0x5edef90e, + 0x29d9c998, + 0xb0d09822, + 0xc7d7a8b4, + 0x59b33d17, + 0x2eb40d81, + 0xb7bd5c3b, + 0xc0ba6cad, + 0xedb88320, + 0x9abfb3b6, + 0x03b6e20c, + 0x74b1d29a, + 0xead54739, + 0x9dd277af, + 0x04db2615, + 0x73dc1683, + 0xe3630b12, + 0x94643b84, + 0x0d6d6a3e, + 0x7a6a5aa8, + 0xe40ecf0b, + 0x9309ff9d, + 0x0a00ae27, + 0x7d079eb1, + 0xf00f9344, + 0x8708a3d2, + 0x1e01f268, + 0x6906c2fe, + 0xf762575d, + 0x806567cb, + 0x196c3671, + 0x6e6b06e7, + 0xfed41b76, + 0x89d32be0, + 0x10da7a5a, + 0x67dd4acc, + 0xf9b9df6f, + 0x8ebeeff9, + 0x17b7be43, + 0x60b08ed5, + 0xd6d6a3e8, + 0xa1d1937e, + 0x38d8c2c4, + 0x4fdff252, + 0xd1bb67f1, + 0xa6bc5767, + 0x3fb506dd, + 0x48b2364b, + 0xd80d2bda, + 0xaf0a1b4c, + 0x36034af6, + 0x41047a60, + 0xdf60efc3, + 0xa867df55, + 0x316e8eef, + 0x4669be79, + 0xcb61b38c, + 0xbc66831a, + 0x256fd2a0, + 0x5268e236, + 0xcc0c7795, + 0xbb0b4703, + 0x220216b9, + 0x5505262f, + 0xc5ba3bbe, + 0xb2bd0b28, + 0x2bb45a92, + 0x5cb36a04, + 0xc2d7ffa7, + 0xb5d0cf31, + 0x2cd99e8b, + 0x5bdeae1d, + 0x9b64c2b0, + 0xec63f226, + 0x756aa39c, + 0x026d930a, + 0x9c0906a9, + 0xeb0e363f, + 0x72076785, + 0x05005713, + 0x95bf4a82, + 0xe2b87a14, + 0x7bb12bae, + 0x0cb61b38, + 0x92d28e9b, + 0xe5d5be0d, + 0x7cdcefb7, + 0x0bdbdf21, + 0x86d3d2d4, + 0xf1d4e242, + 0x68ddb3f8, + 0x1fda836e, + 0x81be16cd, + 0xf6b9265b, + 0x6fb077e1, + 0x18b74777, + 0x88085ae6, + 0xff0f6a70, + 0x66063bca, + 0x11010b5c, + 0x8f659eff, + 0xf862ae69, + 0x616bffd3, + 0x166ccf45, + 0xa00ae278, + 0xd70dd2ee, + 0x4e048354, + 0x3903b3c2, + 0xa7672661, + 0xd06016f7, + 0x4969474d, + 0x3e6e77db, + 0xaed16a4a, + 0xd9d65adc, + 0x40df0b66, + 0x37d83bf0, + 0xa9bcae53, + 0xdebb9ec5, + 0x47b2cf7f, + 0x30b5ffe9, + 0xbdbdf21c, + 0xcabac28a, + 0x53b39330, + 0x24b4a3a6, + 0xbad03605, + 0xcdd70693, + 0x54de5729, + 0x23d967bf, + 0xb3667a2e, + 0xc4614ab8, + 0x5d681b02, + 0x2a6f2b94, + 0xb40bbe37, + 0xc30c8ea1, + 0x5a05df1b, + 0x2d02ef8d +]; + +module.exports = function crc32(uint8Array, previous) { + let crc = previous === 0 ? 0 : ~~previous ^ -1; + for (let i = 0; i < uint8Array.byteLength; i++) { + crc = LOOKUP[(crc ^ uint8Array[i]) & 0xff] ^ (crc >>> 8); + } + return (crc ^ -1) >>> 0; +}; diff --git a/app/ece.js b/app/ece.js index 4cd6b45e..7fff87b4 100644 --- a/app/ece.js +++ b/app/ece.js @@ -1,5 +1,5 @@ -import 'buffer'; import { transformStream } from './streams'; +import { concat } from './utils'; const NONCE_LENGTH = 12; const TAG_LENGTH = 16; @@ -81,19 +81,18 @@ class ECETransformer { ) ); - return Buffer.from(base.slice(0, NONCE_LENGTH)); + return base.slice(0, NONCE_LENGTH); } generateNonce(seq) { if (seq > 0xffffffff) { throw new Error('record sequence number exceeds limit'); } - const nonce = Buffer.from(this.nonceBase); - const m = nonce.readUIntBE(nonce.length - 4, 4); + const nonce = new DataView(this.nonceBase.slice()); + const m = nonce.getUint32(nonce.byteLength - 4); const xor = (m ^ seq) >>> 0; //forces unsigned int xor - nonce.writeUIntBE(xor, nonce.length - 4, 4); - - return nonce; + nonce.setUint32(nonce.byteLength - 4, xor); + return new Uint8Array(nonce.buffer); } pad(data, isLast) { @@ -103,14 +102,11 @@ class ECETransformer { } if (isLast) { - const padding = Buffer.alloc(1); - padding.writeUInt8(2, 0); - return Buffer.concat([data, padding]); + return concat(data, Uint8Array.of(2)); } else { - const padding = Buffer.alloc(this.rs - len - TAG_LENGTH); - padding.fill(0); - padding.writeUInt8(1, 0); - return Buffer.concat([data, padding]); + const padding = new Uint8Array(this.rs - len - TAG_LENGTH); + padding[0] = 1; + return concat(data, padding); } } @@ -133,10 +129,9 @@ class ECETransformer { } createHeader() { - const nums = Buffer.alloc(5); - nums.writeUIntBE(this.rs, 0, 4); - nums.writeUIntBE(0, 4, 1); - return Buffer.concat([Buffer.from(this.salt), nums]); + const nums = new DataView(new ArrayBuffer(5)); + nums.setUint32(0, this.rs); + return concat(new Uint8Array(this.salt), new Uint8Array(nums.buffer)); } readHeader(buffer) { @@ -144,9 +139,10 @@ class ECETransformer { throw new Error('chunk too small for reading header'); } const header = {}; - header.salt = buffer.buffer.slice(0, KEY_LENGTH); - header.rs = buffer.readUIntBE(KEY_LENGTH, 4); - const idlen = buffer.readUInt8(KEY_LENGTH + 4); + const dv = new DataView(buffer.buffer); + header.salt = buffer.slice(0, KEY_LENGTH); + header.rs = dv.getUint32(KEY_LENGTH); + const idlen = dv.getUint8(KEY_LENGTH + 4); header.length = idlen + KEY_LENGTH + 5; return header; } @@ -158,7 +154,7 @@ class ECETransformer { this.key, this.pad(buffer, isLast) ); - return Buffer.from(encrypted); + return new Uint8Array(encrypted); } async decryptRecord(buffer, seq, isLast) { @@ -173,7 +169,7 @@ class ECETransformer { buffer ); - return this.unpad(Buffer.from(data), isLast); + return this.unpad(new Uint8Array(data), isLast); } async start(controller) { @@ -214,7 +210,7 @@ class ECETransformer { await this.transformPrevChunk(false, controller); } this.firstchunk = false; - this.prevChunk = Buffer.from(chunk.buffer); + this.prevChunk = new Uint8Array(chunk.buffer); } async flush(controller) { diff --git a/app/fxa.js b/app/fxa.js index 7827d33e..6af7da27 100644 --- a/app/fxa.js +++ b/app/fxa.js @@ -1,5 +1,5 @@ /* global AUTH_CONFIG */ -import { arrayToB64, b64ToArray } from './utils'; +import { arrayToB64, b64ToArray, concat } from './utils'; const encoder = new TextEncoder(); const decoder = new TextDecoder(); @@ -23,13 +23,6 @@ function getOtherInfo(enc) { return result; } -function concat(b1, b2) { - const result = new Uint8Array(b1.length + b2.length); - result.set(b1, 0); - result.set(b2, b1.length); - return result; -} - async function concatKdf(key, enc) { if (key.length !== 32) { throw new Error('unsupported key length'); diff --git a/app/utils.js b/app/utils.js index a71cd70f..bbe20d23 100644 --- a/app/utils.js +++ b/app/utils.js @@ -272,7 +272,15 @@ function setTranslate(t) { translate = t; } +function concat(b1, b2) { + const result = new Uint8Array(b1.length + b2.length); + result.set(b1, 0); + result.set(b2, b1.length); + return result; +} + module.exports = { + concat, locale, fadeOut, delay, diff --git a/app/zip.js b/app/zip.js index 1363da82..bf62726f 100644 --- a/app/zip.js +++ b/app/zip.js @@ -1,4 +1,4 @@ -import crc32 from 'crc/crc32'; +import crc32 from './crc32'; const encoder = new TextEncoder(); diff --git a/package-lock.json b/package-lock.json index 182ecae2..6a6525cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3584,27 +3584,6 @@ "safe-buffer": "^5.0.1" } }, - "crc": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "dev": true, - "requires": { - "buffer": "^5.1.0" - }, - "dependencies": { - "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - } - } - }, "create-ecdh": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", diff --git a/package.json b/package.json index c7456b91..c3425f2b 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,6 @@ "content-disposition": "^0.5.3", "copy-webpack-plugin": "^5.0.5", "core-js": "^3.4.0", - "crc": "^3.8.0", "cross-env": "^6.0.3", "css-loader": "^3.2.0", "css-mqpacker": "^7.0.0", @@ -150,7 +149,7 @@ "node-fetch": "^2.6.0", "redis": "^3.0.2", "selenium-standalone": "^6.15.6", - "ua-parser-js": "^0.7.20" + "ua-parser-js": "^0.7.21" }, "availableLanguages": [ "en-US", diff --git a/test/frontend/tests/streaming-tests.js b/test/frontend/tests/streaming-tests.js index 0e690505..b2a88f45 100644 --- a/test/frontend/tests/streaming-tests.js +++ b/test/frontend/tests/streaming-tests.js @@ -1,12 +1,11 @@ const ece = require('http_ece'); -require('buffer'); import assert from 'assert'; import Archive from '../../../app/archive'; import { b64ToArray } from '../../../app/utils'; import { blobStream, concatStream } from '../../../app/streams'; import { decryptStream, encryptStream } from '../../../app/ece.js'; -import { encryptedSize } from '../../../app/utils'; +import { encryptedSize, concat } from '../../../app/utils'; const rs = 36; @@ -75,15 +74,15 @@ describe('Streaming', function() { const encStream = encryptStream(stream, key, rs, salt); const reader = encStream.getReader(); - let result = Buffer.from([]); + let result = new Uint8Array(0); let state = await reader.read(); while (!state.done) { - result = Buffer.concat([result, state.value]); + result = concat(result, state.value); state = await reader.read(); } - assert.deepEqual(result, encrypted); + assert.deepEqual(result, new Uint8Array(encrypted)); }); it('can decrypt', async function() { @@ -91,15 +90,14 @@ describe('Streaming', function() { const decStream = decryptStream(stream, key, rs); const reader = decStream.getReader(); - let result = Buffer.from([]); + let result = new Uint8Array(0); let state = await reader.read(); while (!state.done) { - result = Buffer.concat([result, state.value]); + result = concat(result, state.value); state = await reader.read(); } - - assert.deepEqual(result, decrypted); + assert.deepEqual(result, new Uint8Array(decrypted)); }); });