import { createHash } from 'node:crypto'; import { lstat, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { unzipSync } from 'fflate'; const repositoryRoot = path.resolve( path.dirname(fileURLToPath(import.meta.url)), '..' ); const lockPath = path.join( repositoryRoot, 'scripts', 'reviewed-ffmpeg-core-lock.json' ); const maximumArchiveBytes = 64 * 1024 * 1024; const maximumAssetBytes = 64 * 1024 * 1024; const requiredAssetPaths = new Set([ 'st/ffmpeg-core.js', 'st/ffmpeg-core.wasm', 'mt/ffmpeg-core.js', 'mt/ffmpeg-core.wasm', 'mt/ffmpeg-core.worker.js', ]); function sha256(bytes) { return createHash('sha256').update(bytes).digest('hex'); } function assertSafeRelativePath(value) { if ( typeof value !== 'string' || value.length === 0 || value.includes('\\') || value.includes('\0') || value.startsWith('/') || path.posix.normalize(value) !== value || value.split('/').some((part) => !part || part === '.' || part === '..') ) { throw new Error(`Unsafe reviewed-core path: ${String(value)}`); } return value; } async function requireRealDirectory(directory, create = false) { let details = await lstat(directory).catch((error) => { if (error && typeof error === 'object' && error.code === 'ENOENT') { return undefined; } throw error; }); if (!details && create) { await mkdir(directory); details = await lstat(directory); } if (!details || details.isSymbolicLink() || !details.isDirectory()) { throw new Error(`Required directory is unsafe: ${directory}`); } } const lock = JSON.parse(await readFile(lockPath, 'utf8')); const lockedAssetPaths = new Set( Array.isArray(lock.assets) ? lock.assets.map((asset) => asset.path) : [] ); if ( lock.schemaVersion !== 1 || typeof lock.buildId !== 'string' || !/^[a-zA-Z0-9._-]+$/.test(lock.buildId) || lock.coreVersion !== '0.12.10' || lock.profile !== 'reviewed-stack5m' || lock.sourceArchive?.path !== 'release/ffmpeg-core-0.12.10-reviewed-stack5m.1-corresponding-source.tar.xz' || !/^[a-f0-9]{64}$/.test(lock.sourceArchive?.sha256 ?? '') || lock.sourceLock?.path !== 'scripts/ffmpeg-source-lock.json' || !/^[a-f0-9]{64}$/.test(lock.sourceLock?.sha256 ?? '') || lock.buildDriver?.path !== 'scripts/build-reviewed-ffmpeg-core.sh' || !/^[a-f0-9]{64}$/.test(lock.buildDriver?.sha256 ?? '') || lock.patch?.upstreamCommit !== 'b409e36475bc21f0451b5b1e1d126fa82871439a' || lock.patch?.stackSizeBytes !== 5 * 1024 * 1024 || typeof lock.opusRegression?.singleThread !== 'boolean' || typeof lock.opusRegression?.multiThread !== 'boolean' || !Array.isArray(lock.assets) || lock.assets.length !== 5 || lock.assets.some( (asset) => !requiredAssetPaths.has(asset.path) || !Number.isSafeInteger(asset.bytes) || asset.bytes < 1 || asset.bytes > maximumAssetBytes || !/^[a-f0-9]{64}$/.test(asset.sha256 ?? '') ) || lockedAssetPaths.size !== requiredAssetPaths.size || [...requiredAssetPaths].some((assetPath) => !lockedAssetPaths.has(assetPath)) ) { throw new Error(`Invalid reviewed FFmpeg core lock: ${lockPath}`); } const artifactRelativePath = assertSafeRelativePath(lock.artifact?.path); if (artifactRelativePath !== `vendor/ffmpeg-core-${lock.buildId}.zip`) { throw new Error('Reviewed-core artifact path and build identity disagree.'); } const artifact = await readFile( path.join(repositoryRoot, ...artifactRelativePath.split('/')) ); if ( artifact.byteLength < 1 || artifact.byteLength > maximumArchiveBytes || artifact.byteLength !== lock.artifact.bytes || sha256(artifact) !== lock.artifact.sha256 ) { throw new Error('Reviewed FFmpeg core archive failed locked verification.'); } const lockedArchiveEntries = new Map( lock.assets.map((asset) => [asset.path, asset]) ); const archiveEntries = new Set(); const uncompressed = unzipSync(artifact, { filter: (entry) => { const relative = assertSafeRelativePath(entry.name); const locked = lockedArchiveEntries.get(relative); if ( !locked || archiveEntries.has(relative) || entry.originalSize !== locked.bytes || entry.originalSize < 1 || entry.originalSize > maximumAssetBytes || entry.size < 1 || entry.size > maximumArchiveBytes ) { throw new Error( `Reviewed FFmpeg core archive has an unexpected entry: ${entry.name}` ); } archiveEntries.add(relative); return true; }, }); if (archiveEntries.size !== lockedArchiveEntries.size) { throw new Error('Reviewed FFmpeg core archive is missing an expected entry.'); } const vendorRoot = path.join(repositoryRoot, 'public', 'vendor', 'ffmpeg'); const outputRoot = path.join(vendorRoot, lock.buildId); await requireRealDirectory(repositoryRoot); await requireRealDirectory(path.join(repositoryRoot, 'public')); await requireRealDirectory(path.join(repositoryRoot, 'public', 'vendor'), true); const existingVendorRoot = await lstat(vendorRoot).catch((error) => { if (error && typeof error === 'object' && error.code === 'ENOENT') { return undefined; } throw error; }); if ( existingVendorRoot && (existingVendorRoot.isSymbolicLink() || !existingVendorRoot.isDirectory()) ) { throw new Error(`Generated FFmpeg vendor root is unsafe: ${vendorRoot}`); } await rm(vendorRoot, { force: true, recursive: true }); for (const asset of lock.assets) { const relativeAssetPath = assertSafeRelativePath(asset.path); const bytes = uncompressed[relativeAssetPath]; if ( !bytes || bytes.byteLength < 1 || bytes.byteLength > maximumAssetBytes || bytes.byteLength !== asset.bytes || sha256(bytes) !== asset.sha256 ) { throw new Error( `Reviewed FFmpeg core entry failed locked verification: ${asset.path}` ); } const destination = path.join(outputRoot, ...relativeAssetPath.split('/')); await mkdir(path.dirname(destination), { recursive: true }); await writeFile(destination, bytes, { flag: 'wx', mode: 0o644 }); } const versionManifest = { schemaVersion: 2, buildId: lock.buildId, profile: lock.profile, coreVersion: lock.coreVersion, ffmpegVersion: lock.ffmpegVersion, sourceArchive: lock.sourceArchive, sourceLock: lock.sourceLock, buildDriver: lock.buildDriver, toolchain: lock.toolchain, patch: lock.patch, opusRegression: lock.opusRegression, assets: lock.assets, }; await writeFile( path.join(outputRoot, 'version.json'), `${JSON.stringify(versionManifest, null, 2)}\n`, { flag: 'wx', mode: 0o644 } ); console.log( `Verified and unpacked ${lock.assets.length} reviewed FFmpeg assets to ${path.relative(repositoryRoot, outputRoot)}` );