123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- import { hasOwnProperty } from './object.js';
- /**
- * Get a property of a plain object
- * Throws an error in case the object is not a plain object or the
- * property is not defined on the object itself
- * @param {Object} object
- * @param {string} prop
- * @return {*} Returns the property value when safe
- */
- function getSafeProperty(object, prop) {
- // only allow getting safe properties of a plain object
- if (isPlainObject(object) && isSafeProperty(object, prop)) {
- return object[prop];
- }
- if (typeof object[prop] === 'function' && isSafeMethod(object, prop)) {
- throw new Error('Cannot access method "' + prop + '" as a property');
- }
- throw new Error('No access to property "' + prop + '"');
- }
- /**
- * Set a property on a plain object.
- * Throws an error in case the object is not a plain object or the
- * property would override an inherited property like .constructor or .toString
- * @param {Object} object
- * @param {string} prop
- * @param {*} value
- * @return {*} Returns the value
- */
- // TODO: merge this function into access.js?
- function setSafeProperty(object, prop, value) {
- // only allow setting safe properties of a plain object
- if (isPlainObject(object) && isSafeProperty(object, prop)) {
- object[prop] = value;
- return value;
- }
- throw new Error('No access to property "' + prop + '"');
- }
- function getSafeProperties(object) {
- return Object.keys(object).filter(prop => hasOwnProperty(object, prop));
- }
- function hasSafeProperty(object, prop) {
- return prop in object;
- }
- /**
- * Test whether a property is safe to use for an object.
- * For example .toString and .constructor are not safe
- * @param {string} prop
- * @return {boolean} Returns true when safe
- */
- function isSafeProperty(object, prop) {
- if (!object || typeof object !== 'object') {
- return false;
- }
- // SAFE: whitelisted
- // e.g length
- if (hasOwnProperty(safeNativeProperties, prop)) {
- return true;
- }
- // UNSAFE: inherited from Object prototype
- // e.g constructor
- if (prop in Object.prototype) {
- // 'in' is used instead of hasOwnProperty for nodejs v0.10
- // which is inconsistent on root prototypes. It is safe
- // here because Object.prototype is a root object
- return false;
- }
- // UNSAFE: inherited from Function prototype
- // e.g call, apply
- if (prop in Function.prototype) {
- // 'in' is used instead of hasOwnProperty for nodejs v0.10
- // which is inconsistent on root prototypes. It is safe
- // here because Function.prototype is a root object
- return false;
- }
- return true;
- }
- /**
- * Validate whether a method is safe.
- * Throws an error when that's not the case.
- * @param {Object} object
- * @param {string} method
- */
- // TODO: merge this function into assign.js?
- function validateSafeMethod(object, method) {
- if (!isSafeMethod(object, method)) {
- throw new Error('No access to method "' + method + '"');
- }
- }
- /**
- * Check whether a method is safe.
- * Throws an error when that's not the case (for example for `constructor`).
- * @param {Object} object
- * @param {string} method
- * @return {boolean} Returns true when safe, false otherwise
- */
- function isSafeMethod(object, method) {
- if (object === null || object === undefined || typeof object[method] !== 'function') {
- return false;
- }
- // UNSAFE: ghosted
- // e.g overridden toString
- // Note that IE10 doesn't support __proto__ and we can't do this check there.
- if (hasOwnProperty(object, method) && Object.getPrototypeOf && method in Object.getPrototypeOf(object)) {
- return false;
- }
- // SAFE: whitelisted
- // e.g toString
- if (hasOwnProperty(safeNativeMethods, method)) {
- return true;
- }
- // UNSAFE: inherited from Object prototype
- // e.g constructor
- if (method in Object.prototype) {
- // 'in' is used instead of hasOwnProperty for nodejs v0.10
- // which is inconsistent on root prototypes. It is safe
- // here because Object.prototype is a root object
- return false;
- }
- // UNSAFE: inherited from Function prototype
- // e.g call, apply
- if (method in Function.prototype) {
- // 'in' is used instead of hasOwnProperty for nodejs v0.10
- // which is inconsistent on root prototypes. It is safe
- // here because Function.prototype is a root object
- return false;
- }
- return true;
- }
- function isPlainObject(object) {
- return typeof object === 'object' && object && object.constructor === Object;
- }
- var safeNativeProperties = {
- length: true,
- name: true
- };
- var safeNativeMethods = {
- toString: true,
- valueOf: true,
- toLocaleString: true
- };
- export { getSafeProperty };
- export { setSafeProperty };
- export { isSafeProperty };
- export { hasSafeProperty };
- export { getSafeProperties };
- export { validateSafeMethod };
- export { isSafeMethod };
- export { isPlainObject };
|