'launcher-test', 'moonwell.launcher.base_path' => 'World of Warcraft 1.12.1', 'moonwell.launcher.manifest_key' => 'manifest-1.12.1.json', ]); Storage::disk('launcher-test')->buildTemporaryUrlsUsing( fn ($path) => 'https://download.example/'.rawurlencode($path), ); } public function test_download_resolves_the_file_from_the_active_release(): void { $key = 'World of Warcraft 1.12.1/releases/build-a/MoonWell.exe'; $this->putManifest([['path' => 'MoonWell.exe', 'objectKey' => $key]]); Storage::disk('launcher-test')->put($key, 'player binary'); $response = app(LauncherController::class)->download('MoonWell.exe'); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('https://download.example/'.rawurlencode($key), $response->getData(true)['url']); } public function test_legacy_manifest_without_object_keys_still_works(): void { $key = 'World of Warcraft 1.12.1/Data/dbc.MPQ'; $this->putManifest([['path' => 'Data/dbc.MPQ']]); Storage::disk('launcher-test')->put($key, 'vanilla data'); $response = app(LauncherController::class)->download('Data/dbc.MPQ'); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('https://download.example/'.rawurlencode($key), $response->getData(true)['url']); } public function test_unlisted_objects_and_path_traversal_cannot_be_downloaded(): void { $this->putManifest([]); Storage::disk('launcher-test')->put('World of Warcraft 1.12.1/secret.txt', 'secret'); $controller = app(LauncherController::class); $this->assertSame(404, $controller->download('secret.txt')->getStatusCode()); foreach (['../secret.txt', '/secret.txt', 'Data/../secret.txt', 'Data\\secret.txt', 'C:/secret.txt'] as $path) { $this->assertSame(422, $controller->download($path)->getStatusCode()); } } public function test_manifest_cannot_reference_an_object_outside_the_client_prefix(): void { $this->putManifest([['path' => 'MoonWell.exe', 'objectKey' => 'another-project/secret.txt']]); $this->assertSame(500, app(LauncherController::class)->download('MoonWell.exe')->getStatusCode()); } private function putManifest(array $files): void { Storage::disk('launcher-test')->put('manifest-1.12.1.json', json_encode(['files' => $files])); } }