'use strict'; const assert = require('node:assert/strict'); const crypto = require('node:crypto'); const fs = require('node:fs'); const os = require('node:os'); const path = require('node:path'); const test = require('node:test'); const { validatePs5FpkgCandidate } = require('../../src/services/ps5-fih-validator'); const { createPs5NativePackageService } = require('../../src/services/ps5-native-package-service'); const { PINNED_PS5_BUILDER } = require('../../src/services/ps5-native-pkg-builder-provider'); const { validatePs5NativePackageManifest } = require('../../src/services/ps5-native-package-registration-service'); const TITLE_ID = 'PPSA12345'; const CONTENT_ID = 'UP0001-PPSA12345_00-CHIMERATEST00001'; function writeFih(filename, contentId = CONTENT_ID) { const fih = Buffer.alloc(0x10000); const pfs = Buffer.alloc(0x10000); const cnt = Buffer.alloc(0x2900); Buffer.from([0x7f, 0x46, 0x49, 0x48]).copy(fih); fih[4] = 1; fih.writeUInt16LE(3, 6); fih.writeUInt32LE(1, 8); fih.writeBigUInt64LE(0x10000n, 0x10); fih.writeBigUInt64LE(0x10000n, 0x18); fih.writeBigUInt64LE(0x20000n, 0x58); fih.writeUInt32LE(1, 0xfc); const gameDigest = crypto.createHash('sha3-256').update(pfs).digest(); for (const offset of [0x30, 0x70, 0xd0]) gameDigest.copy(fih, offset); Buffer.from([0x7f, 0x43, 0x4e, 0x54]).copy(cnt); cnt.writeUInt32BE(1, 0x10); cnt.writeUInt16BE(1, 0x14); cnt.writeUInt16BE(1, 0x16); cnt.writeUInt32BE(0x2000, 0x18); cnt.writeBigUInt64BE(0x2000n, 0x20); cnt.writeBigUInt64BE(0x900n, 0x28); Buffer.from(contentId, 'ascii').copy(cnt, 0x40, 0, 0x30); cnt.writeUInt32BE(0x20, 0x2000); cnt.writeUInt32BE(0x2100, 0x2010); cnt.writeUInt32BE(0x800, 0x2014); for (const [record, offset] of [0x000, 0x180, 0x300, 0x480, 0x600].entries()) crypto.createHash('sha256').update(`${contentId}:${record}`).digest().copy(cnt, 0x2100 + offset); crypto.createHash('sha3-256').update(cnt.subarray(0, 0xfe0)).digest().copy(cnt, 0xfe0); fs.mkdirSync(path.dirname(filename), { recursive: true }); fs.writeFileSync(filename, Buffer.concat([fih, pfs, cnt])); } function writeBackup(root) { const source = path.join(root, 'source'); fs.mkdirSync(path.join(source, 'sce_sys'), { recursive: true }); fs.writeFileSync(path.join(source, 'eboot.bin'), Buffer.concat([Buffer.from([0x7f, 0x45, 0x4c, 0x46]), Buffer.alloc(64)])); fs.writeFileSync(path.join(source, 'sce_sys', 'param.json'), JSON.stringify({ titleId: TITLE_ID, contentId: CONTENT_ID, contentVersion: '01.00', titleName: 'Artifact test' })); return source; } function upstream(accepted = true) { return { accepted, validator: 'ProsperoPkgValidator', launchReady: true, unresolvedModules: [] }; } test('admits only literal finalized FIH .pkg candidates with matching upstream identity', t => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-fpkg-format-')); t.after(() => fs.rmSync(root, { recursive: true, force: true })); const fih = path.join(root, 'game.pkg'); writeFih(fih); assert.equal(validatePs5FpkgCandidate(fih, { expectedContentId: CONTENT_ID, upstreamValidation: upstream() }).accepted, true); for (const [name, bytes] of [ ['cnt.pkg', Buffer.concat([Buffer.from([0x7f, 0x43, 0x4e, 0x54]), Buffer.alloc(32)])], ['mount.ffpkg', Buffer.concat([Buffer.from([0x7f, 0x46, 0x49, 0x48]), Buffer.alloc(32)])], ['renamed.pkg', Buffer.from('ffpkg/UFS image renamed as pkg')], ['unknown.pkg', Buffer.from('unknown package')], ]) { const candidate = path.join(root, name); fs.writeFileSync(candidate, bytes); assert.throws(() => validatePs5FpkgCandidate(candidate, { expectedContentId: CONTENT_ID, upstreamValidation: upstream() }), error => error.code === 'PS5_FPKG_OUTPUT_NOT_FIH'); } assert.throws(() => validatePs5FpkgCandidate(fih, { expectedContentId: 'UP0001-PPSA99999_00-CHIMERATEST00001', upstreamValidation: upstream() }), error => error.code === 'PS5_FPKG_TITLE_MISMATCH'); assert.throws(() => validatePs5FpkgCandidate(fih, { expectedContentId: CONTENT_ID, upstreamValidation: upstream(false) }), error => error.code === 'PS5_FPKG_VALIDATION_FAILED'); }); test('direct builder registers truthful manifest v2 provenance without install or launch claims', async t => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-fpkg-manifest-')); t.after(() => fs.rmSync(root, { recursive: true, force: true })); const libraryRoot = path.join(root, 'library'); const outputRoot = path.join(root, 'vault'); fs.mkdirSync(libraryRoot); const registrations = []; const provider = { probe: async () => ({ available: true, ...PINNED_PS5_BUILDER, capabilities: { backupBuildApi: 'ProsperoPackageBuilder', backupToDebugFpkg: true, dataDlcToDebugFpkg: true, updateToDebugFpkg: false, packageValidation: true, licenseFreeBuild: true, finalizedFihOutput: true } }), build: async input => { writeFih(input.outputPath, input.contentId); return { provider: PINNED_PS5_BUILDER }; }, validatePackage: async () => upstream(), }; const service = createPs5NativePackageService({ allowedRoots: () => [libraryRoot, outputRoot], outputRoot, stateFile: path.join(root, 'jobs.json'), provider, registrar: async manifest => { registrations.push(manifest); return { packageSetId: 1303 }; }, idFactory: () => 'artifact-job', now: () => 1_800_000_000_000 }); const created = await service.create({ sourcePath: writeBackup(libraryRoot) }); assert.equal(created.status, 'package_ready'); const result = await service.run(created.id); assert.equal(result.status, 'artifact_registered'); assert.equal(result.launchVerified, false); assert.equal(result.productionRestorable, false); const manifest = registrations[0]; assert.equal(validatePs5NativePackageManifest(manifest).schemaVersion, 2); assert.equal(manifest.builder.api, 'ProsperoPackageBuilder'); const historical = structuredClone(manifest); historical.builder.api = 'ProsperoBackupConverter'; assert.equal(validatePs5NativePackageManifest(historical).schemaVersion, 2); const invalid = structuredClone(manifest); invalid.builder.api = 'arbitrary-builder'; assert.throws(() => validatePs5NativePackageManifest(invalid)); assert.deepEqual(manifest.packageFormat, { family: 'ps5-fpkg', extension: '.pkg', container: 'FIH', magic: '7f464948', debug: true, licenseFree: true, retail: false }); assert.equal(manifest.builder.bridgeAbi, 'chimera-prospero-bridge-v4'); assert.equal(manifest.builder.patched, true); assert.equal(manifest.builder.patch, 'chimera-stream-large-package-assembly-u2c24-v2'); assert.equal(manifest.evidence.consoleInstall.status, 'unproven'); assert.equal(manifest.evidence.consoleLaunch.status, 'unproven'); assert.equal(manifest.launchVerified, false); assert.equal(manifest.productionRestorable, false); }); test('registration interruption preserves the artifact and hash drift blocks retry', async t => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-fpkg-drift-')); t.after(() => fs.rmSync(root, { recursive: true, force: true })); const libraryRoot = path.join(root, 'library'); const outputRoot = path.join(root, 'vault'); fs.mkdirSync(libraryRoot); let builds = 0; const provider = { probe: async () => ({ available: true, ...PINNED_PS5_BUILDER, capabilities: { backupToDebugFpkg: true, dataDlcToDebugFpkg: true, updateToDebugFpkg: false, packageValidation: true, licenseFreeBuild: true, finalizedFihOutput: true } }), build: async input => { builds++; writeFih(input.outputPath, input.contentId); }, validatePackage: async () => upstream(), }; const service = createPs5NativePackageService({ allowedRoots: () => [libraryRoot, outputRoot], outputRoot, stateFile: path.join(root, 'jobs.json'), provider, registrar: async () => ({}), idFactory: () => 'drift-job' }); const created = await service.create({ sourcePath: writeBackup(libraryRoot) }); await assert.rejects(() => service.run(created.id), error => error.code === 'PS5_PACKAGE_REGISTRATION_INCOMPLETE'); const pending = service.get(created.id); assert.equal(pending.status, 'registration_pending'); const fd = fs.openSync(pending.manifest.components[0].absolutePath, 'r+'); fs.writeSync(fd, Buffer.from([0x01]), 0, 1, 0x10010); fs.closeSync(fd); await assert.rejects(() => service.run(created.id), error => error.code === 'PS5_FPKG_ARTIFACT_HASH_DRIFT'); assert.equal(builds, 1); assert.equal(service.get(created.id).status, 'registration_pending'); }); test('blocked fPKG analysis remains a safe preservation result', async t => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-fpkg-blocked-')); t.after(() => fs.rmSync(root, { recursive: true, force: true })); const libraryRoot = path.join(root, 'library'); const outputRoot = path.join(root, 'vault'); fs.mkdirSync(libraryRoot); const source = writeBackup(libraryRoot); fs.writeFileSync(path.join(source, 'eboot.bin'), Buffer.concat([Buffer.from([0x54, 0x14, 0xf5, 0xee]), Buffer.alloc(64)])); const service = createPs5NativePackageService({ allowedRoots: () => [libraryRoot, outputRoot], outputRoot, stateFile: path.join(root, 'jobs.json'), provider: { probe: async () => ({}), build: async () => ({}) }, registrar: async () => ({ packageSetId: 1 }) }); const result = await service.create({ sourcePath: source }); assert.equal(result.status, 'package_blocked'); assert.notEqual(result.status, 'failed'); assert.equal(result.components[0].preservation.complete, true); assert.equal(result.components[0].fpkgReadiness.state, 'blocked'); });