From de46b30b8aa08de413f37d9f25f9d7acf87aaaaa Mon Sep 17 00:00:00 2001 From: Graphictoria Date: Fri, 16 Dec 2022 23:04:44 -0500 Subject: [PATCH] QoL and development changes. I have a lot of work to do... - Case insensitive URLS. - More deployment stuff. --- web/app/Helpers/GridHelper.php | 4 +- .../Controllers/Web/ClientGameController.php | 46 +++++++ web/app/Http/Kernel.php | 3 +- web/app/Jobs/AppDeployment.php | 33 ++++- .../Routing/RouteParameterBinder.php | 117 ++++++++++++++++++ web/app/Providers/AppServiceProvider.php | 10 ++ .../CaseInsensitiveUriValidator.php | 17 +++ web/composer.json | 4 + web/database/seeders/AssetTypeSeeder.php | 20 +++ web/resources/js/components/PlaceButtons.js | 11 +- web/routes/web.php | 11 +- web/storage/app/grid/scripts/Hat.lua | 4 +- 12 files changed, 264 insertions(+), 16 deletions(-) create mode 100644 web/app/Http/Controllers/Web/ClientGameController.php create mode 100644 web/app/Overrides/Routing/RouteParameterBinder.php create mode 100644 web/app/Validators/CaseInsensitiveUriValidator.php diff --git a/web/app/Helpers/GridHelper.php b/web/app/Helpers/GridHelper.php index 3b9bf30..248bf16 100644 --- a/web/app/Helpers/GridHelper.php +++ b/web/app/Helpers/GridHelper.php @@ -124,12 +124,12 @@ class GridHelper public static function gameArbiter() { - return sprintf('http://%s:64989', self::getArbiter('Game')); + return sprintf('http://%s:9999', self::getArbiter('Game')); } public static function thumbnailArbiter() { - return sprintf('http://%s:64989', self::getArbiter('Thumbnail')); + return sprintf('http://%s:9999', self::getArbiter('Thumbnail')); } public static function gameArbiterMonitor() diff --git a/web/app/Http/Controllers/Web/ClientGameController.php b/web/app/Http/Controllers/Web/ClientGameController.php new file mode 100644 index 0000000..d00067c --- /dev/null +++ b/web/app/Http/Controllers/Web/ClientGameController.php @@ -0,0 +1,46 @@ + 0, + 'authenticationUrl' => '', + 'authenticationTicket' => '', + 'joinScriptUrl' => '' + ]); + } +} diff --git a/web/app/Http/Kernel.php b/web/app/Http/Kernel.php index 17e5547..fffe5d2 100644 --- a/web/app/Http/Kernel.php +++ b/web/app/Http/Kernel.php @@ -36,7 +36,7 @@ class Kernel extends HttpKernel */ protected $middlewareGroups = [ 'web' => [ - \App\Http\Middleware\VerifyCsrfToken::class, + 'csrf', \Illuminate\Routing\Middleware\SubstituteBindings::class, // XlXi: Yeah no, the double session protector was stupid. @@ -73,5 +73,6 @@ class Kernel extends HttpKernel 'roleset' => \App\Http\Middleware\Roleset::class, 'banned' => \App\Http\Middleware\CheckBan::class, 'lastseen' => \App\Http\Middleware\LastSeenMiddleware::class, + 'csrf' => \App\Http\Middleware\VerifyCsrfToken::class, ]; } diff --git a/web/app/Jobs/AppDeployment.php b/web/app/Jobs/AppDeployment.php index df4d274..333acdd 100644 --- a/web/app/Jobs/AppDeployment.php +++ b/web/app/Jobs/AppDeployment.php @@ -2,6 +2,7 @@ namespace App\Jobs; +use Carbon\Carbon; use COM; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeUnique; @@ -42,8 +43,10 @@ class AppDeployment implements ShouldQueue $this->deployment->step = 2; // Unpacking files. $this->deployment->save(); - $workingDirectory = storage_path(sprintf('app/setuptmp/%s', $this->deployment->version)); - Storage::makeDirectory($workingDirectory); + $workingDirectoryStorage = sprintf('setuptmp/%s', $this->deployment->version); + $workingDirectory = storage_path(sprintf('app/%s', $workingDirectoryStorage)); + + Storage::makeDirectory($workingDirectoryStorage); $appArchive = ''; $appName = ''; @@ -52,7 +55,7 @@ class AppDeployment implements ShouldQueue switch($this->deployment->app) { case 'client': - $appArchive = 'GraphictoriaApp.zip'; + $appArchive = 'Graphictoria.zip'; $appName = 'GraphictoriaPlayer.exe'; $bootstrapperName = 'GraphictoriaPlayerLauncher.exe'; $bootstrapperVersionName = 'BootstrapperVersion.txt'; @@ -82,7 +85,7 @@ class AppDeployment implements ShouldQueue // XlXi: this will not work on linux. $fso = new COM("Scripting.FileSystemObject"); $appVersion = $fso->GetFileVersion(sprintf('%s/%s', $workingDirectory, $appName)); - $bootstrapperVersion = $fso->GetFileVersion($bootstrapperLocation); + $bootstrapperVersion = str_replace('.', ', ', $fso->GetFileVersion($bootstrapperLocation)); $hashConfig = DynamicWebConfiguration::where('name', sprintf('%sUploadVersion', $this->deployment->app))->first(); $versionConfig = DynamicWebConfiguration::where('name', sprintf('%sDeployVersion', $this->deployment->app))->first(); @@ -99,7 +102,7 @@ class AppDeployment implements ShouldQueue $this->deployment->save(); Storage::copy(sprintf('setuptmp/%s-%s', $this->deployment->version, $bootstrapperName), sprintf('setup/%s', $bootstrapperName)); - Storage::put(sprintf('setup/%s-%s', $this->deployment->version, $bootstrapperVersionName), str_replace('.', ', ', $bootstrapperVersion)); + Storage::put(sprintf('setup/%s-%s', $this->deployment->version, $bootstrapperVersionName), $bootstrapperVersion); Storage::put(sprintf('setup/%s-gtManifest.txt', $this->deployment->version), ''); $files = Storage::files('setuptmp'); @@ -111,15 +114,33 @@ class AppDeployment implements ShouldQueue Storage::move($file, sprintf('setup/%s', $fileName)); } - Storage::deleteDirectory(sprintf('setuptmp/%s', $this->deployment->version)); + Storage::deleteDirectory($workingDirectoryStorage); $this->deployment->step = 5; // Success. $this->deployment->save(); + + $this->writeDeploy('Done!'); } public function failed($exception) { $this->deployment->error = $exception->getMessage(); $this->deployment->save(); + + $this->writeDeploy('Error!'); + } + + protected function writeDeploy(string $message) + { + $string = sprintf( + 'New %s %s at %s, file version: %s...%s', + ucfirst($this->deployment->app), + $this->deployment->version, + Carbon::now()->isoFormat('l LTS'), + DynamicWebConfiguration::where('name', sprintf('%sLauncherDeployVersion', $this->deployment->app))->first()->value, + $message + ); + + Storage::append('setup/DeployHistory.txt', $string . "\r\n\r\n", null); } } diff --git a/web/app/Overrides/Routing/RouteParameterBinder.php b/web/app/Overrides/Routing/RouteParameterBinder.php new file mode 100644 index 0000000..fb348be --- /dev/null +++ b/web/app/Overrides/Routing/RouteParameterBinder.php @@ -0,0 +1,117 @@ +route = $route; + } + + /** + * Get the parameters for the route. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function parameters($request) + { + $parameters = $this->bindPathParameters($request); + + // If the route has a regular expression for the host part of the URI, we will + // compile that and get the parameter matches for this domain. We will then + // merge them into this parameters array so that this array is completed. + if (! is_null($this->route->compiled->getHostRegex())) { + $parameters = $this->bindHostParameters( + $request, $parameters + ); + } + + return $this->replaceDefaults($parameters); + } + + /** + * Get the parameter matches for the path portion of the URI. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + protected function bindPathParameters($request) + { + $path = '/'.ltrim($request->decodedPath(), '/'); + + preg_match($this->route->compiled->getRegex() . 'i', $path, $matches); + + return $this->matchToKeys(array_slice($matches, 1)); + } + + /** + * Extract the parameter list from the host part of the request. + * + * @param \Illuminate\Http\Request $request + * @param array $parameters + * @return array + */ + protected function bindHostParameters($request, $parameters) + { + preg_match($this->route->compiled->getHostRegex(), $request->getHost(), $matches); + + return array_merge($this->matchToKeys(array_slice($matches, 1)), $parameters); + } + + /** + * Combine a set of parameter matches with the route's keys. + * + * @param array $matches + * @return array + */ + protected function matchToKeys(array $matches) + { + if (empty($parameterNames = $this->route->parameterNames())) { + return []; + } + + $parameters = array_intersect_key($matches, array_flip($parameterNames)); + + return array_filter($parameters, function ($value) { + return is_string($value) && strlen($value) > 0; + }); + } + + /** + * Replace null parameters with their defaults. + * + * @param array $parameters + * @return array + */ + protected function replaceDefaults(array $parameters) + { + foreach ($parameters as $key => $value) { + $parameters[$key] = $value ?? Arr::get($this->route->defaults, $key); + } + + foreach ($this->route->defaults as $key => $value) { + if (! isset($parameters[$key])) { + $parameters[$key] = $value; + } + } + + return $parameters; + } +} diff --git a/web/app/Providers/AppServiceProvider.php b/web/app/Providers/AppServiceProvider.php index 485a9b0..e99fd19 100644 --- a/web/app/Providers/AppServiceProvider.php +++ b/web/app/Providers/AppServiceProvider.php @@ -2,10 +2,14 @@ namespace App\Providers; +use Illuminate\Routing\Route as IlluminateRoute; +use Illuminate\Routing\Matching\UriValidator; use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\URL; use Illuminate\Support\ServiceProvider; +use App\Validators\CaseInsensitiveUriValidator; + class AppServiceProvider extends ServiceProvider { /** @@ -27,6 +31,12 @@ class AppServiceProvider extends ServiceProvider { URL::forceScheme('https'); + $validators = IlluminateRoute::getValidators(); + $validators[] = new CaseInsensitiveUriValidator; + IlluminateRoute::$validators = array_filter($validators, function($validator) { + return get_class($validator) != UriValidator::class; + }); + Blade::directive('owner', function() { return 'hasRoleset(\'Owner\')): ?>'; }); diff --git a/web/app/Validators/CaseInsensitiveUriValidator.php b/web/app/Validators/CaseInsensitiveUriValidator.php new file mode 100644 index 0000000..3ff8b89 --- /dev/null +++ b/web/app/Validators/CaseInsensitiveUriValidator.php @@ -0,0 +1,17 @@ +getPathInfo(), '/') ?: '/'; + + return preg_match($route->getCompiled()->getRegex() . 'i', rawurldecode($path)); + } +} diff --git a/web/composer.json b/web/composer.json index b11c1b1..b7b55f5 100644 --- a/web/composer.json +++ b/web/composer.json @@ -22,8 +22,12 @@ "spatie/laravel-ignition": "^1.0" }, "autoload": { + "exclude-from-classmap": [ + "vendor\\laravel\\framework\\src\\Illuminate\\Routing\\RouteParameterBinder.php" + ], "psr-4": { "App\\": "app/", + "Illuminate\\": "app/Overrides/", "Database\\Factories\\": "database/factories/", "Database\\Seeders\\": "database/seeders/" } diff --git a/web/database/seeders/AssetTypeSeeder.php b/web/database/seeders/AssetTypeSeeder.php index 00f1991..3302e4c 100644 --- a/web/database/seeders/AssetTypeSeeder.php +++ b/web/database/seeders/AssetTypeSeeder.php @@ -405,6 +405,26 @@ class AssetTypeSeeder extends Seeder [ 'name' => 'MeshHiddenSurfaceRemoval', 'locked' => true + ], + [ + 'name' => 'Eyebrow Accessory', + 'locked' => true + ], + [ + 'name' => 'Eyelash Accessory', + 'locked' => true + ], + [ + 'name' => 'Mood Animation', + 'locked' => true + ], + [ + 'name' => 'Dynamic Head', + 'locked' => true + ], + [ + 'name' => 'CodeSnippet', + 'locked' => true ] ]; diff --git a/web/resources/js/components/PlaceButtons.js b/web/resources/js/components/PlaceButtons.js index 52d7482..526d35b 100644 --- a/web/resources/js/components/PlaceButtons.js +++ b/web/resources/js/components/PlaceButtons.js @@ -31,13 +31,20 @@ class PlaceLoadingModal extends Component { this.Modal = new Bootstrap.Modal(this.ModalRef.current); this.Modal.show(); + let gone = false; this.ModalRef.current.addEventListener('hidden.bs.modal', (event) => { + gone = true; this.props.setModal(null); }); setTimeout(function(){ this.setState({showDownloadScreen: true}); - }.bind(this), 10000) + }.bind(this), 10000); + + setTimeout(function(){ + if(gone == false) + this.props.setModal(null); + }.bind(this), 20000); } componentWillUnmount() { @@ -175,7 +182,7 @@ class PlaceButtons extends Component { + ':1' + '+launchmode:play' + '+gameinfo:' + res.data - + '+placelauncherurl:' + encodeURIComponent(buildGenericApiUrl('www', `Game/PlaceLauncher?request=RequestGame&placeId=&${this.placeId}&isPlayTogetherGame=false`)); + + '+placelauncherurl:' + encodeURIComponent(buildGenericApiUrl('www', `Game/PlaceLauncher?request=RequestGame&placeId=${this.placeId}&isPlayTogetherGame=false`)); }) .catch(function(error) { this.setModal(); diff --git a/web/routes/web.php b/web/routes/web.php index c806662..94185a5 100644 --- a/web/routes/web.php +++ b/web/routes/web.php @@ -99,6 +99,13 @@ Route::group(['as' => 'auth.', 'namespace' => 'Auth'], function() { }); }); -Route::group(['as' => 'client.'], function() { - Route::get('/asset', 'ClientController@asset')->name('asset'); + +Route::withoutMiddleware(['csrf'])->group(function () { + Route::group(['as' => 'client.'], function() { + Route::get('/asset', 'ClientController@asset')->name('asset'); + + Route::group(['as' => 'game.', 'prefix' => 'game'], function() { + Route::post('/PlaceLauncher', 'ClientGameController@placeLauncher')->name('placelauncher'); + }); + }); }); \ No newline at end of file diff --git a/web/storage/app/grid/scripts/Hat.lua b/web/storage/app/grid/scripts/Hat.lua index 40095b4..636545d 100644 --- a/web/storage/app/grid/scripts/Hat.lua +++ b/web/storage/app/grid/scripts/Hat.lua @@ -9,8 +9,6 @@ local Lighting = game:GetService("Lighting") Lighting.ClockTime = 13 Lighting.GeographicLatitude = -5 -for _, object in pairs(game:GetObjects(assetUrl)) do - object.Parent = workspace -end +game:Load(assetUrl) return game:GetService("ThumbnailGenerator"):Click(fileExtension, x, y, --[[hideSky = ]] true, --[[crop = ]] true)