Files
ycode/src/main/sandbox/native-component.ts
T

33 lines
2.4 KiB
TypeScript

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<Buffer> {
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<string> {
const directory = sandboxConfiguration().resourceDirectory
const manifest = JSON.parse(await fs.readFile(join(directory, 'manifest.json'), 'utf8')) as Record<string, unknown>
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
}