Sandbox: Fix history.replace calls inside the sandbox (#76049)

* Sandbox: Fix `history.replace` calls inside the sandbox

* Improve signature verification and comments

* Add clarifying comment
This commit is contained in:
Esteban Beltran
2023-10-09 10:42:38 +02:00
committed by GitHub
parent dcd0c6b11e
commit 5549cd7a76
2 changed files with 37 additions and 11 deletions
@@ -1,3 +1,4 @@
import { ProxyTarget } from '@locker/near-membrane-shared';
import { cloneDeep, isFunction } from 'lodash';
import { PluginMeta } from '@grafana/data';
@@ -520,13 +521,31 @@ async function distortPostMessage(distortions: DistortionMap) {
}
/**
* We define "live" APIs as APIs that can only be distorted in runtime on-the-fly and not at initialization
* time like other distortions do.
*
* This could be because the objects we want to patch only become available after specific states are reached
* or because the libraries we want to patch are lazy-loaded and we don't have access to their definitions
*
* "Live" APIs are APIs that can only be distorted at runtime.
* This could be because the objects we want to patch only become available after specific states are reached,
* or because the libraries we want to patch are lazy-loaded and we don't have access to their definitions.
* We put here only distortions that can't be static because they are dynamicly loaded
*/
export async function distortLiveApis() {
export function distortLiveApis(originalValue: ProxyTarget): ProxyTarget | undefined {
distortMonacoEditor(generalDistortionMap);
// This distorts the `history.replace` function in react-router-dom.
// constructed for each browser history and is only accessible within the react context.
// Note that this distortion does not affect `String.prototype.replace` calls.
// because they don't go through distortions
if (
originalValue instanceof Function &&
originalValue.name === 'replace' &&
originalValue.prototype.constructor.length === 2
) {
return function replace(this: unknown, ...args: unknown[]) {
// validate history.replace signature further
if (args && args[0] && typeof args[0] === 'string' && args[1] && !(args[1] instanceof Function)) {
const newArgs = cloneDeep(args);
return Reflect.apply(originalValue, this, newArgs);
}
return Reflect.apply(originalValue, this, args);
};
}
return;
}
@@ -63,10 +63,17 @@ async function doImportPluginModuleInSandbox(meta: PluginMeta): Promise<System.M
} else {
patchObjectAsLiveTarget(originalValue);
}
distortLiveApis();
const distortion = generalDistortionMap.get(originalValue);
if (distortion) {
return distortion(originalValue, meta, sandboxEnvironment) as ProxyTarget;
// static distortions are faster distortions with direct object descriptors checks
const staticDistortion = generalDistortionMap.get(originalValue);
if (staticDistortion) {
return staticDistortion(originalValue, meta, sandboxEnvironment) as ProxyTarget;
}
// live distortions are slower and have to do runtime checks
const liveDistortion = distortLiveApis(originalValue);
if (liveDistortion) {
return liveDistortion;
}
return originalValue;
}