Initial curated chimera source from a8ae5b1db07fb49926c94585e2718e5130330974

This commit is contained in:
Public Source Publisher committed 2026-10-01 01:38:08 +02:00
commit c737a37f71
531 files changed
+119270

No files matched your search

@@ -0,0 +1,131 @@
'use strict';
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const test = require('node:test');
const initSqlJs = require('sql.js');
const migration = require('../../src/database/migrations/0012-create-trophy-psn-snapshots');
const { SecretsStore } = require('../../src/security/secrets-store');
const {
createAuthorizedPsnTrophyProvider,
createJsonTrophySnapshotProvider,
createSqliteTrophySnapshotRepository,
parseTrophySnapshot,
} = require('../../src/services/trophy-snapshot-service');
function sample(overrides = {}) {
return {
schemaVersion: 1,
provider: { id: 'user-export', version: '2.4.0' },
account: { accountId: '1234567890123456', onlineId: 'Player_One' },
context: { region: 'BE', language: 'nl-BE' },
fetchedAt: '2026-07-20T12:00:00.000Z',
warnings: ['export is read-only'],
titles: [{
npCommunicationId: 'NPWR12345_00', titleId: 'PPSA12345', contentId: 'EP0001-PPSA12345_00-GAME000000000001', name: 'Example Game', platform: 'PS5', service: 'trophy2',
groups: [{ groupId: 'default', name: 'Base Game' }],
trophies: [
{ groupId: 'default', trophyId: 2, name: 'Second', grade: 'silver', hidden: false, earned: false, progress: 20 },
{ groupId: 'default', trophyId: 1, name: 'First', grade: 'gold', hidden: false, earned: true, earnedDateTime: '2026-01-02T03:04:05Z', progress: 100 },
],
}],
...overrides,
};
}
async function repository() {
const SQL = await initSqlJs();
const db = new SQL.Database();
migration.up(db);
return { db, repository: createSqliteTrophySnapshotRepository({ db }) };
}
test('JSON import validates, normalizes and stores canonical immutable proof', async t => {
const { db, repository: repo } = await repository();
t.after(() => db.close());
const provider = createJsonTrophySnapshotProvider({ repository: repo, now: () => 1800000000000 });
const first = provider.authenticateOrImport({ ...sample(), signature: 'signature-a' }, { filename: 'proof.json' });
const reordered = sample({ warnings: ['export is read-only'], signature: 'signature-b' });
reordered.titles[0].trophies.reverse();
const second = provider.authenticateOrImport(JSON.stringify(reordered), { filename: 'other.json' });
assert.equal(first.id, second.id);
assert.equal(first.canonicalSha256, second.canonicalSha256);
assert.deepEqual(first.snapshot.titles[0].trophies.map(item => item.trophyId), [1, 2]);
assert.equal(repo.list().length, 1);
assert.throws(() => db.run('UPDATE trophy_psn_snapshots SET online_id = ?', ['Changed']), /immutable/);
const publicModel = provider.sanitizePublicModel(first);
assert.equal(publicModel.account.accountId.endsWith('3456'), true);
assert.equal(publicModel.account.accountId.includes('123456789012'), false);
assert.equal(publicModel.readOnly, true);
});
test('invalid JSON, unknown fields, invalid timestamps and duplicate identities fail closed', () => {
assert.throws(() => parseTrophySnapshot('{'), error => error.code === 'TROPHY_SCHEMA');
assert.throws(() => parseTrophySnapshot({ ...sample(), writeEndpoint: 'https://example.invalid' }), error => error.code === 'TROPHY_SCHEMA');
const missingTime = sample();
delete missingTime.titles[0].trophies[1].earnedDateTime;
assert.throws(() => parseTrophySnapshot(missingTime), error => error.code === 'TROPHY_SCHEMA');
const duplicate = sample();
duplicate.titles[0].trophies.push({ ...duplicate.titles[0].trophies[0] });
assert.throws(() => parseTrophySnapshot(duplicate), error => error.code === 'TROPHY_SCHEMA');
});
test('authorized provider encrypts and redacts its token and revoke retains proof', async t => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-trophy-secrets-'));
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
const { db, repository: repo } = await repository();
t.after(() => db.close());
const secrets = new SecretsStore({ filePath: path.join(root, 'secrets.json'), keyFile: path.join(root, 'secret.key') });
const token = 'read-only-token-that-must-never-leak';
const provider = createAuthorizedPsnTrophyProvider({ repository: repo, secrets, fetchPage: async () => ({ titles: [], nextCursor: null }), now: () => 1800000000000 });
const auth = provider.authenticateOrImport({ accessToken: token });
assert.equal(auth.authenticated, true);
assert.equal(fs.readFileSync(path.join(root, 'secrets.json'), 'utf8').includes(token), false);
assert.equal(JSON.stringify(provider.sanitizePublicModel()).includes(token), false);
assert.equal(provider.revoke().snapshotsRetained, true);
assert.equal(secrets.has('trophy.psn.readonly.access-token'), false);
});
test('authorized provider paginates with bounded GET requests and rate limiting', async t => {
const { db, repository: repo } = await repository();
t.after(() => db.close());
const values = new Map([['trophy.psn.readonly.access-token', 'read-only-token-123456']]);
const secrets = { set: (key, value) => value ? values.set(key, value) : values.delete(key), get: key => values.get(key) || '', has: key => values.has(key) };
let clock = 1800000000000;
const calls = [];
const pages = [
{ titles: [sample().titles[0]], nextCursor: 'page-2' },
{ titles: [{ ...sample().titles[0], npCommunicationId: 'NPWR54321_00', titleId: 'PPSA54321' }], nextCursor: null },
];
const provider = createAuthorizedPsnTrophyProvider({
repository: repo,
secrets,
now: () => clock,
sleep: async ms => { clock += ms; },
limits: { minIntervalMs: 100, pageSize: 1, pages: 3 },
fetchPage: async request => { calls.push({ method: request.method, cursor: request.cursor, at: clock, token: request.accessToken }); return pages.shift(); },
});
const stored = await provider.fetchSnapshot({ accountId: '1234567890123456', onlineId: 'Player_One', region: 'BE', language: 'nl-BE' });
assert.equal(stored.titleCount, 2);
assert.deepEqual(calls.map(call => call.method), ['GET', 'GET']);
assert.ok(calls[1].at - calls[0].at >= 100);
assert.equal(JSON.stringify(provider.sanitizePublicModel(stored)).includes(calls[0].token), false);
const looping = createAuthorizedPsnTrophyProvider({ repository: repo, secrets, now: () => clock, sleep: async ms => { clock += ms; }, limits: { pages: 2, minIntervalMs: 0 }, fetchPage: async ({ cursor }) => ({ titles: [], nextCursor: cursor ? 'third' : 'second' }) });
await assert.rejects(() => looping.fetchSnapshot({ accountId: '1234567890123456', onlineId: 'Player_One', region: 'BE', language: 'nl-BE' }), error => error.code === 'TROPHY_LIMIT');
});
test('snapshot providers expose only read-only remote trophy contracts', () => {
const schema = require('../../schemas/trophy-psn-proof.schema.json');
assert.equal(schema.properties.schemaVersion.const, 1);
assert.equal(schema.additionalProperties, false);
const source = fs.readFileSync(path.resolve(__dirname, '../../src/services/trophy-snapshot-service.js'), 'utf8');
assert.match(source, /capabilities:\s*CAPABILITIES/);
assert.doesNotMatch(source, /method:\s*['"](?:POST|PUT|PATCH|DELETE)['"]/i);
assert.doesNotMatch(source, /troph(?:y|ies).{0,40}(?:sync|unlock|write)/i);
const importer = fs.readFileSync(path.resolve(__dirname, '../../src/services/psn-trophy-history-import-service.js'), 'utf8');
assert.doesNotMatch(importer, /method:\s*['"](?:POST|PUT|PATCH|DELETE)['"]/i);
assert.doesNotMatch(importer, /troph(?:y|ies).{0,40}(?:sync|unlock|write)/i);
});