Giter VIP home page Giter VIP logo

canonicalize's People

Contributors

erdtman avatar yacinehmito avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

canonicalize's Issues

Throw an error on Infinity of NaN values

According to the spec:

Note: Since Not a Number (NaN) and Infinity are not permitted in JSON, occurrences of NaN or Infinity MUST cause a compliant JCS implementation to terminate with an appropriate error.

I believe, this is currently not the case. Instead, JSON.canonicalize(Number.POSITIVE_INFINITY) currently returns null.

Hello 👋🏻 : FYI @truestamp/truestamp-canonify port

Hello, this is not an issue, but just to say thanks for the code which served as part of the base for our Typescript port.

https://github.com/truestamp/truestamp-canonify

You library, along with the reference code, was super helpful.

We ported this to typescript as it is important for us to not only gain the security advantages, but to further flesh out the test suite and allow use of the library in not only Node.js but also in Deno and the browser.

We'd love for you to take a look, and if there are any comments about our friendly fork please do let me know.

Out of curiosity I also copied your most current code over and ran our test suite against it. The following was the output (and will show a couple of the differences in how we're handling certain cases. I went through a number of manual test cases to see how JSON.stringify() is documented to work and tried to get the output to align closely with that.

Some of the differences are the handling of:

  • BigInt values should throw an Error as JSON.stringify() does. The user would need to call .toString() on the BigInt.
  • Serialization of function values to in Arrays/Objects to null, not undefined which is not valid JSON
  • Removal of Object key:value where the value is undefined (e.g. Symbol() values)

Here's the test output.

❯ npm t 

> @truestamp/[email protected] test
> jest

 PASS  tests/testdata.spec.ts
 FAIL  tests/basics.spec.ts
  ● serializing › should behave like JSON.stringify() for › BigInt should throw a TypeError

    expect(received).toThrow(expected)

    Expected substring: "BigInt value can't be serialized in JSON"
    Received message:   "Do not know how to serialize a BigInt"

          2 | export default function canonify(object: any): string | undefined {
          3 |   if (object === null || typeof object !== 'object') {
        > 4 |     return JSON.stringify(object);
            |                 ^
          5 |   }
          6 |
          7 |   if (object.toJSON instanceof Function) {

          at canonify (src/index.ts:4:17)
          at t (tests/basics.spec.ts:69:17)
          at Object.<anonymous> (node_modules/expect/build/toThrowMatchers.js:83:11)
          at Object.throwingMatcher [as toThrow] (node_modules/expect/build/index.js:382:21)
          at Object.<anonymous> (tests/basics.spec.ts:72:17)

      70 |       };
      71 |       expect(t).toThrow(TypeError);
    > 72 |       expect(t).toThrow("BigInt value can't be serialized in JSON");
         |                 ^
      73 |     });
      74 |
      75 |     // JSON.stringify('foo')

      at Object.<anonymous> (tests/basics.spec.ts:72:17)

  ● serializing › should behave like JSON.stringify() for › Array

    expect(received).toEqual(expected) // deep equality

    Expected: "[null,null,true,false,\"foo\",42,\"42\",null,null]"
    Received: "[null,null,true,false,\"foo\",42,\"42\",null,undefined]"

      93 |     test('Array', () => {
      94 |       const a = [undefined, null, true, false, "foo", 42, BigInt(42).toString(), Symbol('hello'), () => { }]
    > 95 |       expect(canonify(a)).toEqual('[null,null,true,false,"foo",42,"42",null,null]')
         |                           ^
      96 |     })
      97 |
      98 |     test('Array with String keys', () => {

      at Object.<anonymous> (tests/basics.spec.ts:95:27)

  ● serializing › should behave like JSON.stringify() for › Object

    expect(received).toEqual(expected) // deep equality

    Expected: "{\"big\":\"42\",\"f\":false,\"n\":null,\"num\":42,\"s\":\"string\",\"t\":true}"
    Received: "{\"big\":\"42\",\"f\":false,\"fun\":undefined,\"n\":null,\"num\":42,\"s\":\"string\",\"t\":true}"

      107 |     test('Object', () => {
      108 |       const o = { big: BigInt(42).toString(), f: false, fun: () => { }, n: null, num: 42, s: "string", sym: Symbol('hello'), t: true, u: undefined }
    > 109 |       expect(canonify(o)).toEqual('{"big":"42","f":false,"n":null,"num":42,"s":"string","t":true}')
          |                           ^
      110 |     })
      111 |
      112 |     // Standard data structures

      at Object.<anonymous> (tests/basics.spec.ts:109:27)

  ● serializing › should behave like JSON.stringify() for › Symbols

    expect(received).toEqual(expected) // deep equality

    Expected: "{}"
    Received: "{\"y\":undefined}"

      146 |       // @ts-ignore-next-line
      147 |       const e1 = { x: undefined, y: Object, z: Symbol('') }
    > 148 |       expect(canonify(e1)).toEqual('{}')
          |                            ^
      149 |
      150 |       // @ts-ignore-next-line
      151 |       const e2 = { [Symbol('foo')]: 'foo' }

      at Object.<anonymous> (tests/basics.spec.ts:148:28)

  ● serializing › arrays should handle › a one element function array

    expect(received).toEqual(expected) // deep equality

    Expected: "[null]"
    Received: "[undefined]"

      232 |     test('a one element function array', () => {
      233 |       let f = function foo() { }
    > 234 |       expect(canonify([f])).toEqual('[null]');
          |                             ^
      235 |     });
      236 |
      237 |     test('a nested array', () => {

      at Object.<anonymous> (tests/basics.spec.ts:234:29)

  ● serializing › objects should handle › an object with a function value

    expect(received).toEqual(expected) // deep equality

    Expected: "{}"
    Received: "{\"test\":undefined}"

      291 |     test('an object with a function value', () => {
      292 |       let f = function foo() { }
    > 293 |       expect(canonify({ test: f })).toEqual('{}');
          |                                     ^
      294 |     });
      295 |
      296 |     test('an object with a toJSON serializer function value', () => {

      at Object.<anonymous> (tests/basics.spec.ts:293:37)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 index.ts |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 failed, 1 passed, 2 total
Tests:       6 failed, 47 passed, 53 total
Snapshots:   0 total
Time:        4.451 s
Ran all test suites.

Cheers.

Glenn

Typescript return string or undefined?

Hi, I have read through your package and source code, and I'm wondering in what situation the serialize method will return undefined. Based on the type definition that is shown in this link, it seems like the output for typescript is shown as string | undefined.

However, when I compare this to the javascript implementation in this file, it appears this method can only return as a string.

Thank you for your contribution! :)

Objects with toJSON defined will use JSON.stringify instead of canonicalize causing the output to change when canonicalizing POJOs

Hi,

I ran into an issue with the order of properties when serializing Objection.js model instances using canonicalize. All Objection.js model instances have a toJSON method which exports the model as a simple JSON object after doing some mapping.

The problem occurs when JSON.stringify is used to serialize the Objection.js records. The order of properties becomes dependent on the implementation of JSON.stringify and not canonicalize.

This is not a problem when you're always working with Objection models, but this is not always the case. Especially when the JSON string is used to sign and verify the data has not been tampered using JWS.

When the signed data is sent back to the client, it becomes a POJO, so when canoicalize serializes it, it orders the properties as expected. This results in the properties being in a different order than when it was generated for signing.

I think the code needs to return serialize(object.toJSON() of object.toJSON() is defined.

Example of something that will cause problems after being converted to a POJO.

{
  a: 123,
  b: 456,
  toJSON: function() {
    return {
      b: this.b,
      a: this.a
    }
  }
}

Expected:

{"a":123,"":456}

Actual:

{"b":345,"a":123}

If I misunderstood the specification, then apologies. I just think the way it is now, creates uncertainties when a non-simple object is serialized by JSON.stringify

If it makes sense, I can create a PR to correct this behavior if that is preferred.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.