11
This commit is contained in:
@@ -109,10 +109,7 @@ export class ApplicationSandboxEngine {
|
||||
private resourceService: ResourceService
|
||||
private eventService: EventCommunicationService
|
||||
|
||||
constructor(
|
||||
resourceService: ResourceService,
|
||||
eventService: EventCommunicationService
|
||||
) {
|
||||
constructor(resourceService: ResourceService, eventService: EventCommunicationService) {
|
||||
this.resourceService = resourceService
|
||||
this.eventService = eventService
|
||||
this.startPerformanceMonitoring()
|
||||
@@ -127,7 +124,7 @@ export class ApplicationSandboxEngine {
|
||||
config: Partial<SandboxConfig> = {}
|
||||
): Promise<SandboxInstance> {
|
||||
const sandboxId = uuidv4()
|
||||
|
||||
|
||||
const defaultConfig: SandboxConfig = {
|
||||
type: SandboxType.IFRAME,
|
||||
securityLevel: SecurityLevel.HIGH,
|
||||
@@ -166,21 +163,20 @@ export class ApplicationSandboxEngine {
|
||||
try {
|
||||
// 根据类型创建沙箱容器
|
||||
await this.createSandboxContainer(sandbox)
|
||||
|
||||
|
||||
// 设置安全策略
|
||||
this.applySecurity(sandbox)
|
||||
|
||||
|
||||
// 设置性能监控
|
||||
this.setupPerformanceMonitoring(sandbox)
|
||||
|
||||
|
||||
// 更新状态
|
||||
this.updateSandboxState(sandbox, SandboxState.READY)
|
||||
|
||||
|
||||
this.sandboxes.set(sandboxId, sandbox)
|
||||
|
||||
|
||||
console.log(`沙箱 ${sandboxId} 创建成功`)
|
||||
return sandbox
|
||||
|
||||
} catch (error) {
|
||||
this.updateSandboxState(sandbox, SandboxState.ERROR)
|
||||
sandbox.errors.push(error instanceof Error ? error.message : String(error))
|
||||
@@ -200,23 +196,25 @@ export class ApplicationSandboxEngine {
|
||||
try {
|
||||
console.log(`开始加载应用: ${sandbox.appId}, 沙箱ID: ${sandboxId}`)
|
||||
this.updateSandboxState(sandbox, SandboxState.RUNNING)
|
||||
|
||||
|
||||
if (sandbox.config.type === SandboxType.IFRAME && sandbox.iframe) {
|
||||
console.log(`使用iframe加载应用: ${applicationUrl}`)
|
||||
|
||||
|
||||
// 检查iframe是否已挂载到DOM
|
||||
if (!document.contains(sandbox.iframe)) {
|
||||
console.warn('检测到iframe未挂载到DOM,尝试重新挂载')
|
||||
await this.mountIframeToWindow(sandbox)
|
||||
}
|
||||
|
||||
|
||||
// 设置iframe源
|
||||
sandbox.iframe.src = applicationUrl
|
||||
|
||||
|
||||
// 等待加载完成
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.error(`应用加载超时: ${sandbox.appId}, URL: ${applicationUrl}, 超时时间: ${sandbox.config.networkTimeout}ms`)
|
||||
console.error(
|
||||
`应用加载超时: ${sandbox.appId}, URL: ${applicationUrl}, 超时时间: ${sandbox.config.networkTimeout}ms`
|
||||
)
|
||||
reject(new Error('应用加载超时'))
|
||||
}, sandbox.config.networkTimeout)
|
||||
|
||||
@@ -241,7 +239,7 @@ export class ApplicationSandboxEngine {
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
return false
|
||||
} catch (error) {
|
||||
console.error(`加载应用失败: ${sandbox.appId}`, error)
|
||||
@@ -251,64 +249,6 @@ export class ApplicationSandboxEngine {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停沙箱
|
||||
*/
|
||||
suspendSandbox(sandboxId: string): boolean {
|
||||
const sandbox = this.sandboxes.get(sandboxId)
|
||||
if (!sandbox || sandbox.state !== SandboxState.RUNNING) {
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
this.updateSandboxState(sandbox, SandboxState.SUSPENDED)
|
||||
|
||||
if (sandbox.iframe) {
|
||||
// 暂停iframe中的脚本执行
|
||||
const iframeWindow = sandbox.iframe.contentWindow
|
||||
if (iframeWindow) {
|
||||
// 发送暂停事件到应用
|
||||
iframeWindow.postMessage({ type: 'system:suspend' }, '*')
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`沙箱 ${sandboxId} 已暂停`)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('暂停沙箱失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复沙箱
|
||||
*/
|
||||
resumeSandbox(sandboxId: string): boolean {
|
||||
const sandbox = this.sandboxes.get(sandboxId)
|
||||
if (!sandbox || sandbox.state !== SandboxState.SUSPENDED) {
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
this.updateSandboxState(sandbox, SandboxState.RUNNING)
|
||||
sandbox.lastActiveAt = new Date()
|
||||
|
||||
if (sandbox.iframe) {
|
||||
const iframeWindow = sandbox.iframe.contentWindow
|
||||
if (iframeWindow) {
|
||||
// 发送恢复事件到应用
|
||||
iframeWindow.postMessage({ type: 'system:resume' }, '*')
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`沙箱 ${sandboxId} 已恢复`)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('恢复沙箱失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁沙箱
|
||||
*/
|
||||
@@ -320,18 +260,18 @@ export class ApplicationSandboxEngine {
|
||||
|
||||
try {
|
||||
this.updateSandboxState(sandbox, SandboxState.DESTROYED)
|
||||
|
||||
|
||||
// 移除消息事件监听器
|
||||
if (sandbox.messageHandler) {
|
||||
window.removeEventListener('message', sandbox.messageHandler);
|
||||
sandbox.messageHandler = undefined;
|
||||
window.removeEventListener('message', sandbox.messageHandler)
|
||||
sandbox.messageHandler = undefined
|
||||
}
|
||||
|
||||
|
||||
// 清理DOM元素
|
||||
if (sandbox.iframe) {
|
||||
sandbox.iframe.remove()
|
||||
}
|
||||
|
||||
|
||||
if (sandbox.container) {
|
||||
sandbox.container.remove()
|
||||
}
|
||||
@@ -343,10 +283,10 @@ export class ApplicationSandboxEngine {
|
||||
|
||||
// 清理性能数据
|
||||
this.performanceData.delete(sandboxId)
|
||||
|
||||
|
||||
// 从集合中移除
|
||||
this.sandboxes.delete(sandboxId)
|
||||
|
||||
|
||||
console.log(`沙箱 ${sandboxId} 已销毁`)
|
||||
return true
|
||||
} catch (error) {
|
||||
@@ -366,7 +306,7 @@ export class ApplicationSandboxEngine {
|
||||
* 获取应用的所有沙箱
|
||||
*/
|
||||
getAppSandboxes(appId: string): SandboxInstance[] {
|
||||
return Array.from(this.sandboxes.values()).filter(sandbox => sandbox.appId === appId)
|
||||
return Array.from(this.sandboxes.values()).filter((sandbox) => sandbox.appId === appId)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,7 +336,7 @@ export class ApplicationSandboxEngine {
|
||||
sandbox.worker.postMessage(message)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
return false
|
||||
} catch (error) {
|
||||
console.error('发送消息到沙箱失败:', error)
|
||||
@@ -421,7 +361,7 @@ export class ApplicationSandboxEngine {
|
||||
clearInterval(this.monitoringInterval)
|
||||
this.monitoringInterval = null
|
||||
}
|
||||
|
||||
|
||||
this.cleanup()
|
||||
console.log('沙箱引擎已销毁')
|
||||
}
|
||||
@@ -453,10 +393,10 @@ export class ApplicationSandboxEngine {
|
||||
private async createIframeSandbox(sandbox: SandboxInstance): Promise<void> {
|
||||
const iframe = document.createElement('iframe')
|
||||
iframe.id = `sandbox-${sandbox.id}`
|
||||
|
||||
|
||||
// 设置sandbox属性
|
||||
const sandboxAttributes: string[] = []
|
||||
|
||||
|
||||
if (sandbox.config.allowScripts) sandboxAttributes.push('allow-scripts')
|
||||
if (sandbox.config.allowSameOrigin) sandboxAttributes.push('allow-same-origin')
|
||||
if (sandbox.config.allowForms) sandboxAttributes.push('allow-forms')
|
||||
@@ -465,9 +405,9 @@ export class ApplicationSandboxEngine {
|
||||
if (sandbox.config.allowPointerLock) sandboxAttributes.push('allow-pointer-lock')
|
||||
if (sandbox.config.allowPresentation) sandboxAttributes.push('allow-presentation')
|
||||
if (sandbox.config.allowTopNavigation) sandboxAttributes.push('allow-top-navigation')
|
||||
|
||||
|
||||
iframe.sandbox = sandboxAttributes.join(' ')
|
||||
|
||||
|
||||
// 设置样式
|
||||
iframe.style.cssText = `
|
||||
width: 100%;
|
||||
@@ -483,11 +423,11 @@ export class ApplicationSandboxEngine {
|
||||
|
||||
sandbox.iframe = iframe
|
||||
sandbox.container = iframe
|
||||
|
||||
|
||||
// 将iframe挂载到对应的窗口内容区域
|
||||
await this.mountIframeToWindow(sandbox)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将iframe挂载到窗口内容区域
|
||||
*/
|
||||
@@ -512,18 +452,18 @@ export class ApplicationSandboxEngine {
|
||||
}
|
||||
throw new Error(`找不到窗口元素: window-${sandbox.windowId}`)
|
||||
}
|
||||
|
||||
|
||||
const contentArea = windowElement.querySelector('.window-content')
|
||||
if (!contentArea) {
|
||||
throw new Error(`找不到窗口内容区域: window-${sandbox.windowId}`)
|
||||
}
|
||||
|
||||
|
||||
// 替换窗口中的默认iframe
|
||||
const existingIframe = contentArea.querySelector('iframe')
|
||||
if (existingIframe) {
|
||||
contentArea.removeChild(existingIframe)
|
||||
}
|
||||
|
||||
|
||||
contentArea.appendChild(sandbox.iframe!)
|
||||
}
|
||||
|
||||
@@ -567,9 +507,9 @@ export class ApplicationSandboxEngine {
|
||||
|
||||
const blob = new Blob([workerScript], { type: 'application/javascript' })
|
||||
const workerUrl = URL.createObjectURL(blob)
|
||||
|
||||
|
||||
const worker = new Worker(workerUrl)
|
||||
|
||||
|
||||
worker.onmessage = (e) => {
|
||||
const { type, error } = e.data
|
||||
if (type === 'error') {
|
||||
@@ -593,9 +533,9 @@ export class ApplicationSandboxEngine {
|
||||
private async createShadowDOMSandbox(sandbox: SandboxInstance): Promise<void> {
|
||||
const container = document.createElement('div')
|
||||
container.id = `sandbox-${sandbox.id}`
|
||||
|
||||
|
||||
const shadowRoot = container.attachShadow({ mode: 'closed' })
|
||||
|
||||
|
||||
// 添加样式隔离
|
||||
const style = document.createElement('style')
|
||||
style.textContent = `
|
||||
@@ -626,16 +566,16 @@ export class ApplicationSandboxEngine {
|
||||
}
|
||||
|
||||
// 这些头部主要用于服务器端设置,在客户端我们通过其他方式实现
|
||||
|
||||
|
||||
// 监听iframe的消息事件
|
||||
const messageHandler = (event: MessageEvent) => {
|
||||
if (event.source === sandbox.iframe!.contentWindow) {
|
||||
this.handleSandboxMessage(sandbox, event.data)
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', messageHandler);
|
||||
}
|
||||
window.addEventListener('message', messageHandler)
|
||||
// 存储事件监听器引用,以便在销毁时移除
|
||||
sandbox.messageHandler = messageHandler;
|
||||
sandbox.messageHandler = messageHandler
|
||||
|
||||
// 简化安全限制,主要依赖iframe的sandbox属性
|
||||
sandbox.iframe.addEventListener('load', () => {
|
||||
@@ -675,15 +615,15 @@ export class ApplicationSandboxEngine {
|
||||
case 'app:ready':
|
||||
sandbox.lastActiveAt = new Date()
|
||||
break
|
||||
|
||||
|
||||
case 'app:error':
|
||||
sandbox.errors.push(message.error || '未知错误')
|
||||
break
|
||||
|
||||
|
||||
case 'app:resource-request':
|
||||
this.handleResourceRequest(sandbox, message.data)
|
||||
break
|
||||
|
||||
|
||||
case 'app:performance':
|
||||
this.recordPerformance(sandbox, message.data)
|
||||
break
|
||||
@@ -695,10 +635,10 @@ export class ApplicationSandboxEngine {
|
||||
*/
|
||||
private async handleResourceRequest(sandbox: SandboxInstance, request: any): Promise<void> {
|
||||
const { type, data } = request
|
||||
|
||||
|
||||
try {
|
||||
let result = null
|
||||
|
||||
|
||||
switch (type) {
|
||||
case 'storage':
|
||||
if (data.action === 'get') {
|
||||
@@ -707,12 +647,16 @@ export class ApplicationSandboxEngine {
|
||||
result = await this.resourceService.setStorage(sandbox.appId, data.key, data.value)
|
||||
}
|
||||
break
|
||||
|
||||
|
||||
case 'network':
|
||||
result = await this.resourceService.makeNetworkRequest(sandbox.appId, data.url, data.options)
|
||||
result = await this.resourceService.makeNetworkRequest(
|
||||
sandbox.appId,
|
||||
data.url,
|
||||
data.options
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// 发送结果回沙箱
|
||||
this.sendMessage(sandbox.id, {
|
||||
type: 'system:resource-response',
|
||||
@@ -1171,10 +1115,10 @@ export class ApplicationSandboxEngine {
|
||||
// 通知系统应用已准备就绪
|
||||
window.parent.postMessage({ type: 'app:ready' }, '*');
|
||||
})();
|
||||
`;
|
||||
|
||||
iframeDoc.head.appendChild(script)
|
||||
}
|
||||
`
|
||||
|
||||
iframeDoc.head.appendChild(script)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置性能监控
|
||||
@@ -1260,9 +1204,12 @@ export class ApplicationSandboxEngine {
|
||||
private collectPerformanceMetrics(sandbox: SandboxInstance): void {
|
||||
if (sandbox.iframe && sandbox.iframe.contentWindow) {
|
||||
// 请求性能数据
|
||||
sandbox.iframe.contentWindow.postMessage({
|
||||
type: 'system:performance-request'
|
||||
}, '*')
|
||||
sandbox.iframe.contentWindow.postMessage(
|
||||
{
|
||||
type: 'system:performance-request'
|
||||
},
|
||||
'*'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1272,7 +1219,7 @@ export class ApplicationSandboxEngine {
|
||||
private updateSandboxState(sandbox: SandboxInstance, newState: SandboxState): void {
|
||||
const oldState = sandbox.state
|
||||
sandbox.state = newState
|
||||
|
||||
|
||||
// 触发状态变化事件
|
||||
this.eventService.sendMessage('system', 'sandbox-state-change', {
|
||||
sandboxId: sandbox.id,
|
||||
@@ -1280,4 +1227,4 @@ export class ApplicationSandboxEngine {
|
||||
oldState
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user