app->bind(StripeClient::class, fn () => new StripeClient(config('subscription.stripe_api_key'))); // Requests must never read a partly written cache file. See AtomicFilesystem. $this->app->extend(ConfigCacheCommand::class, fn () => new ConfigCacheCommand(new AtomicFilesystem)); $this->app->extend(RouteCacheCommand::class, fn () => new RouteCacheCommand(new AtomicFilesystem)); } public function boot(): void { $this->configureCommands(); $this->configureModels(); $this->configurePasswords(); $this->configureSanctumModel(); $this->configureHttpClient(); $this->configureGitHubHttp(); $this->configureGitLabHttp(); $this->configureOidcSocialite(); $this->configureQueue(); $this->configureServerTransferImport(); } /** * A server transfer bundle carries stored values (files, variables, keys, compose files) that must * arrive unchanged, so the import request skips the global trimming and empty-string conversion. */ private function configureServerTransferImport(): void { $isImport = fn (Request $request): bool => $request->is('api/v1/servers/import'); TrimStrings::skipWhen($isImport); ConvertEmptyStringsToNull::skipWhen($isImport); } /** * Queue workers are long-running processes, so once() values (e.g. instanceSettings()) * and the Server identity map would stay stale across jobs. Flush them before each job, * like a fresh web request. */ private function configureQueue(): void { Queue::before(function (): void { Once::flush(); Server::flushIdentityMap(); }); } private function configureCommands(): void { if (App::isProduction()) { DB::prohibitDestructiveCommands(); } } private function configureModels(): void { // Disabled because it's causing issues with the application // Model::shouldBeStrict(); } private function configurePasswords(): void { Password::defaults(function () { return App::isProduction() ? Password::min(8) ->mixedCase() ->letters() ->numbers() ->symbols() ->uncompromised() : Password::min(8)->letters(); }); } private function configureSanctumModel(): void { Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class); } private function configureOidcSocialite(): void { if (! $this->app->bound(SocialiteFactory::class)) { return; } $this->app->make(SocialiteFactory::class)->extend('oidc', function ($app) { return new OidcProvider( $app['request'], $app->make(OidcDiscoveryService::class), $app->make(OidcTokenValidator::class), '', '', '', ); }); } private function configureHttpClient(): void { Http::globalOptions(['connect_timeout' => 10, 'timeout' => 30]); Http::globalMiddleware(new RetryHttpConnectionFailures); } private function configureGitHubHttp(): void { Http::macro('GitSource', function (string $url) { return Http::withOptions([ ...SafeExternalUrl::httpClientOptions( $url, allowPrivateNetworks: SafeExternalUrl::gitSourcesMayUsePrivateNetworks(), ), 'allow_redirects' => SafeExternalUrl::sameOriginRedirectOptions(), ]); }); Http::macro('GitHub', function (string $api_url, ?string $github_access_token = null) { if ($github_access_token) { return Http::GitSource($api_url)->withHeaders([ 'X-GitHub-Api-Version' => '2022-11-28', 'Accept' => 'application/vnd.github.v3+json', 'Authorization' => "Bearer $github_access_token", ])->baseUrl($api_url); } else { return Http::GitSource($api_url)->withHeaders([ 'Accept' => 'application/vnd.github.v3+json', ])->baseUrl($api_url); } }); } private function configureGitLabHttp(): void { Http::macro('GitLab', function (string $api_url, ?string $access_token = null) { $client = Http::GitSource($api_url)->withHeaders([ 'Accept' => 'application/json', ])->baseUrl($api_url); return $access_token ? $client->withToken($access_token) : $client; }); Http::macro('Gitea', function (string $api_url, ?string $access_token = null) { $client = Http::GitSource($api_url)->withHeaders([ 'Accept' => 'application/json', ])->baseUrl($api_url); return $access_token ? $client->withToken($access_token) : $client; }); } }