diff --git a/framework/core/src/Core/CoreServiceProvider.php b/framework/core/src/Core/CoreServiceProvider.php index d6c3f7de2..551cdcfda 100644 --- a/framework/core/src/Core/CoreServiceProvider.php +++ b/framework/core/src/Core/CoreServiceProvider.php @@ -104,6 +104,7 @@ class CoreServiceProvider extends AbstractServiceProvider $events = $this->app->make('events'); + $events->subscribe('Flarum\Core\Listener\SelfDemotionGuard'); $events->subscribe('Flarum\Core\Listener\DiscussionMetadataUpdater'); $events->subscribe('Flarum\Core\Listener\UserMetadataUpdater'); $events->subscribe('Flarum\Core\Listener\ExtensionValidator'); diff --git a/framework/core/src/Core/Listener/SelfDemotionGuard.php b/framework/core/src/Core/Listener/SelfDemotionGuard.php new file mode 100644 index 000000000..500de5c44 --- /dev/null +++ b/framework/core/src/Core/Listener/SelfDemotionGuard.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Core\Listener; + +use Flarum\Core\Exception\PermissionDeniedException; +use Flarum\Core\Group; +use Flarum\Event\UserWillBeSaved; +use Illuminate\Contracts\Events\Dispatcher; + +class SelfDemotionGuard +{ + /** + * @param Dispatcher $events + */ + public function subscribe(Dispatcher $events) + { + $events->listen(UserWillBeSaved::class, [$this, 'whenUserWillBeSaved']); + } + + /** + * Prevent an admin from removing their admin permission via the API. + * @param UserWillBeSaved $event + * @throws PermissionDeniedException + */ + public function whenUserWillBeSaved(UserWillBeSaved $event) + { + $actor = $event->actor; + $user = $event->user; + $groups = array_get($event->data, 'relationships.groups.data'); + + if (isset($groups) && $actor->id === $user->id && $actor->isAdmin()) { + $adminGroupRemoved = empty(array_filter($groups, function ($group) { + return $group['id'] == Group::ADMINISTRATOR_ID; + })); + + if ($adminGroupRemoved) { + throw new PermissionDeniedException; + } + } + } +}