FE Sandbox: Fix worker post message not handling proxy objects correctly (#86654)

* FE Sandbox: Fix worker post message not handling proxy objects correctly

* use expect error instead of ignore

* use assertion instead of ignore

* Fix formatting
This commit is contained in:
Esteban Beltran 2024-04-23 14:08:34 +02:00 committed by GitHub
parent 3d55602fde
commit 0ec9c3e01a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 44 additions and 1 deletions

View File

@ -6,7 +6,7 @@ import { CustomVariableSupport, DataSourceApi } from '@grafana/data';
import { config } from '@grafana/runtime'; import { config } from '@grafana/runtime';
import { forbiddenElements } from './constants'; import { forbiddenElements } from './constants';
import { isReactClassComponent, logWarning } from './utils'; import { isReactClassComponent, logWarning, unboxNearMembraneProxies } from './utils';
// IMPORTANT: NEVER export this symbol from a public (e.g `@grafana/*`) package // IMPORTANT: NEVER export this symbol from a public (e.g `@grafana/*`) package
const SANDBOX_LIVE_VALUE = Symbol.for('@@SANDBOX_LIVE_VALUE'); const SANDBOX_LIVE_VALUE = Symbol.for('@@SANDBOX_LIVE_VALUE');
@ -194,9 +194,30 @@ export function patchWebAPIs() {
if (!nativeAPIsPatched) { if (!nativeAPIsPatched) {
nativeAPIsPatched = true; nativeAPIsPatched = true;
patchHistoryReplaceState(); patchHistoryReplaceState();
patchWorkerPostMessage();
} }
} }
/*
*
* Worker.postMessage uses internally structureClone which won't work with proxies.
*
* In case where the blue realm code is directly handling proxy objects that
* should be send over a post message the blue realm will call postMessage and try to
* send the proxy resulting in an error.
*
* This makes sure all proxies are unboxed before being sent over the post message
*/
function patchWorkerPostMessage() {
const originalPostMessage = Worker.prototype.postMessage;
Object.defineProperty(Worker.prototype, 'postMessage', {
value: function (...args: Parameters<typeof Worker.prototype.postMessage>) {
// eslint-disable-next-line
return originalPostMessage.apply(this, unboxNearMembraneProxies(args) as typeof args);
},
});
}
/* /*
* window.history.replaceState is a native API that won't work with proxies * window.history.replaceState is a native API that won't work with proxies
* so we need to patch it to unwrap any possible proxies you pass to it. * so we need to patch it to unwrap any possible proxies you pass to it.

View File

@ -1,4 +1,5 @@
import { isNearMembraneProxy } from '@locker/near-membrane-shared'; import { isNearMembraneProxy } from '@locker/near-membrane-shared';
import { cloneDeep } from 'lodash';
import React from 'react'; import React from 'react';
import { PluginSignatureType, PluginType } from '@grafana/data'; import { PluginSignatureType, PluginType } from '@grafana/data';
@ -112,3 +113,24 @@ export function unboxRegexesFromMembraneProxy(structure: unknown): unknown {
} }
return structure; return structure;
} }
export function unboxNearMembraneProxies(structure: unknown): unknown {
if (!structure) {
return structure;
}
if (isNearMembraneProxy(structure)) {
return cloneDeep(structure);
}
if (Array.isArray(structure)) {
return structure.map(unboxNearMembraneProxies);
}
if (typeof structure === 'object') {
return Object.keys(structure).reduce((acc, key) => {
Reflect.set(acc, key, unboxNearMembraneProxies(Reflect.get(structure, key)));
return acc;
}, {});
}
return structure;
}