From 665581d80c48510d54e8bb605296b27768a95d95 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 12 Mar 2024 01:03:33 -0600 Subject: [PATCH] Update cloud storage, use config_cache --- app/Console/Commands/AvatarStorage.php | 10 +- .../Commands/AvatarStorageDeepClean.php | 2 +- app/Console/Commands/CloudMediaMigrate.php | 6 +- app/Console/Commands/FixMediaDriver.php | 2 +- app/Console/Commands/MediaCloudUrlRewrite.php | 2 +- .../Commands/MediaS3GarbageCollector.php | 2 +- app/Console/Kernel.php | 2 +- app/Http/Controllers/ComposeController.php | 2 +- app/Http/Controllers/MediaController.php | 37 +- app/Http/Controllers/RemoteAuthController.php | 170 ++++----- app/Jobs/AvatarPipeline/AvatarOptimize.php | 152 ++++---- app/Jobs/AvatarPipeline/RemoteAvatarFetch.php | 157 ++++---- .../RemoteAvatarFetchFromUrl.php | 133 ++++--- .../MediaPipeline/MediaDeletePipeline.php | 97 ++--- ...MediaFixLocalFilesystemCleanupPipeline.php | 97 ++--- app/Observers/AvatarObserver.php | 14 +- app/Services/ConfigCacheService.php | 1 + app/Services/MediaStorageService.php | 117 +++--- app/Util/ActivityPub/Helpers.php | 337 +++++++++--------- .../views/admin/diagnostics/home.blade.php | 2 +- 20 files changed, 669 insertions(+), 673 deletions(-) diff --git a/app/Console/Commands/AvatarStorage.php b/app/Console/Commands/AvatarStorage.php index 054802f42..a6bb70e3d 100644 --- a/app/Console/Commands/AvatarStorage.php +++ b/app/Console/Commands/AvatarStorage.php @@ -82,7 +82,7 @@ class AvatarStorage extends Command $this->line(' '); - if(config_cache('pixelfed.cloud_storage')) { + if((bool) config_cache('pixelfed.cloud_storage')) { $this->info('✅ - Cloud storage configured'); $this->line(' '); } @@ -92,7 +92,7 @@ class AvatarStorage extends Command $this->line(' '); } - if(config_cache('pixelfed.cloud_storage') && config('instance.avatar.local_to_cloud')) { + if((bool) config_cache('pixelfed.cloud_storage') && config('instance.avatar.local_to_cloud')) { $disk = Storage::disk(config_cache('filesystems.cloud')); $exists = $disk->exists('cache/avatars/default.jpg'); $state = $exists ? '✅' : '❌'; @@ -100,7 +100,7 @@ class AvatarStorage extends Command $this->info($msg); } - $options = config_cache('pixelfed.cloud_storage') && config('instance.avatar.local_to_cloud') ? + $options = (bool) config_cache('pixelfed.cloud_storage') && config('instance.avatar.local_to_cloud') ? [ 'Cancel', 'Upload default avatar to cloud', @@ -164,7 +164,7 @@ class AvatarStorage extends Command protected function uploadAvatarsToCloud() { - if(!config_cache('pixelfed.cloud_storage') || !config('instance.avatar.local_to_cloud')) { + if(!(bool) config_cache('pixelfed.cloud_storage') || !config('instance.avatar.local_to_cloud')) { $this->error('Enable cloud storage and avatar cloud storage to perform this action'); return; } @@ -213,7 +213,7 @@ class AvatarStorage extends Command return; } - if(config_cache('pixelfed.cloud_storage') == false && config_cache('federation.avatars.store_local') == false) { + if((bool) config_cache('pixelfed.cloud_storage') == false && config_cache('federation.avatars.store_local') == false) { $this->error('You have cloud storage disabled and local avatar storage disabled, we cannot refetch avatars.'); return; } diff --git a/app/Console/Commands/AvatarStorageDeepClean.php b/app/Console/Commands/AvatarStorageDeepClean.php index 5840142f5..6f773bd42 100644 --- a/app/Console/Commands/AvatarStorageDeepClean.php +++ b/app/Console/Commands/AvatarStorageDeepClean.php @@ -44,7 +44,7 @@ class AvatarStorageDeepClean extends Command $this->line(' '); $storage = [ - 'cloud' => boolval(config_cache('pixelfed.cloud_storage')), + 'cloud' => (bool) config_cache('pixelfed.cloud_storage'), 'local' => boolval(config_cache('federation.avatars.store_local')) ]; diff --git a/app/Console/Commands/CloudMediaMigrate.php b/app/Console/Commands/CloudMediaMigrate.php index 0f2d177b8..174b33e83 100644 --- a/app/Console/Commands/CloudMediaMigrate.php +++ b/app/Console/Commands/CloudMediaMigrate.php @@ -35,12 +35,16 @@ class CloudMediaMigrate extends Command */ public function handle() { - $enabled = config('pixelfed.cloud_storage'); + $enabled = (bool) config_cache('pixelfed.cloud_storage'); if(!$enabled) { $this->error('Cloud storage not enabled. Exiting...'); return; } + if(!$this->confirm('Are you sure you want to proceed?')) { + return; + } + $limit = $this->option('limit'); $hugeMode = $this->option('huge'); diff --git a/app/Console/Commands/FixMediaDriver.php b/app/Console/Commands/FixMediaDriver.php index c743d6c64..a20b0574e 100644 --- a/app/Console/Commands/FixMediaDriver.php +++ b/app/Console/Commands/FixMediaDriver.php @@ -37,7 +37,7 @@ class FixMediaDriver extends Command return Command::SUCCESS; } - if(config_cache('pixelfed.cloud_storage') == false) { + if((bool) config_cache('pixelfed.cloud_storage') == false) { $this->error('Cloud storage not enabled, exiting...'); return Command::SUCCESS; } diff --git a/app/Console/Commands/MediaCloudUrlRewrite.php b/app/Console/Commands/MediaCloudUrlRewrite.php index 54329f7c7..367c22d1f 100644 --- a/app/Console/Commands/MediaCloudUrlRewrite.php +++ b/app/Console/Commands/MediaCloudUrlRewrite.php @@ -47,7 +47,7 @@ class MediaCloudUrlRewrite extends Command implements PromptsForMissingInput protected function preflightCheck() { - if(config_cache('pixelfed.cloud_storage') != true) { + if(!(bool) config_cache('pixelfed.cloud_storage')) { $this->info('Error: Cloud storage is not enabled!'); $this->error('Aborting...'); exit; diff --git a/app/Console/Commands/MediaS3GarbageCollector.php b/app/Console/Commands/MediaS3GarbageCollector.php index b6cda43c3..e66fdd2a8 100644 --- a/app/Console/Commands/MediaS3GarbageCollector.php +++ b/app/Console/Commands/MediaS3GarbageCollector.php @@ -45,7 +45,7 @@ class MediaS3GarbageCollector extends Command */ public function handle() { - $enabled = in_array(config_cache('pixelfed.cloud_storage'), ['1', true, 'true']); + $enabled = (bool) config_cache('pixelfed.cloud_storage'); if(!$enabled) { $this->error('Cloud storage not enabled. Exiting...'); return; diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index dcee73ee1..938696a1d 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -33,7 +33,7 @@ class Kernel extends ConsoleKernel $schedule->command('gc:passwordreset')->dailyAt('09:41')->onOneServer(); $schedule->command('gc:sessions')->twiceDaily(13, 23)->onOneServer(); - if (in_array(config_cache('pixelfed.cloud_storage'), ['1', true, 'true']) && config('media.delete_local_after_cloud')) { + if ((bool) config_cache('pixelfed.cloud_storage') && (bool) config_cache('media.delete_local_after_cloud')) { $schedule->command('media:s3gc')->hourlyAt(15); } diff --git a/app/Http/Controllers/ComposeController.php b/app/Http/Controllers/ComposeController.php index 341d56ea8..4c27aa18e 100644 --- a/app/Http/Controllers/ComposeController.php +++ b/app/Http/Controllers/ComposeController.php @@ -741,7 +741,7 @@ class ComposeController extends Controller case 'image/jpeg': case 'image/png': case 'video/mp4': - $finished = config_cache('pixelfed.cloud_storage') ? (bool) $media->cdn_url : (bool) $media->processed_at; + $finished = (bool) config_cache('pixelfed.cloud_storage') ? (bool) $media->cdn_url : (bool) $media->processed_at; break; default: diff --git a/app/Http/Controllers/MediaController.php b/app/Http/Controllers/MediaController.php index b10e75795..cbc08cb5a 100644 --- a/app/Http/Controllers/MediaController.php +++ b/app/Http/Controllers/MediaController.php @@ -2,30 +2,31 @@ namespace App\Http\Controllers; -use Illuminate\Http\Request; use App\Media; +use Illuminate\Http\Request; class MediaController extends Controller { - public function index(Request $request) - { - //return view('settings.drive.index'); - } + public function index(Request $request) + { + //return view('settings.drive.index'); + abort(404); + } - public function composeUpdate(Request $request, $id) - { + public function composeUpdate(Request $request, $id) + { abort(400, 'Endpoint deprecated'); - } + } - public function fallbackRedirect(Request $request, $pid, $mhash, $uhash, $f) - { - abort_if(!config_cache('pixelfed.cloud_storage'), 404); - $path = 'public/m/_v2/' . $pid . '/' . $mhash . '/' . $uhash . '/' . $f; - $media = Media::whereProfileId($pid) - ->whereMediaPath($path) - ->whereNotNull('cdn_url') - ->firstOrFail(); + public function fallbackRedirect(Request $request, $pid, $mhash, $uhash, $f) + { + abort_if(! (bool) config_cache('pixelfed.cloud_storage'), 404); + $path = 'public/m/_v2/'.$pid.'/'.$mhash.'/'.$uhash.'/'.$f; + $media = Media::whereProfileId($pid) + ->whereMediaPath($path) + ->whereNotNull('cdn_url') + ->firstOrFail(); - return redirect()->away($media->cdn_url); - } + return redirect()->away($media->cdn_url); + } } diff --git a/app/Http/Controllers/RemoteAuthController.php b/app/Http/Controllers/RemoteAuthController.php index e068f5d75..e0afd82ef 100644 --- a/app/Http/Controllers/RemoteAuthController.php +++ b/app/Http/Controllers/RemoteAuthController.php @@ -2,22 +2,20 @@ namespace App\Http\Controllers; -use Illuminate\Support\Str; -use Illuminate\Http\Request; -use App\Services\Account\RemoteAuthService; use App\Models\RemoteAuth; -use App\Profile; -use App\Instance; -use App\User; -use Purify; -use Illuminate\Support\Facades\Auth; -use Illuminate\Support\Facades\Hash; -use Illuminate\Auth\Events\Registered; -use App\Util\Lexer\RestrictedNames; +use App\Services\Account\RemoteAuthService; use App\Services\EmailService; use App\Services\MediaStorageService; +use App\User; use App\Util\ActivityPub\Helpers; +use App\Util\Lexer\RestrictedNames; +use Illuminate\Auth\Events\Registered; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Str; use InvalidArgumentException; +use Purify; class RemoteAuthController extends Controller { @@ -30,9 +28,10 @@ class RemoteAuthController extends Controller config('remote-auth.mastodon.ignore_closed_state') && config('remote-auth.mastodon.enabled') ), 404); - if($request->user()) { + if ($request->user()) { return redirect('/'); } + return view('auth.remote.start'); } @@ -51,25 +50,27 @@ class RemoteAuthController extends Controller config('remote-auth.mastodon.enabled') ), 404); - if(config('remote-auth.mastodon.domains.only_custom')) { + if (config('remote-auth.mastodon.domains.only_custom')) { $res = config('remote-auth.mastodon.domains.custom'); - if(!$res || !strlen($res)) { + if (! $res || ! strlen($res)) { return []; } $res = explode(',', $res); + return response()->json($res); } - if( config('remote-auth.mastodon.domains.custom') && - !config('remote-auth.mastodon.domains.only_default') && + if (config('remote-auth.mastodon.domains.custom') && + ! config('remote-auth.mastodon.domains.only_default') && strlen(config('remote-auth.mastodon.domains.custom')) > 3 && strpos(config('remote-auth.mastodon.domains.custom'), '.') > -1 ) { $res = config('remote-auth.mastodon.domains.custom'); - if(!$res || !strlen($res)) { + if (! $res || ! strlen($res)) { return []; } $res = explode(',', $res); + return response()->json($res); } @@ -93,57 +94,62 @@ class RemoteAuthController extends Controller $domain = $request->input('domain'); - if(str_starts_with(strtolower($domain), 'http')) { + if (str_starts_with(strtolower($domain), 'http')) { $res = [ 'domain' => $domain, 'ready' => false, - 'action' => 'incompatible_domain' + 'action' => 'incompatible_domain', ]; + return response()->json($res); } - $validateInstance = Helpers::validateUrl('https://' . $domain . '/?block-check=' . time()); + $validateInstance = Helpers::validateUrl('https://'.$domain.'/?block-check='.time()); - if(!$validateInstance) { - $res = [ + if (! $validateInstance) { + $res = [ 'domain' => $domain, 'ready' => false, - 'action' => 'blocked_domain' + 'action' => 'blocked_domain', ]; + return response()->json($res); } $compatible = RemoteAuthService::isDomainCompatible($domain); - if(!$compatible) { + if (! $compatible) { $res = [ 'domain' => $domain, 'ready' => false, - 'action' => 'incompatible_domain' + 'action' => 'incompatible_domain', ]; + return response()->json($res); } - if(config('remote-auth.mastodon.domains.only_default')) { + if (config('remote-auth.mastodon.domains.only_default')) { $defaultDomains = explode(',', config('remote-auth.mastodon.domains.default')); - if(!in_array($domain, $defaultDomains)) { + if (! in_array($domain, $defaultDomains)) { $res = [ 'domain' => $domain, 'ready' => false, - 'action' => 'incompatible_domain' + 'action' => 'incompatible_domain', ]; + return response()->json($res); } } - if(config('remote-auth.mastodon.domains.only_custom') && config('remote-auth.mastodon.domains.custom')) { + if (config('remote-auth.mastodon.domains.only_custom') && config('remote-auth.mastodon.domains.custom')) { $customDomains = explode(',', config('remote-auth.mastodon.domains.custom')); - if(!in_array($domain, $customDomains)) { + if (! in_array($domain, $customDomains)) { $res = [ 'domain' => $domain, 'ready' => false, - 'action' => 'incompatible_domain' + 'action' => 'incompatible_domain', ]; + return response()->json($res); } } @@ -163,13 +169,13 @@ class RemoteAuthController extends Controller 'state' => $state, ]); - $request->session()->put('oauth_redirect_to', 'https://' . $domain . '/oauth/authorize?' . $query); + $request->session()->put('oauth_redirect_to', 'https://'.$domain.'/oauth/authorize?'.$query); $dsh = Str::random(17); $res = [ 'domain' => $domain, 'ready' => true, - 'dsh' => $dsh + 'dsh' => $dsh, ]; return response()->json($res); @@ -185,7 +191,7 @@ class RemoteAuthController extends Controller config('remote-auth.mastodon.enabled') ), 404); - if(!$request->filled('d') || !$request->filled('dsh') || !$request->session()->exists('oauth_redirect_to')) { + if (! $request->filled('d') || ! $request->filled('dsh') || ! $request->session()->exists('oauth_redirect_to')) { return redirect('/login'); } @@ -204,7 +210,7 @@ class RemoteAuthController extends Controller $domain = $request->session()->get('oauth_domain'); - if($request->filled('code')) { + if ($request->filled('code')) { $code = $request->input('code'); $state = $request->session()->pull('state'); @@ -216,12 +222,14 @@ class RemoteAuthController extends Controller $res = RemoteAuthService::getToken($domain, $code); - if(!$res || !isset($res['access_token'])) { + if (! $res || ! isset($res['access_token'])) { $request->session()->regenerate(); + return redirect('/login'); } $request->session()->put('oauth_remote_session_token', $res['access_token']); + return redirect('/auth/mastodon/getting-started'); } @@ -237,9 +245,10 @@ class RemoteAuthController extends Controller config('remote-auth.mastodon.ignore_closed_state') && config('remote-auth.mastodon.enabled') ), 404); - if($request->user()) { + if ($request->user()) { return redirect('/'); } + return view('auth.remote.onboarding'); } @@ -261,36 +270,36 @@ class RemoteAuthController extends Controller $res = RemoteAuthService::getVerifyCredentials($domain, $token); - abort_if(!$res || !isset($res['acct']), 403, 'Invalid credentials'); + abort_if(! $res || ! isset($res['acct']), 403, 'Invalid credentials'); - $webfinger = strtolower('@' . $res['acct'] . '@' . $domain); + $webfinger = strtolower('@'.$res['acct'].'@'.$domain); $request->session()->put('oauth_masto_webfinger', $webfinger); - if(config('remote-auth.mastodon.max_uses.enabled')) { + if (config('remote-auth.mastodon.max_uses.enabled')) { $limit = config('remote-auth.mastodon.max_uses.limit'); $uses = RemoteAuthService::lookupWebfingerUses($webfinger); - if($uses >= $limit) { + if ($uses >= $limit) { return response()->json([ 'code' => 200, 'msg' => 'Success!', - 'action' => 'max_uses_reached' + 'action' => 'max_uses_reached', ]); } } $exists = RemoteAuth::whereDomain($domain)->where('webfinger', $webfinger)->whereNotNull('user_id')->first(); - if($exists && $exists->user_id) { + if ($exists && $exists->user_id) { return response()->json([ 'code' => 200, 'msg' => 'Success!', - 'action' => 'redirect_existing_user' + 'action' => 'redirect_existing_user', ]); } return response()->json([ 'code' => 200, 'msg' => 'Success!', - 'action' => 'onboard' + 'action' => 'onboard', ]); } @@ -311,7 +320,7 @@ class RemoteAuthController extends Controller $token = $request->session()->get('oauth_remote_session_token'); $res = RemoteAuthService::getVerifyCredentials($domain, $token); - $res['_webfinger'] = strtolower('@' . $res['acct'] . '@' . $domain); + $res['_webfinger'] = strtolower('@'.$res['acct'].'@'.$domain); $res['_domain'] = strtolower($domain); $request->session()->put('oauth_remasto_id', $res['id']); @@ -324,7 +333,7 @@ class RemoteAuthController extends Controller 'bearer_token' => $token, 'verify_credentials' => $res, 'last_verify_credentials_at' => now(), - 'last_successful_login_at' => now() + 'last_successful_login_at' => now(), ]); $request->session()->put('oauth_masto_raid', $ra->id); @@ -355,24 +364,24 @@ class RemoteAuthController extends Controller $underscore = substr_count($value, '_'); $period = substr_count($value, '.'); - if(ends_with($value, ['.php', '.js', '.css'])) { + if (ends_with($value, ['.php', '.js', '.css'])) { return $fail('Username is invalid.'); } - if(($dash + $underscore + $period) > 1) { + if (($dash + $underscore + $period) > 1) { return $fail('Username is invalid. Can only contain one dash (-), period (.) or underscore (_).'); } - if (!ctype_alnum($value[0])) { + if (! ctype_alnum($value[0])) { return $fail('Username is invalid. Must start with a letter or number.'); } - if (!ctype_alnum($value[strlen($value) - 1])) { + if (! ctype_alnum($value[strlen($value) - 1])) { return $fail('Username is invalid. Must end with a letter or number.'); } $val = str_replace(['_', '.', '-'], '', $value); - if(!ctype_alnum($val)) { + if (! ctype_alnum($val)) { return $fail('Username is invalid. Username must be alpha-numeric and may contain dashes (-), periods (.) and underscores (_).'); } @@ -380,8 +389,8 @@ class RemoteAuthController extends Controller if (in_array(strtolower($value), array_map('strtolower', $restricted))) { return $fail('Username cannot be used.'); } - } - ] + }, + ], ]); $username = strtolower($request->input('username')); @@ -390,7 +399,7 @@ class RemoteAuthController extends Controller return response()->json([ 'code' => 200, 'username' => $username, - 'exists' => $exists + 'exists' => $exists, ]); } @@ -411,7 +420,7 @@ class RemoteAuthController extends Controller 'email' => [ 'required', 'email:strict,filter_unicode,dns,spoof', - ] + ], ]); $email = $request->input('email'); @@ -422,7 +431,7 @@ class RemoteAuthController extends Controller 'code' => 200, 'email' => $email, 'exists' => $exists, - 'banned' => $banned + 'banned' => $banned, ]); } @@ -445,18 +454,18 @@ class RemoteAuthController extends Controller $res = RemoteAuthService::getFollowing($domain, $token, $id); - if(!$res) { + if (! $res) { return response()->json([ 'code' => 200, - 'following' => [] + 'following' => [], ]); } - $res = collect($res)->filter(fn($acct) => Helpers::validateUrl($acct['url']))->values()->toArray(); + $res = collect($res)->filter(fn ($acct) => Helpers::validateUrl($acct['url']))->values()->toArray(); return response()->json([ 'code' => 200, - 'following' => $res + 'following' => $res, ]); } @@ -487,24 +496,24 @@ class RemoteAuthController extends Controller $underscore = substr_count($value, '_'); $period = substr_count($value, '.'); - if(ends_with($value, ['.php', '.js', '.css'])) { + if (ends_with($value, ['.php', '.js', '.css'])) { return $fail('Username is invalid.'); } - if(($dash + $underscore + $period) > 1) { + if (($dash + $underscore + $period) > 1) { return $fail('Username is invalid. Can only contain one dash (-), period (.) or underscore (_).'); } - if (!ctype_alnum($value[0])) { + if (! ctype_alnum($value[0])) { return $fail('Username is invalid. Must start with a letter or number.'); } - if (!ctype_alnum($value[strlen($value) - 1])) { + if (! ctype_alnum($value[strlen($value) - 1])) { return $fail('Username is invalid. Must end with a letter or number.'); } $val = str_replace(['_', '.', '-'], '', $value); - if(!ctype_alnum($val)) { + if (! ctype_alnum($val)) { return $fail('Username is invalid. Username must be alpha-numeric and may contain dashes (-), periods (.) and underscores (_).'); } @@ -512,10 +521,10 @@ class RemoteAuthController extends Controller if (in_array(strtolower($value), array_map('strtolower', $restricted))) { return $fail('Username cannot be used.'); } - } + }, ], 'password' => 'required|string|min:8|confirmed', - 'name' => 'nullable|max:30' + 'name' => 'nullable|max:30', ]); $email = $request->input('email'); @@ -527,7 +536,7 @@ class RemoteAuthController extends Controller 'name' => $name, 'username' => $username, 'password' => $password, - 'email' => $email + 'email' => $email, ]); $raid = $request->session()->pull('oauth_masto_raid'); @@ -541,7 +550,7 @@ class RemoteAuthController extends Controller return [ 'code' => 200, 'msg' => 'Success', - 'token' => $token + 'token' => $token, ]; } @@ -585,7 +594,7 @@ class RemoteAuthController extends Controller abort_unless($request->session()->exists('oauth_remasto_id'), 403); $this->validate($request, [ - 'account' => 'required|url' + 'account' => 'required|url', ]); $account = $request->input('account'); @@ -594,10 +603,10 @@ class RemoteAuthController extends Controller $host = strtolower(config('pixelfed.domain.app')); $domain = strtolower(parse_url($account, PHP_URL_HOST)); - if($domain == $host) { + if ($domain == $host) { $username = Str::of($account)->explode('/')->last(); $user = User::where('username', $username)->first(); - if($user) { + if ($user) { return ['id' => (string) $user->profile_id]; } else { return []; @@ -605,7 +614,7 @@ class RemoteAuthController extends Controller } else { try { $profile = Helpers::profileFetch($account); - if($profile) { + if ($profile) { return ['id' => (string) $profile->id]; } else { return []; @@ -635,13 +644,13 @@ class RemoteAuthController extends Controller $user = $request->user(); $profile = $user->profile; - abort_if(!$profile->avatar, 404, 'Missing avatar'); + abort_if(! $profile->avatar, 404, 'Missing avatar'); $avatar = $profile->avatar; $avatar->remote_url = $request->input('avatar_url'); $avatar->save(); - MediaStorageService::avatar($avatar, config_cache('pixelfed.cloud_storage') == false); + MediaStorageService::avatar($avatar, (bool) config_cache('pixelfed.cloud_storage') == false); return [200]; } @@ -657,7 +666,7 @@ class RemoteAuthController extends Controller ), 404); abort_unless($request->user(), 404); - $currentWebfinger = '@' . $request->user()->username . '@' . config('pixelfed.domain.app'); + $currentWebfinger = '@'.$request->user()->username.'@'.config('pixelfed.domain.app'); $ra = RemoteAuth::where('user_id', $request->user()->id)->firstOrFail(); RemoteAuthService::submitToBeagle( $ra->webfinger, @@ -691,19 +700,20 @@ class RemoteAuthController extends Controller $user = User::findOrFail($ra->user_id); abort_if($user->is_admin || $user->status != null, 422, 'Invalid auth action'); Auth::loginUsingId($ra->user_id); + return [200]; } protected function createUser($data) { event(new Registered($user = User::create([ - 'name' => Purify::clean($data['name']), + 'name' => Purify::clean($data['name']), 'username' => $data['username'], - 'email' => $data['email'], + 'email' => $data['email'], 'password' => Hash::make($data['password']), 'email_verified_at' => config('remote-auth.mastodon.contraints.skip_email_verification') ? now() : null, 'app_register_ip' => request()->ip(), - 'register_source' => 'mastodon' + 'register_source' => 'mastodon', ]))); $this->guarder()->login($user); diff --git a/app/Jobs/AvatarPipeline/AvatarOptimize.php b/app/Jobs/AvatarPipeline/AvatarOptimize.php index 4464dff4e..8b50d8330 100644 --- a/app/Jobs/AvatarPipeline/AvatarOptimize.php +++ b/app/Jobs/AvatarPipeline/AvatarOptimize.php @@ -2,9 +2,9 @@ namespace App\Jobs\AvatarPipeline; -use Cache; use App\Avatar; use App\Profile; +use Cache; use Carbon\Carbon; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -17,88 +17,88 @@ use Storage; class AvatarOptimize implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - protected $profile; - protected $current; + protected $profile; - /** - * Delete the job if its models no longer exist. - * - * @var bool - */ - public $deleteWhenMissingModels = true; + protected $current; - /** - * Create a new job instance. - * - * @return void - */ - public function __construct(Profile $profile, $current) - { - $this->profile = $profile; - $this->current = $current; - } + /** + * Delete the job if its models no longer exist. + * + * @var bool + */ + public $deleteWhenMissingModels = true; - /** - * Execute the job. - * - * @return void - */ - public function handle() - { - $avatar = $this->profile->avatar; - $file = storage_path("app/$avatar->media_path"); + /** + * Create a new job instance. + * + * @return void + */ + public function __construct(Profile $profile, $current) + { + $this->profile = $profile; + $this->current = $current; + } - try { - $img = Intervention::make($file)->orientate(); - $img->fit(200, 200, function ($constraint) { - $constraint->upsize(); - }); - $quality = config_cache('pixelfed.image_quality'); - $img->save($file, $quality); + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $avatar = $this->profile->avatar; + $file = storage_path("app/$avatar->media_path"); - $avatar = Avatar::whereProfileId($this->profile->id)->firstOrFail(); - $avatar->change_count = ++$avatar->change_count; - $avatar->last_processed_at = Carbon::now(); - $avatar->save(); - Cache::forget('avatar:' . $avatar->profile_id); - $this->deleteOldAvatar($avatar->media_path, $this->current); + try { + $img = Intervention::make($file)->orientate(); + $img->fit(200, 200, function ($constraint) { + $constraint->upsize(); + }); + $quality = config_cache('pixelfed.image_quality'); + $img->save($file, $quality); - if(config_cache('pixelfed.cloud_storage') && config('instance.avatar.local_to_cloud')) { - $this->uploadToCloud($avatar); - } else { - $avatar->cdn_url = null; - $avatar->save(); - } - } catch (Exception $e) { - } - } + $avatar = Avatar::whereProfileId($this->profile->id)->firstOrFail(); + $avatar->change_count = ++$avatar->change_count; + $avatar->last_processed_at = Carbon::now(); + $avatar->save(); + Cache::forget('avatar:'.$avatar->profile_id); + $this->deleteOldAvatar($avatar->media_path, $this->current); - protected function deleteOldAvatar($new, $current) - { - if ( storage_path('app/'.$new) == $current || - Str::endsWith($current, 'avatars/default.png') || - Str::endsWith($current, 'avatars/default.jpg')) - { - return; - } - if (is_file($current)) { - @unlink($current); - } - } + if ((bool) config_cache('pixelfed.cloud_storage') && (bool) config_cache('instance.avatar.local_to_cloud')) { + $this->uploadToCloud($avatar); + } else { + $avatar->cdn_url = null; + $avatar->save(); + } + } catch (Exception $e) { + } + } - protected function uploadToCloud($avatar) - { - $base = 'cache/avatars/' . $avatar->profile_id; - $disk = Storage::disk(config('filesystems.cloud')); - $disk->deleteDirectory($base); - $path = $base . '/' . 'avatar_' . strtolower(Str::random(random_int(3,6))) . $avatar->change_count . '.' . pathinfo($avatar->media_path, PATHINFO_EXTENSION); - $url = $disk->put($path, Storage::get($avatar->media_path)); - $avatar->media_path = $path; - $avatar->cdn_url = $disk->url($path); - $avatar->save(); - Storage::delete($avatar->media_path); - Cache::forget('avatar:' . $avatar->profile_id); - } + protected function deleteOldAvatar($new, $current) + { + if (storage_path('app/'.$new) == $current || + Str::endsWith($current, 'avatars/default.png') || + Str::endsWith($current, 'avatars/default.jpg')) { + return; + } + if (is_file($current)) { + @unlink($current); + } + } + + protected function uploadToCloud($avatar) + { + $base = 'cache/avatars/'.$avatar->profile_id; + $disk = Storage::disk(config('filesystems.cloud')); + $disk->deleteDirectory($base); + $path = $base.'/'.'avatar_'.strtolower(Str::random(random_int(3, 6))).$avatar->change_count.'.'.pathinfo($avatar->media_path, PATHINFO_EXTENSION); + $url = $disk->put($path, Storage::get($avatar->media_path)); + $avatar->media_path = $path; + $avatar->cdn_url = $disk->url($path); + $avatar->save(); + Storage::delete($avatar->media_path); + Cache::forget('avatar:'.$avatar->profile_id); + } } diff --git a/app/Jobs/AvatarPipeline/RemoteAvatarFetch.php b/app/Jobs/AvatarPipeline/RemoteAvatarFetch.php index 4e4a1b2ec..c2a2b2a16 100644 --- a/app/Jobs/AvatarPipeline/RemoteAvatarFetch.php +++ b/app/Jobs/AvatarPipeline/RemoteAvatarFetch.php @@ -4,112 +4,107 @@ namespace App\Jobs\AvatarPipeline; use App\Avatar; use App\Profile; +use App\Services\MediaStorageService; +use App\Util\ActivityPub\Helpers; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use App\Util\ActivityPub\Helpers; -use Illuminate\Support\Str; -use Zttp\Zttp; -use App\Http\Controllers\AvatarController; -use Storage; -use Log; -use Illuminate\Http\File; -use App\Services\MediaStorageService; -use App\Services\ActivityPubFetchService; class RemoteAvatarFetch implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - protected $profile; + protected $profile; - /** - * Delete the job if its models no longer exist. - * - * @var bool - */ - public $deleteWhenMissingModels = true; + /** + * Delete the job if its models no longer exist. + * + * @var bool + */ + public $deleteWhenMissingModels = true; - /** - * The number of times the job may be attempted. - * - * @var int - */ - public $tries = 1; - public $timeout = 300; - public $maxExceptions = 1; + /** + * The number of times the job may be attempted. + * + * @var int + */ + public $tries = 1; - /** - * Create a new job instance. - * - * @return void - */ - public function __construct(Profile $profile) - { - $this->profile = $profile; - } + public $timeout = 300; - /** - * Execute the job. - * - * @return void - */ - public function handle() - { - $profile = $this->profile; + public $maxExceptions = 1; - if(boolval(config_cache('pixelfed.cloud_storage')) == false && boolval(config_cache('federation.avatars.store_local')) == false) { - return 1; - } + /** + * Create a new job instance. + * + * @return void + */ + public function __construct(Profile $profile) + { + $this->profile = $profile; + } - if($profile->domain == null || $profile->private_key) { - return 1; - } + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $profile = $this->profile; - $avatar = Avatar::whereProfileId($profile->id)->first(); + if ((bool) config_cache('pixelfed.cloud_storage') == false && (bool) config_cache('federation.avatars.store_local') == false) { + return 1; + } - if(!$avatar) { - $avatar = new Avatar; - $avatar->profile_id = $profile->id; - $avatar->save(); - } + if ($profile->domain == null || $profile->private_key) { + return 1; + } - if($avatar->media_path == null && $avatar->remote_url == null) { - $avatar->media_path = 'public/avatars/default.jpg'; - $avatar->is_remote = true; - $avatar->save(); - } + $avatar = Avatar::whereProfileId($profile->id)->first(); - $person = Helpers::fetchFromUrl($profile->remote_url); + if (! $avatar) { + $avatar = new Avatar; + $avatar->profile_id = $profile->id; + $avatar->save(); + } - if(!$person || !isset($person['@context'])) { - return 1; - } + if ($avatar->media_path == null && $avatar->remote_url == null) { + $avatar->media_path = 'public/avatars/default.jpg'; + $avatar->is_remote = true; + $avatar->save(); + } - if( !isset($person['icon']) || - !isset($person['icon']['type']) || - !isset($person['icon']['url']) - ) { - return 1; - } + $person = Helpers::fetchFromUrl($profile->remote_url); - if($person['icon']['type'] !== 'Image') { - return 1; - } + if (! $person || ! isset($person['@context'])) { + return 1; + } - if(!Helpers::validateUrl($person['icon']['url'])) { - return 1; - } + if (! isset($person['icon']) || + ! isset($person['icon']['type']) || + ! isset($person['icon']['url']) + ) { + return 1; + } - $icon = $person['icon']; + if ($person['icon']['type'] !== 'Image') { + return 1; + } - $avatar->remote_url = $icon['url']; - $avatar->save(); + if (! Helpers::validateUrl($person['icon']['url'])) { + return 1; + } - MediaStorageService::avatar($avatar, boolval(config_cache('pixelfed.cloud_storage')) == false, true); + $icon = $person['icon']; - return 1; - } + $avatar->remote_url = $icon['url']; + $avatar->save(); + + MediaStorageService::avatar($avatar, (bool) config_cache('pixelfed.cloud_storage') == false, true); + + return 1; + } } diff --git a/app/Jobs/AvatarPipeline/RemoteAvatarFetchFromUrl.php b/app/Jobs/AvatarPipeline/RemoteAvatarFetchFromUrl.php index c8c6820e4..f8a63c5bd 100644 --- a/app/Jobs/AvatarPipeline/RemoteAvatarFetchFromUrl.php +++ b/app/Jobs/AvatarPipeline/RemoteAvatarFetchFromUrl.php @@ -4,93 +4,88 @@ namespace App\Jobs\AvatarPipeline; use App\Avatar; use App\Profile; +use App\Services\AccountService; +use App\Services\MediaStorageService; +use Cache; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use App\Util\ActivityPub\Helpers; -use Illuminate\Support\Str; -use Zttp\Zttp; -use App\Http\Controllers\AvatarController; -use Cache; -use Storage; -use Log; -use Illuminate\Http\File; -use App\Services\AccountService; -use App\Services\MediaStorageService; -use App\Services\ActivityPubFetchService; class RemoteAvatarFetchFromUrl implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - protected $profile; - protected $url; + protected $profile; - /** - * Delete the job if its models no longer exist. - * - * @var bool - */ - public $deleteWhenMissingModels = true; + protected $url; - /** - * The number of times the job may be attempted. - * - * @var int - */ - public $tries = 1; - public $timeout = 300; - public $maxExceptions = 1; + /** + * Delete the job if its models no longer exist. + * + * @var bool + */ + public $deleteWhenMissingModels = true; - /** - * Create a new job instance. - * - * @return void - */ - public function __construct(Profile $profile, $url) - { - $this->profile = $profile; - $this->url = $url; - } + /** + * The number of times the job may be attempted. + * + * @var int + */ + public $tries = 1; - /** - * Execute the job. - * - * @return void - */ - public function handle() - { - $profile = $this->profile; + public $timeout = 300; - Cache::forget('avatar:' . $profile->id); - AccountService::del($profile->id); + public $maxExceptions = 1; - if(boolval(config_cache('pixelfed.cloud_storage')) == false && boolval(config_cache('federation.avatars.store_local')) == false) { - return 1; - } + /** + * Create a new job instance. + * + * @return void + */ + public function __construct(Profile $profile, $url) + { + $this->profile = $profile; + $this->url = $url; + } - if($profile->domain == null || $profile->private_key) { - return 1; - } + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $profile = $this->profile; - $avatar = Avatar::whereProfileId($profile->id)->first(); + Cache::forget('avatar:'.$profile->id); + AccountService::del($profile->id); - if(!$avatar) { - $avatar = new Avatar; - $avatar->profile_id = $profile->id; - $avatar->is_remote = true; - $avatar->remote_url = $this->url; - $avatar->save(); - } else { - $avatar->remote_url = $this->url; - $avatar->is_remote = true; - $avatar->save(); - } + if ((bool) config_cache('pixelfed.cloud_storage') == false && (bool) config_cache('federation.avatars.store_local') == false) { + return 1; + } - MediaStorageService::avatar($avatar, boolval(config_cache('pixelfed.cloud_storage')) == false, true); + if ($profile->domain == null || $profile->private_key) { + return 1; + } - return 1; - } + $avatar = Avatar::whereProfileId($profile->id)->first(); + + if (! $avatar) { + $avatar = new Avatar; + $avatar->profile_id = $profile->id; + $avatar->is_remote = true; + $avatar->remote_url = $this->url; + $avatar->save(); + } else { + $avatar->remote_url = $this->url; + $avatar->is_remote = true; + $avatar->save(); + } + + MediaStorageService::avatar($avatar, (bool) config_cache('pixelfed.cloud_storage') == false, true); + + return 1; + } } diff --git a/app/Jobs/MediaPipeline/MediaDeletePipeline.php b/app/Jobs/MediaPipeline/MediaDeletePipeline.php index 55df84948..df16a42d5 100644 --- a/app/Jobs/MediaPipeline/MediaDeletePipeline.php +++ b/app/Jobs/MediaPipeline/MediaDeletePipeline.php @@ -3,27 +3,30 @@ namespace App\Jobs\MediaPipeline; use App\Media; +use App\Services\Media\MediaHlsService; use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Facades\Redis; -use Illuminate\Support\Facades\Storage; -use App\Services\Media\MediaHlsService; use Illuminate\Queue\Middleware\WithoutOverlapping; -use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing; +use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Storage; -class MediaDeletePipeline implements ShouldQueue, ShouldBeUniqueUntilProcessing +class MediaDeletePipeline implements ShouldBeUniqueUntilProcessing, ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - protected $media; + protected $media; public $timeout = 300; + public $tries = 3; + public $maxExceptions = 1; + public $failOnTimeout = true; + public $deleteWhenMissingModels = true; /** @@ -38,7 +41,7 @@ class MediaDeletePipeline implements ShouldQueue, ShouldBeUniqueUntilProcessing */ public function uniqueId(): string { - return 'media:purge-job:id-' . $this->media->id; + return 'media:purge-job:id-'.$this->media->id; } /** @@ -51,58 +54,58 @@ class MediaDeletePipeline implements ShouldQueue, ShouldBeUniqueUntilProcessing return [(new WithoutOverlapping("media:purge-job:id-{$this->media->id}"))->shared()->dontRelease()]; } - public function __construct(Media $media) - { - $this->media = $media; - } + public function __construct(Media $media) + { + $this->media = $media; + } - public function handle() - { - $media = $this->media; - $path = $media->media_path; - $thumb = $media->thumbnail_path; + public function handle() + { + $media = $this->media; + $path = $media->media_path; + $thumb = $media->thumbnail_path; - if(!$path) { - return 1; - } + if (! $path) { + return 1; + } - $e = explode('/', $path); - array_pop($e); - $i = implode('/', $e); + $e = explode('/', $path); + array_pop($e); + $i = implode('/', $e); - if(config_cache('pixelfed.cloud_storage') == true) { - $disk = Storage::disk(config('filesystems.cloud')); + if ((bool) config_cache('pixelfed.cloud_storage') == true) { + $disk = Storage::disk(config('filesystems.cloud')); - if($path && $disk->exists($path)) { - $disk->delete($path); - } + if ($path && $disk->exists($path)) { + $disk->delete($path); + } - if($thumb && $disk->exists($thumb)) { - $disk->delete($thumb); - } - } + if ($thumb && $disk->exists($thumb)) { + $disk->delete($thumb); + } + } - $disk = Storage::disk(config('filesystems.local')); + $disk = Storage::disk(config('filesystems.local')); - if($path && $disk->exists($path)) { - $disk->delete($path); - } + if ($path && $disk->exists($path)) { + $disk->delete($path); + } - if($thumb && $disk->exists($thumb)) { - $disk->delete($thumb); - } + if ($thumb && $disk->exists($thumb)) { + $disk->delete($thumb); + } - if($media->hls_path != null) { + if ($media->hls_path != null) { $files = MediaHlsService::allFiles($media); - if($files && count($files)) { - foreach($files as $file) { + if ($files && count($files)) { + foreach ($files as $file) { $disk->delete($file); } } - } + } - $media->delete(); + $media->delete(); - return 1; - } + return 1; + } } diff --git a/app/Jobs/MediaPipeline/MediaFixLocalFilesystemCleanupPipeline.php b/app/Jobs/MediaPipeline/MediaFixLocalFilesystemCleanupPipeline.php index bbd3851b9..a972f1f86 100644 --- a/app/Jobs/MediaPipeline/MediaFixLocalFilesystemCleanupPipeline.php +++ b/app/Jobs/MediaPipeline/MediaFixLocalFilesystemCleanupPipeline.php @@ -8,68 +8,69 @@ use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Storage; class MediaFixLocalFilesystemCleanupPipeline implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public $timeout = 1800; - public $tries = 5; - public $maxExceptions = 1; + public $timeout = 1800; - public function handle() - { - if(config_cache('pixelfed.cloud_storage') == false) { - // Only run if cloud storage is enabled - return; - } + public $tries = 5; - $disk = Storage::disk('local'); - $cloud = Storage::disk(config('filesystems.cloud')); + public $maxExceptions = 1; - Media::whereNotNull(['status_id', 'cdn_url', 'replicated_at']) - ->chunk(20, function ($medias) use($disk, $cloud) { - foreach($medias as $media) { - if(!str_starts_with($media->media_path, 'public')) { - continue; - } + public function handle() + { + if ((bool) config_cache('pixelfed.cloud_storage') == false) { + // Only run if cloud storage is enabled + return; + } - if($disk->exists($media->media_path) && $cloud->exists($media->media_path)) { - $disk->delete($media->media_path); - } + $disk = Storage::disk('local'); + $cloud = Storage::disk(config('filesystems.cloud')); - if($media->thumbnail_path) { - if($disk->exists($media->thumbnail_path)) { - $disk->delete($media->thumbnail_path); - } - } + Media::whereNotNull(['status_id', 'cdn_url', 'replicated_at']) + ->chunk(20, function ($medias) use ($disk, $cloud) { + foreach ($medias as $media) { + if (! str_starts_with($media->media_path, 'public')) { + continue; + } - $paths = explode('/', $media->media_path); - if(count($paths) === 7) { - array_pop($paths); - $baseDir = implode('/', $paths); + if ($disk->exists($media->media_path) && $cloud->exists($media->media_path)) { + $disk->delete($media->media_path); + } - if(count($disk->allFiles($baseDir)) === 0) { - $disk->deleteDirectory($baseDir); + if ($media->thumbnail_path) { + if ($disk->exists($media->thumbnail_path)) { + $disk->delete($media->thumbnail_path); + } + } - array_pop($paths); - $baseDir = implode('/', $paths); + $paths = explode('/', $media->media_path); + if (count($paths) === 7) { + array_pop($paths); + $baseDir = implode('/', $paths); - if(count($disk->allFiles($baseDir)) === 0) { - $disk->deleteDirectory($baseDir); + if (count($disk->allFiles($baseDir)) === 0) { + $disk->deleteDirectory($baseDir); - array_pop($paths); - $baseDir = implode('/', $paths); + array_pop($paths); + $baseDir = implode('/', $paths); - if(count($disk->allFiles($baseDir)) === 0) { - $disk->deleteDirectory($baseDir); - } - } - } - } - } - }); - } + if (count($disk->allFiles($baseDir)) === 0) { + $disk->deleteDirectory($baseDir); + + array_pop($paths); + $baseDir = implode('/', $paths); + + if (count($disk->allFiles($baseDir)) === 0) { + $disk->deleteDirectory($baseDir); + } + } + } + } + } + }); + } } diff --git a/app/Observers/AvatarObserver.php b/app/Observers/AvatarObserver.php index b7854e66f..557773ce0 100644 --- a/app/Observers/AvatarObserver.php +++ b/app/Observers/AvatarObserver.php @@ -3,9 +3,9 @@ namespace App\Observers; use App\Avatar; +use App\Services\AccountService; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; -use App\Services\AccountService; class AvatarObserver { @@ -19,7 +19,6 @@ class AvatarObserver /** * Handle the avatar "created" event. * - * @param \App\Avatar $avatar * @return void */ public function created(Avatar $avatar) @@ -30,7 +29,6 @@ class AvatarObserver /** * Handle the avatar "updated" event. * - * @param \App\Avatar $avatar * @return void */ public function updated(Avatar $avatar) @@ -41,7 +39,6 @@ class AvatarObserver /** * Handle the avatar "deleted" event. * - * @param \App\Avatar $avatar * @return void */ public function deleted(Avatar $avatar) @@ -52,23 +49,22 @@ class AvatarObserver /** * Handle the avatar "deleting" event. * - * @param \App\Avatar $avatar * @return void */ public function deleting(Avatar $avatar) { $path = storage_path('app/'.$avatar->media_path); - if( is_file($path) && + if (is_file($path) && $avatar->media_path != 'public/avatars/default.png' && $avatar->media_path != 'public/avatars/default.jpg' ) { @unlink($path); } - if(config_cache('pixelfed.cloud_storage')) { + if ((bool) config_cache('pixelfed.cloud_storage')) { $disk = Storage::disk(config('filesystems.cloud')); $base = Str::startsWith($avatar->media_path, 'cache/avatars/'); - if($base && $disk->exists($avatar->media_path)) { + if ($base && $disk->exists($avatar->media_path)) { $disk->delete($avatar->media_path); } } @@ -78,7 +74,6 @@ class AvatarObserver /** * Handle the avatar "restored" event. * - * @param \App\Avatar $avatar * @return void */ public function restored(Avatar $avatar) @@ -89,7 +84,6 @@ class AvatarObserver /** * Handle the avatar "force deleted" event. * - * @param \App\Avatar $avatar * @return void */ public function forceDeleted(Avatar $avatar) diff --git a/app/Services/ConfigCacheService.php b/app/Services/ConfigCacheService.php index c5bb9bca9..c17f6375f 100644 --- a/app/Services/ConfigCacheService.php +++ b/app/Services/ConfigCacheService.php @@ -102,6 +102,7 @@ class ConfigCacheService 'pixelfed.optimize_image', 'pixelfed.optimize_video', 'pixelfed.max_collection_length', + 'media.delete_local_after_cloud', // 'system.user_mode' ]; diff --git a/app/Services/MediaStorageService.php b/app/Services/MediaStorageService.php index 216e37497..87bb9a586 100644 --- a/app/Services/MediaStorageService.php +++ b/app/Services/MediaStorageService.php @@ -2,44 +2,38 @@ namespace App\Services; +use App\Jobs\AvatarPipeline\AvatarStorageCleanup; +use App\Jobs\MediaPipeline\MediaDeletePipeline; +use App\Media; use App\Util\ActivityPub\Helpers; +use GuzzleHttp\Client; +use GuzzleHttp\Exception\RequestException; use Illuminate\Http\File; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\Cache; -use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; -use App\Media; -use App\Profile; -use App\User; -use GuzzleHttp\Client; -use App\Services\AccountService; -use App\Http\Controllers\AvatarController; -use GuzzleHttp\Exception\RequestException; -use App\Jobs\MediaPipeline\MediaDeletePipeline; -use Illuminate\Support\Arr; -use App\Jobs\AvatarPipeline\AvatarStorageCleanup; - -class MediaStorageService { +class MediaStorageService +{ public static function store(Media $media) { - if(config_cache('pixelfed.cloud_storage') == true) { + if ((bool) config_cache('pixelfed.cloud_storage') == true) { (new self())->cloudStore($media); } - return; } public static function move(Media $media) { - if($media->remote_media) { + if ($media->remote_media) { return; } - if(config_cache('pixelfed.cloud_storage') == true) { + if ((bool) config_cache('pixelfed.cloud_storage') == true) { return (new self())->cloudMove($media); } - return; + } public static function avatar($avatar, $local = false, $skipRecentCheck = false) @@ -56,31 +50,31 @@ class MediaStorageService { return false; } - $h = Arr::mapWithKeys($r->getHeaders(), function($item, $key) { + $h = Arr::mapWithKeys($r->getHeaders(), function ($item, $key) { return [strtolower($key) => last($item)]; }); - if(!isset($h['content-length'], $h['content-type'])) { + if (! isset($h['content-length'], $h['content-type'])) { return false; } $len = (int) $h['content-length']; $mime = $h['content-type']; - if($len < 10 || $len > ((config_cache('pixelfed.max_photo_size') * 1000))) { + if ($len < 10 || $len > ((config_cache('pixelfed.max_photo_size') * 1000))) { return false; } return [ 'length' => $len, - 'mime' => $mime + 'mime' => $mime, ]; } protected function cloudStore($media) { - if($media->remote_media == true) { - if(config('media.storage.remote.cloud')) { + if ($media->remote_media == true) { + if (config('media.storage.remote.cloud')) { (new self())->remoteToCloud($media); } } else { @@ -100,7 +94,7 @@ class MediaStorageService { $storagePath = implode('/', $p); $url = ResilientMediaStorageService::store($storagePath, $path, $name); - if($thumb) { + if ($thumb) { $thumbUrl = ResilientMediaStorageService::store($storagePath, $thumb, $thumbname); $media->thumbnail_url = $thumbUrl; } @@ -108,8 +102,8 @@ class MediaStorageService { $media->optimized_url = $url; $media->replicated_at = now(); $media->save(); - if($media->status_id) { - Cache::forget('status:transformer:media:attachments:' . $media->status_id); + if ($media->status_id) { + Cache::forget('status:transformer:media:attachments:'.$media->status_id); MediaService::del($media->status_id); StatusService::del($media->status_id, false); } @@ -119,20 +113,20 @@ class MediaStorageService { { $url = $media->remote_url; - if(!Helpers::validateUrl($url)) { + if (! Helpers::validateUrl($url)) { return; } $head = $this->head($media->remote_url); - if(!$head) { + if (! $head) { return; } $mimes = [ 'image/jpeg', 'image/png', - 'video/mp4' + 'video/mp4', ]; $mime = $head['mime']; @@ -141,11 +135,11 @@ class MediaStorageService { $media->remote_media = true; $media->save(); - if(!in_array($mime, $mimes)) { + if (! in_array($mime, $mimes)) { return; } - if($head['length'] >= $max_size) { + if ($head['length'] >= $max_size) { return; } @@ -168,10 +162,10 @@ class MediaStorageService { } $base = MediaPathService::get($media->profile); - $path = Str::random(40) . $ext; + $path = Str::random(40).$ext; $tmpBase = storage_path('app/remcache/'); - $tmpPath = $media->profile_id . '-' . $path; - $tmpName = $tmpBase . $tmpPath; + $tmpPath = $media->profile_id.'-'.$path; + $tmpName = $tmpBase.$tmpPath; $data = file_get_contents($url, false, null, 0, $head['length']); file_put_contents($tmpName, $data); $hash = hash_file('sha256', $tmpName); @@ -186,8 +180,8 @@ class MediaStorageService { $media->replicated_at = now(); $media->save(); - if($media->status_id) { - Cache::forget('status:transformer:media:attachments:' . $media->status_id); + if ($media->status_id) { + Cache::forget('status:transformer:media:attachments:'.$media->status_id); } unlink($tmpName); @@ -199,13 +193,13 @@ class MediaStorageService { $url = $avatar->remote_url; $driver = $local ? 'local' : config('filesystems.cloud'); - if(empty($url) || Helpers::validateUrl($url) == false) { + if (empty($url) || Helpers::validateUrl($url) == false) { return; } $head = $this->head($url); - if($head == false) { + if ($head == false) { return; } @@ -218,46 +212,47 @@ class MediaStorageService { $mime = $head['mime']; $max_size = (int) config('pixelfed.max_avatar_size') * 1000; - if(!$skipRecentCheck) { - if($avatar->last_fetched_at && $avatar->last_fetched_at->gt(now()->subMonths(3))) { + if (! $skipRecentCheck) { + if ($avatar->last_fetched_at && $avatar->last_fetched_at->gt(now()->subMonths(3))) { return; } } - Cache::forget('avatar:' . $avatar->profile_id); + Cache::forget('avatar:'.$avatar->profile_id); AccountService::del($avatar->profile_id); // handle pleroma edge case - if(Str::endsWith($mime, '; charset=utf-8')) { + if (Str::endsWith($mime, '; charset=utf-8')) { $mime = str_replace('; charset=utf-8', '', $mime); } - if(!in_array($mime, $mimes)) { + if (! in_array($mime, $mimes)) { return; } - if($head['length'] >= $max_size) { + if ($head['length'] >= $max_size) { return; } - $base = ($local ? 'public/cache/' : 'cache/') . 'avatars/' . $avatar->profile_id; + $base = ($local ? 'public/cache/' : 'cache/').'avatars/'.$avatar->profile_id; $ext = $head['mime'] == 'image/jpeg' ? 'jpg' : 'png'; - $path = 'avatar_' . strtolower(Str::random(random_int(3,6))) . '.' . $ext; + $path = 'avatar_'.strtolower(Str::random(random_int(3, 6))).'.'.$ext; $tmpBase = storage_path('app/remcache/'); - $tmpPath = 'avatar_' . $avatar->profile_id . '-' . $path; - $tmpName = $tmpBase . $tmpPath; + $tmpPath = 'avatar_'.$avatar->profile_id.'-'.$path; + $tmpName = $tmpBase.$tmpPath; $data = @file_get_contents($url, false, null, 0, $head['length']); - if(!$data) { + if (! $data) { return; } file_put_contents($tmpName, $data); - $mimeCheck = Storage::mimeType('remcache/' . $tmpPath); + $mimeCheck = Storage::mimeType('remcache/'.$tmpPath); - if(!$mimeCheck || !in_array($mimeCheck, ['image/png', 'image/jpeg'])) { + if (! $mimeCheck || ! in_array($mimeCheck, ['image/png', 'image/jpeg'])) { $avatar->last_fetched_at = now(); $avatar->save(); unlink($tmpName); + return; } @@ -265,15 +260,15 @@ class MediaStorageService { $file = $disk->putFileAs($base, new File($tmpName), $path, 'public'); $permalink = $disk->url($file); - $avatar->media_path = $base . '/' . $path; + $avatar->media_path = $base.'/'.$path; $avatar->is_remote = true; - $avatar->cdn_url = $local ? config('app.url') . $permalink : $permalink; + $avatar->cdn_url = $local ? config('app.url').$permalink : $permalink; $avatar->size = $head['length']; $avatar->change_count = $avatar->change_count + 1; $avatar->last_fetched_at = now(); $avatar->save(); - Cache::forget('avatar:' . $avatar->profile_id); + Cache::forget('avatar:'.$avatar->profile_id); AccountService::del($avatar->profile_id); AvatarStorageCleanup::dispatch($avatar)->onQueue($queue)->delay(now()->addMinutes(random_int(3, 15))); @@ -282,7 +277,7 @@ class MediaStorageService { public static function delete(Media $media, $confirm = false) { - if(!$confirm) { + if (! $confirm) { return; } MediaDeletePipeline::dispatch($media)->onQueue('mmo'); @@ -290,13 +285,13 @@ class MediaStorageService { protected function cloudMove($media) { - if(!Storage::exists($media->media_path)) { + if (! Storage::exists($media->media_path)) { return 'invalid file'; } $path = storage_path('app/'.$media->media_path); $thumb = false; - if($media->thumbnail_path) { + if ($media->thumbnail_path) { $thumb = storage_path('app/'.$media->thumbnail_path); $pt = explode('/', $media->thumbnail_path); $thumbname = array_pop($pt); @@ -307,7 +302,7 @@ class MediaStorageService { $storagePath = implode('/', $p); $url = ResilientMediaStorageService::store($storagePath, $path, $name); - if($thumb) { + if ($thumb) { $thumbUrl = ResilientMediaStorageService::store($storagePath, $thumb, $thumbname); $media->thumbnail_url = $thumbUrl; } @@ -316,8 +311,8 @@ class MediaStorageService { $media->replicated_at = now(); $media->save(); - if($media->status_id) { - Cache::forget('status:transformer:media:attachments:' . $media->status_id); + if ($media->status_id) { + Cache::forget('status:transformer:media:attachments:'.$media->status_id); MediaService::del($media->status_id); StatusService::del($media->status_id, false); } diff --git a/app/Util/ActivityPub/Helpers.php b/app/Util/ActivityPub/Helpers.php index bcf4f359c..2002a8967 100644 --- a/app/Util/ActivityPub/Helpers.php +++ b/app/Util/ActivityPub/Helpers.php @@ -2,49 +2,34 @@ namespace App\Util\ActivityPub; -use DB, Cache, Purify, Storage, Request, Validator; -use App\{ - Activity, - Follower, - Instance, - Like, - Media, - Notification, - Profile, - Status -}; -use Zttp\Zttp; -use Carbon\Carbon; -use GuzzleHttp\Client; -use Illuminate\Http\File; -use Illuminate\Validation\Rule; -use App\Jobs\AvatarPipeline\CreateAvatar; -use App\Jobs\RemoteFollowPipeline\RemoteFollowImportRecent; -use App\Jobs\ImageOptimizePipeline\{ImageOptimize,ImageThumbnail}; -use App\Jobs\StatusPipeline\NewStatusPipeline; -use App\Jobs\StatusPipeline\StatusReplyPipeline; -use App\Jobs\StatusPipeline\StatusTagsPipeline; -use App\Util\ActivityPub\HttpSignature; -use Illuminate\Support\Str; -use App\Services\ActivityPubFetchService; -use App\Services\ActivityPubDeliveryService; -use App\Services\CustomEmojiService; -use App\Services\InstanceService; -use App\Services\MediaPathService; -use App\Services\MediaStorageService; -use App\Services\NetworkTimelineService; -use App\Jobs\MediaPipeline\MediaStoragePipeline; +use App\Instance; use App\Jobs\AvatarPipeline\RemoteAvatarFetch; use App\Jobs\HomeFeedPipeline\FeedInsertRemotePipeline; -use App\Util\Media\License; +use App\Jobs\MediaPipeline\MediaStoragePipeline; +use App\Jobs\StatusPipeline\StatusReplyPipeline; +use App\Jobs\StatusPipeline\StatusTagsPipeline; +use App\Media; use App\Models\Poll; -use Illuminate\Contracts\Cache\LockTimeoutException; -use App\Services\DomainService; -use App\Services\UserFilterService; +use App\Profile; use App\Services\Account\AccountStatService; +use App\Services\ActivityPubDeliveryService; +use App\Services\ActivityPubFetchService; +use App\Services\DomainService; +use App\Services\InstanceService; +use App\Services\MediaPathService; +use App\Services\NetworkTimelineService; +use App\Services\UserFilterService; +use App\Status; +use App\Util\Media\License; +use Cache; +use Carbon\Carbon; +use Illuminate\Support\Str; +use Illuminate\Validation\Rule; +use Purify; +use Validator; -class Helpers { - +class Helpers +{ public static function validateObject($data) { $verbs = ['Create', 'Announce', 'Like', 'Follow', 'Delete', 'Accept', 'Reject', 'Undo', 'Tombstone']; @@ -53,14 +38,14 @@ class Helpers { 'type' => [ 'required', 'string', - Rule::in($verbs) + Rule::in($verbs), ], 'id' => 'required|string', 'actor' => 'required|string|url', 'object' => 'required', 'object.type' => 'required_if:type,Create', 'object.attributedTo' => 'required_if:type,Create|url', - 'published' => 'required_if:type,Create|date' + 'published' => 'required_if:type,Create|date', ])->passes(); return $valid; @@ -68,8 +53,8 @@ class Helpers { public static function verifyAttachments($data) { - if(!isset($data['object']) || empty($data['object'])) { - $data = ['object'=>$data]; + if (! isset($data['object']) || empty($data['object'])) { + $data = ['object' => $data]; } $activity = $data['object']; @@ -80,7 +65,7 @@ class Helpers { // Peertube // $mediaTypes = in_array('video/mp4', $mimeTypes) ? ['Document', 'Image', 'Video', 'Link'] : ['Document', 'Image']; - if(!isset($activity['attachment']) || empty($activity['attachment'])) { + if (! isset($activity['attachment']) || empty($activity['attachment'])) { return false; } @@ -100,13 +85,13 @@ class Helpers { '*.type' => [ 'required', 'string', - Rule::in($mediaTypes) + Rule::in($mediaTypes), ], '*.url' => 'required|url', - '*.mediaType' => [ + '*.mediaType' => [ 'required', 'string', - Rule::in($mimeTypes) + Rule::in($mimeTypes), ], '*.name' => 'sometimes|nullable|string', '*.blurhash' => 'sometimes|nullable|string|min:6|max:164', @@ -119,7 +104,7 @@ class Helpers { public static function normalizeAudience($data, $localOnly = true) { - if(!isset($data['to'])) { + if (! isset($data['to'])) { return; } @@ -128,32 +113,35 @@ class Helpers { $audience['cc'] = []; $scope = 'private'; - if(is_array($data['to']) && !empty($data['to'])) { + if (is_array($data['to']) && ! empty($data['to'])) { foreach ($data['to'] as $to) { - if($to == 'https://www.w3.org/ns/activitystreams#Public') { + if ($to == 'https://www.w3.org/ns/activitystreams#Public') { $scope = 'public'; + continue; } $url = $localOnly ? self::validateLocalUrl($to) : self::validateUrl($to); - if($url != false) { + if ($url != false) { array_push($audience['to'], $url); } } } - if(is_array($data['cc']) && !empty($data['cc'])) { + if (is_array($data['cc']) && ! empty($data['cc'])) { foreach ($data['cc'] as $cc) { - if($cc == 'https://www.w3.org/ns/activitystreams#Public') { + if ($cc == 'https://www.w3.org/ns/activitystreams#Public') { $scope = 'unlisted'; + continue; } $url = $localOnly ? self::validateLocalUrl($cc) : self::validateUrl($cc); - if($url != false) { + if ($url != false) { array_push($audience['cc'], $url); } } } $audience['scope'] = $scope; + return $audience; } @@ -161,56 +149,57 @@ class Helpers { { $audience = self::normalizeAudience($data); $url = $profile->permalink(); + return in_array($url, $audience['to']) || in_array($url, $audience['cc']); } public static function validateUrl($url) { - if(is_array($url)) { + if (is_array($url)) { $url = $url[0]; } $hash = hash('sha256', $url); $key = "helpers:url:valid:sha256-{$hash}"; - $valid = Cache::remember($key, 900, function() use($url) { + $valid = Cache::remember($key, 900, function () use ($url) { $localhosts = [ - '127.0.0.1', 'localhost', '::1' + '127.0.0.1', 'localhost', '::1', ]; - if(strtolower(mb_substr($url, 0, 8)) !== 'https://') { + if (strtolower(mb_substr($url, 0, 8)) !== 'https://') { return false; } - if(substr_count($url, '://') !== 1) { + if (substr_count($url, '://') !== 1) { return false; } - if(mb_substr($url, 0, 8) !== 'https://') { - $url = 'https://' . substr($url, 8); + if (mb_substr($url, 0, 8) !== 'https://') { + $url = 'https://'.substr($url, 8); } $valid = filter_var($url, FILTER_VALIDATE_URL); - if(!$valid) { + if (! $valid) { return false; } $host = parse_url($valid, PHP_URL_HOST); - if(in_array($host, $localhosts)) { + if (in_array($host, $localhosts)) { return false; } - if(config('security.url.verify_dns')) { - if(DomainService::hasValidDns($host) === false) { + if (config('security.url.verify_dns')) { + if (DomainService::hasValidDns($host) === false) { return false; } } - if(app()->environment() === 'production') { + if (app()->environment() === 'production') { $bannedInstances = InstanceService::getBannedDomains(); - if(in_array($host, $bannedInstances)) { + if (in_array($host, $bannedInstances)) { return false; } } @@ -224,12 +213,14 @@ class Helpers { public static function validateLocalUrl($url) { $url = self::validateUrl($url); - if($url == true) { + if ($url == true) { $domain = config('pixelfed.domain.app'); $host = parse_url($url, PHP_URL_HOST); $url = strtolower($domain) === strtolower($host) ? $url : false; + return $url; } + return false; } @@ -237,15 +228,16 @@ class Helpers { { $version = config('pixelfed.version'); $url = config('app.url'); + return [ - 'Accept' => 'application/activity+json', + 'Accept' => 'application/activity+json', 'User-Agent' => "(Pixelfed/{$version}; +{$url})", ]; } public static function fetchFromUrl($url = false) { - if(self::validateUrl($url) == false) { + if (self::validateUrl($url) == false) { return; } @@ -253,13 +245,13 @@ class Helpers { $key = "helpers:url:fetcher:sha256-{$hash}"; $ttl = now()->addMinutes(15); - return Cache::remember($key, $ttl, function() use($url) { + return Cache::remember($key, $ttl, function () use ($url) { $res = ActivityPubFetchService::get($url); - if(!$res || empty($res)) { + if (! $res || empty($res)) { return false; } $res = json_decode($res, true, 8); - if(json_last_error() == JSON_ERROR_NONE) { + if (json_last_error() == JSON_ERROR_NONE) { return $res; } else { return false; @@ -274,12 +266,12 @@ class Helpers { public static function pluckval($val) { - if(is_string($val)) { + if (is_string($val)) { return $val; } - if(is_array($val)) { - return !empty($val) ? head($val) : null; + if (is_array($val)) { + return ! empty($val) ? head($val) : null; } return null; @@ -288,51 +280,52 @@ class Helpers { public static function statusFirstOrFetch($url, $replyTo = false) { $url = self::validateUrl($url); - if($url == false) { + if ($url == false) { return; } $host = parse_url($url, PHP_URL_HOST); $local = config('pixelfed.domain.app') == $host ? true : false; - if($local) { + if ($local) { $id = (int) last(explode('/', $url)); - return Status::whereNotIn('scope', ['draft','archived'])->findOrFail($id); + + return Status::whereNotIn('scope', ['draft', 'archived'])->findOrFail($id); } - $cached = Status::whereNotIn('scope', ['draft','archived']) + $cached = Status::whereNotIn('scope', ['draft', 'archived']) ->whereUri($url) ->orWhere('object_url', $url) ->first(); - if($cached) { + if ($cached) { return $cached; } $res = self::fetchFromUrl($url); - if(!$res || empty($res) || isset($res['error']) || !isset($res['@context']) || !isset($res['published']) ) { + if (! $res || empty($res) || isset($res['error']) || ! isset($res['@context']) || ! isset($res['published'])) { return; } - if(config('autospam.live_filters.enabled')) { + if (config('autospam.live_filters.enabled')) { $filters = config('autospam.live_filters.filters'); - if(!empty($filters) && isset($res['content']) && !empty($res['content']) && strlen($filters) > 3) { + if (! empty($filters) && isset($res['content']) && ! empty($res['content']) && strlen($filters) > 3) { $filters = array_map('trim', explode(',', $filters)); $content = $res['content']; - foreach($filters as $filter) { + foreach ($filters as $filter) { $filter = trim(strtolower($filter)); - if(!$filter || !strlen($filter)) { + if (! $filter || ! strlen($filter)) { continue; } - if(str_contains(strtolower($content), $filter)) { + if (str_contains(strtolower($content), $filter)) { return; } } } } - if(isset($res['object'])) { + if (isset($res['object'])) { $activity = $res; } else { $activity = ['object' => $res]; @@ -342,37 +335,37 @@ class Helpers { $cw = isset($res['sensitive']) ? (bool) $res['sensitive'] : false; - if(isset($res['to']) == true) { - if(is_array($res['to']) && in_array('https://www.w3.org/ns/activitystreams#Public', $res['to'])) { + if (isset($res['to']) == true) { + if (is_array($res['to']) && in_array('https://www.w3.org/ns/activitystreams#Public', $res['to'])) { $scope = 'public'; } - if(is_string($res['to']) && 'https://www.w3.org/ns/activitystreams#Public' == $res['to']) { + if (is_string($res['to']) && $res['to'] == 'https://www.w3.org/ns/activitystreams#Public') { $scope = 'public'; } } - if(isset($res['cc']) == true) { - if(is_array($res['cc']) && in_array('https://www.w3.org/ns/activitystreams#Public', $res['cc'])) { + if (isset($res['cc']) == true) { + if (is_array($res['cc']) && in_array('https://www.w3.org/ns/activitystreams#Public', $res['cc'])) { $scope = 'unlisted'; } - if(is_string($res['cc']) && 'https://www.w3.org/ns/activitystreams#Public' == $res['cc']) { + if (is_string($res['cc']) && $res['cc'] == 'https://www.w3.org/ns/activitystreams#Public') { $scope = 'unlisted'; } } - if(config('costar.enabled') == true) { + if (config('costar.enabled') == true) { $blockedKeywords = config('costar.keyword.block'); - if($blockedKeywords !== null) { + if ($blockedKeywords !== null) { $keywords = config('costar.keyword.block'); - foreach($keywords as $kw) { - if(Str::contains($res['content'], $kw) == true) { + foreach ($keywords as $kw) { + if (Str::contains($res['content'], $kw) == true) { return; } } } $unlisted = config('costar.domain.unlisted'); - if(in_array(parse_url($url, PHP_URL_HOST), $unlisted) == true) { + if (in_array(parse_url($url, PHP_URL_HOST), $unlisted) == true) { $unlisted = true; $scope = 'unlisted'; } else { @@ -380,7 +373,7 @@ class Helpers { } $cwDomains = config('costar.domain.cw'); - if(in_array(parse_url($url, PHP_URL_HOST), $cwDomains) == true) { + if (in_array(parse_url($url, PHP_URL_HOST), $cwDomains) == true) { $cw = true; } } @@ -389,15 +382,15 @@ class Helpers { $idDomain = parse_url($id, PHP_URL_HOST); $urlDomain = parse_url($url, PHP_URL_HOST); - if($idDomain && $urlDomain && strtolower($idDomain) !== strtolower($urlDomain)) { + if ($idDomain && $urlDomain && strtolower($idDomain) !== strtolower($urlDomain)) { return; } - if(!self::validateUrl($id)) { + if (! self::validateUrl($id)) { return; } - if(!isset($activity['object']['attributedTo'])) { + if (! isset($activity['object']['attributedTo'])) { return; } @@ -405,39 +398,38 @@ class Helpers { $activity['object']['attributedTo'] : (is_array($activity['object']['attributedTo']) ? collect($activity['object']['attributedTo']) - ->filter(function($o) { + ->filter(function ($o) { return $o && isset($o['type']) && $o['type'] == 'Person'; }) ->pluck('id') ->first() : null ); - if($attributedTo) { + if ($attributedTo) { $actorDomain = parse_url($attributedTo, PHP_URL_HOST); - if(!self::validateUrl($attributedTo) || + if (! self::validateUrl($attributedTo) || $idDomain !== $actorDomain || $actorDomain !== $urlDomain - ) - { + ) { return; } } - if($idDomain !== $urlDomain) { + if ($idDomain !== $urlDomain) { return; } $profile = self::profileFirstOrNew($attributedTo); - if(!$profile) { + if (! $profile) { return; } - if(isset($activity['object']['inReplyTo']) && !empty($activity['object']['inReplyTo']) || $replyTo == true) { + if (isset($activity['object']['inReplyTo']) && ! empty($activity['object']['inReplyTo']) || $replyTo == true) { $reply_to = self::statusFirstOrFetch(self::pluckval($activity['object']['inReplyTo']), false); - if($reply_to) { + if ($reply_to) { $blocks = UserFilterService::blocks($reply_to->profile_id); - if(in_array($profile->id, $blocks)) { + if (in_array($profile->id, $blocks)) { return; } } @@ -447,15 +439,15 @@ class Helpers { } $ts = self::pluckval($res['published']); - if($scope == 'public' && in_array($urlDomain, InstanceService::getUnlistedDomains())) { + if ($scope == 'public' && in_array($urlDomain, InstanceService::getUnlistedDomains())) { $scope = 'unlisted'; } - if(in_array($urlDomain, InstanceService::getNsfwDomains())) { + if (in_array($urlDomain, InstanceService::getNsfwDomains())) { $cw = true; } - if($res['type'] === 'Question') { + if ($res['type'] === 'Question') { $status = self::storePoll( $profile, $res, @@ -466,6 +458,7 @@ class Helpers { $scope, $id ); + return $status; } else { $status = self::storeStatus($url, $profile, $res); @@ -482,12 +475,12 @@ class Helpers { $idDomain = parse_url($id, PHP_URL_HOST); $urlDomain = parse_url($url, PHP_URL_HOST); $originalUrlDomain = parse_url($originalUrl, PHP_URL_HOST); - if(!self::validateUrl($id) || !self::validateUrl($url)) { + if (! self::validateUrl($id) || ! self::validateUrl($url)) { return; } - if( strtolower($originalUrlDomain) !== strtolower($idDomain) || - strtolower($originalUrlDomain) !== strtolower($urlDomain) ) { + if (strtolower($originalUrlDomain) !== strtolower($idDomain) || + strtolower($originalUrlDomain) !== strtolower($urlDomain)) { return; } @@ -498,21 +491,21 @@ class Helpers { $cw = self::getSensitive($activity, $url); $pid = is_object($profile) ? $profile->id : (is_array($profile) ? $profile['id'] : null); $isUnlisted = is_object($profile) ? $profile->unlisted : (is_array($profile) ? $profile['unlisted'] : false); - $commentsDisabled = isset($activity['commentsEnabled']) ? !boolval($activity['commentsEnabled']) : false; + $commentsDisabled = isset($activity['commentsEnabled']) ? ! boolval($activity['commentsEnabled']) : false; - if(!$pid) { + if (! $pid) { return; } - if($scope == 'public') { - if($isUnlisted == true) { + if ($scope == 'public') { + if ($isUnlisted == true) { $scope = 'unlisted'; } } $status = Status::updateOrCreate( [ - 'uri' => $url + 'uri' => $url, ], [ 'profile_id' => $pid, 'url' => $url, @@ -527,24 +520,24 @@ class Helpers { 'visibility' => $scope, 'cw_summary' => ($cw == true && isset($activity['summary']) ? Purify::clean(strip_tags($activity['summary'])) : null), - 'comments_disabled' => $commentsDisabled + 'comments_disabled' => $commentsDisabled, ] ); - if($reply_to == null) { + if ($reply_to == null) { self::importNoteAttachment($activity, $status); } else { - if(isset($activity['attachment']) && !empty($activity['attachment'])) { + if (isset($activity['attachment']) && ! empty($activity['attachment'])) { self::importNoteAttachment($activity, $status); } StatusReplyPipeline::dispatch($status); } - if(isset($activity['tag']) && is_array($activity['tag']) && !empty($activity['tag'])) { + if (isset($activity['tag']) && is_array($activity['tag']) && ! empty($activity['tag'])) { StatusTagsPipeline::dispatch($activity, $status); } - if( config('instance.timeline.network.cached') && + if (config('instance.timeline.network.cached') && $status->in_reply_to_id === null && $status->reblog_of_id === null && in_array($status->type, ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album']) && @@ -556,8 +549,8 @@ class Helpers { ->unique() ->values() ->toArray(); - if(!in_array($urlDomain, $filteredDomains)) { - if(!$isUnlisted) { + if (! in_array($urlDomain, $filteredDomains)) { + if (! $isUnlisted) { NetworkTimelineService::add($status->id); } } @@ -565,7 +558,7 @@ class Helpers { AccountStatService::incrementPostCount($pid); - if( $status->in_reply_to_id === null && + if ($status->in_reply_to_id === null && in_array($status->type, ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album']) ) { FeedInsertRemotePipeline::dispatch($status->id, $pid)->onQueue('feed'); @@ -576,14 +569,14 @@ class Helpers { public static function getSensitive($activity, $url) { - if(!$url || !strlen($url)) { + if (! $url || ! strlen($url)) { return true; } $urlDomain = parse_url($url, PHP_URL_HOST); $cw = isset($activity['sensitive']) ? (bool) $activity['sensitive'] : false; - if(in_array($urlDomain, InstanceService::getNsfwDomains())) { + if (in_array($urlDomain, InstanceService::getNsfwDomains())) { $cw = true; } @@ -593,13 +586,13 @@ class Helpers { public static function getReplyTo($activity) { $reply_to = null; - $inReplyTo = isset($activity['inReplyTo']) && !empty($activity['inReplyTo']) ? + $inReplyTo = isset($activity['inReplyTo']) && ! empty($activity['inReplyTo']) ? self::pluckval($activity['inReplyTo']) : false; - if($inReplyTo) { + if ($inReplyTo) { $reply_to = self::statusFirstOrFetch($inReplyTo); - if($reply_to) { + if ($reply_to) { $reply_to = optional($reply_to)->id; } } else { @@ -616,25 +609,25 @@ class Helpers { $urlDomain = parse_url(self::pluckval($url), PHP_URL_HOST); $scope = 'private'; - if(isset($activity['to']) == true) { - if(is_array($activity['to']) && in_array('https://www.w3.org/ns/activitystreams#Public', $activity['to'])) { + if (isset($activity['to']) == true) { + if (is_array($activity['to']) && in_array('https://www.w3.org/ns/activitystreams#Public', $activity['to'])) { $scope = 'public'; } - if(is_string($activity['to']) && 'https://www.w3.org/ns/activitystreams#Public' == $activity['to']) { + if (is_string($activity['to']) && $activity['to'] == 'https://www.w3.org/ns/activitystreams#Public') { $scope = 'public'; } } - if(isset($activity['cc']) == true) { - if(is_array($activity['cc']) && in_array('https://www.w3.org/ns/activitystreams#Public', $activity['cc'])) { + if (isset($activity['cc']) == true) { + if (is_array($activity['cc']) && in_array('https://www.w3.org/ns/activitystreams#Public', $activity['cc'])) { $scope = 'unlisted'; } - if(is_string($activity['cc']) && 'https://www.w3.org/ns/activitystreams#Public' == $activity['cc']) { + if (is_string($activity['cc']) && $activity['cc'] == 'https://www.w3.org/ns/activitystreams#Public') { $scope = 'unlisted'; } } - if($scope == 'public' && in_array($urlDomain, InstanceService::getUnlistedDomains())) { + if ($scope == 'public' && in_array($urlDomain, InstanceService::getUnlistedDomains())) { $scope = 'unlisted'; } @@ -643,15 +636,15 @@ class Helpers { private static function storePoll($profile, $res, $url, $ts, $reply_to, $cw, $scope, $id) { - if(!isset($res['endTime']) || !isset($res['oneOf']) || !is_array($res['oneOf']) || count($res['oneOf']) > 4) { + if (! isset($res['endTime']) || ! isset($res['oneOf']) || ! is_array($res['oneOf']) || count($res['oneOf']) > 4) { return; } - $options = collect($res['oneOf'])->map(function($option) { + $options = collect($res['oneOf'])->map(function ($option) { return $option['name']; })->toArray(); - $cachedTallies = collect($res['oneOf'])->map(function($option) { + $cachedTallies = collect($res['oneOf'])->map(function ($option) { return $option['replies']['totalItems'] ?? 0; })->toArray(); @@ -697,9 +690,10 @@ class Helpers { public static function importNoteAttachment($data, Status $status) { - if(self::verifyAttachments($data) == false) { + if (self::verifyAttachments($data) == false) { // \Log::info('importNoteAttachment::failedVerification.', [$data['id']]); $status->viewType(); + return; } $attachments = isset($data['object']) ? $data['object']['attachment'] : $data['attachment']; @@ -712,11 +706,11 @@ class Helpers { $storagePath = MediaPathService::get($user, 2); $allowed = explode(',', config_cache('pixelfed.media_types')); - foreach($attachments as $key => $media) { + foreach ($attachments as $key => $media) { $type = $media['mediaType']; $url = $media['url']; $valid = self::validateUrl($url); - if(in_array($type, $allowed) == false || $valid == false) { + if (in_array($type, $allowed) == false || $valid == false) { continue; } $blurhash = isset($media['blurhash']) ? $media['blurhash'] : null; @@ -735,50 +729,52 @@ class Helpers { $media->remote_url = $url; $media->caption = $caption; $media->order = $key + 1; - if($width) { + if ($width) { $media->width = $width; } - if($height) { + if ($height) { $media->height = $height; } - if($license) { + if ($license) { $media->license = $license; } $media->mime = $type; $media->version = 3; $media->save(); - if(config_cache('pixelfed.cloud_storage') == true) { + if ((bool) config_cache('pixelfed.cloud_storage') == true) { MediaStoragePipeline::dispatch($media); } } $status->viewType(); - return; + } public static function profileFirstOrNew($url) { $url = self::validateUrl($url); - if($url == false) { + if ($url == false) { return; } $host = parse_url($url, PHP_URL_HOST); $local = config('pixelfed.domain.app') == $host ? true : false; - if($local == true) { + if ($local == true) { $id = last(explode('/', $url)); + return Profile::whereNull('status') ->whereNull('domain') ->whereUsername($id) ->firstOrFail(); } - if($profile = Profile::whereRemoteUrl($url)->first()) { - if($profile->last_fetched_at && $profile->last_fetched_at->lt(now()->subHours(24))) { + if ($profile = Profile::whereRemoteUrl($url)->first()) { + if ($profile->last_fetched_at && $profile->last_fetched_at->lt(now()->subHours(24))) { return self::profileUpdateOrCreate($url); } + return $profile; } @@ -788,42 +784,42 @@ class Helpers { public static function profileUpdateOrCreate($url) { $res = self::fetchProfileFromUrl($url); - if(!$res || isset($res['id']) == false) { + if (! $res || isset($res['id']) == false) { return; } $urlDomain = parse_url($url, PHP_URL_HOST); $domain = parse_url($res['id'], PHP_URL_HOST); - if(strtolower($urlDomain) !== strtolower($domain)) { + if (strtolower($urlDomain) !== strtolower($domain)) { return; } - if(!isset($res['preferredUsername']) && !isset($res['nickname'])) { + if (! isset($res['preferredUsername']) && ! isset($res['nickname'])) { return; } // skip invalid usernames - if(!ctype_alnum($res['preferredUsername'])) { + if (! ctype_alnum($res['preferredUsername'])) { $tmpUsername = str_replace(['_', '.', '-'], '', $res['preferredUsername']); - if(!ctype_alnum($tmpUsername)) { + if (! ctype_alnum($tmpUsername)) { return; } } $username = (string) Purify::clean($res['preferredUsername'] ?? $res['nickname']); - if(empty($username)) { + if (empty($username)) { return; } $remoteUsername = $username; $webfinger = "@{$username}@{$domain}"; - if(!self::validateUrl($res['inbox'])) { + if (! self::validateUrl($res['inbox'])) { return; } - if(!self::validateUrl($res['id'])) { + if (! self::validateUrl($res['id'])) { return; } $instance = Instance::updateOrCreate([ - 'domain' => $domain + 'domain' => $domain, ]); - if($instance->wasRecentlyCreated == true) { + if ($instance->wasRecentlyCreated == true) { \App\Jobs\InstancePipeline\FetchNodeinfoPipeline::dispatch($instance)->onQueue('low'); } @@ -846,13 +842,14 @@ class Helpers { ] ); - if( $profile->last_fetched_at == null || + if ($profile->last_fetched_at == null || $profile->last_fetched_at->lt(now()->subMonths(3)) ) { RemoteAvatarFetch::dispatch($profile); } $profile->last_fetched_at = now(); $profile->save(); + return $profile; } @@ -863,7 +860,7 @@ class Helpers { public static function sendSignedObject($profile, $url, $body) { - if(app()->environment() !== 'production') { + if (app()->environment() !== 'production') { return; } ActivityPubDeliveryService::queue() diff --git a/resources/views/admin/diagnostics/home.blade.php b/resources/views/admin/diagnostics/home.blade.php index 74f6100f0..0d8b21e47 100644 --- a/resources/views/admin/diagnostics/home.blade.php +++ b/resources/views/admin/diagnostics/home.blade.php @@ -740,7 +740,7 @@ PIXELFED PF_ENABLE_CLOUD - {{config_cache('pixelfed.cloud_storage') ? '✅ true' : '❌ false' }} + {{(bool) config_cache('pixelfed.cloud_storage') ? '✅ true' : '❌ false' }} PIXELFED