Update ApiV1Controller, handle Moved accounts

This commit is contained in:
Daniel Supernault 2024-09-11 02:47:34 -06:00
parent 0d8c142bf3
commit 6c48a12423
No known key found for this signature in database
GPG Key ID: 23740873EE6F76A1
2 changed files with 59 additions and 36 deletions

View File

@ -67,9 +67,7 @@ use App\Transformer\Api\Mastodon\v1\AccountTransformer;
use App\Transformer\Api\Mastodon\v1\MediaTransformer; use App\Transformer\Api\Mastodon\v1\MediaTransformer;
use App\Transformer\Api\Mastodon\v1\NotificationTransformer; use App\Transformer\Api\Mastodon\v1\NotificationTransformer;
use App\Transformer\Api\Mastodon\v1\StatusTransformer; use App\Transformer\Api\Mastodon\v1\StatusTransformer;
use App\Transformer\Api\{ use App\Transformer\Api\RelationshipTransformer;
RelationshipTransformer,
};
use App\User; use App\User;
use App\UserFilter; use App\UserFilter;
use App\UserSetting; use App\UserSetting;
@ -98,8 +96,8 @@ class ApiV1Controller extends Controller
public function __construct() public function __construct()
{ {
$this->fractal = new Fractal\Manager(); $this->fractal = new Fractal\Manager;
$this->fractal->setSerializer(new ArraySerializer()); $this->fractal->setSerializer(new ArraySerializer);
} }
public function json($res, $code = 200, $headers = []) public function json($res, $code = 200, $headers = [])
@ -490,6 +488,7 @@ class ApiV1Controller extends Controller
$account = AccountService::get($id); $account = AccountService::get($id);
abort_if(! $account, 404); abort_if(! $account, 404);
abort_if(isset($account['moved'], $account['moved']['id']), 404, 'Account moved');
$pid = $request->user()->profile_id; $pid = $request->user()->profile_id;
$this->validate($request, [ $this->validate($request, [
'limit' => 'sometimes|integer|min:1', 'limit' => 'sometimes|integer|min:1',
@ -591,6 +590,7 @@ class ApiV1Controller extends Controller
$account = AccountService::get($id); $account = AccountService::get($id);
abort_if(! $account, 404); abort_if(! $account, 404);
abort_if(isset($account['moved'], $account['moved']['id']), 404, 'Account moved');
$pid = $request->user()->profile_id; $pid = $request->user()->profile_id;
$this->validate($request, [ $this->validate($request, [
'limit' => 'sometimes|integer|min:1', 'limit' => 'sometimes|integer|min:1',
@ -818,6 +818,8 @@ class ApiV1Controller extends Controller
->whereNull('status') ->whereNull('status')
->findOrFail($id); ->findOrFail($id);
abort_if($target && $target->moved_to_profile_id, 400, 'Cannot follow an account that has moved!');
if ($target && $target->domain) { if ($target && $target->domain) {
$domain = $target->domain; $domain = $target->domain;
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404); abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
@ -857,7 +859,7 @@ class ApiV1Controller extends Controller
'following_id' => $target->id, 'following_id' => $target->id,
]); ]);
if ($remote == true && config('federation.activitypub.remoteFollow') == true) { if ($remote == true && config('federation.activitypub.remoteFollow') == true) {
(new FollowerController())->sendFollow($user->profile, $target); (new FollowerController)->sendFollow($user->profile, $target);
} }
} else { } else {
$follower = Follower::firstOrCreate([ $follower = Follower::firstOrCreate([
@ -866,7 +868,7 @@ class ApiV1Controller extends Controller
]); ]);
if ($remote == true && config('federation.activitypub.remoteFollow') == true) { 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'); FollowPipeline::dispatch($follower)->onQueue('high');
} }
@ -925,7 +927,7 @@ class ApiV1Controller extends Controller
$followRequest->delete(); $followRequest->delete();
RelationshipService::refresh($target->id, $user->profile_id); 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(); $res = $this->fractal->createData($resource)->toArray();
return $this->json($res); return $this->json($res);
@ -938,7 +940,7 @@ class ApiV1Controller extends Controller
UnfollowPipeline::dispatch($user->profile_id, $target->id)->onQueue('high'); UnfollowPipeline::dispatch($user->profile_id, $target->id)->onQueue('high');
if ($remote == true && config('federation.activitypub.remoteFollow') == true) { 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); RelationshipService::refresh($user->profile_id, $target->id);
@ -1132,6 +1134,8 @@ class ApiV1Controller extends Controller
$profile = Profile::findOrFail($id); $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) { if ($profile->user && $profile->user->is_admin == true) {
abort(400, 'You cannot block an admin'); abort(400, 'You cannot block an admin');
} }
@ -1198,7 +1202,7 @@ class ApiV1Controller extends Controller
UserFilterService::block($pid, $id); UserFilterService::block($pid, $id);
RelationshipService::refresh($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(); $res = $this->fractal->createData($resource)->toArray();
return $this->json($res); return $this->json($res);
@ -1225,6 +1229,8 @@ class ApiV1Controller extends Controller
$profile = Profile::findOrFail($id); $profile = Profile::findOrFail($id);
abort_if($profile->moved_to_profile_id, 422, 'Cannot unblock an account that has migrated!');
$filter = UserFilter::whereUserId($pid) $filter = UserFilter::whereUserId($pid)
->whereFilterableId($profile->id) ->whereFilterableId($profile->id)
->whereFilterableType('App\Profile') ->whereFilterableType('App\Profile')
@ -1237,7 +1243,7 @@ class ApiV1Controller extends Controller
} }
RelationshipService::refresh($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(); $res = $this->fractal->createData($resource)->toArray();
return $this->json($res); return $this->json($res);
@ -1372,6 +1378,8 @@ class ApiV1Controller extends Controller
abort_unless($status, 404); 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) { if ($status && isset($status['account'], $status['account']['acct']) && strpos($status['account']['acct'], '@') != -1) {
$domain = parse_url($status['account']['url'], PHP_URL_HOST); $domain = parse_url($status['account']['url'], PHP_URL_HOST);
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404); 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); $status = $napi ? StatusService::get($id, false) : StatusService::getMastodon($id, false);
abort_unless($status && isset($status['account']), 404); 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) { if ($status && isset($status['account'], $status['account']['acct']) && strpos($status['account']['acct'], '@') != -1) {
$domain = parse_url($status['account']['url'], PHP_URL_HOST); $domain = parse_url($status['account']['url'], PHP_URL_HOST);
@ -1540,6 +1549,8 @@ class ApiV1Controller extends Controller
$pid = $request->user()->profile_id; $pid = $request->user()->profile_id;
$target = AccountService::getMastodon($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) { if (! $target) {
return response()->json(['error' => 'Record not found'], 404); return response()->json(['error' => 'Record not found'], 404);
} }
@ -1556,7 +1567,7 @@ class ApiV1Controller extends Controller
} }
$follower = $followRequest->follower; $follower = $followRequest->follower;
$follow = new Follower(); $follow = new Follower;
$follow->profile_id = $follower->id; $follow->profile_id = $follower->id;
$follow->following_id = $pid; $follow->following_id = $pid;
$follow->save(); $follow->save();
@ -1603,6 +1614,8 @@ class ApiV1Controller extends Controller
return response()->json(['error' => 'Record not found'], 404); 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(); $followRequest = FollowRequest::whereFollowingId($pid)->whereFollowerId($id)->first();
if (! $followRequest) { if (! $followRequest) {
@ -1661,7 +1674,7 @@ class ApiV1Controller extends Controller
null; null;
}); });
$stats = Cache::remember('api:v1:instance-data:stats', 43200, function () { $stats = Cache::remember('api:v1:instance-data:stats:v0', 43200, function () {
return [ return [
'user_count' => (int) User::count(), 'user_count' => (int) User::count(),
'status_count' => (int) StatusService::totalLocalStatuses(), 'status_count' => (int) StatusService::totalLocalStatuses(),
@ -1857,7 +1870,7 @@ class ApiV1Controller extends Controller
abort_if(MediaBlocklistService::exists($hash) == true, 451); abort_if(MediaBlocklistService::exists($hash) == true, 451);
$media = new Media(); $media = new Media;
$media->status_id = null; $media->status_id = null;
$media->profile_id = $profile->id; $media->profile_id = $profile->id;
$media->user_id = $user->id; $media->user_id = $user->id;
@ -1891,7 +1904,7 @@ class ApiV1Controller extends Controller
$user->save(); $user->save();
Cache::forget($limitKey); 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 = $this->fractal->createData($resource)->toArray();
$res['preview_url'] = $media->url().'?v='.time(); $res['preview_url'] = $media->url().'?v='.time();
$res['url'] = $media->url().'?v='.time(); $res['url'] = $media->url().'?v='.time();
@ -1946,9 +1959,9 @@ class ApiV1Controller extends Controller
], 429); ], 429);
} }
$fractal = new Fractal\Manager(); $fractal = new Fractal\Manager;
$fractal->setSerializer(new ArraySerializer()); $fractal->setSerializer(new ArraySerializer);
$resource = new Fractal\Resource\Item($media, new MediaTransformer()); $resource = new Fractal\Resource\Item($media, new MediaTransformer);
return $this->json($fractal->createData($resource)->toArray()); return $this->json($fractal->createData($resource)->toArray());
} }
@ -1972,7 +1985,7 @@ class ApiV1Controller extends Controller
->whereNull('status_id') ->whereNull('status_id')
->findOrFail($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(); $res = $this->fractal->createData($resource)->toArray();
return $this->json($res); return $this->json($res);
@ -2085,7 +2098,7 @@ class ApiV1Controller extends Controller
} }
} }
$media = new Media(); $media = new Media;
$media->status_id = null; $media->status_id = null;
$media->profile_id = $profile->id; $media->profile_id = $profile->id;
$media->user_id = $user->id; $media->user_id = $user->id;
@ -2119,7 +2132,7 @@ class ApiV1Controller extends Controller
$user->save(); $user->save();
Cache::forget($limitKey); 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 = $this->fractal->createData($resource)->toArray();
$res['preview_url'] = $media->url().'?v='.time(); $res['preview_url'] = $media->url().'?v='.time();
$res['url'] = null; $res['url'] = null;
@ -2204,6 +2217,8 @@ class ApiV1Controller extends Controller
$account = Profile::findOrFail($id); $account = Profile::findOrFail($id);
abort_if($account->moved_to_profile_id, 422, 'Cannot mute an account that has migrated!');
if ($account && $account->domain) { if ($account && $account->domain) {
$domain = $account->domain; $domain = $account->domain;
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404); abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
@ -2237,7 +2252,7 @@ class ApiV1Controller extends Controller
RelationshipService::refresh($pid, $id); 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(); $res = $this->fractal->createData($resource)->toArray();
return $this->json($res); return $this->json($res);
@ -2263,6 +2278,8 @@ class ApiV1Controller extends Controller
$profile = Profile::findOrFail($id); $profile = Profile::findOrFail($id);
abort_if($profile->moved_to_profile_id, 422, 'Cannot unmute an account that has migrated!');
$filter = UserFilter::whereUserId($pid) $filter = UserFilter::whereUserId($pid)
->whereFilterableId($profile->id) ->whereFilterableId($profile->id)
->whereFilterableType('App\Profile') ->whereFilterableType('App\Profile')
@ -2276,7 +2293,7 @@ class ApiV1Controller extends Controller
RelationshipService::refresh($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(); $res = $this->fractal->createData($resource)->toArray();
return $this->json($res); return $this->json($res);
@ -3209,6 +3226,7 @@ class ApiV1Controller extends Controller
$status = Status::findOrFail($id); $status = Status::findOrFail($id);
$account = AccountService::get($status->profile_id, true); $account = AccountService::get($status->profile_id, true);
abort_if(! $account, 404); abort_if(! $account, 404);
abort_if(isset($account['moved'], $account['moved']['id']), 404, 'Account moved');
if ($account && strpos($account['acct'], '@') != -1) { if ($account && strpos($account['acct'], '@') != -1) {
$domain = parse_url($account['url'], PHP_URL_HOST); $domain = parse_url($account['url'], PHP_URL_HOST);
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404); abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
@ -3308,11 +3326,12 @@ class ApiV1Controller extends Controller
$pid = $user->profile_id; $pid = $user->profile_id;
$status = Status::findOrFail($id); $status = Status::findOrFail($id);
$account = AccountService::get($status->profile_id, true); $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) { if ($account && strpos($account['acct'], '@') != -1) {
$domain = parse_url($account['url'], PHP_URL_HOST); $domain = parse_url($account['url'], PHP_URL_HOST);
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404); abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
} }
abort_if(! $account, 404);
$author = intval($status->profile_id) === intval($pid) || $user->is_admin; $author = intval($status->profile_id) === intval($pid) || $user->is_admin;
$napi = $request->has(self::PF_API_ENTITY_KEY); $napi = $request->has(self::PF_API_ENTITY_KEY);
@ -3617,7 +3636,7 @@ class ApiV1Controller extends Controller
$status = Status::whereProfileId($request->user()->profile->id) $status = Status::whereProfileId($request->user()->profile->id)
->findOrFail($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); Cache::forget('profile:status_count:'.$status->profile_id);
StatusDelete::dispatch($status); 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'); abort_if($user->has_roles && ! UserRoleService::can('can-share', $user->id), 403, 'Invalid permissions for this action');
AccountService::setLastActive($user->id); AccountService::setLastActive($user->id);
$status = Status::whereScope('public')->findOrFail($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)) { if ($status && ($status->uri || $status->url || $status->object_url)) {
$url = $status->uri ?? $status->url ?? $status->object_url; $url = $status->uri ?? $status->url ?? $status->object_url;
$domain = parse_url($url, PHP_URL_HOST); $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'); abort_if($user->has_roles && ! UserRoleService::can('can-share', $user->id), 403, 'Invalid permissions for this action');
AccountService::setLastActive($user->id); AccountService::setLastActive($user->id);
$status = Status::whereScope('public')->findOrFail($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 (intval($status->profile_id) !== intval($user->profile_id)) {
if ($status->scope == 'private') { if ($status->scope == 'private') {
@ -3929,7 +3952,8 @@ class ApiV1Controller extends Controller
$status = Status::findOrFail($id); $status = Status::findOrFail($id);
$pid = $request->user()->profile_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($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($status->in_reply_to_id || $status->reblog_of_id, 404);
abort_if(! in_array($status->scope, ['public', 'unlisted', 'private']), 404); abort_if(! in_array($status->scope, ['public', 'unlisted', 'private']), 404);
@ -4045,8 +4069,8 @@ class ApiV1Controller extends Controller
} }
$pid = $request->user()->profile_id; $pid = $request->user()->profile_id;
$status = StatusService::getMastodon($id, false); $status = StatusService::getMastodon($id, false);
abort_if(! $status, 404); abort_if(! $status, 404);
abort_if(isset($status['account'], $account['account']['moved']['id']), 404, 'Account moved');
if ($status['visibility'] == 'private') { if ($status['visibility'] == 'private') {
if ($pid != $status['account']['id']) { if ($pid != $status['account']['id']) {
@ -4135,11 +4159,11 @@ class ApiV1Controller extends Controller
{ {
abort_if(! $request->user(), 403); abort_if(! $request->user(), 403);
$status = Status::findOrFail($id); $status = StatusService::get($id, false, true);
$pid = $request->user()->profile_id; abort_if(! $status, 404);
abort_if(! in_array($status->scope, ['public', 'unlisted', 'private']), 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));
} }
/** /**

View File

@ -24,13 +24,13 @@ class AccountService
public static function get($id, $softFail = false) public static function get($id, $softFail = false)
{ {
$res = Cache::remember(self::CACHE_KEY.$id, 43200, function () use ($id) { $res = Cache::remember(self::CACHE_KEY.$id, 43200, function () use ($id) {
$fractal = new Fractal\Manager(); $fractal = new Fractal\Manager;
$fractal->setSerializer(new ArraySerializer()); $fractal->setSerializer(new ArraySerializer);
$profile = Profile::find($id); $profile = Profile::find($id);
if (! $profile || $profile->status === 'delete') { if (! $profile || $profile->status === 'delete') {
return null; return null;
} }
$resource = new Fractal\Resource\Item($profile, new AccountTransformer()); $resource = new Fractal\Resource\Item($profile, new AccountTransformer);
return $fractal->createData($resource)->toArray(); return $fractal->createData($resource)->toArray();
}); });
@ -291,7 +291,6 @@ class AccountService
$user->save(); $user->save();
Cache::put($key, 1, 14400); Cache::put($key, 1, 14400);
} }
} }
public static function blocksDomain($pid, $domain = false) public static function blocksDomain($pid, $domain = false)