Files
chimera-Public/test/server/ch-0913-legacy-detached-trophy-mutation-adapter.test.js

94 lines
3.4 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const crypto = require('node:crypto');
const test = require('node:test');
const { CONSENT } = require('../../src/services/inactive-legacy-trophy-unlock-service');
const { createLegacyDetachedTrophyMutationAdapter } = require('../../src/services/legacy-detached-trophy-mutation-adapter');
function sha256(value) {
return crypto.createHash('sha256').update(value).digest('hex');
}
test('native inactive mutation adapter is fail-closed without artifact pins', () => {
assert.deepEqual(createLegacyDetachedTrophyMutationAdapter().status(), {
available: false,
reasonCode: 'NATIVE_MUTATION_ADAPTER_NOT_PINNED',
});
});
test('native inactive mutation adapter verifies both artifacts and forwards an exact-one request', async () => {
const cliPath = 'cli';
const elfPath = 'elf';
const cli = Buffer.from('cli');
const elf = Buffer.from('elf');
const files = new Map([[cliPath, cli], [elfPath, elf]]);
const catalogSha256 = 'a'.repeat(64);
const trophySha256 = 'b'.repeat(64);
const backupSha256 = 'c'.repeat(64);
let forwarded;
const adapter = createLegacyDetachedTrophyMutationAdapter({
cliPath,
elfPath,
expectedCliSha256: sha256(cli),
expectedElfSha256: sha256(elf),
fs: { existsSync: (candidate) => files.has(candidate), readFileSync: (candidate) => files.get(candidate) },
runAdapter: async (request) => {
forwarded = request;
return {
status: 'unlocked',
catalogSha256,
trophySha256,
targetInactive: true,
unlockCalls: 1,
psnRequests: 0,
contextDestroyed: true,
handleDestroyed: true,
filesPersisted: 0,
};
},
});
const result = await adapter.unlockOne({
consent: CONSENT,
catalogSha256,
trophySha256,
trophyId: 7,
backupSha256,
});
assert.equal(result.status, 'unlocked');
assert.equal(forwarded.trophyId, 7);
assert.equal(forwarded.expectedElfSha256, sha256(elf));
assert.equal(Object.hasOwn(forwarded, 'titleId'), false);
});
test('native inactive mutation adapter rejects a hash mismatch before execution', async () => {
let ran = false;
const files = new Map([['cli', Buffer.from('cli')], ['elf', Buffer.from('elf')]]);
const adapter = createLegacyDetachedTrophyMutationAdapter({
cliPath: 'cli',
elfPath: 'elf',
expectedCliSha256: '0'.repeat(64),
expectedElfSha256: sha256(files.get('elf')),
fs: { existsSync: (candidate) => files.has(candidate), readFileSync: (candidate) => files.get(candidate) },
runAdapter: async () => { ran = true; },
});
assert.equal(adapter.status().reasonCode, 'NATIVE_MUTATION_ADAPTER_HASH_MISMATCH');
await assert.rejects(adapter.unlockOne({}), /unavailable/i);
assert.equal(ran, false);
});
test('native inactive mutation adapter rejects caller-supplied title metadata', async () => {
const files = new Map([['cli', Buffer.from('cli')], ['elf', Buffer.from('elf')]]);
const adapter = createLegacyDetachedTrophyMutationAdapter({
cliPath: 'cli',
elfPath: 'elf',
expectedCliSha256: sha256(files.get('cli')),
expectedElfSha256: sha256(files.get('elf')),
fs: { existsSync: (candidate) => files.has(candidate), readFileSync: (candidate) => files.get(candidate) },
runAdapter: async () => { throw new Error('must not run'); },
});
await assert.rejects(adapter.unlockOne({ titleId: 'CUSA00000' }), /forbidden field/i);
});