| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- 'use strict';
- const internals = {
- suspectRx: /"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*\:/
- };
- exports.parse = function (text, ...args) {
- // Normalize arguments
- const firstOptions = typeof args[0] === 'object' && args[0];
- const reviver = args.length > 1 || !firstOptions ? args[0] : undefined;
- const options = (args.length > 1 && args[1]) || firstOptions || {};
- // Parse normally, allowing exceptions
- const obj = JSON.parse(text, reviver);
- // options.protoAction: 'error' (default) / 'remove' / 'ignore'
- if (options.protoAction === 'ignore') {
- return obj;
- }
- // Ignore null and non-objects
- if (!obj ||
- typeof obj !== 'object') {
- return obj;
- }
- // Check original string for potential exploit
- if (!text.match(internals.suspectRx)) {
- return obj;
- }
- // Scan result for proto keys
- exports.scan(obj, options);
- return obj;
- };
- exports.scan = function (obj, options = {}) {
- let next = [obj];
- while (next.length) {
- const nodes = next;
- next = [];
- for (const node of nodes) {
- if (Object.prototype.hasOwnProperty.call(node, '__proto__')) { // Avoid calling node.hasOwnProperty directly
- if (options.protoAction !== 'remove') {
- throw new SyntaxError('Object contains forbidden prototype property');
- }
- delete node.__proto__;
- }
- for (const key in node) {
- const value = node[key];
- if (value &&
- typeof value === 'object') {
- next.push(node[key]);
- }
- }
- }
- }
- };
- exports.safeParse = function (text, reviver) {
- try {
- return exports.parse(text, reviver);
- }
- catch (ignoreError) {
- return null;
- }
- };
|