2424use Illuminate \Support \Facades \Crypt ;
2525use Illuminate \Support \Facades \Log ;
2626use Illuminate \Support \Facades \Storage ;
27+ use Safe \Exceptions \FilesystemException ;
28+ use function Safe \realpath ;
2729
2830/**
2931 * Controller responsible for serving files securely.
@@ -48,10 +50,6 @@ public function __invoke(SecurePathRequest $request, ?string $path)
4850 throw new InvalidSignatureException ();
4951 }
5052
51- if (is_null ($ path )) {
52- throw new WrongPathException ();
53- }
54-
5553 if ($ request ->configs ()->getValueAsBool ('secure_image_link_enabled ' )) {
5654 try {
5755 $ path = Crypt::decryptString ($ path );
@@ -60,7 +58,14 @@ public function __invoke(SecurePathRequest $request, ?string $path)
6058 }
6159 }
6260
63- $ file = Storage::disk (StorageDiskType::LOCAL ->value )->path ($ path );
61+ $ this ->prevalidation_path ($ path );
62+
63+ try {
64+ $ file = realpath (Storage::disk (StorageDiskType::LOCAL ->value )->path ($ path ));
65+ } catch (FilesystemException ) {
66+ throw new WrongPathException ();
67+ }
68+
6469 $ valid_path_start = Storage::disk (StorageDiskType::LOCAL ->value )->path ('' );
6570 if (!str_starts_with ($ file , $ valid_path_start )) {
6671 Log::error ('Invalid path for secure path request. ' , [
@@ -104,4 +109,26 @@ private function signatureHasNotExpired(Request $request)
104109
105110 return !($ expires !== null && $ expires !== '' && Carbon::now ()->getTimestamp () > $ expires );
106111 }
112+
113+ /**
114+ * Validate the path.
115+ *
116+ * @param string|null $path
117+ *
118+ * @return void
119+ *
120+ * @throws WrongPathException
121+ */
122+ private function prevalidation_path (?string $ path ): void
123+ {
124+ if (is_null ($ path )) {
125+ throw new WrongPathException ();
126+ }
127+
128+ foreach (['.. ' , '%2e ' , '%2f ' , '\\' ] as $ invalid_sequence ) {
129+ if (str_contains ($ path , $ invalid_sequence )) {
130+ throw new PathTraversalException ('Invalid path for secure path request. ' );
131+ }
132+ }
133+ }
107134}
0 commit comments