diff --git a/CHANGELOG.md b/CHANGELOG.md index 28ce10d32..81dfa0b14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Add MediaPathService ([c54b29c5](https://github.com/pixelfed/pixelfed/commit/c54b29c5)) - Add Media Tags ([711fc020](https://github.com/pixelfed/pixelfed/commit/711fc020)) - Add MediaTagService ([524c6d45](https://github.com/pixelfed/pixelfed/commit/524c6d45)) +- Add MediaBlocklist feature ([ba1f7e7e](https://github.com/pixelfed/pixelfed/commit/ba1f7e7e)) ### Updated - Updated PostComponent, fix remote urls ([42716ccc](https://github.com/pixelfed/pixelfed/commit/42716ccc)) @@ -75,6 +76,8 @@ - Updated ComposeModal.vue, add 451 http code warning. ([b213dcda](https://github.com/pixelfed/pixelfed/commit/b213dcda)) - Updated Profile.vue, add empty follower modal placeholder. ([b542a3c5](https://github.com/pixelfed/pixelfed/commit/b542a3c5)) - Updated private profiles, add context menu to mute, block or report. ([487c4ffc](https://github.com/pixelfed/pixelfed/commit/487c4ffc)) +- Updated webfinger util, fix bug preventing username with dots. ([c2d194af](https://github.com/pixelfed/pixelfed/commit/c2d194af)) +- Updated upload endpoints with MediaBlocklist checks. ([597378bf](https://github.com/pixelfed/pixelfed/commit/597378bf)) ## [v0.10.9 (2020-04-17)](https://github.com/pixelfed/pixelfed/compare/v0.10.8...v0.10.9) ### Added diff --git a/app/Http/Controllers/Admin/AdminMediaController.php b/app/Http/Controllers/Admin/AdminMediaController.php index 736922813..eb4bd93a8 100644 --- a/app/Http/Controllers/Admin/AdminMediaController.php +++ b/app/Http/Controllers/Admin/AdminMediaController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers\Admin; use DB, Cache; use App\{ Media, + MediaBlocklist, Profile, Status }; @@ -21,8 +22,8 @@ trait AdminMediaController 'nullable', 'string', 'min:1', - 'max:4', - Rule::in(['grid','list']) + 'max:13', + Rule::in(['grid','list', 'banned', 'addbanned']) ], 'search' => 'nullable|string|min:1|max:20' ]); @@ -34,9 +35,14 @@ trait AdminMediaController ->whereIn('profile_id', $profiles) ->orWhere('mime', $request->input('search')) ->paginate(12); - } else { - $media = Media::whereHas('status')->with('status')->orderby('id', 'desc')->paginate(12); + return view('admin.media.home', compact('media')); } + + if($request->input('layout') == 'banned') { + $media = MediaBlocklist::latest()->paginate(12); + return view('admin.media.home', compact('media')); + } + $media = Media::whereHas('status')->with('status')->orderby('id', 'desc')->paginate(12); return view('admin.media.home', compact('media')); } diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index dd6112831..7bf0646e2 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -48,9 +48,11 @@ use App\Jobs\VideoPipeline\{ use App\Services\{ NotificationService, MediaPathService, - SearchApiV2Service + SearchApiV2Service, + MediaBlocklistService }; + class ApiV1Controller extends Controller { protected $fractal; @@ -1046,6 +1048,8 @@ class ApiV1Controller extends Controller $path = $photo->store($storagePath); $hash = \hash_file('sha256', $photo); + abort_if(MediaBlocklistService::exists($hash) == true, 451); + $media = new Media(); $media->status_id = null; $media->profile_id = $profile->id; diff --git a/app/Http/Controllers/Api/BaseApiController.php b/app/Http/Controllers/Api/BaseApiController.php index 433841fbf..6c14d07a2 100644 --- a/app/Http/Controllers/Api/BaseApiController.php +++ b/app/Http/Controllers/Api/BaseApiController.php @@ -36,6 +36,7 @@ use App\Jobs\VideoPipeline\{ }; use App\Services\NotificationService; use App\Services\MediaPathService; +use App\Services\MediaBlocklistService; class BaseApiController extends Controller { @@ -247,6 +248,8 @@ class BaseApiController extends Controller $path = $photo->store($storagePath); $hash = \hash_file('sha256', $photo); + abort_if(MediaBlocklistService::exists($hash) == true, 451); + $media = new Media(); $media->status_id = null; $media->profile_id = $profile->id; diff --git a/app/Http/Controllers/MediaBlocklistController.php b/app/Http/Controllers/MediaBlocklistController.php new file mode 100644 index 000000000..bf862be0b --- /dev/null +++ b/app/Http/Controllers/MediaBlocklistController.php @@ -0,0 +1,50 @@ +middleware('auth'); + $this->middleware('admin'); + } + + public function add(Request $request) + { + $this->validate($request, [ + 'hash' => 'required|string|size:64', + 'name' => 'nullable|string', + 'description' => 'nullable|string|max:500', + ]); + + $hash = $request->input('hash'); + abort_if(preg_match("/^([a-f0-9]{64})$/", $hash) !== 1, 400); + + $name = $request->input('name'); + $description = $request->input('description'); + + $mb = new MediaBlocklist; + $mb->sha256 = $hash; + $mb->name = $name; + $mb->description = $description; + $mb->save(); + + return redirect('/i/admin/media?layout=banned'); + } + + public function delete(Request $request) + { + $this->validate($request, [ + 'id' => 'required|integer' + ]); + + $media = MediaBlocklist::findOrFail($request->input('id')); + $media->delete(); + + return redirect('/i/admin/media?layout=banned'); + } +} diff --git a/app/Http/Middleware/TwoFactorAuth.php b/app/Http/Middleware/TwoFactorAuth.php index b59b2c31f..ff3244575 100644 --- a/app/Http/Middleware/TwoFactorAuth.php +++ b/app/Http/Middleware/TwoFactorAuth.php @@ -21,7 +21,7 @@ class TwoFactorAuth $enabled = (bool) $user->{'2fa_enabled'}; if($enabled != false) { $checkpoint = 'i/auth/checkpoint'; - if($request->session()->has('2fa.session.active') !== true && !$request->is($checkpoint)) + if($request->session()->has('2fa.session.active') !== true && !$request->is($checkpoint) && !$request->is('logout')) { return redirect('/i/auth/checkpoint'); } elseif($request->session()->has('2fa.attempts') && (int) $request->session()->get('2fa.attempts') > 3) { diff --git a/app/MediaBlocklist.php b/app/MediaBlocklist.php new file mode 100644 index 000000000..221ff6e2c --- /dev/null +++ b/app/MediaBlocklist.php @@ -0,0 +1,10 @@ +pluck('sha256') + ->toArray(); + } + + public static function exists($hash) + { + $hashes = self::get(); + return in_array($hash, $hashes) == true; + } + + public static function remove($hash) + { + if(!self::exists($hash)) { + return; + } + MediaBlocklist::whereSha256($hash)->delete(); + return; + } + + public static function add($hash, $metadata) + { + $m = new MediaBlocklist; + $m->sha256 = $hash; + $m->active = true; + $m->metadata = json_encode($metadata); + $m->save(); + + return $m; + } +} \ No newline at end of file diff --git a/app/Util/Lexer/Nickname.php b/app/Util/Lexer/Nickname.php index 809605abf..00a9b23d2 100644 --- a/app/Util/Lexer/Nickname.php +++ b/app/Util/Lexer/Nickname.php @@ -10,32 +10,13 @@ class Nickname $url = str_replace('acct:', '', $url); } - if (!str_contains($url, '@') && filter_var($url, FILTER_VALIDATE_URL)) { - $parsed = parse_url($url); - $username = str_replace(['/', '\\', '@'], '', $parsed['path']); - - return ['domain' => $parsed['host'], 'username' => $username]; + if(starts_with($url, '@')) { + $url = substr($url, 1); } + $parts = explode('@', $url); - $username = null; - $domain = null; - - foreach ($parts as $part) { - - // skip empty array slices - if (empty($part)) { - continue; - } - - // if slice contains . assume its a domain - if (str_contains($part, '.')) { - $domain = filter_var($part, FILTER_VALIDATE_URL) ? - parse_url($part, PHP_URL_HOST) : - $part; - } else { - $username = $part; - } - } + $username = $parts[0]; + $domain = $parts[1]; return ['domain' => $domain, 'username' => $username]; } diff --git a/database/migrations/2020_07_25_230100_create_media_blocklists_table.php b/database/migrations/2020_07_25_230100_create_media_blocklists_table.php new file mode 100644 index 000000000..1fa624398 --- /dev/null +++ b/database/migrations/2020_07_25_230100_create_media_blocklists_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('sha256')->nullable()->unique()->index(); + $table->string('sha512')->nullable()->unique()->index(); + $table->string('name')->nullable(); + $table->text('description')->nullable(); + $table->boolean('active')->default(true)->index(); + $table->json('metadata')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('media_blocklists'); + } +} diff --git a/resources/views/admin/media/home.blade.php b/resources/views/admin/media/home.blade.php index 4344afb73..a26132941 100644 --- a/resources/views/admin/media/home.blade.php +++ b/resources/views/admin/media/home.blade.php @@ -4,11 +4,11 @@

Media

- - + + All - - + + Banned