hildjj / node-cbor

Encode and decode CBOR documents, with both easy mode, streaming mode, and SAX-style evented mode.
MIT License
356 stars 73 forks source link

Webpack minimize causes cbor.encode to generate a different value #164

Closed noway closed 2 years ago

noway commented 2 years ago

Webpack minimize (https://webpack.js.org/configuration/optimization/#optimizationminimize, uses Terser) causes cbor.encode to produce a different value from when no minimize is applied.

I'm working on a minimum reproducable example for this, but essentially production build generates Uint8Array of 1661 length, and development build generates Uint8Array of 314 length.

I've pinpointed the bug to switching between optimization.minimize: false and optimization.minimize: true in my webpack config.

I'm working on a minimum reproducable example, but does this issue ring a bell? I searched github issues a bit, but there's nothing that precisely fits the bill.

I've put together the test case that fails for me on production/development builds.


  const fromHexString = (hexString: string) =>
    new Uint8Array(
      (hexString.match(/.{1,2}/g) ?? []).map((byte) => parseInt(byte, 16))
  );

  const bufferProtected_ = Buffer.from(fromHexString("a204456b65792d310126"))
  const buffer0 = Buffer.alloc(0)
  const bufferPayload_ = Buffer.from(fromHexString("a501781e6469643a7765623a6e7a63702e636f76696431392e6865616c74682e6e7a051a61819a0a041a7450400a627663a46840636f6e7465787482782668747470733a2f2f7777772e77332e6f72672f323031382f63726564656e7469616c732f7631782a68747470733a2f2f6e7a63702e636f76696431392e6865616c74682e6e7a2f636f6e74657874732f76316776657273696f6e65312e302e306474797065827456657269666961626c6543726564656e7469616c6f5075626c6963436f766964506173737163726564656e7469616c5375626a656374a369676976656e4e616d65644a61636b6a66616d696c794e616d656753706172726f7763646f626a313936302d30342d3136075060a4f54d4e304332be33ad78b1eafa4b"))

  const SigStructure = ["Signature1", bufferProtected_, buffer0, bufferPayload_];

  const unstableResult = cbor.encode(SigStructure);
hildjj commented 2 years ago

This is likely because the Buffer implementation you're using outside of the WebPack'd code is different from the one inside. The one inside got mangled, and the one outside didn't, so when node-cbor is trying to find out "is this a Buffer?" it doesn't get a match. This leads to the buffer being encoded as a plain object, which, if I recall correctly, serializes it as a string with comma-delimited decimal numbers, one per byte -- which will be much larger than the correct serialization.

To fix this, either pack all of your code together, or export the Buffer implementation from inside the packed code, then use that in your unpacked code. There are likely other ways to fix it, but let's see if this hypothesis proves out first.

noway commented 2 years ago

You're right, Buffer.name gets mangled and the encoding can't find a proper converter. I'll make a PR.

hildjj commented 2 years ago

Can you try passing in a genTypes option into the Encoder instance?

Encoder.encodeOne(Buffer.alloc(2), { genTypes: [Buffer, Encoder._pushBuffer] });

and if that doesn't work, try:

Encoder.encodeOne(Buffer.alloc(2), { genTypes: [Buffer.name, Encoder._pushBuffer] });
noway commented 2 years ago

That worked! Passing in my implementation of Buffer from import { Buffer } from "buffer" package using genTypes worked for me. Now I don't need the patch in https://github.com/hildjj/node-cbor/pull/166

I gonna close that pull request since this workaround solves it.

noway commented 2 years ago

Here's how i've done it: https://github.com/vaxxnz/nzcp-js/pull/60