import { promises as fs } from 'node:fs' import { createHash } from 'node:crypto' import { join } from 'node:path' import { sandboxConfiguration } from './configuration' async function checkedBytes(path: string, limit: number): Promise { const before = await fs.lstat(path) if (!before.isFile() || before.isSymbolicLink() || before.nlink !== 1 || before.size > limit) throw new Error('沙盒组件类型或大小无效') const handle = await fs.open(path, 'r') try { const opened = await handle.stat() if (opened.ino !== before.ino || opened.dev !== before.dev || opened.nlink !== 1 || opened.size !== before.size) throw new Error('沙盒组件在读取前发生变化') const bytes = await handle.readFile(), after = await handle.stat() if (bytes.length !== opened.size || after.size !== opened.size || after.mtimeMs !== opened.mtimeMs) throw new Error('沙盒组件在读取期间发生变化') return bytes } finally { await handle.close() } } export async function verifiedBinary(requireTransactions = false, requireWorkspace = false, requireGitMetadata = false): Promise { const directory = sandboxConfiguration().resourceDirectory const manifest = JSON.parse(await fs.readFile(join(directory, 'manifest.json'), 'utf8')) as Record const binary = join(directory, 'ycode-sandbox.exe') const hash = (bytes: Uint8Array): string => createHash('sha256').update(bytes).digest('hex') if (manifest.protocol !== 1 || manifest.backend !== 'windows-appcontainer' || manifest.architecture !== 'x64' || requireTransactions && manifest.workspaceTransactions !== 1 || requireWorkspace && manifest.workspaceState !== 1 || requireGitMetadata && manifest.gitMetadataTransactions !== 1 || typeof manifest.binarySha256 !== 'string' || hash(await checkedBytes(binary, 16 * 1024 * 1024)) !== manifest.binarySha256) throw new Error('沙盒原生组件缺失、版本不匹配或摘要校验失败;请运行 npm run sandbox:build') for (const [file, key] of [['node-bridge.cjs', 'nodeBridgeSha256'], ['node-process.cjs', 'nodeProcessSha256'], ['python-sitecustomize.py', 'pythonAdapterSha256']]) { if (typeof manifest[key] !== 'string' || hash(await checkedBytes(join(directory, file), 64 * 1024)) !== manifest[key]) throw new Error('沙盒适配组件缺失或摘要校验失败;请运行 npm run sandbox:build') } return binary }