Skip to content

Commit 0138f96

Browse files
committed
Securing Exported Files By Hiding Behind Cache
1 parent 0a75a2d commit 0138f96

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

app/Http/Controllers/Dashboard/CrudController.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
namespace App\Http\Controllers\Dashboard;
66

7+
use App\Exceptions\NotFoundException;
78
use Illuminate\Http\Request;
89
use Illuminate\Support\Facades\Event;
910
use Illuminate\Support\Str;
@@ -15,6 +16,8 @@
1516
use App\Services\CrudService;
1617
use TorMorten\Eventy\Facades\Events as Hook;
1718
use Illuminate\Support\Facades\Auth;
19+
use Illuminate\Support\Facades\Cache;
20+
use Illuminate\Support\Facades\Storage;
1821
use PhpOffice\PhpSpreadsheet\Spreadsheet;
1922
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
2023
use PhpOffice\PhpSpreadsheet\Writer\Csv;
@@ -561,7 +564,13 @@ public function exportCrud( $namespace, Request $request )
561564
* let's define what will be the output name
562565
* of the exported file.
563566
*/
564-
$fileName = 'export/' . Str::slug( $resource->getLabels()[ 'list_title' ] ) . '.csv';
567+
if ( ! is_dir( storage_path( 'app/public/exports' ) ) ) {
568+
mkdir( storage_path( 'app/public/exports' ) );
569+
}
570+
571+
$dateFormat = Str::slug( ns()->date->toDateTimeString() );
572+
$relativePath = 'exports/' . Str::slug( $resource->getLabels()[ 'list_title' ] ) . '-' . $dateFormat . '.csv';
573+
$fileName = storage_path( 'app/public/' . $relativePath );
565574

566575
/**
567576
* We'll prepare the writer
@@ -570,8 +579,15 @@ public function exportCrud( $namespace, Request $request )
570579
$writer = new Csv($spreadsheet);
571580
$writer->save( $fileName );
572581

582+
/**
583+
* We'll hide the asset URL behind random lettes
584+
*/
585+
$hash = Str::random(20);
586+
587+
Cache::put( $hash, $relativePath, now()->addMinutes(5) );
588+
573589
return [
574-
'url' => asset( $fileName )
590+
'url' => route( 'ns.dashboard.crud-download', compact( 'hash' ) )
575591
];
576592
}
577593

@@ -609,4 +625,15 @@ public function canAccess( $namespace, Request $request )
609625
'message' => __( 'This resource is not protected. The access is granted.' )
610626
]);
611627
}
628+
629+
public function downloadSavedFile( $hash )
630+
{
631+
$relativePath = Cache::pull( $hash );
632+
633+
if ( Storage::disk( 'public' )->exists( $relativePath ) ) {
634+
return Storage::disk( 'public' )->download( $relativePath );
635+
}
636+
637+
throw new NotFoundException( __( 'The requested file cannot be downloaded or has already been downloaded.' ) );
638+
}
612639
}

routes/web.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use App\Http\Controllers\AuthController;
44
use App\Http\Middleware\CheckMigrationStatus;
55
use App\Events\WebRoutesLoadedEvent;
6+
use App\Http\Controllers\Dashboard\CrudController;
67
use App\Http\Controllers\Dashboard\ModulesController;
78
use App\Http\Controllers\Dashboard\UsersController;
89
use App\Http\Middleware\Authenticate;
@@ -83,6 +84,8 @@
8384
Route::get( '/users/roles', [ UsersController::class, 'rolesList' ]);
8485
Route::get( '/users/roles/create', [ UsersController::class, 'createRole' ]);
8586
Route::get( '/users/roles/edit/{role}', [ UsersController::class, 'editRole' ]);
87+
88+
Route::get( '/crud/download/{hash}', [ CrudController::class, 'downloadSavedFile' ])->name( 'ns.dashboard.crud-download' );
8689
});
8790
});
8891
});

0 commit comments

Comments
 (0)