90 lines
4.9 KiB
JavaScript
90 lines
4.9 KiB
JavaScript
import * as r from './install_common.mjs';
|
|
const {
|
|
e
|
|
} =r;
|
|
export const NAMES=['rounds.json', 'tutorial.json', 'levels.json', 'rounds_raw.json', 'levels_raw.json'];
|
|
export const replace=r.replace;
|
|
export function install(a){
|
|
const provenance=e.loadJSON(e.path.join(a.stage, 'provenance.json'));
|
|
return r.withLock(a['launcher-root'], ()=>{
|
|
const launcher=a['launcher-root'],
|
|
registryPath=e.path.join(launcher, 'client-profiles.json'),
|
|
registry=e.loadJSON(registryPath),
|
|
profile=registry.beta,
|
|
bundle=profile.bundle_dir,
|
|
runtime=profile.runtime_dir,
|
|
version=profile.version,
|
|
client=profile.client_dir,
|
|
identity=e.loadJSON(e.path.join(bundle, 'dump/client.json'));
|
|
if(e.json(identity)!==e.json(provenance.client)||identity.version!==version||!version.includes('BETA'))e.fail('Extraction is not for the installed BETA profile');
|
|
r.verify_bundle(bundle, version);
|
|
r.verify_client(bundle, client, version, 'beta');
|
|
r.verify_runtime(runtime, bundle, version);
|
|
for(const name of NAMES)if(r.digest(e.path.join(a.stage, name))!==provenance.outputs[name])e.fail('Extracted resource hash changed');
|
|
const proofs=new Map([...provenance.collections, provenance.node_textmap].map(p=>[p.blob, p]));
|
|
for(const proof of proofs.values())if(r.digest(e.path.join(client, 'StarRail_Data', proof.blob))!==proof.blob_sha256)e.fail('Client DesignData changed after extraction');
|
|
for(const proof of provenance.catalogues)if(r.digest(e.path.join(client, proof.path))!==proof.sha256)e.fail('Installed active DesignV changed');
|
|
const token=r.token(),
|
|
backup=e.path.join(launcher, '.pearl-cache/gridfight-data-backups', token),
|
|
roots={
|
|
source:e.path.join(a['server-root'], 'resources/grid_fight'),
|
|
bundle:e.path.join(bundle, 'server/resources/grid_fight'),
|
|
runtime:e.path.join(runtime, 'resources/grid_fight')
|
|
},
|
|
targets=Object.entries(roots).flatMap(([area, root])=>NAMES.map(n=>[area, e.path.join(root, n), e.path.join(a.stage, n)]));
|
|
targets.push(['bundle', e.path.join(bundle, 'SHA256SUMS'), null]);
|
|
const excluded=new Set(targets.map(([, p])=>p)),
|
|
bundleBefore=r.snapshot(bundle, excluded),
|
|
runtimeBefore=r.snapshot(e.path.join(runtime, 'resources'), excluded),
|
|
binaries=Object.fromEntries(['gameserver', 'dispatch'].map(n=>[n, r.digest(e.path.join(runtime, 'zig-out/bin', n))])),
|
|
registryBefore=r.digest(registryPath),
|
|
liveBundle=registry.live.bundle_dir,
|
|
liveBefore=r.snapshot(liveBundle, excluded);
|
|
r.transaction(targets, backup, write=>{
|
|
for(const [, p, incoming]of targets)if(incoming)write(p, e.fs.readFileSync(incoming));
|
|
write(e.path.join(bundle, 'SHA256SUMS'), r.manifest(bundle));
|
|
}, ()=>{
|
|
r.verify_bundle(bundle, version);
|
|
r.verify_runtime(runtime, bundle, version);
|
|
for(const name of NAMES)if(new Set(Object.values(roots).map(root=>r.digest(e.path.join(root, name)))).size!==1||r.digest(e.path.join(roots.source, name))!==provenance.outputs[name])e.fail('Source/bundle/runtime resource mismatch');
|
|
if(!r.equal(r.snapshot(bundle, excluded), bundleBefore)||!r.equal(r.snapshot(e.path.join(runtime, 'resources'), excluded), runtimeBefore))e.fail('An unrelated managed resource changed');
|
|
if(!r.equal(r.snapshot(liveBundle, excluded), liveBefore)||r.digest(registryPath)!==registryBefore)e.fail('LIVE bundle or profile registry changed');
|
|
for(const [name, d]of Object.entries(binaries))if(r.digest(e.path.join(runtime, 'zig-out/bin', name))!==d)e.fail('Runtime binaries changed');
|
|
}, 'gridfight-data');
|
|
const cache=e.path.join(launcher, '.pearl-cache/gridfight-rounds', version, token);
|
|
e.fs.cpSync(a.stage, cache, {
|
|
recursive:true,
|
|
errorOnExist:true,
|
|
force:false
|
|
});
|
|
const evidence=e.path.join(a['server-root'], 'tools/gridfight-extract-node/evidence/rounds');
|
|
e.fs.cpSync(e.path.join(a.stage, 'evidence'), evidence, {
|
|
recursive:true
|
|
});
|
|
for(const name of ['schemas.json', 'provenance.json'])r.replace(e.path.join(evidence, name), e.fs.readFileSync(e.path.join(a.stage, name)));
|
|
const report={
|
|
version,
|
|
token,
|
|
outputs:provenance.outputs,
|
|
counts:provenance.counts,
|
|
backup:e.path.relative(launcher, backup),
|
|
bundle_manifest_verified:true,
|
|
source_bundle_runtime_match:true,
|
|
beta_non_target_resources_preserved:Object.keys(runtimeBefore).length,
|
|
live_bundle_files_preserved:Object.keys(liveBefore).length,
|
|
runtime_binaries_preserved:true,
|
|
registry_preserved:true,
|
|
processes_started_or_stopped:0,
|
|
gameplay_verified:false
|
|
};
|
|
e.atomic_json(e.path.join(evidence, 'validation.json'), report, 2, true);
|
|
e.atomic_json(e.path.join(cache, 'install.json'), report, 2, true);
|
|
console.log(e.json(report));
|
|
return report;
|
|
});
|
|
}
|
|
export function main(){
|
|
install(e.cli(['server-root', 'launcher-root', 'stage']));
|
|
}
|
|
e.runMain(import.meta.url, main);
|