2020-11-24 04:26:43 +01:00
|
|
|
// Freezes all intrinsics
|
2020-12-10 18:33:04 +01:00
|
|
|
try {
|
|
|
|
// eslint-disable-next-line no-undef,import/unambiguous
|
|
|
|
lockdown({
|
|
|
|
consoleTaming: 'unsafe',
|
|
|
|
errorTaming: 'unsafe',
|
|
|
|
mathTaming: 'unsafe',
|
|
|
|
dateTaming: 'unsafe',
|
2021-03-26 05:27:25 +01:00
|
|
|
overrideTaming: 'severe',
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
2020-12-10 18:33:04 +01:00
|
|
|
} catch (error) {
|
|
|
|
// If the `lockdown` call throws an exception, it interferes with the
|
|
|
|
// contentscript injection on some versions of Firefox. The error is
|
|
|
|
// caught and logged here so that the contentscript still gets injected.
|
2021-08-30 23:30:48 +02:00
|
|
|
// This affects Firefox v56 and Waterfox Classic.
|
2021-02-04 19:15:23 +01:00
|
|
|
console.error('Lockdown failed:', error);
|
2021-07-15 19:59:34 +02:00
|
|
|
if (globalThis.sentry && globalThis.sentry.captureException) {
|
2021-08-30 23:30:48 +02:00
|
|
|
globalThis.sentry.captureException(
|
|
|
|
new Error(`Lockdown failed: ${error.message}`),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make all "object" and "function" own properties of globalThis
|
|
|
|
// non-configurable and non-writable, when possible.
|
|
|
|
// We call the a property that is non-configurable and non-writable,
|
|
|
|
// "non-modifiable".
|
|
|
|
try {
|
|
|
|
/**
|
|
|
|
* `lockdown` only hardens the properties enumerated by the
|
|
|
|
* universalPropertyNames constant specified in 'ses/src/whitelist'. This
|
|
|
|
* function makes all function and object properties on the start compartment
|
|
|
|
* global non-configurable and non-writable, unless they are already
|
|
|
|
* non-configurable.
|
|
|
|
*
|
|
|
|
* It is critical that this function runs at the right time during
|
|
|
|
* initialization, which should always be immediately after `lockdown` has been
|
|
|
|
* called. At the time of writing, the modifications this function makes to the
|
|
|
|
* runtime environment appear to be non-breaking, but that could change with
|
|
|
|
* the addition of dependencies, or the order of our scripts in our HTML files.
|
|
|
|
* Exercise caution.
|
|
|
|
*
|
|
|
|
* See inline comments for implementation details.
|
|
|
|
*
|
|
|
|
* We write this function in IIFE format to avoid polluting global scope.
|
|
|
|
*/
|
|
|
|
(function protectIntrinsics() {
|
|
|
|
const namedIntrinsics = Reflect.ownKeys(new Compartment().globalThis);
|
|
|
|
|
|
|
|
// These named intrinsics are not automatically hardened by `lockdown`
|
|
|
|
const shouldHardenManually = new Set(['eval', 'Function']);
|
|
|
|
|
|
|
|
const globalProperties = new Set([
|
|
|
|
// universalPropertyNames is a constant added by lockdown to global scope
|
|
|
|
// at the time of writing, it is initialized in 'ses/src/whitelist'.
|
|
|
|
// These properties tend to be non-enumerable.
|
|
|
|
...namedIntrinsics,
|
|
|
|
|
|
|
|
// TODO: Also include the named platform globals
|
|
|
|
// This grabs every enumerable property on globalThis.
|
|
|
|
// ...Object.keys(globalThis),
|
|
|
|
]);
|
|
|
|
|
|
|
|
globalProperties.forEach((propertyName) => {
|
|
|
|
const descriptor = Reflect.getOwnPropertyDescriptor(
|
|
|
|
globalThis,
|
|
|
|
propertyName,
|
|
|
|
);
|
|
|
|
|
|
|
|
if (descriptor) {
|
|
|
|
if (descriptor.configurable) {
|
|
|
|
// If the property on globalThis is configurable, make it
|
|
|
|
// non-configurable. If it has no accessor properties, also make it
|
|
|
|
// non-writable.
|
|
|
|
if (hasAccessor(descriptor)) {
|
|
|
|
Object.defineProperty(globalThis, propertyName, {
|
|
|
|
configurable: false,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
Object.defineProperty(globalThis, propertyName, {
|
|
|
|
configurable: false,
|
|
|
|
writable: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shouldHardenManually.has(propertyName)) {
|
|
|
|
harden(globalThis[propertyName]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether the given propertyName descriptor has any accessors, i.e. the
|
|
|
|
* properties `get` or `set`.
|
|
|
|
*
|
|
|
|
* We want to make globals non-writable, and we can't set the `writable`
|
|
|
|
* property and accessor properties at the same time.
|
|
|
|
*
|
|
|
|
* @param {Object} descriptor - The propertyName descriptor to check.
|
|
|
|
* @returns {boolean} Whether the propertyName descriptor has any accessors.
|
|
|
|
*/
|
|
|
|
function hasAccessor(descriptor) {
|
|
|
|
return 'set' in descriptor || 'get' in descriptor;
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Protecting intrinsics failed:', error);
|
|
|
|
if (globalThis.sentry && globalThis.sentry.captureException) {
|
|
|
|
globalThis.sentry.captureException(
|
|
|
|
new Error(`Protecting intrinsics failed: ${error.message}`),
|
|
|
|
);
|
2020-12-10 18:33:04 +01:00
|
|
|
}
|
|
|
|
}
|