Comparing version 0.15.15 to 0.15.16
@@ -6,2 +6,23 @@ # Change Log | ||
### [0.15.16](https://github.com/endojs/endo/compare/ses@0.15.15...ses@0.15.16) (2022-06-11) | ||
### Features | ||
* **console-taming:** `unhandledRejectionTrapping` after finalized ([7dccecf](https://github.com/endojs/endo/commit/7dccecfc1766b5287eeb0ebe958d1e1715cb63a4)) | ||
* **ses:** add to commons ([9dc2de8](https://github.com/endojs/endo/commit/9dc2de812755a3c2ba6f73764f8ee7f43dd6f717)) | ||
### Bug Fixes | ||
* **console:** close over severity for error note callbacks ([59910b2](https://github.com/endojs/endo/commit/59910b2a0ac146162c5191a3b315421b92ac5d77)) | ||
* **console:** direct error output to the current severity ([f5d460d](https://github.com/endojs/endo/commit/f5d460d1cc1828100ce0ad237cb0f6bfd0a8e45c)) | ||
* **ses:** Fix compartment with name from object with toString ([405c00b](https://github.com/endojs/endo/commit/405c00b3cc8f663ef73ef4275ba1776913dc26e7)) | ||
* **static-module-record:** Make types consistent with implementation ([#1184](https://github.com/endojs/endo/issues/1184)) ([5b7e3a6](https://github.com/endojs/endo/commit/5b7e3a6d006a686520c4ffeedea5428a720f7e7d)) | ||
* all errors have stacks, even if empty ([#1171](https://github.com/endojs/endo/issues/1171)) ([25b7d86](https://github.com/endojs/endo/commit/25b7d86240a5fc2772343664e5a42d1400d363d9)) | ||
* make `*Trapping` orthogonal to `consoleTaming` ([8c5e12e](https://github.com/endojs/endo/commit/8c5e12e96f8c71d0c52e2d17786558e88585e04b)) | ||
* repair deviations from local convention ([#1183](https://github.com/endojs/endo/issues/1183)) ([13614f5](https://github.com/endojs/endo/commit/13614f56872ac976e3440f8bcce706200ffe9822)) | ||
### [0.15.15](https://github.com/endojs/endo/compare/ses@0.15.14...ses@0.15.15) (2022-04-15) | ||
@@ -8,0 +29,0 @@ |
@@ -27,2 +27,3 @@ /** | ||
errorTrapping?: 'platform' | 'exit' | 'abort' | 'report' | 'none'; | ||
unhandledRejectionTrapping?: 'report' | 'none'; | ||
errorTaming?: 'safe' | 'unsafe'; | ||
@@ -41,4 +42,4 @@ dateTaming?: 'safe' | 'unsafe'; // deprecated | ||
export type __LiveExportsMap__ = Record<string, [string, boolean]>; | ||
export type __FixedExportsMap__ = Record<string, [string]>; | ||
export type __LiveExportMap__ = Record<string, [string, boolean]>; | ||
export type __FixedExportMap__ = Record<string, [string]>; | ||
@@ -50,4 +51,4 @@ export interface PrecompiledStaticModuleInterface { | ||
__syncModuleProgram__: string; | ||
__liveExportsMap__: __LiveExportsMap__; | ||
__fixedExportsMap__: __FixedExportsMap__; | ||
__liveExportMap__: __LiveExportMap__; | ||
__fixedExportMap__: __FixedExportMap__; | ||
} | ||
@@ -54,0 +55,0 @@ |
{ | ||
"name": "ses", | ||
"version": "0.15.15", | ||
"version": "0.15.16", | ||
"description": "Hardened JavaScript for Fearless Cooperation", | ||
@@ -62,15 +62,15 @@ "keywords": [ | ||
"devDependencies": { | ||
"@endo/compartment-mapper": "^0.7.5", | ||
"@endo/eslint-config": "^0.4.10", | ||
"@endo/static-module-record": "^0.7.4", | ||
"@endo/test262-runner": "^0.1.26", | ||
"@endo/compartment-mapper": "^0.7.6", | ||
"@endo/eslint-config": "^0.5.0", | ||
"@endo/static-module-record": "^0.7.5", | ||
"@endo/test262-runner": "^0.1.27", | ||
"ava": "^3.12.1", | ||
"babel-eslint": "^10.0.3", | ||
"c8": "^7.7.3", | ||
"eslint": "^7.23.0", | ||
"eslint": "^7.32.0", | ||
"eslint-config-airbnb-base": "^14.0.0", | ||
"eslint-config-prettier": "^6.9.0", | ||
"eslint-plugin-eslint-comments": "^3.1.2", | ||
"eslint-plugin-import": "^2.19.1", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"eslint-plugin-import": "^2.26.0", | ||
"eslint-plugin-prettier": "^3.4.1", | ||
"prettier": "^1.19.1", | ||
@@ -183,3 +183,3 @@ "sinon": "8.0.4", | ||
}, | ||
"gitHead": "3ae52352ca54614f0bf40f74a6f3959ea5973c2e" | ||
"gitHead": "7be9306df5e5eae280134cbbaf0d3886b4e51536" | ||
} |
@@ -707,5 +707,5 @@ # SES | ||
[define shim]: https://en.wikipedia.org/wiki/Shim_(computing | ||
[define shim]: https://en.wikipedia.org/wiki/Shim_(computing) | ||
[SES proposal]: https://github.com/tc39/proposal-ses | ||
[SECURITY.md]: https://github.com/endojs/endo/blob/master/packages/ses/SECURITY.md | ||
[SES Issues]: https://github.com/endojs/endo/issues |
@@ -23,2 +23,3 @@ /* global globalThis */ | ||
Date, | ||
FinalizationRegistry, | ||
Float32Array, | ||
@@ -161,3 +162,5 @@ JSON, | ||
* | ||
* @param {(thisArg: Object, ...args: any[]) => any} fn | ||
* @template {Function} F | ||
* @param {F} fn | ||
* returns {(thisArg: ThisParameterType<F>, ...args: Parameters<F>) => ReturnType<F>} | ||
*/ | ||
@@ -183,2 +186,4 @@ export const uncurryThis = fn => (thisArg, ...args) => apply(fn, thisArg, args); | ||
export const mapHas = uncurryThis(mapPrototype.has); | ||
export const mapDelete = uncurryThis(mapPrototype.delete); | ||
export const mapEntries = uncurryThis(mapPrototype.entries); | ||
export const iterateMap = uncurryThis(mapPrototype[iteratorSymbol]); | ||
@@ -208,2 +213,3 @@ // | ||
export const weakmapDelete = uncurryThis(weakmapPrototype.delete); | ||
/** @type {<K, V>(thisArg: WeakMap<K, V>, ...args: Parameters<WeakMap<K,V>['get']>) => ReturnType<WeakMap<K,V>['get']>} */ | ||
export const weakmapGet = uncurryThis(weakmapPrototype.get); | ||
@@ -223,2 +229,8 @@ export const weakmapHas = uncurryThis(weakmapPrototype.has); | ||
export const promiseThen = uncurryThis(promisePrototype.then); | ||
// | ||
export const finalizationRegistryRegister = | ||
FinalizationRegistry && uncurryThis(FinalizationRegistry.prototype.register); | ||
export const finalizationRegistryUnregister = | ||
FinalizationRegistry && | ||
uncurryThis(FinalizationRegistry.prototype.unregister); | ||
@@ -225,0 +237,0 @@ /** |
@@ -309,3 +309,3 @@ // @ts-check | ||
weakmapSet(privateFields, this, { | ||
name, | ||
name: `${name}`, | ||
globalTransforms, | ||
@@ -312,0 +312,0 @@ globalObject, |
@@ -175,11 +175,2 @@ // @ts-check | ||
/** | ||
* The error annotations are sent to the baseConsole by calling some level | ||
* method. The 'debug' level seems best, because the Chrome console classifies | ||
* `debug` as verbose and does not show it by default. But we keep it symbolic | ||
* so we can change our mind. (On Node, `debug`, `log`, and `info` are aliases | ||
* for the same function and so will behave the same there.) | ||
*/ | ||
export const BASE_CONSOLE_LEVEL = 'debug'; | ||
/** @type {MakeCausalConsole} */ | ||
@@ -211,2 +202,3 @@ const makeCausalConsole = (baseConsole, loggedErrorHandler) => { | ||
/** | ||
* @param {LogSeverity} severity | ||
* @param {Error} error | ||
@@ -217,3 +209,3 @@ * @param {ErrorInfoKind} kind | ||
*/ | ||
const logErrorInfo = (error, kind, logArgs, subErrorsSink) => { | ||
const logErrorInfo = (severity, error, kind, logArgs, subErrorsSink) => { | ||
const errorTag = tagError(error); | ||
@@ -224,3 +216,3 @@ const errorName = | ||
// eslint-disable-next-line @endo/no-polymorphic-call | ||
baseConsole[BASE_CONSOLE_LEVEL](errorName, ...argTags); | ||
baseConsole[severity](errorName, ...argTags); | ||
}; | ||
@@ -231,2 +223,3 @@ | ||
* | ||
* @param {LogSeverity} severity | ||
* @param {Error[]} subErrors | ||
@@ -236,3 +229,3 @@ * @param {string | undefined} optTag | ||
*/ | ||
const logSubErrors = (subErrors, optTag = undefined) => { | ||
const logSubErrors = (severity, subErrors, optTag = undefined) => { | ||
if (subErrors.length === 0) { | ||
@@ -243,3 +236,3 @@ return; | ||
// eslint-disable-next-line no-use-before-define | ||
logError(subErrors[0]); | ||
logError(severity, subErrors[0]); | ||
return; | ||
@@ -261,3 +254,3 @@ } | ||
// eslint-disable-next-line no-use-before-define | ||
logError(subError); | ||
logError(severity, subError); | ||
} | ||
@@ -272,15 +265,16 @@ } finally { | ||
/** @type {NoteCallback} */ | ||
const noteCallback = (error, noteLogArgs) => { | ||
/** @type {(severity: LogSeverity) => NoteCallback} */ | ||
const makeNoteCallback = severity => (error, noteLogArgs) => { | ||
const subErrors = []; | ||
// Annotation arrived after the error has already been logged, | ||
// so just log the annotation immediately, rather than remembering it. | ||
logErrorInfo(error, ErrorInfo.NOTE, noteLogArgs, subErrors); | ||
logSubErrors(subErrors, tagError(error)); | ||
logErrorInfo(severity, error, ErrorInfo.NOTE, noteLogArgs, subErrors); | ||
logSubErrors(severity, subErrors, tagError(error)); | ||
}; | ||
/** | ||
* @param {LogSeverity} severity | ||
* @param {Error} error | ||
*/ | ||
const logError = error => { | ||
const logError = (severity, error) => { | ||
if (weaksetHas(errorsLogged, error)) { | ||
@@ -293,3 +287,6 @@ return; | ||
const messageLogArgs = takeMessageLogArgs(error); | ||
const noteLogArgsArray = takeNoteLogArgsArray(error, noteCallback); | ||
const noteLogArgsArray = takeNoteLogArgsArray( | ||
error, | ||
makeNoteCallback(severity), | ||
); | ||
// Show the error's most informative error message | ||
@@ -300,7 +297,13 @@ if (messageLogArgs === undefined) { | ||
// eslint-disable-next-line @endo/no-polymorphic-call | ||
baseConsole[BASE_CONSOLE_LEVEL](`${errorTag}:`, error.message); | ||
baseConsole[severity](`${errorTag}:`, error.message); | ||
} else { | ||
// If there is one, we take it to be strictly more informative than the | ||
// message string carried by the error, so show it *instead*. | ||
logErrorInfo(error, ErrorInfo.MESSAGE, messageLogArgs, subErrors); | ||
logErrorInfo( | ||
severity, | ||
error, | ||
ErrorInfo.MESSAGE, | ||
messageLogArgs, | ||
subErrors, | ||
); | ||
} | ||
@@ -317,9 +320,9 @@ // After the message but before any other annotations, show the stack. | ||
// eslint-disable-next-line @endo/no-polymorphic-call | ||
baseConsole[BASE_CONSOLE_LEVEL](stackString); | ||
baseConsole[severity](stackString); | ||
// Show the other annotations on error | ||
for (const noteLogArgs of noteLogArgsArray) { | ||
logErrorInfo(error, ErrorInfo.NOTE, noteLogArgs, subErrors); | ||
logErrorInfo(severity, error, ErrorInfo.NOTE, noteLogArgs, subErrors); | ||
} | ||
// explain all the errors seen in the messages already emitted. | ||
logSubErrors(subErrors, errorTag); | ||
logSubErrors(severity, subErrors, errorTag); | ||
}; | ||
@@ -337,3 +340,3 @@ | ||
baseConsole[level](...argTags); | ||
logSubErrors(subErrors); | ||
logSubErrors(level, subErrors); | ||
}; | ||
@@ -340,0 +343,0 @@ defineProperty(levelMethod, 'name', { value: level }); |
@@ -6,2 +6,3 @@ // @ts-check | ||
import { makeCausalConsole } from './console.js'; | ||
import { makeRejectionHandlers } from './unhandled-rejection.js'; | ||
import './types.js'; | ||
@@ -21,2 +22,3 @@ import './internal-types.js'; | ||
* @param {"platform" | "exit" | "abort" | "report" | "none"} [errorTrapping] | ||
* @param {"report" | "none"} [unhandledRejectionTrapping] | ||
* @param {GetStackString=} optGetStackString | ||
@@ -27,2 +29,3 @@ */ | ||
errorTrapping = 'platform', | ||
unhandledRejectionTrapping = 'report', | ||
optGetStackString = undefined, | ||
@@ -34,5 +37,2 @@ ) => { | ||
if (consoleTaming === 'unsafe') { | ||
return { console: originalConsole }; | ||
} | ||
let loggedErrorHandler; | ||
@@ -47,3 +47,6 @@ if (optGetStackString === undefined) { | ||
} | ||
const causalConsole = makeCausalConsole(originalConsole, loggedErrorHandler); | ||
const ourConsole = | ||
consoleTaming === 'unsafe' | ||
? originalConsole | ||
: makeCausalConsole(originalConsole, loggedErrorHandler); | ||
@@ -61,14 +64,14 @@ // Attach platform-specific error traps such that any error that gets thrown | ||
// Disable the polymorphic check for the rest of this file. It's too noisy | ||
// when dealing with platform APIs. | ||
/* eslint-disable @endo/no-polymorphic-call */ | ||
// Node.js | ||
if (errorTrapping !== 'none' && globalThis.process !== undefined) { | ||
// eslint-disable-next-line @endo/no-polymorphic-call | ||
globalThis.process.on('uncaughtException', error => { | ||
// causalConsole is born frozen so not vulnerable to method tampering. | ||
// eslint-disable-next-line @endo/no-polymorphic-call | ||
causalConsole.error(error); | ||
ourConsole.error(error); | ||
if (errorTrapping === 'platform' || errorTrapping === 'exit') { | ||
// eslint-disable-next-line @endo/no-polymorphic-call | ||
globalThis.process.exit(globalThis.process.exitCode || -1); | ||
} else if (errorTrapping === 'abort') { | ||
// eslint-disable-next-line @endo/no-polymorphic-call | ||
globalThis.process.abort(); | ||
@@ -79,2 +82,20 @@ } | ||
if ( | ||
unhandledRejectionTrapping !== 'none' && | ||
globalThis.process !== undefined | ||
) { | ||
const handleRejection = reason => { | ||
// 'platform' and 'report' just log the reason. | ||
ourConsole.error('SES_UNHANDLED_REJECTION:', reason); | ||
}; | ||
// Maybe track unhandled promise rejections. | ||
const h = makeRejectionHandlers(handleRejection); | ||
if (h) { | ||
// Rejection handlers are supported. | ||
globalThis.process.on('unhandledRejection', h.unhandledRejectionHandler); | ||
globalThis.process.on('rejectionHandled', h.rejectionHandledHandler); | ||
globalThis.process.on('exit', h.processTerminationHandler); | ||
} | ||
} | ||
// Browser | ||
@@ -86,8 +107,6 @@ if ( | ||
) { | ||
// eslint-disable-next-line @endo/no-polymorphic-call | ||
globalThis.window.addEventListener('error', event => { | ||
// eslint-disable-next-line @endo/no-polymorphic-call | ||
event.preventDefault(); | ||
// eslint-disable-next-line @endo/no-polymorphic-call | ||
causalConsole.error(event.error); | ||
// 'platform' and 'report' just log the reason. | ||
ourConsole.error(event.error); | ||
if (errorTrapping === 'exit' || errorTrapping === 'abort') { | ||
@@ -99,3 +118,32 @@ globalThis.window.location.href = `about:blank`; | ||
return { console: causalConsole }; | ||
if ( | ||
unhandledRejectionTrapping !== 'none' && | ||
globalThis.window !== undefined && | ||
globalThis.window.addEventListener !== undefined | ||
) { | ||
const handleRejection = reason => { | ||
ourConsole.error('SES_UNHANDLED_REJECTION:', reason); | ||
}; | ||
const h = makeRejectionHandlers(handleRejection); | ||
if (h) { | ||
// Rejection handlers are supported. | ||
globalThis.window.addEventListener('unhandledrejection', event => { | ||
event.preventDefault(); | ||
h.unhandledRejectionHandler(event.reason, event.promise); | ||
}); | ||
globalThis.window.addEventListener('rejectionhandled', event => { | ||
event.preventDefault(); | ||
h.rejectionHandledHandler(event.promise); | ||
}); | ||
globalThis.window.addEventListener('beforeunload', _event => { | ||
h.processTerminationHandler(); | ||
}); | ||
} | ||
} | ||
/* eslint-enable @endo/no-polymorphic-call */ | ||
return { console: ourConsole }; | ||
}; |
@@ -13,4 +13,5 @@ import { | ||
// Present on at least FF. Proposed by Error-proposal. Not on SES whitelist | ||
// so grab it before it is removed. | ||
// Present on at least FF and XS. Proposed by Error-proposal. The original | ||
// is dangerous, so tameErrorConstructor replaces it with a safe one. | ||
// We grab the original here before it gets replaced. | ||
const stackDesc = getOwnPropertyDescriptor(FERAL_ERROR.prototype, 'stack'); | ||
@@ -78,12 +79,2 @@ const stackGetter = stackDesc && stackDesc.get; | ||
constructor: { value: SharedError }, | ||
/* TODO | ||
stack: { | ||
get() { | ||
return ''; | ||
}, | ||
set(_) { | ||
// ignore | ||
}, | ||
}, | ||
*/ | ||
}); | ||
@@ -159,3 +150,66 @@ | ||
); | ||
} else if (errorTaming === 'unsafe') { | ||
// v8 has too much magic around their 'stack' own property for it to | ||
// coexist cleanly with this accessor. So only install it on non-v8 | ||
// Error.prototype.stack property as proposed at | ||
// https://tc39.es/proposal-error-stacks/ | ||
// with the fix proposed at | ||
// https://github.com/tc39/proposal-error-stacks/issues/46 | ||
// On others, this still protects from the override mistake, | ||
// essentially like enable-property-overrides.js would | ||
// once this accessor property itself is frozen, as will happen | ||
// later during lockdown. | ||
// | ||
// However, there is here a change from the intent in the current | ||
// state of the proposal. If experience tells us whether this change | ||
// is a good idea, we should modify the proposal accordingly. There is | ||
// much code in the world that assumes `error.stack` is a string. So | ||
// where the proposal accommodates secure operation by making the | ||
// property optional, we instead accommodate secure operation by | ||
// having the secure form always return only the stable part, the | ||
// stringified error instance, and omitting all the frame information | ||
// rather than omitting the property. | ||
defineProperties(ErrorPrototype, { | ||
stack: { | ||
get() { | ||
return initialGetStackString(this); | ||
}, | ||
set(newValue) { | ||
defineProperties(this, { | ||
stack: { | ||
value: newValue, | ||
writable: true, | ||
enumerable: true, | ||
configurable: true, | ||
}, | ||
}); | ||
}, | ||
}, | ||
}); | ||
} else { | ||
// v8 has too much magic around their 'stack' own property for it to | ||
// coexist cleanly with this accessor. So only install it on non-v8 | ||
defineProperties(ErrorPrototype, { | ||
stack: { | ||
get() { | ||
// https://github.com/tc39/proposal-error-stacks/issues/46 | ||
// allows this to not add an unpleasant newline. Otherwise | ||
// we should fix this. | ||
return `${this}`; | ||
}, | ||
set(newValue) { | ||
defineProperties(this, { | ||
stack: { | ||
value: newValue, | ||
writable: true, | ||
enumerable: true, | ||
configurable: true, | ||
}, | ||
}); | ||
}, | ||
}, | ||
}); | ||
} | ||
return { | ||
@@ -162,0 +216,0 @@ '%InitialGetStackString%': initialGetStackString, |
@@ -163,2 +163,6 @@ // Copyright (C) 2018 Agoric | ||
errorTrapping = getenv('LOCKDOWN_ERROR_TRAPPING', 'platform'), | ||
unhandledRejectionTrapping = getenv( | ||
'LOCKDOWN_UNHANDLED_REJECTION_TRAPPING', | ||
'report', | ||
), | ||
regExpTaming = getenv('LOCKDOWN_REGEXP_TAMING', 'safe'), | ||
@@ -290,6 +294,10 @@ localeTaming = getenv('LOCKDOWN_LOCALE_TAMING', 'safe'), | ||
// Wrap console unless suppressed. | ||
// At the moment, the console is considered a host power in the start | ||
// compartment, and not a primordial. Hence it is absent from the whilelist | ||
// and bypasses the intrinsicsCollector. | ||
/** | ||
* Wrap console unless suppressed. | ||
* At the moment, the console is considered a host power in the start | ||
* compartment, and not a primordial. Hence it is absent from the whilelist | ||
* and bypasses the intrinsicsCollector. | ||
* | ||
* @type {((error: any) => string | undefined) | undefined} | ||
*/ | ||
let optGetStackString; | ||
@@ -300,5 +308,6 @@ if (errorTaming !== 'unsafe') { | ||
const consoleRecord = tameConsole( | ||
// @ts-ignore tameConsole does its own input validation | ||
// @ts-expect-error tameConsole does its own input validation | ||
consoleTaming, | ||
errorTrapping, | ||
unhandledRejectionTrapping, | ||
optGetStackString, | ||
@@ -305,0 +314,0 @@ ); |
@@ -559,3 +559,3 @@ /* eslint-disable no-restricted-globals */ | ||
// Seen on FF and XS | ||
stack: false, | ||
stack: accessor, | ||
// Superfluously present in some versions of V8. | ||
@@ -562,0 +562,0 @@ // https://github.com/tc39/notes/blob/master/meetings/2021-10/oct-26.md#:~:text=However%2C%20Chrome%2093,and%20node%2016.11. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2791394
63
58814