Initial curated chimera source from a8ae5b1db07fb49926c94585e2718e5130330974
This commit is contained in:
commit
c737a37f71
531 files changed
+119270
No files matched your search
@@ -0,0 +1,124 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const crypto = require('node:crypto');
|
||||
const test = require('node:test');
|
||||
|
||||
const {
|
||||
CONSENT,
|
||||
canonicalCatalogDigest,
|
||||
createLegacyDetachedTrophyPreflightService,
|
||||
normalizeDetachedPreflight,
|
||||
} = require('../../src/services/legacy-detached-trophy-preflight-service');
|
||||
|
||||
const game = {
|
||||
title: 'Detached test game',
|
||||
trophies: [
|
||||
{ id: 0, grade: 'bronze', name: 'First', description: 'First trophy', hidden: false },
|
||||
{ id: 1, grade: 'gold', name: 'Second', description: 'Second trophy', hidden: true },
|
||||
],
|
||||
};
|
||||
|
||||
function digest(value) {
|
||||
return crypto.createHash('sha256').update(value).digest('hex');
|
||||
}
|
||||
|
||||
function readyResult(catalogSha256) {
|
||||
return {
|
||||
status: 'ready',
|
||||
readOnly: true,
|
||||
persisted: false,
|
||||
identifiersReturned: false,
|
||||
pointersReturned: false,
|
||||
catalogSha256,
|
||||
targetInactive: true,
|
||||
cleanupComplete: true,
|
||||
metadata: { paramSfo: true, npbind: true, trophyPackage: true, npTitleAuth: true },
|
||||
context: { created: true, registered: true, stateRead: true, destroyed: true },
|
||||
handle: { created: true, destroyed: true },
|
||||
sideEffects: { unlockCalls: 0, storageWrites: 0, mounts: 0, psnRequests: 0, filesPersisted: 0 },
|
||||
};
|
||||
}
|
||||
|
||||
test('detached preflight is fail-closed until both native artifacts are pinned', () => {
|
||||
const service = createLegacyDetachedTrophyPreflightService();
|
||||
assert.deepEqual(service.status(), {
|
||||
available: false,
|
||||
readOnly: true,
|
||||
reasonCode: 'NATIVE_ADAPTER_NOT_PINNED',
|
||||
});
|
||||
});
|
||||
|
||||
test('detached preflight is bound to an exact catalog digest and read-only consent', async () => {
|
||||
const cliPath = 'C:\\fixture\\preflight-cli.mjs';
|
||||
const elfPath = 'C:\\fixture\\preflight.elf';
|
||||
const files = new Map([[cliPath, Buffer.from('cli')], [elfPath, Buffer.from('elf')]]);
|
||||
const calls = [];
|
||||
const catalogSha256 = canonicalCatalogDigest(game);
|
||||
const service = createLegacyDetachedTrophyPreflightService({
|
||||
cliPath,
|
||||
elfPath,
|
||||
expectedCliSha256: digest(files.get(cliPath)),
|
||||
expectedElfSha256: digest(files.get(elfPath)),
|
||||
fs: {
|
||||
existsSync: (candidate) => files.has(candidate),
|
||||
readFileSync: (candidate) => files.get(candidate),
|
||||
},
|
||||
installedCatalog: async () => ({ games: [game] }),
|
||||
runAdapter: async (request) => {
|
||||
calls.push(request);
|
||||
return readyResult(catalogSha256);
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(service.status().available, true);
|
||||
const result = await service.preflight({ catalogSha256 });
|
||||
assert.equal(result.ready, true);
|
||||
assert.equal(result.cleanupComplete, true);
|
||||
assert.deepEqual(result.sideEffects, {
|
||||
unlockCalls: 0,
|
||||
storageWrites: 0,
|
||||
mounts: 0,
|
||||
psnRequests: 0,
|
||||
filesPersisted: 0,
|
||||
});
|
||||
assert.equal(calls.length, 1);
|
||||
assert.equal(calls[0].consent, CONSENT);
|
||||
assert.equal(calls[0].catalogSha256, catalogSha256);
|
||||
assert.equal(Object.hasOwn(calls[0], 'titleId'), false);
|
||||
assert.equal(Object.hasOwn(calls[0], 'trophyId'), false);
|
||||
});
|
||||
|
||||
test('detached preflight rejects a stale or invented selection digest', async () => {
|
||||
const cliPath = 'cli';
|
||||
const elfPath = 'elf';
|
||||
const files = new Map([[cliPath, Buffer.from('cli')], [elfPath, Buffer.from('elf')]]);
|
||||
const service = createLegacyDetachedTrophyPreflightService({
|
||||
cliPath,
|
||||
elfPath,
|
||||
expectedCliSha256: digest(files.get(cliPath)),
|
||||
expectedElfSha256: digest(files.get(elfPath)),
|
||||
fs: { existsSync: (candidate) => files.has(candidate), readFileSync: (candidate) => files.get(candidate) },
|
||||
installedCatalog: async () => ({ games: [game] }),
|
||||
runAdapter: async () => { throw new Error('must not run'); },
|
||||
});
|
||||
await assert.rejects(service.preflight({ catalogSha256: '0'.repeat(64) }), /no longer matches/i);
|
||||
});
|
||||
|
||||
test('detached preflight rejects writes, unlocks and incomplete cleanup', () => {
|
||||
const catalogSha256 = canonicalCatalogDigest(game);
|
||||
const wroteStorage = readyResult(catalogSha256);
|
||||
wroteStorage.sideEffects.storageWrites = 1;
|
||||
assert.throws(() => normalizeDetachedPreflight(wroteStorage, catalogSha256), /read-only contract/i);
|
||||
|
||||
const leaked = readyResult(catalogSha256);
|
||||
leaked.context.destroyed = false;
|
||||
assert.throws(() => normalizeDetachedPreflight(leaked, catalogSha256), /leaked a context|every phase/i);
|
||||
|
||||
const wrongCatalog = readyResult('f'.repeat(64));
|
||||
assert.throws(() => normalizeDetachedPreflight(wrongCatalog, catalogSha256), /catalog binding/i);
|
||||
|
||||
const leakedIdentifier = readyResult(catalogSha256);
|
||||
leakedIdentifier.titleId = 'CUSA00000';
|
||||
assert.throws(() => normalizeDetachedPreflight(leakedIdentifier, catalogSha256), /forbidden top-level data/i);
|
||||
});
|
||||
Reference in new issue
Block a user