Ver código fonte

Encode documents with TextEncoder instead of utf16To8()

compress() percent-encoded the whole message, mapped the escapes back to
one character per byte, then walked that string again to fill a
Uint8Array. Peak allocation was roughly 20 times the payload: 1.8 GB for
a 90 MB base64 attachment, and a 120 MB one killed the renderer. On
ideographic text the old path also hit the V8 string length limit and
threw RangeError before it ran out of memory.

TextEncoder does the same conversion in one pass and allocates exactly
the payload: 90 MB in 257 ms instead of 3.3 s, and 120 MB no longer
crashes.

The two implementations produce identical bytes on every well-formed
input, checked in the browser over 20 000 random strings plus the
boundary cases. They differ only on lone surrogates, where
encodeURIComponent throws URIError and TextEncoder substitutes U+FFFD.
That is unreachable here: the only caller of cipher() passes
JSON.stringify output, which escapes lone surrogates.

utf16To8() had no other caller and is removed. stringToArraybuffer()
stays: its remaining callers pass the key, the password, the IV, the
salt and the AAD, which are latin1 by wire format, not UTF-8 text.
Gwénolé PAUGAM 1 mês atrás
pai
commit
7417854169
2 arquivos alterados com 2 adições e 24 exclusões
  1. 1 0
      CHANGELOG.md
  2. 1 24
      js/privatebin.js

+ 1 - 0
CHANGELOG.md

@@ -8,6 +8,7 @@
 * CHANGED: Removed the unmaintained js-verify and replaced it with fast-check library.
 * CHANGED: Added a `jsconfig.json` in order to check the types of JavaScript.
 * CHANGED: Removed support for Bootstrap 3 as it requires jQuery.
+* CHANGED: Encode documents with `TextEncoder` in `compress()`, instead of the `utf16To8()` percent-encoding round trip, which allocated ~20 times the payload
 * FIXED: Decode decompressed documents with `TextDecoder` instead of `utf8To16()`, which allocated ~3.4 GB for a 100 MB document and killed the tab (#2027)
 * FIXED: Prevent browsers guessing MIME types on JSON(LD) API responses (#164)
 * FIXED: Insert quoted base path into JSON-LD documents

+ 1 - 24
js/privatebin.js

@@ -992,27 +992,6 @@ window.PrivateBin = (function () {
          */
         const base58 = new baseX('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
 
-        /**
-         * convert DOMString (UTF-16) to a UTF-8 string stored in a DOMString
-         *
-         * URI encodes the message, then finds the percent encoded characters
-         * and transforms these hexadecimal representation back into bytes
-         *
-         * @name   CryptTool.utf16To8
-         * @function
-         * @private
-         * @param  {string} message UTF-16 string
-         * @return {string} UTF-8 string
-         */
-        function utf16To8(message) {
-            return encodeURIComponent(message).replace(
-                /%([0-9A-F]{2})/g,
-                function (match, hexCharacter) {
-                    return String.fromCharCode('0x' + hexCharacter);
-                }
-            );
-        }
-
         /**
          * convert ArrayBuffer into a UTF-8 string
          *
@@ -1064,9 +1043,7 @@ window.PrivateBin = (function () {
          * @return {ArrayBuffer} data
          */
         async function compress(message, mode, zlib) {
-            message = stringToArraybuffer(
-                utf16To8(message)
-            );
+            message = new TextEncoder().encode(message);
             if (mode === 'zlib') {
                 if (typeof zlib === 'undefined') {
                     throw new Error('Error compressing document, due to missing WebAssembly support.');