UNPKG

ses

Version:

Hardened JavaScript for Fearless Cooperation

128 lines (119 loc) 3.5 kB
// @ts-check import { Date, TypeError, apply, construct, defineProperties, } from './commons.js'; export default function tameDateConstructor() { const OriginalDate = Date; const DatePrototype = OriginalDate.prototype; // Use concise methods to obtain named functions without constructors. const tamedMethods = { /** * `%SharedDate%.now()` throw a `TypeError` starting with "secure mode". * See https://github.com/endojs/endo/issues/910#issuecomment-1581855420 */ now() { throw TypeError('secure mode Calling %SharedDate%.now() throws'); }, }; /** * Tame the Date constructor. * See https://github.com/endojs/endo/issues/910#issuecomment-1581855420 * * Common behavior * * `new Date(x)` coerces x into a number and then returns a Date * for that number of millis since the epoch * * `new Date(NaN)` returns a Date object which stringifies to * 'Invalid Date' * * `new Date(undefined)` returns a Date object which stringifies to * 'Invalid Date' * * OriginalDate (normal standard) behavior preserved by * `%InitialDate%`. * * `Date(anything)` gives a string with the current time * * `new Date()` returns the current time, as a Date object * * `%SharedDate%` behavior * * `Date(anything)` throws a TypeError starting with "secure mode" * * `new Date()` throws a TypeError starting with "secure mode" * * @param {{powers?: string}} [opts] */ const makeDateConstructor = ({ powers = 'none' } = {}) => { let ResultDate; if (powers === 'original') { // eslint-disable-next-line no-shadow ResultDate = function Date(...rest) { if (new.target === undefined) { return apply(OriginalDate, undefined, rest); } return construct(OriginalDate, rest, new.target); }; } else { // eslint-disable-next-line no-shadow ResultDate = function Date(...rest) { if (new.target === undefined) { throw TypeError( 'secure mode Calling %SharedDate% constructor as a function throws', ); } if (rest.length === 0) { throw TypeError( 'secure mode Calling new %SharedDate%() with no arguments throws', ); } return construct(OriginalDate, rest, new.target); }; } defineProperties(ResultDate, { length: { value: 7 }, prototype: { value: DatePrototype, writable: false, enumerable: false, configurable: false, }, parse: { value: OriginalDate.parse, writable: true, enumerable: false, configurable: true, }, UTC: { value: OriginalDate.UTC, writable: true, enumerable: false, configurable: true, }, }); return ResultDate; }; const InitialDate = makeDateConstructor({ powers: 'original' }); const SharedDate = makeDateConstructor({ powers: 'none' }); defineProperties(InitialDate, { now: { value: OriginalDate.now, writable: true, enumerable: false, configurable: true, }, }); defineProperties(SharedDate, { now: { value: tamedMethods.now, writable: true, enumerable: false, configurable: true, }, }); defineProperties(DatePrototype, { constructor: { value: SharedDate }, }); return { '%InitialDate%': InitialDate, '%SharedDate%': SharedDate, }; }