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,145 @@
|
||||
'use strict';
|
||||
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const { Readable } = require('stream');
|
||||
const { Response } = require('node-fetch');
|
||||
const {
|
||||
createGameUpdateService, normalizeManifest, officialSonyUrl,
|
||||
ps4VersionUrl, parseVersionXml, findVersionFileUri,
|
||||
} = require('../../src/services/game-update-service');
|
||||
|
||||
test('Sony update manifests require contiguous hash-verified official pieces', () => {
|
||||
const source = 'https://gs2.ww.prod.dl.playstation.net/path/CUSA00001-update.json';
|
||||
const manifest = normalizeManifest({
|
||||
originalFileSize: 12,
|
||||
packageDigest: 'a'.repeat(64),
|
||||
pieces: [
|
||||
{ url: 'https://gs2.ww.prod.dl.playstation.net/path/CUSA00001-part1.pkg', fileOffset: 0, fileSize: 5, hashValue: 'b'.repeat(40) },
|
||||
{ url: 'https://gs2.ww.prod.dl.playstation.net/path/CUSA00001-part2.pkg', fileOffset: 5, fileSize: 7, hashValue: 'c'.repeat(40) },
|
||||
],
|
||||
}, source, 'CUSA00001');
|
||||
assert.equal(manifest.gameId, 'CUSA00001');
|
||||
assert.equal(manifest.originalFileSize, 12);
|
||||
assert.equal(manifest.pieces.length, 2);
|
||||
assert.equal(manifest.packageDigest, 'a'.repeat(64));
|
||||
|
||||
assert.throws(() => normalizeManifest({
|
||||
originalFileSize: 12,
|
||||
pieces: [{ url: 'https://evil.example/CUSA00001.pkg', fileOffset: 0, fileSize: 12, hashValue: 'b'.repeat(40) }],
|
||||
}, source), /playstation\.net/);
|
||||
assert.throws(() => normalizeManifest({
|
||||
originalFileSize: 12,
|
||||
pieces: [{ url: 'https://gs2.ww.prod.dl.playstation.net/CUSA00001.pkg', fileOffset: 1, fileSize: 11, hashValue: 'b'.repeat(40) }],
|
||||
}, source), /aaneensluitend/);
|
||||
});
|
||||
|
||||
test('Sony URL validation blocks credentials, ports and lookalike domains', () => {
|
||||
assert.equal(officialSonyUrl('http://gs2.ww.prod.dl.playstation.net/file.json').hostname, 'gs2.ww.prod.dl.playstation.net');
|
||||
assert.throws(() => officialSonyUrl('https://playstation.net.evil.example/file.json'), /playstation\.net/);
|
||||
assert.throws(() => officialSonyUrl('https://user:pass@playstation.net/file.json'), /credentials/);
|
||||
assert.throws(() => officialSonyUrl('https://playstation.net:444/file.json'), /poort/);
|
||||
});
|
||||
|
||||
test('PS4 version URLs and Sony XML manifests are discovered without pasted JSON URLs', () => {
|
||||
assert.equal(
|
||||
ps4VersionUrl('CUSA03041'),
|
||||
'http://gs-sec.ww.np.dl.playstation.net/plo/np/CUSA03041/f3bc1dbcdfc190b2efdda011bdd49cbe344c0ea418faf1b511616b8460f8a835/CUSA03041-ver.xml',
|
||||
);
|
||||
const parsed = parseVersionXml(`<?xml version="1.0"?>
|
||||
<titlepatch titleid="CUSA03041"><tag><package version="01.32" system_ver="1"
|
||||
digest="${'a'.repeat(64)}"
|
||||
manifest_url="http://gs2.ww.prod.dl.playstation.net/path/CUSA03041-update.json"/></tag></titlepatch>`, 'CUSA03041');
|
||||
assert.equal(parsed.version, '01.32');
|
||||
assert.equal(parsed.manifestUrl, 'http://gs2.ww.prod.dl.playstation.net/path/CUSA03041-update.json');
|
||||
assert.throws(() => parseVersionXml('<!DOCTYPE x><titlepatch titleid="CUSA03041"/>', 'CUSA03041'), /declaraties/);
|
||||
assert.throws(() => parseVersionXml('<titlepatch titleid="CUSA99999"><package manifest_url="https://playstation.net/CUSA99999.json"/></titlepatch>', 'CUSA03041'), /hoort niet/);
|
||||
});
|
||||
|
||||
test('PS5 versionFileUri is found in bounded nested param JSON structures', () => {
|
||||
const uri = 'https://sgst.prod.dl.playstation.net/sgst/prod/00/np/PPSA00001_00/example-version.xml';
|
||||
assert.equal(findVersionFileUri({ application: { metadata: { versionFileUri: uri } } }), uri);
|
||||
assert.equal(findVersionFileUri({ application: {} }), '');
|
||||
});
|
||||
|
||||
test('automatic discovery resolves a PS4 version XML into the existing safe manifest plan', async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-update-discovery-'));
|
||||
const gameId = 'CUSA03041';
|
||||
const versionUrl = ps4VersionUrl(gameId);
|
||||
const manifestUrl = `https://gs2.ww.prod.dl.playstation.net/path/${gameId}-update.json`;
|
||||
const packageUrl = `https://gs2.ww.prod.dl.playstation.net/path/${gameId}.pkg`;
|
||||
const fetchImpl = async url => {
|
||||
if (url === versionUrl) return new Response(`<titlepatch titleid="${gameId}"><tag><package version="01.32" manifest_url="${manifestUrl}"/></tag></titlepatch>`);
|
||||
if (url === manifestUrl) return new Response(JSON.stringify({
|
||||
originalFileSize: 4,
|
||||
pieces: [{ url: packageUrl, fileOffset: 0, fileSize: 4, hashValue: 'b'.repeat(40) }],
|
||||
}));
|
||||
throw new Error(`Unexpected URL ${url}`);
|
||||
};
|
||||
const service = createGameUpdateService({
|
||||
db: { listGames: () => [{ game_id: gameId }], listBackups: () => [] },
|
||||
ftp: {},
|
||||
paths: { backups: path.join(root, 'backups'), cache: path.join(root, 'cache') },
|
||||
fetchImpl,
|
||||
});
|
||||
try {
|
||||
const plan = await service.inspectAutomatic({ gameId });
|
||||
assert.equal(plan.manifest.gameId, gameId);
|
||||
assert.equal(service.catalog().games[0].discovery.status, 'available');
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('package downloads disable the JSON size cap but enforce exact bytes and hashes', async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-update-'));
|
||||
const payload = Buffer.from('safe-package');
|
||||
const gameId = 'CUSA00001';
|
||||
const manifestUrl = `https://gs2.ww.prod.dl.playstation.net/path/${gameId}-update.json`;
|
||||
const packageUrl = `https://gs2.ww.prod.dl.playstation.net/path/${gameId}.pkg`;
|
||||
const manifest = {
|
||||
originalFileSize: payload.length,
|
||||
packageDigest: crypto.createHash('sha256').update(payload).digest('hex'),
|
||||
pieces: [{
|
||||
url: packageUrl,
|
||||
fileOffset: 0,
|
||||
fileSize: payload.length,
|
||||
hashValue: crypto.createHash('sha1').update(payload).digest('hex'),
|
||||
}],
|
||||
};
|
||||
const fetchImpl = async (url, options) => {
|
||||
if (url === manifestUrl) return new Response(JSON.stringify(manifest), { headers: { 'content-type': 'application/json' } });
|
||||
assert.equal(url, packageUrl);
|
||||
assert.equal(options.size, 0);
|
||||
return new Response(Readable.from([payload]), { headers: { 'content-length': String(payload.length) } });
|
||||
};
|
||||
const service = createGameUpdateService({
|
||||
db: { listGames: () => [] },
|
||||
ftp: {},
|
||||
paths: { backups: path.join(root, 'backups'), cache: path.join(root, 'cache') },
|
||||
settings: { get: (key, fallback) => key === 'publicOrigin' ? 'https://chimera.example.test' : fallback },
|
||||
fetchImpl,
|
||||
});
|
||||
try {
|
||||
const plan = await service.inspectManifest({ url: manifestUrl, gameId });
|
||||
const queued = service.queueDownload({ token: plan.token });
|
||||
let job;
|
||||
for (let attempt = 0; attempt < 100; attempt += 1) {
|
||||
job = service.listJobs().find(item => item.id === queued.id);
|
||||
if (['completed', 'failed'].includes(job.status)) break;
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
}
|
||||
assert.equal(job.status, 'completed', job.error);
|
||||
assert.deepEqual(fs.readFileSync(job.localPath), payload);
|
||||
const handoff = await service.preparePackageHandoff({ id: job.id });
|
||||
assert.match(handoff.url, /^https:\/\/chimera\.example\.test\/game-update-package\/[A-Za-z0-9_-]{43}\/CUSA00001\.pkg$/);
|
||||
assert.equal(service.resolvePackageHandoff(new URL(handoff.url).pathname).sha256, manifest.packageDigest);
|
||||
assert.equal(handoff.installExecuted, false);
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user