diff --git a/packages/near-membrane-dom/src/browser-realm.ts b/packages/near-membrane-dom/src/browser-realm.ts index ec9169dd..b8488ef8 100644 --- a/packages/near-membrane-dom/src/browser-realm.ts +++ b/packages/near-membrane-dom/src/browser-realm.ts @@ -80,7 +80,7 @@ function createIframeVirtualEnvironment( instrumentation, keepAlive = true, liveTargetCallback, - remapTypedArrays, + remapTypedArrays = true, signSourceCallback, // eslint-disable-next-line prefer-object-spread } = ObjectAssign({ __proto__: null }, providedOptions) as BrowserEnvironmentOptions; @@ -94,7 +94,8 @@ function createIframeVirtualEnvironment( typeof globalObjectShape !== 'object' || globalObjectShape === null; if (shouldUseDefaultGlobalOwnKeys && defaultGlobalOwnKeys === null) { defaultGlobalOwnKeys = filterWindowKeys( - getFilteredGlobalOwnKeys(redWindow, remapTypedArrays) + getFilteredGlobalOwnKeys(redWindow, remapTypedArrays), + remapTypedArrays ); } let blueConnector = blueCreateHooksCallbackCache.get(blueRefs.document) as @@ -145,7 +146,7 @@ function createIframeVirtualEnvironment( blueRefs.window, shouldUseDefaultGlobalOwnKeys ? (defaultGlobalOwnKeys as PropertyKey[]) - : filterWindowKeys(getFilteredGlobalOwnKeys(globalObjectShape)), + : filterWindowKeys(getFilteredGlobalOwnKeys(globalObjectShape), remapTypedArrays), // Chromium based browsers have a bug that nulls the result of `window` // getters in detached iframes when the property descriptor of `window.window` // is retrieved. @@ -159,7 +160,7 @@ function createIframeVirtualEnvironment( endowments, remapTypedArrays ); - removeWindowDescriptors(filteredEndowments); + removeWindowDescriptors(filteredEndowments, remapTypedArrays); env.remapProperties(blueRefs.window, filteredEndowments); } // We intentionally skip remapping Window.prototype because there is nothing diff --git a/packages/near-membrane-dom/src/window.ts b/packages/near-membrane-dom/src/window.ts index d8e6c071..bdbc220c 100644 --- a/packages/near-membrane-dom/src/window.ts +++ b/packages/near-membrane-dom/src/window.ts @@ -2,6 +2,7 @@ import { ReflectDeleteProperty, ReflectGetPrototypeOf, ReflectOwnKeys, + toSafeArray, toSafeWeakMap, } from '@locker/near-membrane-shared'; import { IS_CHROMIUM_BROWSER, rootWindow } from '@locker/near-membrane-shared-dom'; @@ -62,8 +63,8 @@ export function getCachedGlobalObjectReferences( return record; } -export function filterWindowKeys(keys: PropertyKey[]): PropertyKey[] { - const result: PropertyKey[] = []; +export function filterWindowKeys(keys: PropertyKey[], remapTypedArrays: boolean): PropertyKey[] { + const result: PropertyKey[] = toSafeArray([]); let resultOffset = 0; for (let i = 0, { length } = keys; i < length; i += 1) { const key = keys[i]; @@ -79,6 +80,12 @@ export function filterWindowKeys(keys: PropertyKey[]): PropertyKey[] { result[resultOffset++] = key; } } + + // Crypto and typed arrays must be from the same global object + if (remapTypedArrays === false) { + result.splice(result.indexOf('Crypto'), 1); + } + return result; } @@ -109,7 +116,10 @@ export function filterWindowKeys(keys: PropertyKey[]): PropertyKey[] { * that will be installed (via the membrane) as global descriptors in * the red realm. */ -export function removeWindowDescriptors(unsafeDescs: T): T { +export function removeWindowDescriptors( + unsafeDescs: T, + remapTypedArrays: boolean +): T { // Remove unforgeable descriptors that cannot be installed. ReflectDeleteProperty(unsafeDescs, 'document'); ReflectDeleteProperty(unsafeDescs, 'location'); @@ -117,6 +127,10 @@ export function removeWindowDescriptors(unsafeD ReflectDeleteProperty(unsafeDescs, 'window'); // Remove other browser specific unforgeables. ReflectDeleteProperty(unsafeDescs, 'chrome'); + // Crypto and typed arrays must be from the same global object + if (remapTypedArrays === false) { + ReflectDeleteProperty(unsafeDescs, 'Crypto'); + } return unsafeDescs; } diff --git a/test/membrane/binary-data.spec.js b/test/membrane/binary-data.spec.js index 9c6a639d..a8ff4af4 100644 --- a/test/membrane/binary-data.spec.js +++ b/test/membrane/binary-data.spec.js @@ -48,6 +48,30 @@ describe('Crypto', () => { endowments: Object.getOwnPropertyDescriptors({ expect }), }); + env.evaluate(` + expect(() => { + crypto.getRandomValues(new Uint8Array(1)); + }).not.toThrow(); + `); + }); + it('works when typed arrays are not remapped', () => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ expect }), + remapTypedArrays: false, + }); + + env.evaluate(` + expect(() => { + crypto.getRandomValues(new Uint8Array(1)); + }).not.toThrow(); + `); + }); + it('ignores the presense of crypto in endowments if remapTypedArrays is false', () => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ Crypto, crypto, expect }), + remapTypedArrays: false, + }); + env.evaluate(` expect(() => { crypto.getRandomValues(new Uint8Array(1));