ServeFile.php 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. <?php
  2. namespace Illuminate\Filesystem;
  3. use Illuminate\Http\Request;
  4. use Illuminate\Support\Facades\Storage;
  5. use League\Flysystem\PathTraversalDetected;
  6. class ServeFile
  7. {
  8. /**
  9. * Create a new invokable controller to serve files.
  10. */
  11. public function __construct(
  12. protected string $disk,
  13. protected array $config,
  14. protected bool $isProduction,
  15. ) {
  16. //
  17. }
  18. /**
  19. * Handle the incoming request.
  20. */
  21. public function __invoke(Request $request, string $path)
  22. {
  23. abort_unless(
  24. $this->hasValidSignature($request),
  25. $this->isProduction ? 404 : 403
  26. );
  27. try {
  28. abort_unless(Storage::disk($this->disk)->exists($path), 404);
  29. $headers = [
  30. 'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
  31. 'Content-Security-Policy' => "default-src 'none'; style-src 'unsafe-inline'; sandbox",
  32. ];
  33. return tap(
  34. Storage::disk($this->disk)->serve($request, $path, headers: $headers),
  35. function ($response) use ($headers) {
  36. if (! $response->headers->has('Content-Security-Policy')) {
  37. $response->headers->replace($headers);
  38. }
  39. }
  40. );
  41. } catch (PathTraversalDetected $e) {
  42. abort(404);
  43. }
  44. }
  45. /**
  46. * Determine if the request has a valid signature if applicable.
  47. */
  48. protected function hasValidSignature(Request $request): bool
  49. {
  50. return ! $request->boolean('upload') && (
  51. ($this->config['visibility'] ?? 'private') === 'public' ||
  52. $request->hasValidRelativeSignature()
  53. );
  54. }
  55. }