From 1a3ab476b074fe769a25b2a89f1468bf21471cfa Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 14 Sep 2026 12:57:37 +0200 Subject: [PATCH] In the asset controller, throw if tenancy isn't initialized Instead of falling back to returning storage_path('app/public') in assetRoot(), throw an exception *at the start of the method* -- tenant assets shouldn't be served in central context. --- src/Controllers/TenantAssetController.php | 13 ++++++------- tests/TenantAssetTest.php | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Controllers/TenantAssetController.php b/src/Controllers/TenantAssetController.php index 16e8a433..af222218 100644 --- a/src/Controllers/TenantAssetController.php +++ b/src/Controllers/TenantAssetController.php @@ -85,13 +85,16 @@ class TenantAssetController implements HasMiddleware /** * Directory the assets are served from -- the root of the $publicDisk, or app/public - * inside the tenant's storage directory when no disk is configured. When no disk is - * configured and there's no current tenant, the central app/public is used. + * inside the tenant's storage directory when no disk is configured. * * The tenant's storage directory is resolved using the FilesystemTenancyBootstrapper::getTenantStoragePath(). */ protected function assetRoot(): string { + if (! tenant()) { + throw new Exception('Tenant assets can only be served in tenant context.'); + } + if (static::$publicDisk) { $disk = Storage::disk(static::$publicDisk); @@ -118,11 +121,7 @@ class TenantAssetController implements HasMiddleware return rtrim($disk->path(''), DIRECTORY_SEPARATOR); } - if ($tenant = tenant()) { - return FilesystemTenancyBootstrapper::getTenantStoragePath($tenant) . '/app/public'; - } - - return storage_path('app/public'); + return FilesystemTenancyBootstrapper::getTenantStoragePath(tenant()) . '/app/public'; } /** diff --git a/tests/TenantAssetTest.php b/tests/TenantAssetTest.php index ed7feaa8..a4e169b7 100644 --- a/tests/TenantAssetTest.php +++ b/tests/TenantAssetTest.php @@ -17,6 +17,7 @@ use Stancl\Tenancy\Middleware\InitializeTenancyByRequestData; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\UrlGeneratorBootstrapper; use Stancl\Tenancy\Controllers\TenantAssetController; +use Stancl\Tenancy\Enums\RouteMode; use Stancl\Tenancy\Events\TenancyEnded; use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Overrides\TenancyUrlGenerator; @@ -180,6 +181,23 @@ test('tenant asset controller throws when the configured disk is not local or no } }); +test('tenant assets cannot be served in central context', function () { + config([ + 'tenancy.identification.default_middleware' => InitializeTenancyByRequestData::class, + // Make the asset route skip tenant identification + 'tenancy.default_route_mode' => RouteMode::UNIVERSAL, + ]); + + $this->withoutExceptionHandling(); + + foreach ([null, 'local'] as $publicDisk) { + TenantAssetController::$publicDisk = $publicDisk; + + expect(fn () => pest()->get(tenant_asset('foo.txt'))) + ->toThrow(Exception::class, 'Tenant assets can only be served in tenant context.'); + } +}); + test('tenant assets are served from the resolved root of the configured disk', function () { config([ 'tenancy.identification.default_middleware' => InitializeTenancyByRequestData::class,