109 lines
4.4 KiB
PHP
109 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use Illuminate\Foundation\Application;
|
|
use Illuminate\Foundation\Configuration\Exceptions;
|
|
use Illuminate\Foundation\Configuration\Middleware;
|
|
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Route;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
|
use Uwil\LaravelCommon\Helpers\InertiaHelper;
|
|
use Uwil\LaravelCommon\Middlewares\HandleInertiaRequests;
|
|
use Uwil\LaravelCommon\Middlewares\SecureHeaders;
|
|
use Uwil\LaravelCommon\Middlewares\TrimStrings;
|
|
use Uwil\LaravelCommon\Middlewares\TrustHosts;
|
|
use Uwil\LaravelCommon\Middlewares\TrustProxies;
|
|
|
|
return Application::configure(basePath: dirname(__DIR__))
|
|
->withRouting(
|
|
health: '/up',
|
|
then: function (): void {
|
|
Route::middleware(['web', 'throttle:5,2'])
|
|
->post('/csp-report', function (): void {
|
|
$isCspRequest = request()->header('Content-Type') === 'application/csp-report';
|
|
abort_if(
|
|
! $isCspRequest or ! request()->json('csp-report') or ! is_array(request()->json('csp-report')),
|
|
401,
|
|
);
|
|
|
|
/** @var array<string, mixed> $rawReport */
|
|
$rawReport = request()->json('csp-report');
|
|
|
|
// * Flatten if needed.
|
|
$cspReport = collect($rawReport)
|
|
->flatMap(fn (mixed $v, string $k) => [
|
|
$k => is_array($v) ? collect($v)->flatten()->implode(', ') : (string) $v,
|
|
])->all();
|
|
|
|
// * Filter array keys.
|
|
$cspReport = collect(array_intersect_key($cspReport, [
|
|
'blocked-uri' => '',
|
|
'document-uri' => '',
|
|
'original-policy' => '',
|
|
'referrer' => '',
|
|
'violated-directive' => '',
|
|
]));
|
|
|
|
Log::warning(sprintf(
|
|
"CSP REPORT for %s : \n %s",
|
|
$cspReport->get('document-uri'),
|
|
$cspReport->implode("\n")
|
|
));
|
|
})->name('cspReportUri');
|
|
}
|
|
)
|
|
->withMiddleware(function (Middleware $middleware): void {
|
|
$middleware->web(append: [
|
|
\Uwil\LaravelI18n\Middlewares\ForceLocale::class,
|
|
HandleInertiaRequests::class,
|
|
AddLinkHeadersForPreloadedAssets::class,
|
|
SecureHeaders::class,
|
|
TrimStrings::class,
|
|
TrustHosts::class,
|
|
TrustProxies::class,
|
|
\Uwil\LaravelBackend\Middlewares\LogoutUnpublishedUsers::class,
|
|
]);
|
|
$middleware->preventRequestForgery(except: [
|
|
'/csp-report',
|
|
]);
|
|
$middleware->group('saml', [
|
|
\Uwil\LaravelBackend\Middlewares\EncryptCookies::class,
|
|
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
|
\Illuminate\Session\Middleware\StartSession::class,
|
|
]);
|
|
$middleware->alias([
|
|
'auth' => \Uwil\LaravelBackend\Middlewares\Authenticate::class,
|
|
'guest' => \Uwil\LaravelBackend\Middlewares\RedirectIfAuthenticated::class,
|
|
]);
|
|
})
|
|
->withExceptions(function (Exceptions $exceptions): void {
|
|
$exceptions->render(function (HttpException $e, Request $request) {
|
|
$status = $e->getStatusCode();
|
|
|
|
return InertiaHelper::errorRender($request, $status);
|
|
});
|
|
/**
|
|
* Automatic exception capture with Sentry.
|
|
*/
|
|
$exceptions->report(function (\Throwable $e): void {
|
|
if (app()->bound('sentry')) {
|
|
resolve('sentry')->captureException($e);
|
|
}
|
|
});
|
|
/**
|
|
* Handling validation errors by excluding sensitive fields from the flash.
|
|
*/
|
|
$exceptions->render(function (ValidationException $e, Request $request) {
|
|
$safeInput = collect($request->all())
|
|
->except(['password', 'password_confirmation', 'current_password'])
|
|
->toArray();
|
|
|
|
return back()
|
|
->withInput($safeInput)
|
|
->withErrors($e->errors());
|
|
});
|
|
})->create();
|