Skip to content

Commit

Permalink
fix(ses): Do not get confused by well-known look-alikes
Browse files Browse the repository at this point in the history
  • Loading branch information
mhofman committed Mar 15, 2022
1 parent ddb2f69 commit 9dcfc6c
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 20 deletions.
65 changes: 45 additions & 20 deletions packages/ses/src/whitelist-intrinsics.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,35 +45,21 @@

import { whitelist, FunctionInstance, isAccessorPermit } from './whitelist.js';
import {
Map,
String,
TypeError,
arrayFilter,
arrayIncludes,
arrayMap,
entries,
getOwnPropertyDescriptor,
getPrototypeOf,
isObject,
mapGet,
objectHasOwnProperty,
ownKeys,
stringSlice,
} from './commons.js';

/**
* asStringPropertyName()
*
* @param {string} path
* @param {string | symbol} prop
*/
function asStringPropertyName(path, prop) {
if (typeof prop === 'string') {
return prop;
}

if (typeof prop === 'symbol') {
return `@@${stringSlice(String(prop), 14, -1)}`;
}

throw new TypeError(`Unexpected property name type ${path} ${prop}`);
}

/**
* whitelistIntrinsics()
* Removes all non-allowed properties found by recursively and
Expand All @@ -86,9 +72,48 @@ export default function whitelistIntrinsics(
intrinsics,
markVirtualizedNativeFunction,
) {
// These primities are allowed allowed for permits.
// These primitives are allowed allowed for permits.
const primitives = ['undefined', 'boolean', 'number', 'string', 'symbol'];

// These symbols are allowed as well-known symbols
const wellKnownSymbolNames = new Map(
intrinsics.Symbol
? arrayMap(
arrayFilter(
entries(whitelist.Symbol),
([name, permit]) =>
permit === 'symbol' &&
typeof intrinsics.Symbol[name] === 'symbol',
),
([name]) => [intrinsics.Symbol[name], `@@${name}`],
)
: [],
);

/**
* asStringPropertyName()
*
* @param {string} path
* @param {string | symbol} prop
*/
function asStringPropertyName(path, prop) {
if (typeof prop === 'string') {
return prop;
}

const wellKnownSymbol = mapGet(wellKnownSymbolNames, prop);

if (typeof prop === 'symbol') {
if (wellKnownSymbol) {
return wellKnownSymbol;
} else {
return `Unique${String(prop)}`;
}
}

throw new TypeError(`Unexpected property name type ${path} ${prop}`);
}

/*
* visitPrototype()
* Validate the object's [[prototype]] against a permit.
Expand Down
41 changes: 41 additions & 0 deletions packages/ses/test/test-whitelist-intrinsics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import test from 'ava';
import '../index.js';
import whitelistIntrinsics from '../src/whitelist-intrinsics.js';

// eslint-disable-next-line no-eval
if (!eval.toString().includes('native code')) {
throw new TypeError('Module "esm" enabled: aborting');
}

test('whitelistIntrinsics - Well-known symbols', t => {
const SymbolIterator = Symbol('Symbol.iterator');
const RogueSymbolIterator = Symbol('Symbol.iterator');
const ArrayProto = { [RogueSymbolIterator]() {} };
const intrinsics = Object.freeze({
__proto__: null,
Symbol: {
__proto__: Function.prototype,
// Well-known symbol under test
iterator: SymbolIterator,
// Needed symbol found on %FunctionPrototype%
hasInstance: Symbol.hasInstance,
},
Array: {
__proto__: Function.prototype,
prototype: ArrayProto,
},
// Required intrinsics
'%ArrayPrototype%': ArrayProto,
'%FunctionPrototype%': Function.prototype,
// Yes, this is clearly not inert
'%InertFunction%': Function.prototype.constructor,
'%ObjectPrototype%': Object.prototype,
Object,
});
whitelistIntrinsics(intrinsics, () => {});
t.is(
ArrayProto[RogueSymbolIterator],
undefined,
`Well-known Symbol look-alike should have been removed`,
);
});

0 comments on commit 9dcfc6c

Please sign in to comment.