Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

number().integer() can fail for values outside MAX_SAFE_INTEGER #1143

Closed
kanongil opened this issue Mar 31, 2017 · 17 comments
Closed

number().integer() can fail for values outside MAX_SAFE_INTEGER #1143

kanongil opened this issue Mar 31, 2017 · 17 comments
Assignees
Labels
bug Bug or defect
Milestone

Comments

@kanongil
Copy link
Contributor

kanongil commented Mar 31, 2017

Context

  • node version: v7.5.0
  • joi version: v10.3.1
  • environment (node, browser): node
  • used with (hapi, standalone, ...): standalone
  • any other relevant information:

What are you trying to achieve or the steps to reproduce ?

const schema = Joi.number().integer();
schema.validate('90071992547409910.1');

Which result you had ?

{ error: null, value: 90071992547409900 }

What did you expect ?

Some kind of error, like:

{ error: 
   { ValidationError: "value" must be an integer
     isJoi: true,
     name: 'ValidationError',
     details: [ [Object] ],
     _object: '90071992547409910.1',
     annotate: [Function] },
  value: '90071992547409910.1' }
@WesTyler
Copy link
Contributor

WesTyler commented Mar 31, 2017

I would argue that this is a failing in Node (because the number is outside of the recognized range of integers):

> const tooBig = 90071992547409910.1;
> tooBig
90071992547409900

If Node can't even assign the value to a variable and remember it correctly, I'm not sure we can expect parseInt and parseFloat (used in Hoek.isInteger) to handle it properly. Unless we assume that anything larger than Number.MAX_SAFE_INTEGER can be assumed not to be an integer.

@WesTyler
Copy link
Contributor

FWIW, number().integer() uses Hoek.isInteger behind the scenes, which uses 3 checks:

typeof value === 'number' &&
parseFloat(value) === parseInt(value, 10) &&
!isNaN(value)

Node just can't hang, which is why this is passing validation:

> typeof 90071992547409910.1
'number'
> parseInt(90071992547409910.1)
90071992547409900
> parseFloat(90071992547409910.1)
90071992547409900
> parseFloat(90071992547409910.1) === parseInt(90071992547409910.1)
true

@Marsup
Copy link
Collaborator

Marsup commented Mar 31, 2017

I think it would be preferable that joi always fails if Number.isSafeInteger returns false, wdyt ?

@kanongil
Copy link
Contributor Author

kanongil commented Mar 31, 2017

Probably the Hoek method can be replaced with:

typeof value === 'number' && Number.isSafeInteger(value)

FYI, I validated that node 4 supports Number.isSafeInteger()

@Marsup
Copy link
Collaborator

Marsup commented Mar 31, 2017

The problem also lies in joi, if you don't have integer() and parse the same number, it'll still give you nonsense.

@kanongil
Copy link
Contributor Author

The problem also lies in joi, if you don't have integer() and parse the same number, it'll still give you nonsense.

That part I expect as a JS quirk. It's only the integer handling that bugs me.

@Marsup
Copy link
Collaborator

Marsup commented Mar 31, 2017

I'm seeing this as the API consumer, if you provide such a number and the backend is not able to parse it correctly, it should reject it, whether you asked for an integer or not.

@kanongil
Copy link
Contributor Author

The problem is that there are valid use-cases for numbers outside the safe integer range, and it is part of how floating point works.

"Fixing" the range for all numbers is likely to cause problems for such use-cases, while it most likely won't make any difference for those outside it.

Essentially, number() should just be parseFloat(), or the actual provided number.

@Marsup
Copy link
Collaborator

Marsup commented Mar 31, 2017

@nlf thoughts ? Are you willing to patch hoek or do I add this check in joi's integer() ?

@nlf
Copy link
Member

nlf commented Mar 31, 2017

sounds like this should probably get patched in hoek

@Marsup
Copy link
Collaborator

Marsup commented Mar 31, 2017

Now it's been discussed on hoek, I'm tempted to qualify this as a bug, as previous behavior was unsafe, thoughts ? (meaning patch version)

@kanongil
Copy link
Contributor Author

kanongil commented Mar 31, 2017

What I originally reported is definitely a bug as it accepted a number followed by a dot + another number, which will never be an integer.

Regarding the specific fix, I would tend to agree on treating this as a bugfix, though as usual it might break existing code that inadvertently relies on this. For semver purposes, it comes down to how it is described in the api, which is currently:

Requires the number to be an integer (no floating point).

@Marsup Marsup self-assigned this Apr 1, 2017
@Marsup Marsup added the bug Bug or defect label Apr 1, 2017
@Marsup Marsup added this to the 10.3.4 milestone Apr 1, 2017
@Marsup Marsup closed this as completed in c075a95 Apr 1, 2017
@rictorres
Copy link

shouldn't this be tagged as a major?

we use int identifiers in our database, so something like 64811494532973582 was being validated just "fine" with Joi.number().integer().positive().min(1).required().

@Marsup
Copy link
Collaborator

Marsup commented Apr 3, 2017

If you provide 64811494532973582 to javascript, you get 64811494532973580, do you really consider it safe ? I know I wouldn't.

@nlf
Copy link
Member

nlf commented Apr 3, 2017

i agree, this isn't a breaking change. while it may be a change in behavior, it's fixing a bug. with the previous behavior if you had a validator such as the one in your example in a handler in hapi, and you were to make a request with an id like the one in your example, by default the id would've been changed and you would've been potentially manipulating an object you didn't expect.

this fix pushes you to find these potential issues and find a safer way to validate your inputs to make sure you're getting reliable and consistent results. it may be inconvenient right now, but it's a win overall and fixes what could be a pretty significant bug in some cases.

@WesTyler
Copy link
Contributor

WesTyler commented Apr 3, 2017

while it may be a change in behavior, it's fixing a bug.

I agree wholeheartedly.

@rictorres
Copy link

rictorres commented Apr 3, 2017

If you provide 64811494532973582 to javascript, you get 64811494532973580, do you really consider it safe ? I know I wouldn't.

my mistake was not actually understanding how joi was validating my input.

@nlf, on a second thought, i totally agree with you.

thanks for all your responses :)

@lock lock bot locked as resolved and limited conversation to collaborators Jan 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Bug or defect
Projects
None yet
Development

No branches or pull requests

5 participants