@@ -524,3 +524,126 @@ test('scan handles optional options', t => {
524
524
t . doesNotThrow ( ( ) => j . scan ( { a : 'b' } ) )
525
525
t . end ( )
526
526
} )
527
+
528
+ test ( 'safe option' , t => {
529
+ t . test ( 'parse with safe=true returns null on __proto__' , t => {
530
+ const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
531
+ t . strictEqual ( j . parse ( text , { safe : true } ) , null )
532
+ t . end ( )
533
+ } )
534
+
535
+ t . test ( 'parse with safe=true returns null on constructor' , t => {
536
+ const text = '{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }'
537
+ t . strictEqual ( j . parse ( text , { safe : true } ) , null )
538
+ t . end ( )
539
+ } )
540
+
541
+ t . test ( 'parse with safe=true returns object when valid' , t => {
542
+ const text = '{ "a": 5, "b": 6 }'
543
+ t . deepEqual ( j . parse ( text , { safe : true } ) , { a : 5 , b : 6 } )
544
+ t . end ( )
545
+ } )
546
+
547
+ t . test ( 'parse with safe=true and reviver' , t => {
548
+ const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
549
+ const reviver = ( _key , value ) => {
550
+ return typeof value === 'number' ? value + 1 : value
551
+ }
552
+ t . strictEqual ( j . parse ( text , reviver , { safe : true } ) , null )
553
+ t . end ( )
554
+ } )
555
+
556
+ t . test ( 'parse with safe=true and protoAction=remove returns null' , t => {
557
+ const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
558
+ t . strictEqual ( j . parse ( text , { safe : true , protoAction : 'remove' } ) , null )
559
+ t . end ( )
560
+ } )
561
+
562
+ t . test ( 'parse with safe=true and constructorAction=remove returns null' , t => {
563
+ const text = '{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }'
564
+ t . strictEqual ( j . parse ( text , { safe : true , constructorAction : 'remove' } ) , null )
565
+ t . end ( )
566
+ } )
567
+
568
+ t . test ( 'parse with safe=false throws on __proto__' , t => {
569
+ const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
570
+ t . throws ( ( ) => j . parse ( text , { safe : false } ) , SyntaxError )
571
+ t . end ( )
572
+ } )
573
+
574
+ t . test ( 'parse with safe=false throws on constructor' , t => {
575
+ const text = '{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }'
576
+ t . throws ( ( ) => j . parse ( text , { safe : false } ) , SyntaxError )
577
+ t . end ( )
578
+ } )
579
+
580
+ t . test ( 'scan with safe=true returns null on __proto__' , t => {
581
+ const obj = JSON . parse ( '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }' )
582
+ t . strictEqual ( j . scan ( obj , { safe : true } ) , null )
583
+ t . end ( )
584
+ } )
585
+
586
+ t . test ( 'scan with safe=true returns null on constructor' , t => {
587
+ const obj = JSON . parse ( '{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }' )
588
+ t . strictEqual ( j . scan ( obj , { safe : true } ) , null )
589
+ t . end ( )
590
+ } )
591
+
592
+ t . test ( 'scan with safe=true returns object when valid' , t => {
593
+ const obj = { a : 5 , b : 6 }
594
+ t . deepEqual ( j . scan ( obj , { safe : true } ) , { a : 5 , b : 6 } )
595
+ t . end ( )
596
+ } )
597
+
598
+ t . test ( 'scan with safe=false throws on __proto__' , t => {
599
+ const obj = JSON . parse ( '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }' )
600
+ t . throws ( ( ) => j . scan ( obj , { safe : false } ) , SyntaxError )
601
+ t . end ( )
602
+ } )
603
+
604
+ t . test ( 'scan with safe=false throws on constructor' , t => {
605
+ const obj = JSON . parse ( '{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }' )
606
+ t . throws ( ( ) => j . scan ( obj , { safe : false } ) , SyntaxError )
607
+ t . end ( )
608
+ } )
609
+
610
+ t . test ( 'parse with safe=true returns null on nested __proto__' , t => {
611
+ const text = '{ "a": 5, "c": { "d": 0, "__proto__": { "y": 8 } } }'
612
+ t . strictEqual ( j . parse ( text , { safe : true } ) , null )
613
+ t . end ( )
614
+ } )
615
+
616
+ t . test ( 'parse with safe=true returns null on nested constructor' , t => {
617
+ const text = '{ "a": 5, "c": { "d": 0, "constructor": {"prototype": {"bar": "baz"}} } }'
618
+ t . strictEqual ( j . parse ( text , { safe : true } ) , null )
619
+ t . end ( )
620
+ } )
621
+
622
+ t . test ( 'parse with safe=true and protoAction=ignore returns object' , t => {
623
+ const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
624
+ t . deepEqual (
625
+ j . parse ( text , { safe : true , protoAction : 'ignore' } ) ,
626
+ JSON . parse ( text )
627
+ )
628
+ t . end ( )
629
+ } )
630
+
631
+ t . test ( 'parse with safe=true and constructorAction=ignore returns object' , t => {
632
+ const text = '{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }'
633
+ t . deepEqual (
634
+ j . parse ( text , { safe : true , constructorAction : 'ignore' } ) ,
635
+ JSON . parse ( text )
636
+ )
637
+ t . end ( )
638
+ } )
639
+
640
+ t . test ( 'should reset stackTraceLimit with safe option' , t => {
641
+ const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
642
+ Error . stackTraceLimit = 42
643
+ t . strictEqual ( j . parse ( text , { safe : true } ) , null )
644
+ t . same ( Error . stackTraceLimit , 42 )
645
+ t . end ( )
646
+ } )
647
+
648
+ t . end ( )
649
+ } )
0 commit comments