From 6c48a12423657bf268f5e3ad3e8698f2eab7944f Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 11 Sep 2024 02:47:34 -0600 Subject: [PATCH] Update ApiV1Controller, handle Moved accounts --- app/Http/Controllers/Api/ApiV1Controller.php | 86 +++++++++++++------- app/Services/AccountService.php | 9 +- 2 files changed, 59 insertions(+), 36 deletions(-) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 253e21f7d..10f8264ab 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -67,9 +67,7 @@ use App\Transformer\Api\Mastodon\v1\AccountTransformer; use App\Transformer\Api\Mastodon\v1\MediaTransformer; use App\Transformer\Api\Mastodon\v1\NotificationTransformer; use App\Transformer\Api\Mastodon\v1\StatusTransformer; -use App\Transformer\Api\{ - RelationshipTransformer, -}; +use App\Transformer\Api\RelationshipTransformer; use App\User; use App\UserFilter; use App\UserSetting; @@ -98,8 +96,8 @@ class ApiV1Controller extends Controller public function __construct() { - $this->fractal = new Fractal\Manager(); - $this->fractal->setSerializer(new ArraySerializer()); + $this->fractal = new Fractal\Manager; + $this->fractal->setSerializer(new ArraySerializer); } public function json($res, $code = 200, $headers = []) @@ -490,6 +488,7 @@ class ApiV1Controller extends Controller $account = AccountService::get($id); abort_if(! $account, 404); + abort_if(isset($account['moved'], $account['moved']['id']), 404, 'Account moved'); $pid = $request->user()->profile_id; $this->validate($request, [ 'limit' => 'sometimes|integer|min:1', @@ -591,6 +590,7 @@ class ApiV1Controller extends Controller $account = AccountService::get($id); abort_if(! $account, 404); + abort_if(isset($account['moved'], $account['moved']['id']), 404, 'Account moved'); $pid = $request->user()->profile_id; $this->validate($request, [ 'limit' => 'sometimes|integer|min:1', @@ -818,6 +818,8 @@ class ApiV1Controller extends Controller ->whereNull('status') ->findOrFail($id); + abort_if($target && $target->moved_to_profile_id, 400, 'Cannot follow an account that has moved!'); + if ($target && $target->domain) { $domain = $target->domain; abort_if(in_array($domain, InstanceService::getBannedDomains()), 404); @@ -857,7 +859,7 @@ class ApiV1Controller extends Controller 'following_id' => $target->id, ]); if ($remote == true && config('federation.activitypub.remoteFollow') == true) { - (new FollowerController())->sendFollow($user->profile, $target); + (new FollowerController)->sendFollow($user->profile, $target); } } else { $follower = Follower::firstOrCreate([ @@ -866,7 +868,7 @@ class ApiV1Controller extends Controller ]); if ($remote == true && config('federation.activitypub.remoteFollow') == true) { - (new FollowerController())->sendFollow($user->profile, $target); + (new FollowerController)->sendFollow($user->profile, $target); } FollowPipeline::dispatch($follower)->onQueue('high'); } @@ -925,7 +927,7 @@ class ApiV1Controller extends Controller $followRequest->delete(); RelationshipService::refresh($target->id, $user->profile_id); } - $resource = new Fractal\Resource\Item($target, new RelationshipTransformer()); + $resource = new Fractal\Resource\Item($target, new RelationshipTransformer); $res = $this->fractal->createData($resource)->toArray(); return $this->json($res); @@ -938,7 +940,7 @@ class ApiV1Controller extends Controller UnfollowPipeline::dispatch($user->profile_id, $target->id)->onQueue('high'); if ($remote == true && config('federation.activitypub.remoteFollow') == true) { - (new FollowerController())->sendUndoFollow($user->profile, $target); + (new FollowerController)->sendUndoFollow($user->profile, $target); } RelationshipService::refresh($user->profile_id, $target->id); @@ -1132,6 +1134,8 @@ class ApiV1Controller extends Controller $profile = Profile::findOrFail($id); + abort_if($profile->moved_to_profile_id, 422, 'Cannot block an account that has migrated!'); + if ($profile->user && $profile->user->is_admin == true) { abort(400, 'You cannot block an admin'); } @@ -1198,7 +1202,7 @@ class ApiV1Controller extends Controller UserFilterService::block($pid, $id); RelationshipService::refresh($pid, $id); - $resource = new Fractal\Resource\Item($profile, new RelationshipTransformer()); + $resource = new Fractal\Resource\Item($profile, new RelationshipTransformer); $res = $this->fractal->createData($resource)->toArray(); return $this->json($res); @@ -1225,6 +1229,8 @@ class ApiV1Controller extends Controller $profile = Profile::findOrFail($id); + abort_if($profile->moved_to_profile_id, 422, 'Cannot unblock an account that has migrated!'); + $filter = UserFilter::whereUserId($pid) ->whereFilterableId($profile->id) ->whereFilterableType('App\Profile') @@ -1237,7 +1243,7 @@ class ApiV1Controller extends Controller } RelationshipService::refresh($pid, $id); - $resource = new Fractal\Resource\Item($profile, new RelationshipTransformer()); + $resource = new Fractal\Resource\Item($profile, new RelationshipTransformer); $res = $this->fractal->createData($resource)->toArray(); return $this->json($res); @@ -1372,6 +1378,8 @@ class ApiV1Controller extends Controller abort_unless($status, 404); + abort_if(isset($status['moved'], $status['moved']['id']), 422, 'Cannot like a post from an account that has migrated'); + if ($status && isset($status['account'], $status['account']['acct']) && strpos($status['account']['acct'], '@') != -1) { $domain = parse_url($status['account']['url'], PHP_URL_HOST); abort_if(in_array($domain, InstanceService::getBannedDomains()), 404); @@ -1440,6 +1448,7 @@ class ApiV1Controller extends Controller $status = $napi ? StatusService::get($id, false) : StatusService::getMastodon($id, false); abort_unless($status && isset($status['account']), 404); + abort_if(isset($status['moved'], $status['moved']['id']), 422, 'Cannot unlike a post from an account that has migrated'); if ($status && isset($status['account'], $status['account']['acct']) && strpos($status['account']['acct'], '@') != -1) { $domain = parse_url($status['account']['url'], PHP_URL_HOST); @@ -1540,6 +1549,8 @@ class ApiV1Controller extends Controller $pid = $request->user()->profile_id; $target = AccountService::getMastodon($id); + abort_if(isset($target['moved'], $target['moved']['id']), 422, 'Cannot accept a request from an account that has migrated!'); + if (! $target) { return response()->json(['error' => 'Record not found'], 404); } @@ -1556,7 +1567,7 @@ class ApiV1Controller extends Controller } $follower = $followRequest->follower; - $follow = new Follower(); + $follow = new Follower; $follow->profile_id = $follower->id; $follow->following_id = $pid; $follow->save(); @@ -1603,6 +1614,8 @@ class ApiV1Controller extends Controller return response()->json(['error' => 'Record not found'], 404); } + abort_if(isset($target['moved'], $target['moved']['id']), 422, 'Cannot reject a request from an account that has migrated!'); + $followRequest = FollowRequest::whereFollowingId($pid)->whereFollowerId($id)->first(); if (! $followRequest) { @@ -1661,7 +1674,7 @@ class ApiV1Controller extends Controller null; }); - $stats = Cache::remember('api:v1:instance-data:stats', 43200, function () { + $stats = Cache::remember('api:v1:instance-data:stats:v0', 43200, function () { return [ 'user_count' => (int) User::count(), 'status_count' => (int) StatusService::totalLocalStatuses(), @@ -1857,7 +1870,7 @@ class ApiV1Controller extends Controller abort_if(MediaBlocklistService::exists($hash) == true, 451); - $media = new Media(); + $media = new Media; $media->status_id = null; $media->profile_id = $profile->id; $media->user_id = $user->id; @@ -1891,7 +1904,7 @@ class ApiV1Controller extends Controller $user->save(); Cache::forget($limitKey); - $resource = new Fractal\Resource\Item($media, new MediaTransformer()); + $resource = new Fractal\Resource\Item($media, new MediaTransformer); $res = $this->fractal->createData($resource)->toArray(); $res['preview_url'] = $media->url().'?v='.time(); $res['url'] = $media->url().'?v='.time(); @@ -1946,9 +1959,9 @@ class ApiV1Controller extends Controller ], 429); } - $fractal = new Fractal\Manager(); - $fractal->setSerializer(new ArraySerializer()); - $resource = new Fractal\Resource\Item($media, new MediaTransformer()); + $fractal = new Fractal\Manager; + $fractal->setSerializer(new ArraySerializer); + $resource = new Fractal\Resource\Item($media, new MediaTransformer); return $this->json($fractal->createData($resource)->toArray()); } @@ -1972,7 +1985,7 @@ class ApiV1Controller extends Controller ->whereNull('status_id') ->findOrFail($id); - $resource = new Fractal\Resource\Item($media, new MediaTransformer()); + $resource = new Fractal\Resource\Item($media, new MediaTransformer); $res = $this->fractal->createData($resource)->toArray(); return $this->json($res); @@ -2085,7 +2098,7 @@ class ApiV1Controller extends Controller } } - $media = new Media(); + $media = new Media; $media->status_id = null; $media->profile_id = $profile->id; $media->user_id = $user->id; @@ -2119,7 +2132,7 @@ class ApiV1Controller extends Controller $user->save(); Cache::forget($limitKey); - $resource = new Fractal\Resource\Item($media, new MediaTransformer()); + $resource = new Fractal\Resource\Item($media, new MediaTransformer); $res = $this->fractal->createData($resource)->toArray(); $res['preview_url'] = $media->url().'?v='.time(); $res['url'] = null; @@ -2204,6 +2217,8 @@ class ApiV1Controller extends Controller $account = Profile::findOrFail($id); + abort_if($account->moved_to_profile_id, 422, 'Cannot mute an account that has migrated!'); + if ($account && $account->domain) { $domain = $account->domain; abort_if(in_array($domain, InstanceService::getBannedDomains()), 404); @@ -2237,7 +2252,7 @@ class ApiV1Controller extends Controller RelationshipService::refresh($pid, $id); - $resource = new Fractal\Resource\Item($account, new RelationshipTransformer()); + $resource = new Fractal\Resource\Item($account, new RelationshipTransformer); $res = $this->fractal->createData($resource)->toArray(); return $this->json($res); @@ -2263,6 +2278,8 @@ class ApiV1Controller extends Controller $profile = Profile::findOrFail($id); + abort_if($profile->moved_to_profile_id, 422, 'Cannot unmute an account that has migrated!'); + $filter = UserFilter::whereUserId($pid) ->whereFilterableId($profile->id) ->whereFilterableType('App\Profile') @@ -2276,7 +2293,7 @@ class ApiV1Controller extends Controller RelationshipService::refresh($pid, $id); - $resource = new Fractal\Resource\Item($profile, new RelationshipTransformer()); + $resource = new Fractal\Resource\Item($profile, new RelationshipTransformer); $res = $this->fractal->createData($resource)->toArray(); return $this->json($res); @@ -3209,6 +3226,7 @@ class ApiV1Controller extends Controller $status = Status::findOrFail($id); $account = AccountService::get($status->profile_id, true); abort_if(! $account, 404); + abort_if(isset($account['moved'], $account['moved']['id']), 404, 'Account moved'); if ($account && strpos($account['acct'], '@') != -1) { $domain = parse_url($account['url'], PHP_URL_HOST); abort_if(in_array($domain, InstanceService::getBannedDomains()), 404); @@ -3308,11 +3326,12 @@ class ApiV1Controller extends Controller $pid = $user->profile_id; $status = Status::findOrFail($id); $account = AccountService::get($status->profile_id, true); + abort_if(! $account, 404); + abort_if(isset($account['moved'], $account['moved']['id']), 404, 'Account moved'); if ($account && strpos($account['acct'], '@') != -1) { $domain = parse_url($account['url'], PHP_URL_HOST); abort_if(in_array($domain, InstanceService::getBannedDomains()), 404); } - abort_if(! $account, 404); $author = intval($status->profile_id) === intval($pid) || $user->is_admin; $napi = $request->has(self::PF_API_ENTITY_KEY); @@ -3617,7 +3636,7 @@ class ApiV1Controller extends Controller $status = Status::whereProfileId($request->user()->profile->id) ->findOrFail($id); - $resource = new Fractal\Resource\Item($status, new StatusTransformer()); + $resource = new Fractal\Resource\Item($status, new StatusTransformer); Cache::forget('profile:status_count:'.$status->profile_id); StatusDelete::dispatch($status); @@ -3644,6 +3663,8 @@ class ApiV1Controller extends Controller abort_if($user->has_roles && ! UserRoleService::can('can-share', $user->id), 403, 'Invalid permissions for this action'); AccountService::setLastActive($user->id); $status = Status::whereScope('public')->findOrFail($id); + $account = AccountService::get($status->profile_id); + abort_if(isset($account['moved'], $account['moved']['id']), 422, 'Cannot share a post from an account that has migrated'); if ($status && ($status->uri || $status->url || $status->object_url)) { $url = $status->uri ?? $status->url ?? $status->object_url; $domain = parse_url($url, PHP_URL_HOST); @@ -3696,6 +3717,8 @@ class ApiV1Controller extends Controller abort_if($user->has_roles && ! UserRoleService::can('can-share', $user->id), 403, 'Invalid permissions for this action'); AccountService::setLastActive($user->id); $status = Status::whereScope('public')->findOrFail($id); + $account = AccountService::get($status->profile_id); + abort_if(isset($account['moved'], $account['moved']['id']), 422, 'Cannot unshare a post from an account that has migrated'); if (intval($status->profile_id) !== intval($user->profile_id)) { if ($status->scope == 'private') { @@ -3929,7 +3952,8 @@ class ApiV1Controller extends Controller $status = Status::findOrFail($id); $pid = $request->user()->profile_id; - + $account = AccountService::get($status->profile_id); + abort_if(isset($account['moved'], $account['moved']['id']), 422, 'Cannot bookmark a post from an account that has migrated'); abort_if($user->has_roles && ! UserRoleService::can('can-bookmark', $user->id), 403, 'Invalid permissions for this action'); abort_if($status->in_reply_to_id || $status->reblog_of_id, 404); abort_if(! in_array($status->scope, ['public', 'unlisted', 'private']), 404); @@ -4045,8 +4069,8 @@ class ApiV1Controller extends Controller } $pid = $request->user()->profile_id; $status = StatusService::getMastodon($id, false); - abort_if(! $status, 404); + abort_if(isset($status['account'], $account['account']['moved']['id']), 404, 'Account moved'); if ($status['visibility'] == 'private') { if ($pid != $status['account']['id']) { @@ -4135,11 +4159,11 @@ class ApiV1Controller extends Controller { abort_if(! $request->user(), 403); - $status = Status::findOrFail($id); - $pid = $request->user()->profile_id; - abort_if(! in_array($status->scope, ['public', 'unlisted', 'private']), 404); + $status = StatusService::get($id, false, true); + abort_if(! $status, 404); + abort_if(! in_array($status['visibility'], ['public', 'unlisted', 'private']), 404); - return $this->json(StatusService::getState($status->id, $pid)); + return $this->json(StatusService::getState($status['id'], $request->user()->profile_id)); } /** diff --git a/app/Services/AccountService.php b/app/Services/AccountService.php index c22226030..3ce04d610 100644 --- a/app/Services/AccountService.php +++ b/app/Services/AccountService.php @@ -24,13 +24,13 @@ class AccountService public static function get($id, $softFail = false) { $res = Cache::remember(self::CACHE_KEY.$id, 43200, function () use ($id) { - $fractal = new Fractal\Manager(); - $fractal->setSerializer(new ArraySerializer()); + $fractal = new Fractal\Manager; + $fractal->setSerializer(new ArraySerializer); $profile = Profile::find($id); if (! $profile || $profile->status === 'delete') { return null; } - $resource = new Fractal\Resource\Item($profile, new AccountTransformer()); + $resource = new Fractal\Resource\Item($profile, new AccountTransformer); return $fractal->createData($resource)->toArray(); }); @@ -202,7 +202,7 @@ class AccountService } $count = Status::whereProfileId($id) - ->whereNull(['in_reply_to_id','reblog_of_id']) + ->whereNull(['in_reply_to_id', 'reblog_of_id']) ->whereIn('scope', ['public', 'unlisted', 'private']) ->count(); @@ -291,7 +291,6 @@ class AccountService $user->save(); Cache::put($key, 1, 14400); } - } public static function blocksDomain($pid, $domain = false)