diff --git a/tools/native_runtime.py b/tools/native_runtime.py index c827cba..dc19c4f 100644 --- a/tools/native_runtime.py +++ b/tools/native_runtime.py @@ -280,6 +280,20 @@ def client_command(java, home, runtime, assets, *, username='LootableTest', extr return command(java,home,runtime,assets,prepared,username=username,extra=extra) +def prepare_vanilla_server(home): + """Stage the official pinned server where the native installer reads it.""" + from native117_client import BASE_VERSION,BASE_SHA1 + descriptor=home/'versions'/BASE_VERSION/(BASE_VERSION+'.json') + _download({'sha1':BASE_SHA1,'url':'https://piston-meta.mojang.com/v1/packages/'+BASE_SHA1+'/1.17.1.json'},descriptor) + metadata=json.loads(descriptor.read_text()) + if metadata['id']!=BASE_VERSION:raise RuntimeError('Wrong official server descriptor') + relative='libraries/net/minecraft/server/'+BASE_VERSION+'/server-'+BASE_VERSION+'.jar' + target=home/relative + _download(metadata['downloads']['server'],target) + if digest(target)!=SERVER_INPUTS[relative]:raise RuntimeError('Official vanilla server checksum mismatch') + return target + + def install(java, home, client=False): """Install the pinned native37 distribution into a new owned directory.""" from prepare_migration_inputs import fetch @@ -292,6 +306,8 @@ def install(java, home, client=False): _download({'sha1':BASE_SHA1,'url':'https://piston-meta.mojang.com/v1/packages/'+BASE_SHA1+'/1.17.1.json'},base) metadata=json.loads(base.read_text());_download(metadata['downloads']['client'],base.with_suffix('.jar')) (home/'launcher_profiles.json').write_text('{"profiles":{}}\n') + else: + prepare_vanilla_server(home) run_logged([str(java),'-Djava.awt.headless=true','-jar',installer.name, '--installClient' if client else '--installServer',str(home)], cwd=home,path=home/'install.log',timeout=600) diff --git a/tools/test_native_server_preparation.py b/tools/test_native_server_preparation.py new file mode 100644 index 0000000..d8f998e --- /dev/null +++ b/tools/test_native_server_preparation.py @@ -0,0 +1,36 @@ +"""The installer must see exact prepared vanilla bytes before it starts.""" +import hashlib,json,tempfile,unittest +from pathlib import Path +from unittest.mock import patch +import native_runtime as runtime +from native117_client import BASE_VERSION,BASE_SHA1 + +class VanillaServerPreparationTests(unittest.TestCase): + def fixture(self,home,*,changed=False): + payload=b'synthetic official server fixture' + relative='libraries/net/minecraft/server/1.17.1/server-1.17.1.jar' + server={'url':'https://fixture.invalid/server.jar','sha1':hashlib.sha1(payload).hexdigest()} + calls=[] + def download(record,path): + calls.append((record,path));path.parent.mkdir(parents=True,exist_ok=True) + if path.suffix=='.json': + self.assertEqual(BASE_SHA1,record['sha1']) + path.write_text(json.dumps({'id':BASE_VERSION,'downloads':{'server':server}})) + else: + self.assertEqual(home/relative,path);self.assertEqual(server,record) + path.write_bytes(b'changed fixture' if changed else payload) + return relative,payload,calls,download + def test_prepared_server_uses_the_exact_installer_path_and_both_pins(self): + with tempfile.TemporaryDirectory() as directory: + home=Path(directory);relative,payload,calls,download=self.fixture(home) + with patch.object(runtime,'_download',side_effect=download),patch.object(runtime,'SERVER_INPUTS',{relative:hashlib.sha256(payload).hexdigest().upper()}): + self.assertEqual(home/relative,runtime.prepare_vanilla_server(home)) + self.assertEqual(2,len(calls));self.assertEqual(payload,(home/relative).read_bytes()) + def test_wrong_vanilla_bytes_refuse_before_the_installer_can_run(self): + with tempfile.TemporaryDirectory() as directory: + home=Path(directory)/'new-sdk';relative,payload,calls,download=self.fixture(home,changed=True) + with patch.object(runtime,'_download',side_effect=download),patch.object(runtime,'SERVER_INPUTS',{relative:hashlib.sha256(payload).hexdigest().upper()}),patch('prepare_migration_inputs.fetch'),patch.object(runtime,'run_logged') as installer: + with self.assertRaisesRegex(RuntimeError,'vanilla server checksum mismatch'):runtime.install(Path('fixture-java'),home) + installer.assert_not_called() + +if __name__=='__main__':unittest.main()