From 34d3ca7763b588ff000ed821f7f5574d63b4a665 Mon Sep 17 00:00:00 2001 From: Sven Slootweg Date: Wed, 25 Nov 2020 21:17:06 +0100 Subject: [PATCH] Skip assigning __proto__ instead of rejecting it during validation --- src/packages/create/index.js | 11 +++++++++-- .../create/validators/forbid-special-properties.js | 12 +----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/packages/create/index.js b/src/packages/create/index.js index bf1a326..0cef1cf 100644 --- a/src/packages/create/index.js +++ b/src/packages/create/index.js @@ -11,6 +11,13 @@ const forbidSpecialProperties = require("./validators/forbid-special-properties" const isErrorConstructor = require("./validators/is-error-constructor"); const isContextSchema = require("./validators/is-context-schema"); +function safeAssign(a, ... rest) { + let previousPrototype = a.__proto__; + Object.assign(a, ... rest); + a.__proto__ = previousPrototype; + return a; +} + module.exports = function createCustomErrorType(_name, _options) { let [ name, options ] = validateArguments(arguments, { name: [ required, isString ], @@ -48,7 +55,7 @@ module.exports = function createCustomErrorType(_name, _options) { } ErrorConstructor._assignDefaultProperties(this); - Object.assign(this, context); + safeAssign(this, context); }; ErrorConstructor._assignDefaultProperties = function (errorObject) { @@ -58,7 +65,7 @@ module.exports = function createCustomErrorType(_name, _options) { options.inheritsFrom._assignDefaultProperties(errorObject); } - Object.assign(errorObject, options.context); + safeAssign(errorObject, options.context); }; ErrorConstructor.prototype = Object.create(options.inheritsFrom.prototype); diff --git a/src/packages/create/validators/forbid-special-properties.js b/src/packages/create/validators/forbid-special-properties.js index f8d5e63..80a421f 100644 --- a/src/packages/create/validators/forbid-special-properties.js +++ b/src/packages/create/validators/forbid-special-properties.js @@ -6,13 +6,12 @@ const syncpipe = require("syncpipe"); const wrapError = require("@validatem/wrap-error"); const forbidden = require("@validatem/forbidden"); const allowExtraProperties = require("@validatem/allow-extra-properties"); -const ValidationError = require("@validatem/error"); const reservedProperties = require("../../reserved-properties"); let forbidSpecialProperty = wrapError("Reserved property name cannot be used", forbidden); -let baseChecks = syncpipe(reservedProperties, [ +module.exports = syncpipe(reservedProperties, [ (_) => _.filter((property) => property !== "constructor"), (_) => _.map((property) => { // NOTE: It is very important that `forbidSpecialProperty` below is wrapped in an array. Otherwise, for the `__proto__` property, it will actually treat the entire rules object as a validatem-special object due to its __proto__ being set directly to an object with the validatem-special marker... We're hacking around this by wrapping it in an array instead, which will not register as such. It's really a hack, though. @@ -21,12 +20,3 @@ let baseChecks = syncpipe(reservedProperties, [ (_) => fromEntries(_), (_) => allowExtraProperties(_) ]); - -module.exports = [ - baseChecks, - (value) => { - if (value.__proto__ != null) { - return new ValidationError("Reserved property name __proto__ cannot be used"); - } - } -];