12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- '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, reviver, options) {
- // Normalize arguments
- if (!options) {
- if (reviver &&
- typeof reviver === 'object') {
- options = reviver;
- reviver = undefined;
- }
- else {
- options = {};
- }
- }
- // 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) {
- options = 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;
- }
- };
|