Skip to content

Commit

Permalink
feat(sandbox): Support for filtering scripts (#671)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhoushaw committed May 22, 2024
1 parent a09cde7 commit 3330f11
Show file tree
Hide file tree
Showing 13 changed files with 5,095 additions and 1,141 deletions.
5 changes: 5 additions & 0 deletions dev/app-main/src/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ export const localApps: AppInfo = [
name: 'react16',
activeWhen: '/react16',
entry: getProxyHost('dev/react16'),
sandbox: {
excludeAssetFilter: (url: string) => {
return url.includes('exclude');
},
},
},
{
name: 'react18',
Expand Down
1 change: 1 addition & 0 deletions dev/app-react-16/public/exclude-dynamic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
window.dynamic2 = 1;
1 change: 1 addition & 0 deletions dev/app-react-16/public/exclude.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
window.dynamic = 1;
6 changes: 6 additions & 0 deletions dev/app-react-16/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
<head>
<meta charset="UTF-8">
<title>app react v17</title>
<script src="/exclude.js" ></script>
<script>
const script = document.createElement('script');
script.src = "/exclude-dynamic.js";
document.body.appendChild(script);
</script>
</head>
<body>
<div id="root"></div>
Expand Down
6 changes: 5 additions & 1 deletion packages/browser-vm/src/dynamicNode/processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,11 @@ export class DynamicNodeProcessor {
const isModule = type === 'module';
const code = this.el.textContent || this.el.text || '';

if (!type || isJsType({ src, type })) {
// Returning true indicates that execution in the sandbox is not required
const excludeAssetFilter = this.sandbox.options.excludeAssetFilter;
const excludeUrl = excludeAssetFilter?.(src);

if ((!type || isJsType({ src, type })) && !excludeUrl) {
// The "src" higher priority
const { baseUrl, namespace } = this.sandbox.options;
if (src) {
Expand Down
2 changes: 2 additions & 0 deletions packages/browser-vm/src/pluginify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ declare module '@garfish/core' {
}

export interface AppInfo {
excludeAssetFilter?: (url: string) => boolean;
protectVariable?: PropertyKey[];
insulationVariable?: PropertyKey[];
}
Expand Down Expand Up @@ -134,6 +135,7 @@ function createOptions(Garfish: interfaces.Garfish) {
disableWith: Boolean(appInfo.sandbox?.disableWith),
disableElementtiming: Boolean(appInfo.sandbox?.disableElementtiming),
strictIsolation: Boolean(appInfo.sandbox?.strictIsolation),
excludeAssetFilter: appInfo.sandbox?.excludeAssetFilter,
// 缓存模式,不收集副作用
disableCollect:
appInfo.cache === undefined ? true : Boolean(appInfo.cache),
Expand Down
1 change: 1 addition & 0 deletions packages/browser-vm/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface SandboxOptions {
disableElementtiming?: boolean;
disableCollect?: boolean;
modules?: Array<Module>;
excludeAssetFilter?: (url: string) => boolean;
addSourceList?: (
sourceInfo:
| Array<{ tagName: string; url: string | URL | Request }>
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export namespace interfaces {
strictIsolation?: boolean;
disableElementtiming?: boolean;
fixOwnerDocument?: boolean;
excludeAssetFilter?: (url: string) => boolean;
}

export interface Config {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/module/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,19 @@ export class App {
return DOMApis.createElement(node);
}
}

// Filter out code that does not require sandboxed execution
if (this.appInfo.sandbox) {
const scriptUrl = entryManager.findAttributeValue(node, 'src');
if (
scriptUrl &&
this.appInfo.sandbox?.excludeAssetFilter &&
this.appInfo.sandbox?.excludeAssetFilter(scriptUrl)
) {
return DOMApis.createElement(node);
}
}

const jsManager = resources.js.find((manager) => {
return !manager.async ? manager.isSameOrigin(node) : false;
});
Expand Down
19 changes: 14 additions & 5 deletions packages/core/src/module/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,35 @@ import type {
TemplateManager,
JavaScriptManager,
} from '@garfish/loader';
import { AppInfo } from './app';
import type { AppInfo } from './app';
import type { interfaces } from '../interface';

// Fetch `script`, `link` and `module meta` elements
function fetchStaticResources(
appName: string,
loader: Loader,
entryManager: TemplateManager,
sandboxConfig: false | interfaces.SandboxConfig | undefined,
) {
const toBoolean = (val) => typeof val !== 'undefined' && val !== 'false';

// Get all script elements
const jsNodes = Promise.all(
entryManager
.findAllJsNodes()
.filter((node) => {
if (sandboxConfig && sandboxConfig.excludeAssetFilter) {
const src = entryManager.findAttributeValue(node, 'src');
if (src && sandboxConfig.excludeAssetFilter(src)) {
return false;
}
}
return true;
})
.map((node) => {
const src = entryManager.findAttributeValue(node, 'src');
const type = entryManager.findAttributeValue(node, 'type');
let crossOrigin = entryManager.findAttributeValue(
node,
'crossorigin',
);
let crossOrigin = entryManager.findAttributeValue(node, 'crossorigin');
if (crossOrigin === '') {
crossOrigin = 'anonymous';
}
Expand Down Expand Up @@ -150,6 +158,7 @@ export async function processAppResources(loader: Loader, appInfo: AppInfo) {
appInfo.name,
loader,
entryManager,
appInfo.sandbox,
);
resources.js = js;
resources.link = link;
Expand Down
Loading

0 comments on commit 3330f11

Please sign in to comment.