UNPKG

4.77 kBJavaScriptView Raw
1import { hasOwnProperty } from './object.js';
2/**
3 * Get a property of a plain object
4 * Throws an error in case the object is not a plain object or the
5 * property is not defined on the object itself
6 * @param {Object} object
7 * @param {string} prop
8 * @return {*} Returns the property value when safe
9 */
10
11function getSafeProperty(object, prop) {
12 // only allow getting safe properties of a plain object
13 if (isPlainObject(object) && isSafeProperty(object, prop)) {
14 return object[prop];
15 }
16
17 if (typeof object[prop] === 'function' && isSafeMethod(object, prop)) {
18 throw new Error('Cannot access method "' + prop + '" as a property');
19 }
20
21 throw new Error('No access to property "' + prop + '"');
22}
23/**
24 * Set a property on a plain object.
25 * Throws an error in case the object is not a plain object or the
26 * property would override an inherited property like .constructor or .toString
27 * @param {Object} object
28 * @param {string} prop
29 * @param {*} value
30 * @return {*} Returns the value
31 */
32// TODO: merge this function into access.js?
33
34
35function setSafeProperty(object, prop, value) {
36 // only allow setting safe properties of a plain object
37 if (isPlainObject(object) && isSafeProperty(object, prop)) {
38 object[prop] = value;
39 return value;
40 }
41
42 throw new Error('No access to property "' + prop + '"');
43}
44
45function getSafeProperties(object) {
46 return Object.keys(object).filter(prop => hasOwnProperty(object, prop));
47}
48
49function hasSafeProperty(object, prop) {
50 return prop in object;
51}
52/**
53 * Test whether a property is safe to use for an object.
54 * For example .toString and .constructor are not safe
55 * @param {string} prop
56 * @return {boolean} Returns true when safe
57 */
58
59
60function isSafeProperty(object, prop) {
61 if (!object || typeof object !== 'object') {
62 return false;
63 } // SAFE: whitelisted
64 // e.g length
65
66
67 if (hasOwnProperty(safeNativeProperties, prop)) {
68 return true;
69 } // UNSAFE: inherited from Object prototype
70 // e.g constructor
71
72
73 if (prop in Object.prototype) {
74 // 'in' is used instead of hasOwnProperty for nodejs v0.10
75 // which is inconsistent on root prototypes. It is safe
76 // here because Object.prototype is a root object
77 return false;
78 } // UNSAFE: inherited from Function prototype
79 // e.g call, apply
80
81
82 if (prop in Function.prototype) {
83 // 'in' is used instead of hasOwnProperty for nodejs v0.10
84 // which is inconsistent on root prototypes. It is safe
85 // here because Function.prototype is a root object
86 return false;
87 }
88
89 return true;
90}
91/**
92 * Validate whether a method is safe.
93 * Throws an error when that's not the case.
94 * @param {Object} object
95 * @param {string} method
96 */
97// TODO: merge this function into assign.js?
98
99
100function validateSafeMethod(object, method) {
101 if (!isSafeMethod(object, method)) {
102 throw new Error('No access to method "' + method + '"');
103 }
104}
105/**
106 * Check whether a method is safe.
107 * Throws an error when that's not the case (for example for `constructor`).
108 * @param {Object} object
109 * @param {string} method
110 * @return {boolean} Returns true when safe, false otherwise
111 */
112
113
114function isSafeMethod(object, method) {
115 if (object === null || object === undefined || typeof object[method] !== 'function') {
116 return false;
117 } // UNSAFE: ghosted
118 // e.g overridden toString
119 // Note that IE10 doesn't support __proto__ and we can't do this check there.
120
121
122 if (hasOwnProperty(object, method) && Object.getPrototypeOf && method in Object.getPrototypeOf(object)) {
123 return false;
124 } // SAFE: whitelisted
125 // e.g toString
126
127
128 if (hasOwnProperty(safeNativeMethods, method)) {
129 return true;
130 } // UNSAFE: inherited from Object prototype
131 // e.g constructor
132
133
134 if (method in Object.prototype) {
135 // 'in' is used instead of hasOwnProperty for nodejs v0.10
136 // which is inconsistent on root prototypes. It is safe
137 // here because Object.prototype is a root object
138 return false;
139 } // UNSAFE: inherited from Function prototype
140 // e.g call, apply
141
142
143 if (method in Function.prototype) {
144 // 'in' is used instead of hasOwnProperty for nodejs v0.10
145 // which is inconsistent on root prototypes. It is safe
146 // here because Function.prototype is a root object
147 return false;
148 }
149
150 return true;
151}
152
153function isPlainObject(object) {
154 return typeof object === 'object' && object && object.constructor === Object;
155}
156
157var safeNativeProperties = {
158 length: true,
159 name: true
160};
161var safeNativeMethods = {
162 toString: true,
163 valueOf: true,
164 toLocaleString: true
165};
166export { getSafeProperty };
167export { setSafeProperty };
168export { isSafeProperty };
169export { hasSafeProperty };
170export { getSafeProperties };
171export { validateSafeMethod };
172export { isSafeMethod };
173export { isPlainObject };
\No newline at end of file