11'use strict'
22
33const test = require ( 'tape' ) . test
4- const j = require ( './index ' )
4+ const j = require ( '.. ' )
55
66test ( 'parse' , t => {
77 t . test ( 'parses object string' , t => {
@@ -324,40 +324,82 @@ test('parse', t => {
324324 t . end ( )
325325 } )
326326
327- t . end ( )
328- } )
329-
330- test ( 'scan' , t => {
331327 t . test ( 'sanitizes nested object string' , t => {
332328 const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
333- const obj = JSON . parse ( text )
334329
335- j . scan ( obj , { protoAction : 'remove' } )
330+ const obj = j . parse ( text , { protoAction : 'remove' } )
336331 t . deepEqual ( obj , { a : 5 , b : 6 , c : { d : 0 , e : 'text' , f : { g : 2 } } } )
337332 t . end ( )
338333 } )
339334
335+ t . test ( 'errors on constructor property' , t => {
336+ const text = '{ "a": 5, "b": 6, "constructor": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
337+
338+ t . throws ( ( ) => j . parse ( text ) , SyntaxError )
339+ t . end ( )
340+ } )
341+
340342 t . test ( 'errors on proto property' , t => {
341343 const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
342- const obj = JSON . parse ( text )
343344
344- t . throws ( ( ) => j . scan ( obj ) , SyntaxError )
345+ t . throws ( ( ) => j . parse ( text ) , SyntaxError )
346+ t . end ( )
347+ } )
348+
349+ t . test ( 'errors on constructor property' , t => {
350+ const text = '{ "a": 5, "b": 6, "constructor": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
351+
352+ t . throws ( ( ) => j . parse ( text ) , SyntaxError )
345353 t . end ( )
346354 } )
347355
348356 t . test ( 'does not break when hasOwnProperty is overwritten' , t => {
349357 const text = '{ "a": 5, "b": 6, "hasOwnProperty": "text", "__proto__": { "x": 7 } }'
350- const obj = JSON . parse ( text )
351358
352- j . scan ( obj , { protoAction : 'remove' } )
359+ const obj = j . parse ( text , { protoAction : 'remove' } )
353360 t . deepEqual ( obj , { a : 5 , b : 6 , hasOwnProperty : 'text' } )
354361 t . end ( )
355362 } )
356-
357363 t . end ( )
358364} )
359365
360366test ( 'safeParse' , t => {
367+ t . test ( 'parses buffer' , t => {
368+ t . strictEqual (
369+ j . safeParse ( Buffer . from ( '"X"' ) ) ,
370+ JSON . parse ( Buffer . from ( '"X"' ) )
371+ )
372+ t . end ( )
373+ } )
374+
375+ t . test ( 'sanitizes nested object string' , t => {
376+ const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
377+
378+ t . same ( j . safeParse ( text ) , null )
379+ t . end ( )
380+ } )
381+
382+ t . test ( 'returns null on constructor property' , t => {
383+ const text = '{ "a": 5, "b": 6, "constructor": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
384+
385+ t . same ( j . safeParse ( text ) , null )
386+ t . end ( )
387+ } )
388+
389+ t . test ( 'returns null on proto property' , t => {
390+ const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
391+
392+ t . same ( j . safeParse ( text ) , null )
393+ t . end ( )
394+ } )
395+
396+ t . test ( 'returns null on constructor property' , t => {
397+ const text = '{ "a": 5, "b": 6, "constructor": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
398+
399+ t . same ( j . safeParse ( text ) , null )
400+ t . end ( )
401+ } )
402+
361403 t . test ( 'parses object string' , t => {
362404 t . deepEqual (
363405 j . safeParse ( '{"a": 5, "b": 6}' ) ,
@@ -382,6 +424,22 @@ test('safeParse', t => {
382424 t . end ( )
383425 } )
384426
427+ t . test ( 'sanitizes object string (options)' , t => {
428+ t . deepEqual (
429+ j . safeParse ( '{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }' ) ,
430+ null
431+ )
432+ t . end ( )
433+ } )
434+
435+ t . test ( 'sanitizes object string (no prototype key)' , t => {
436+ t . deepEqual (
437+ j . safeParse ( '{"a": 5, "b": 6,"constructor":{"bar":"baz"} }' ) ,
438+ { a : 5 , b : 6 , constructor : { bar : 'baz' } }
439+ )
440+ t . end ( )
441+ } )
442+
385443 t . end ( )
386444} )
387445
@@ -404,3 +462,28 @@ test('parse buffer with BOM', t => {
404462 t . deepEqual ( j . parse ( buffer ) , theJson )
405463 t . end ( )
406464} )
465+
466+ test ( 'safeParse string with BOM' , t => {
467+ const theJson = { hello : 'world' }
468+ const buffer = Buffer . concat ( [
469+ Buffer . from ( [ 239 , 187 , 191 ] ) , // the utf8 BOM
470+ Buffer . from ( JSON . stringify ( theJson ) )
471+ ] )
472+ t . deepEqual ( j . safeParse ( buffer . toString ( ) ) , theJson )
473+ t . end ( )
474+ } )
475+
476+ test ( 'safeParse buffer with BOM' , t => {
477+ const theJson = { hello : 'world' }
478+ const buffer = Buffer . concat ( [
479+ Buffer . from ( [ 239 , 187 , 191 ] ) , // the utf8 BOM
480+ Buffer . from ( JSON . stringify ( theJson ) )
481+ ] )
482+ t . deepEqual ( j . safeParse ( buffer ) , theJson )
483+ t . end ( )
484+ } )
485+
486+ test ( 'scan handles optional options' , t => {
487+ t . doesNotThrow ( ( ) => j . scan ( { a : 'b' } ) )
488+ t . end ( )
489+ } )
0 commit comments