mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
Git source HTTP clients previously disabled redirects entirely, so API
calls for renamed repositories (e.g. GitHub 301 to /repositories/{id})
failed. Add SafeExternalUrl::sameOriginRedirectOptions() and use it in
the GitSource HTTP macro to follow up to five strict redirects that stay
on the same scheme, host and port.
A redirect to a different origin gets a RequestException, because the
DNS pin covers only the original host and port. This blocks SSRF via
redirects to metadata or attacker hosts. Authorization headers and the
original request method and body are kept on same-origin redirects.
Tests cover following same-host redirects, keeping POST on a redirect,
refusing cross-host/scheme/port redirects and the five-redirect cap.
143 lines
4.4 KiB
PHP
143 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace App\Providers;
|
|
|
|
use App\Auth\Oidc\OidcDiscoveryService;
|
|
use App\Auth\Oidc\OidcTokenValidator;
|
|
use App\Auth\Oidc\Socialite\OidcProvider;
|
|
use App\Models\PersonalAccessToken;
|
|
use App\Models\Server;
|
|
use App\Rules\SafeExternalUrl;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Support\Facades\App;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Queue;
|
|
use Illuminate\Support\Once;
|
|
use Illuminate\Support\ServiceProvider;
|
|
use Illuminate\Validation\Rules\Password;
|
|
use Laravel\Sanctum\Sanctum;
|
|
use Laravel\Socialite\Contracts\Factory as SocialiteFactory;
|
|
use Stripe\StripeClient;
|
|
|
|
class AppServiceProvider extends ServiceProvider
|
|
{
|
|
public function register(): void
|
|
{
|
|
$this->app->bind(StripeClient::class, fn () => new StripeClient(config('subscription.stripe_api_key')));
|
|
}
|
|
|
|
public function boot(): void
|
|
{
|
|
$this->configureCommands();
|
|
$this->configureModels();
|
|
$this->configurePasswords();
|
|
$this->configureSanctumModel();
|
|
$this->configureGitHubHttp();
|
|
$this->configureGitLabHttp();
|
|
$this->configureOidcSocialite();
|
|
$this->configureQueue();
|
|
}
|
|
|
|
/**
|
|
* 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 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;
|
|
});
|
|
}
|
|
}
|