Sandbox: Fix react class components stale state (#70572)

pull/70618/head
Esteban Beltran 2 years ago committed by GitHub
parent 6c25342ecb
commit 53231cb68d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 28
      public/app/features/plugins/sandbox/document_sandbox.ts
  2. 3
      public/app/features/plugins/sandbox/sandbox_plugin_loader.ts
  3. 6
      public/app/features/plugins/sandbox/utils.ts

@ -1,6 +1,7 @@
import { ProxyTarget } from '@locker/near-membrane-shared';
import { isNearMembraneProxy, ProxyTarget } from '@locker/near-membrane-shared';
import { forbiddenElements } from './constants';
import { isReactClassComponent } from './utils';
// IMPORTANT: NEVER export this symbol from a public (e.g `@grafana/*`) package
const SANDBOX_LIVE_VALUE = Symbol.for('@@SANDBOX_LIVE_VALUE');
@ -72,6 +73,31 @@ export function markDomElementStyleAsALiveTarget(el: Element) {
}
}
/**
* Some specific near membrane proxies interfere with plugins
* an example of this is React class components state and their fast life cycles
* with cached objects.
*
* This function marks an object as a live target inside the sandbox
* but not all objects, only the ones that are allowed to be modified
*/
export function patchObjectAsLiveTarget(obj: unknown) {
if (
obj &&
// do not define it twice
!Object.hasOwn(obj, SANDBOX_LIVE_VALUE) &&
// only for proxies
isNearMembraneProxy(obj) &&
// do not patch functions
!(obj instanceof Function) &&
// conditions for allowed objects
// react class components
isReactClassComponent(obj)
) {
Reflect.defineProperty(obj, SANDBOX_LIVE_VALUE, {});
}
}
export function isLiveTarget(el: ProxyTarget) {
return Object.hasOwn(el, SANDBOX_LIVE_VALUE);
}

@ -11,6 +11,7 @@ import {
isDomElement,
isLiveTarget,
markDomElementStyleAsALiveTarget,
patchObjectAsLiveTarget,
} from './document_sandbox';
import { sandboxPluginDependencies } from './plugin_dependencies';
import { sandboxPluginComponents } from './sandbox_components';
@ -48,6 +49,8 @@ async function doImportPluginModuleInSandbox(meta: PluginMeta): Promise<unknown>
// the element.style attribute should be a live target to work in chrome
markDomElementStyleAsALiveTarget(element);
return element;
} else {
patchObjectAsLiveTarget(originalValue);
}
const distortion = generalDistortionMap.get(originalValue);
if (distortion) {

@ -1,3 +1,5 @@
import React from 'react';
import { SandboxedPluginObject } from './types';
export function isSandboxedPluginObject(value: unknown): value is SandboxedPluginObject {
@ -7,3 +9,7 @@ export function isSandboxedPluginObject(value: unknown): value is SandboxedPlugi
export function assertNever(x: never): never {
throw new Error(`Unexpected object: ${x}. This should never happen.`);
}
export function isReactClassComponent(obj: unknown): obj is React.Component {
return obj instanceof React.Component;
}

Loading…
Cancel
Save