ses
Version:
Hardened JavaScript for Fearless Cooperation
100 lines (88 loc) • 2.84 kB
JavaScript
import {
Proxy,
String,
TypeError,
ReferenceError,
create,
freeze,
getOwnPropertyDescriptors,
} from './commons.js';
import { assert } from './error/assert.js';
const { Fail, quote: q } = assert;
/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* Thus, it should not be shared outside this module.
*
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const objTarget = freeze({ __proto__: null });
/**
* alwaysThrowHandler
* This is an object that throws if any property is called. It's used as
* a proxy handler which throws on any trap called.
* It's made from a proxy with a get trap that throws. It's safe to
* create one and share it between all Proxy handlers.
*/
export const alwaysThrowHandler = new Proxy(
objTarget,
freeze({
get(_shadow, prop) {
Fail`Please report unexpected scope handler trap: ${q(String(prop))}`;
},
}),
);
/*
* scopeProxyHandlerProperties
* scopeTerminatorHandler manages a strictScopeTerminator Proxy which serves as
* the final scope boundary that will always return "undefined" in order
* to prevent access to "start compartment globals".
*/
const scopeProxyHandlerProperties = {
get(_shadow, _prop) {
return undefined;
},
set(_shadow, prop, _value) {
// We should only hit this if the has() hook returned true matches the v8
// ReferenceError message "Uncaught ReferenceError: xyz is not defined"
throw ReferenceError(`${String(prop)} is not defined`);
},
has(_shadow, prop) {
// we must at least return true for all properties on the realm globalThis
return true;
},
// note: this is likely a bug of safari
// https://bugs.webkit.org/show_bug.cgi?id=195534
getPrototypeOf(_shadow) {
return null;
},
// See https://github.com/endojs/endo/issues/1510
// TODO: report as bug to v8 or Chrome, and record issue link here.
getOwnPropertyDescriptor(_shadow, prop) {
// Coerce with `String` in case prop is a symbol.
const quotedProp = q(String(prop));
// eslint-disable-next-line @endo/no-polymorphic-call
console.warn(
`getOwnPropertyDescriptor trap on scopeTerminatorHandler for ${quotedProp}`,
TypeError().stack,
);
return undefined;
},
// See https://github.com/endojs/endo/issues/1490
// TODO Report bug to JSC or Safari
ownKeys(_shadow) {
return [];
},
};
// The scope handler's prototype is a proxy that throws if any trap other
// than get/set/has are run (like getOwnPropertyDescriptors, apply,
// getPrototypeOf).
export const strictScopeTerminatorHandler = freeze(
create(
alwaysThrowHandler,
getOwnPropertyDescriptors(scopeProxyHandlerProperties),
),
);
export const strictScopeTerminator = new Proxy(
objTarget,
strictScopeTerminatorHandler,
);