Skip to content

Commit 7879b43

Browse files
authored
Merge pull request #4497 from Roardom/public-private
(Fix) Store user-uploaded files in private directories
2 parents d92bd67 + 1af1862 commit 7879b43

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+362
-98
lines changed

app/Console/Commands/CleanTorrentFiles.php

+5-7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use App\Models\Torrent;
2121
use Exception;
2222
use Illuminate\Console\Command;
23+
use Illuminate\Support\Facades\Storage;
2324
use Throwable;
2425

2526
class CleanTorrentFiles extends Command
@@ -47,13 +48,10 @@ final public function handle(): void
4748
{
4849
$this->alert('Torrent file cleaning started');
4950

50-
$directory = public_path('/files/torrents/');
51-
52-
Torrent::withoutGlobalScopes()->select('file_name')->orderBy('id')->chunk(100, function ($torrents) use ($directory): void {
51+
Torrent::withoutGlobalScopes()->select('file_name')->orderBy('id')->chunk(100, function ($torrents): void {
5352
foreach ($torrents as $torrent) {
54-
$filePath = $directory.$torrent->file_name;
55-
56-
if (file_exists($filePath)) {
53+
if (Storage::disk('torrent-files')->exists($torrent->file_name)) {
54+
$filePath = Storage::disk('torrent-files')->path($torrent->file_name);
5755
$dict = Bencode::bdecode_file($filePath);
5856

5957
// Whitelisted keys
@@ -63,7 +61,7 @@ final public function handle(): void
6361
'info' => '',
6462
]);
6563

66-
file_put_contents($filePath, Bencode::bencode($dict));
64+
Storage::disk('torrent-files')->put($filePath, Bencode::bencode($dict));
6765
}
6866
}
6967
});

app/Helpers/TorrentTools.php

+6-4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
namespace App\Helpers;
1818

1919
use Illuminate\Http\UploadedFile;
20+
use Illuminate\Support\Facades\Storage;
2021
use Illuminate\Support\Stringable;
2122

2223
class TorrentTools
@@ -141,11 +142,12 @@ public static function getNfo(?UploadedFile $inputFile): bool|string|null
141142
}
142143

143144
$fileName = uniqid('', true).'.nfo';
144-
$inputFile->move(getcwd().'/files/tmp/', $fileName);
145+
$path = Storage::disk('temporary-nfos')->path('');
146+
$inputFile->move($path, $fileName);
145147

146-
if (file_exists(getcwd().'/files/tmp/'.$fileName)) {
147-
$fileContent = file_get_contents(getcwd().'/files/tmp/'.$fileName);
148-
unlink(getcwd().'/files/tmp/'.$fileName);
148+
if (Storage::disk('temporary-nfos')->exists($fileName)) {
149+
$fileContent = Storage::disk('temporary-nfos')->get($fileName);
150+
Storage::disk('temporary-nfos')->delete($fileName);
149151
} else {
150152
$fileContent = null;
151153
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* NOTICE OF LICENSE.
7+
*
8+
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
9+
* The details is bundled with this project in the file LICENSE.txt.
10+
*
11+
* @project UNIT3D Community Edition
12+
*
13+
* @author Roardom <roardom@protonmail.com>
14+
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
15+
*/
16+
17+
namespace App\Http\Controllers;
18+
19+
use App\Models\Article;
20+
use App\Models\Category;
21+
use App\Models\Playlist;
22+
use App\Models\Torrent;
23+
use App\Models\User;
24+
use Illuminate\Support\Facades\Storage;
25+
26+
class AuthenticatedImageController extends Controller
27+
{
28+
private const array HEADERS = [
29+
'Cache-Control' => 'private, max-age=7200',
30+
];
31+
32+
public function articleImage(Article $article): \Symfony\Component\HttpFoundation\BinaryFileResponse
33+
{
34+
$path = $article->image === null
35+
? public_path('img/missing-image.png')
36+
: Storage::disk('article-images')->path($article->image);
37+
38+
abort_unless(file_exists($path), 404);
39+
40+
return response()->file($path, self::HEADERS);
41+
}
42+
43+
public function categoryImage(Category $category): \Symfony\Component\HttpFoundation\BinaryFileResponse
44+
{
45+
$path = Storage::disk('category-images')->path($category->image);
46+
47+
abort_unless(file_exists($path), 404);
48+
49+
return response()->file($path, self::HEADERS);
50+
}
51+
52+
public function playlistImage(Playlist $playlist): \Symfony\Component\HttpFoundation\BinaryFileResponse
53+
{
54+
$path = Storage::disk('playlist-images')->path($playlist->cover_image);
55+
56+
abort_unless(file_exists($path), 404);
57+
58+
return response()->file($path, self::HEADERS);
59+
}
60+
61+
public function torrentBanner(Torrent $torrent): \Symfony\Component\HttpFoundation\BinaryFileResponse
62+
{
63+
$path = Storage::disk('torrent-banners')->path("torrent-banner_{$torrent->id}");
64+
65+
abort_unless(file_exists($path), 404);
66+
67+
return response()->file($path, self::HEADERS);
68+
}
69+
70+
public function torrentCover(Torrent $torrent): \Symfony\Component\HttpFoundation\BinaryFileResponse
71+
{
72+
$path = Storage::disk('torrent-covers')->path("torrent-cover_{$torrent->id}");
73+
74+
abort_unless(file_exists($path), 404);
75+
76+
return response()->file($path, self::HEADERS);
77+
}
78+
79+
public function userAvatar(User $user): \Symfony\Component\HttpFoundation\BinaryFileResponse
80+
{
81+
$path = Storage::disk('user-avatars')->path($user->image);
82+
83+
abort_unless(file_exists($path), 404);
84+
85+
return response()->file($path, self::HEADERS);
86+
}
87+
88+
public function userIcon(User $user): \Symfony\Component\HttpFoundation\BinaryFileResponse
89+
{
90+
$path = Storage::disk('user-icons')->path($user->icon);
91+
92+
abort_unless(file_exists($path), 404);
93+
94+
return response()->file($path, self::HEADERS);
95+
}
96+
}

app/Http/Controllers/PlaylistController.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use Illuminate\Http\Request;
2727
use Intervention\Image\Facades\Image;
2828
use Exception;
29+
use Illuminate\Support\Facades\Storage;
2930

3031
/**
3132
* @see \Tests\Todo\Feature\Http\Controllers\PlaylistControllerTest
@@ -69,7 +70,7 @@ public function store(StorePlaylistRequest $request): \Illuminate\Http\RedirectR
6970

7071
$image = $request->file('cover_image');
7172
$filename = 'playlist-cover_'.uniqid('', true).'.'.$image->getClientOriginalExtension();
72-
$path = public_path('/files/img/'.$filename);
73+
$path = Storage::disk('playlist-images')->path($filename);
7374
Image::make($image->getRealPath())->fit(400, 225)->encode('png', 100)->save($path);
7475
}
7576

@@ -153,7 +154,7 @@ public function update(UpdatePlaylistRequest $request, Playlist $playlist): \Ill
153154
abort_unless($image->getError() === UPLOAD_ERR_OK, 500);
154155

155156
$filename = 'playlist-cover_'.uniqid('', true).'.'.$image->getClientOriginalExtension();
156-
$path = public_path('/files/img/'.$filename);
157+
$path = Storage::disk('playlist-images')->path($filename);
157158
Image::make($image->getRealPath())->fit(400, 225)->encode('png', 100)->save($path);
158159

159160
$playlist->update(['cover_image' => $filename] + $request->validated());

app/Http/Controllers/PlaylistZipController.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use App\Helpers\Bencode;
2020
use App\Models\Playlist;
2121
use Illuminate\Support\Facades\File;
22+
use Illuminate\Support\Facades\Storage;
2223
use ZipArchive;
2324

2425
/**
@@ -41,7 +42,7 @@ public function show(Playlist $playlist): \Illuminate\Http\RedirectResponse|\Sym
4142
$user = auth()->user();
4243

4344
// Define Dir Folder
44-
$path = getcwd().'/files/tmp_zip/';
45+
$path = Storage::disk('temporary-zips')->path('');
4546

4647
// Check Directory exists
4748
if (!File::isDirectory($path)) {
@@ -58,7 +59,7 @@ public function show(Playlist $playlist): \Illuminate\Http\RedirectResponse|\Sym
5859
$announceUrl = route('announce', ['passkey' => $user->passkey]);
5960

6061
foreach ($playlist->torrents()->get() as $torrent) {
61-
$dict = Bencode::bdecode(file_get_contents(getcwd().'/files/torrents/'.$torrent->file_name));
62+
$dict = Bencode::bdecode(Storage::disk('torrent-files')->get($torrent->file_name));
6263

6364
// Set the announce key and add the user passkey
6465
$dict['announce'] = $announceUrl;
@@ -80,8 +81,8 @@ public function show(Playlist $playlist): \Illuminate\Http\RedirectResponse|\Sym
8081
$zipArchive->close();
8182
}
8283

83-
if (file_exists($path.$zipFileName)) {
84-
return response()->download($path.$zipFileName)->deleteFileAfterSend(true);
84+
if (Storage::disk('temporary-zips')->exists($zipFileName)) {
85+
return response()->download(Storage::disk('temporary-zips')->path($zipFileName))->deleteFileAfterSend(true);
8586
}
8687

8788
return redirect()->back()->withErrors(trans('common.something-went-wrong'));

app/Http/Controllers/Staff/ArticleController.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use App\Models\Article;
2323
use Intervention\Image\Facades\Image;
2424
use Exception;
25+
use Illuminate\Support\Facades\Storage;
2526

2627
/**
2728
* @see \Tests\Feature\Http\Controllers\ArticleControllerTest
@@ -60,7 +61,7 @@ public function store(StoreArticleRequest $request): \Illuminate\Http\RedirectRe
6061
abort_if(\is_array($image), 400);
6162

6263
$filename = 'article-'.uniqid('', true).'.'.$image->getClientOriginalExtension();
63-
$path = public_path('/files/img/'.$filename);
64+
$path = Storage::disk('article-images')->path($filename);
6465
Image::make($image->getRealPath())->fit(75, 75)->encode('png', 100)->save($path);
6566
}
6667

@@ -91,7 +92,7 @@ public function update(UpdateArticleRequest $request, Article $article): \Illumi
9192
abort_if(\is_array($image), 400);
9293

9394
$filename = 'article-'.uniqid('', true).'.'.$image->getClientOriginalExtension();
94-
$path = public_path('/files/img/'.$filename);
95+
$path = Storage::disk('article-images')->path($filename);
9596
Image::make($image->getRealPath())->fit(75, 75)->encode('png', 100)->save($path);
9697
}
9798

app/Http/Controllers/Staff/CategoryController.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use App\Models\Category;
2323
use Intervention\Image\Facades\Image;
2424
use Exception;
25+
use Illuminate\Support\Facades\Storage;
2526

2627
/**
2728
* @see \Tests\Feature\Http\Controllers\CategoryControllerTest
@@ -57,7 +58,7 @@ public function store(StoreCategoryRequest $request): \Illuminate\Http\RedirectR
5758
abort_if(\is_array($image), 400);
5859

5960
$filename = 'category-'.uniqid('', true).'.'.$image->getClientOriginalExtension();
60-
$path = public_path('/files/img/'.$filename);
61+
$path = Storage::disk('category-images')->path($filename);
6162
Image::make($image->getRealPath())->fit(50, 50)->encode('png', 100)->save($path);
6263
}
6364

@@ -95,7 +96,7 @@ public function update(UpdateCategoryRequest $request, Category $category): \Ill
9596
abort_if(\is_array($image), 400);
9697

9798
$filename = 'category-'.uniqid('', true).'.'.$image->getClientOriginalExtension();
98-
$path = public_path('/files/img/'.$filename);
99+
$path = Storage::disk('category-images')->path($filename);
99100
Image::make($image->getRealPath())->fit(50, 50)->encode('png', 100)->save($path);
100101
}
101102

app/Http/Controllers/SubtitleController.php

+5-5
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public function store(StoreSubtitleRequest $request): \Illuminate\Http\RedirectR
9797
] + $request->safe()->except('subtitle_file'));
9898

9999
// Save Subtitle
100-
Storage::disk('subtitles')->putFileAs('', $subtitleFile, $filename);
100+
Storage::disk('subtitle-files')->putFileAs('', $subtitleFile, $filename);
101101

102102
// Announce To Shoutbox
103103
if (!$subtitle->anon) {
@@ -165,8 +165,8 @@ public function destroy(Request $request, Subtitle $subtitle): \Illuminate\Http\
165165

166166
abort_unless($user->group->is_modo || $user->id === $subtitle->user_id, 403);
167167

168-
if (Storage::disk('subtitles')->exists($subtitle->file_name)) {
169-
Storage::disk('subtitles')->delete($subtitle->file_name);
168+
if (Storage::disk('subtitle-files')->exists($subtitle->file_name)) {
169+
Storage::disk('subtitle-files')->delete($subtitle->file_name);
170170
}
171171

172172
$subtitle->delete();
@@ -194,8 +194,8 @@ public function download(Request $request, Subtitle $subtitle): \Illuminate\Http
194194
// Increment downloads count
195195
$subtitle->increment('downloads');
196196

197-
$headers = ['Content-Type: '.Storage::disk('subtitles')->mimeType($subtitle->file_name)];
197+
$headers = ['Content-Type: '.Storage::disk('subtitle-files')->mimeType($subtitle->file_name)];
198198

199-
return Storage::disk('subtitles')->download($subtitle->file_name, $tempFilename, $headers);
199+
return Storage::disk('subtitle-files')->download($subtitle->file_name, $tempFilename, $headers);
200200
}
201201
}

app/Http/Controllers/TicketAttachmentController.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use App\Models\Ticket;
2121
use App\Models\TicketAttachment;
2222
use Illuminate\Http\Request;
23+
use Illuminate\Support\Facades\Storage;
2324

2425
class TicketAttachmentController extends Controller
2526
{
@@ -30,7 +31,7 @@ final public function download(Request $request, Ticket $ticket, TicketAttachmen
3031
{
3132
abort_unless($request->user()->group->is_modo || $request->user()->id === $ticket->user_id, 403);
3233

33-
return response()->download(getcwd().'/files/attachments/attachments/'.$attachment->file_name)->deleteFileAfterSend(false);
34+
return response()->download(Storage::disk('attachment-files')->path($attachment->file_name))->deleteFileAfterSend(false);
3435
}
3536

3637
/**

app/Http/Controllers/TorrentController.php

+6-5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
use MarcReichel\IGDBLaravel\Models\PlatformLogo;
4848
use Exception;
4949
use Illuminate\Support\Facades\Notification;
50+
use Illuminate\Support\Facades\Storage;
5051
use ReflectionException;
5152
use JsonException;
5253

@@ -232,7 +233,7 @@ public function update(UpdateTorrentRequest $request, int $id): \Illuminate\Http
232233
abort_if(\is_array($image_cover), 400);
233234

234235
$filename_cover = 'torrent-cover_'.$torrent->id.'.jpg';
235-
$path_cover = public_path('/files/img/'.$filename_cover);
236+
$path_cover = Storage::disk('torrent-covers')->path($filename_cover);
236237
Image::make($image_cover->getRealPath())->fit(400, 600)->encode('jpg', 90)->save($path_cover);
237238
}
238239

@@ -243,7 +244,7 @@ public function update(UpdateTorrentRequest $request, int $id): \Illuminate\Http
243244
abort_if(\is_array($image_cover), 400);
244245

245246
$filename_cover = 'torrent-banner_'.$torrent->id.'.jpg';
246-
$path_cover = public_path('/files/img/'.$filename_cover);
247+
$path_cover = Storage::disk('torrent-banners')->path($filename_cover);
247248
Image::make($image_cover->getRealPath())->fit(960, 540)->encode('jpg', 90)->save($path_cover);
248249
}
249250

@@ -395,7 +396,7 @@ public function store(StoreTorrentRequest $request): \Illuminate\Http\RedirectRe
395396
$meta = Bencode::get_meta($decodedTorrent);
396397

397398
$fileName = uniqid('', true).'.torrent'; // Generate a unique name
398-
file_put_contents(getcwd().'/files/torrents/'.$fileName, Bencode::bencode($decodedTorrent));
399+
Storage::disk('torrent-files')->put($fileName, Bencode::bencode($decodedTorrent));
399400

400401
$torrent = Torrent::create([
401402
'mediainfo' => TorrentTools::anonymizeMediainfo($request->filled('mediainfo') ? $request->string('mediainfo') : null),
@@ -435,7 +436,7 @@ public function store(StoreTorrentRequest $request): \Illuminate\Http\RedirectRe
435436
abort_if(\is_array($image_cover), 400);
436437

437438
$filename_cover = 'torrent-cover_'.$torrent->id.'.jpg';
438-
$path_cover = public_path('/files/img/'.$filename_cover);
439+
$path_cover = Storage::disk('torrent-covers')->path($filename_cover);
439440
Image::make($image_cover->getRealPath())->fit(400, 600)->encode('jpg', 90)->save($path_cover);
440441
}
441442

@@ -446,7 +447,7 @@ public function store(StoreTorrentRequest $request): \Illuminate\Http\RedirectRe
446447
abort_if(\is_array($image_cover), 400);
447448

448449
$filename_cover = 'torrent-banner_'.$torrent->id.'.jpg';
449-
$path_cover = public_path('/files/img/'.$filename_cover);
450+
$path_cover = Storage::disk('torrent-banners')->path($filename_cover);
450451
Image::make($image_cover->getRealPath())->fit(960, 540)->encode('jpg', 90)->save($path_cover);
451452
}
452453

app/Http/Controllers/TorrentDownloadController.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use App\Models\TorrentDownload;
2323
use App\Models\User;
2424
use Illuminate\Http\Request;
25+
use Illuminate\Support\Facades\Storage;
2526

2627
class TorrentDownloadController extends Controller
2728
{
@@ -68,7 +69,7 @@ public function store(Request $request, int $id, ?string $rsskey = null): \Illum
6869
}
6970

7071
// The torrent file exist ?
71-
if (!file_exists(getcwd().'/files/torrents/'.$torrent->file_name)) {
72+
if (!Storage::disk('torrents')->exists($torrent->file_name)) {
7273
return to_route('torrents.show', ['id' => $torrent->id])
7374
->withErrors('Torrent File Not Found! Please Report This Torrent!');
7475
}
@@ -85,7 +86,7 @@ public function store(Request $request, int $id, ?string $rsskey = null): \Illum
8586

8687
return response()->streamDownload(
8788
function () use ($id, $user, $torrent): void {
88-
$dict = Bencode::bdecode(file_get_contents(getcwd().'/files/torrents/'.$torrent->file_name));
89+
$dict = Bencode::bdecode(Storage::disk('torrents')->get($torrent->file_name));
8990

9091
// Set the announce key and add the user passkey
9192
$dict['announce'] = route('announce', ['passkey' => $user->passkey]);

0 commit comments

Comments
 (0)