Make toStringTag checks resistant to spoofing.

This commit is contained in:
John-David Dalton
2016-10-08 10:43:08 -07:00
parent 52e96c38dc
commit 03a194fcb9

View File

@@ -93,6 +93,7 @@
genTag = '[object GeneratorFunction]', genTag = '[object GeneratorFunction]',
mapTag = '[object Map]', mapTag = '[object Map]',
numberTag = '[object Number]', numberTag = '[object Number]',
nullTag = '[object Null]',
objectTag = '[object Object]', objectTag = '[object Object]',
promiseTag = '[object Promise]', promiseTag = '[object Promise]',
proxyTag = '[object Proxy]', proxyTag = '[object Proxy]',
@@ -100,6 +101,7 @@
setTag = '[object Set]', setTag = '[object Set]',
stringTag = '[object String]', stringTag = '[object String]',
symbolTag = '[object Symbol]', symbolTag = '[object Symbol]',
undefinedTag = '[object Undefined]',
weakMapTag = '[object WeakMap]', weakMapTag = '[object WeakMap]',
weakSetTag = '[object WeakSet]'; weakSetTag = '[object WeakSet]';
@@ -1471,11 +1473,12 @@
Uint8Array = context.Uint8Array, Uint8Array = context.Uint8Array,
allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
getPrototype = overArg(Object.getPrototypeOf, Object), getPrototype = overArg(Object.getPrototypeOf, Object),
iteratorSymbol = Symbol ? Symbol.iterator : undefined,
objectCreate = Object.create, objectCreate = Object.create,
propertyIsEnumerable = objectProto.propertyIsEnumerable, propertyIsEnumerable = objectProto.propertyIsEnumerable,
splice = arrayProto.splice, splice = arrayProto.splice,
spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined; spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
symIterator = Symbol ? Symbol.iterator : undefined,
symToStringTag = Symbol ? Symbol.toStringTag : undefined;
var defineProperty = (function() { var defineProperty = (function() {
try { try {
@@ -3050,7 +3053,19 @@
* @returns {string} Returns the `toStringTag`. * @returns {string} Returns the `toStringTag`.
*/ */
function baseGetTag(value) { function baseGetTag(value) {
return objectToString.call(value); if (value == null) {
return value === undefined ? undefinedTag : nullTag;
}
value = Object(value);
if (symToStringTag && symToStringTag in value) {
var symbol = value[symToStringTag];
value[symToStringTag] = undefined;
}
var result = objectToString.call(value);
if (symbol) {
value[symToStringTag] = symbol;
}
return result;
} }
/** /**
@@ -3212,7 +3227,7 @@
* @returns {boolean} Returns `true` if `value` is an `arguments` object, * @returns {boolean} Returns `true` if `value` is an `arguments` object,
*/ */
function baseIsArguments(value) { function baseIsArguments(value) {
return isObjectLike(value) && objectToString.call(value) == argsTag; return isObjectLike(value) && baseGetTag(value) == argsTag;
} }
/** /**
@@ -3223,7 +3238,7 @@
* @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
*/ */
function baseIsArrayBuffer(value) { function baseIsArrayBuffer(value) {
return isObjectLike(value) && objectToString.call(value) == arrayBufferTag; return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
} }
/** /**
@@ -3234,7 +3249,7 @@
* @returns {boolean} Returns `true` if `value` is a date object, else `false`. * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
*/ */
function baseIsDate(value) { function baseIsDate(value) {
return isObjectLike(value) && objectToString.call(value) == dateTag; return isObjectLike(value) && baseGetTag(value) == dateTag;
} }
/** /**
@@ -3416,7 +3431,7 @@
* @returns {boolean} Returns `true` if `value` is a regexp, else `false`. * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
*/ */
function baseIsRegExp(value) { function baseIsRegExp(value) {
return isObject(value) && objectToString.call(value) == regexpTag; return isObject(value) && baseGetTag(value) == regexpTag;
} }
/** /**
@@ -3439,7 +3454,7 @@
*/ */
function baseIsTypedArray(value) { function baseIsTypedArray(value) {
return isObjectLike(value) && return isObjectLike(value) &&
isLength(value.length) && !!typedArrayTags[objectToString.call(value)]; isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
} }
/** /**
@@ -5976,7 +5991,7 @@
(Set && getTag(new Set) != setTag) || (Set && getTag(new Set) != setTag) ||
(WeakMap && getTag(new WeakMap) != weakMapTag)) { (WeakMap && getTag(new WeakMap) != weakMapTag)) {
getTag = function(value) { getTag = function(value) {
var result = objectToString.call(value), var result = baseGetTag(value),
Ctor = result == objectTag ? value.constructor : undefined, Ctor = result == objectTag ? value.constructor : undefined,
ctorString = Ctor ? toSource(Ctor) : undefined; ctorString = Ctor ? toSource(Ctor) : undefined;
@@ -11328,7 +11343,7 @@
*/ */
function isBoolean(value) { function isBoolean(value) {
return value === true || value === false || return value === true || value === false ||
(isObjectLike(value) && objectToString.call(value) == boolTag); (isObjectLike(value) && baseGetTag(value) == boolTag);
} }
/** /**
@@ -11539,7 +11554,7 @@
if (!isObjectLike(value)) { if (!isObjectLike(value)) {
return false; return false;
} }
return (objectToString.call(value) == errorTag) || return (baseGetTag(value) == errorTag) ||
(typeof value.message == 'string' && typeof value.name == 'string'); (typeof value.message == 'string' && typeof value.name == 'string');
} }
@@ -11593,7 +11608,7 @@
function isFunction(value) { function isFunction(value) {
// The use of `Object#toString` avoids issues with the `typeof` operator // The use of `Object#toString` avoids issues with the `typeof` operator
// in Safari 9 which returns 'object' for typed array and other constructors. // in Safari 9 which returns 'object' for typed array and other constructors.
var tag = isObject(value) ? objectToString.call(value) : ''; var tag = isObject(value) ? baseGetTag(value) : '';
return tag == funcTag || tag == genTag || tag == proxyTag; return tag == funcTag || tag == genTag || tag == proxyTag;
} }
@@ -11945,7 +11960,7 @@
*/ */
function isNumber(value) { function isNumber(value) {
return typeof value == 'number' || return typeof value == 'number' ||
(isObjectLike(value) && objectToString.call(value) == numberTag); (isObjectLike(value) && baseGetTag(value) == numberTag);
} }
/** /**
@@ -11977,7 +11992,7 @@
* // => true * // => true
*/ */
function isPlainObject(value) { function isPlainObject(value) {
if (!isObjectLike(value) || objectToString.call(value) != objectTag) { if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
return false; return false;
} }
var proto = getPrototype(value); var proto = getPrototype(value);
@@ -12077,7 +12092,7 @@
*/ */
function isString(value) { function isString(value) {
return typeof value == 'string' || return typeof value == 'string' ||
(!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag); (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);
} }
/** /**
@@ -12099,7 +12114,7 @@
*/ */
function isSymbol(value) { function isSymbol(value) {
return typeof value == 'symbol' || return typeof value == 'symbol' ||
(isObjectLike(value) && objectToString.call(value) == symbolTag); (isObjectLike(value) && baseGetTag(value) == symbolTag);
} }
/** /**
@@ -12181,7 +12196,7 @@
* // => false * // => false
*/ */
function isWeakSet(value) { function isWeakSet(value) {
return isObjectLike(value) && objectToString.call(value) == weakSetTag; return isObjectLike(value) && baseGetTag(value) == weakSetTag;
} }
/** /**
@@ -12266,8 +12281,8 @@
if (isArrayLike(value)) { if (isArrayLike(value)) {
return isString(value) ? stringToArray(value) : copyArray(value); return isString(value) ? stringToArray(value) : copyArray(value);
} }
if (iteratorSymbol && value[iteratorSymbol]) { if (symIterator && value[symIterator]) {
return iteratorToArray(value[iteratorSymbol]()); return iteratorToArray(value[symIterator]());
} }
var tag = getTag(value), var tag = getTag(value),
func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);
@@ -16946,8 +16961,8 @@
// Add lazy aliases. // Add lazy aliases.
lodash.prototype.first = lodash.prototype.head; lodash.prototype.first = lodash.prototype.head;
if (iteratorSymbol) { if (symIterator) {
lodash.prototype[iteratorSymbol] = wrapperToIterator; lodash.prototype[symIterator] = wrapperToIterator;
} }
return lodash; return lodash;
}); });