From 25ac988328293e1762bb9acbc618f3b81e98bb16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Mon, 8 Mar 2021 22:00:44 +0100 Subject: [PATCH] feat: show a shinny error on duplicated account when an user attempt to link a discord account which has already be linked to another SeAT user, it's throwing an exception due to the table integrity constraints. this is introducing a more user-friendly experience by showing them explicitly they're attempting to link their account to another one. action is logged with further details which can be useful for staff. --- .../Controllers/RegistrationController.php | 65 ++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/src/Http/Controllers/RegistrationController.php b/src/Http/Controllers/RegistrationController.php index 1257f1e..e1b19d8 100644 --- a/src/Http/Controllers/RegistrationController.php +++ b/src/Http/Controllers/RegistrationController.php @@ -96,20 +96,60 @@ public function handleProviderCallback() // retrieve authenticated user $socialite_user = Socialite::driver('discord')->setConfig($config)->user(); - // update or create the connector user - $original_user = User::where('connector_type', 'discord')->where('user_id', auth()->user()->id)->first(); + // attempt to retrieve a duplicated account + $duplicated_user = $this->getDuplicatedAccount($socialite_user); + + if (! is_null($duplicated_user)) + return $this->handleDuplicateResponse($duplicated_user, $socialite_user); + + // attempt to retrieve authenticated account + $original_user = User::where('connector_type', 'discord') + ->where('user_id', auth()->user()->id) + ->first(); // if connector ID is a new one - revoke existing access on the old ID if (! is_null($original_user) && $original_user->connector_id != $socialite_user->id) $this->revokeOldIdentity($client, $original_user); + // attach account and redirect user to discord guild + return $this->handleSuccessResponse($settings, $socialite_user); + } + + /** + * Determine if there is another account linked to the registering one. + * + * @param \Laravel\Socialite\Two\User $socialite_user + * @return \Warlof\Seat\Connector\Models\User|null + */ + private function getDuplicatedAccount(\Laravel\Socialite\Two\User $socialite_user): ?User + { + return User::where('connector_type', 'discord') + ->where('connector_id', $socialite_user->id) + ->where('user_id', '<>', auth()->user()->id) + ->first(); + } + + /** + * @param $settings + * @param \Laravel\Socialite\Two\User $socialite_user + * @return \Illuminate\Http\RedirectResponse + * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \Warlof\Seat\Connector\Exceptions\DriverException + */ + private function handleSuccessResponse($settings, \Laravel\Socialite\Two\User $socialite_user) + { + // retrieve driver instance + $client = DiscordClient::getInstance(); + + $discord_username = $socialite_user->name . '#' . $socialite_user->user['discriminator']; + // spawn or update existing identity using returned information $driver_user = User::updateOrCreate([ 'connector_type' => 'discord', 'user_id' => auth()->user()->id, ], [ 'connector_id' => $socialite_user->id, - 'unique_id' => ($settings->use_email_scope == 1) ? $socialite_user->email : $socialite_user->name . '#' . $socialite_user->user['discriminator'], + 'unique_id' => ($settings->use_email_scope == 1) ? $socialite_user->email : $discord_username, 'connector_name' => $socialite_user->nickname, ]); @@ -130,6 +170,25 @@ public function handleProviderCallback() return redirect()->to(sprintf('https://discord.com/channels/%s', $client->getGuildId())); } + /** + * Handle duplicate account response. + * + * @param \Warlof\Seat\Connector\Models\User $duplicated_user + * @param \Laravel\Socialite\Two\User $socialite_user + * @return \Illuminate\Http\RedirectResponse|void + */ + private function handleDuplicateResponse(User $duplicated_user, \Laravel\Socialite\Two\User $socialite_user) + { + event(new EventLogger('discord', 'error', 'registration', + sprintf('User %s (%d) is trying to link account %s - but it\'s already linked to %s', + auth()->user()->name, auth()->user()->id, $socialite_user->nickname, $duplicated_user->user->name + ) + )); + + return redirect()->back() + ->with('error', 'Your account is already linked. This attempt has been recorded. Please contact your administrator.'); + } + /** * @param \Warlof\Seat\Connector\Drivers\IClient $client * @param \Warlof\Seat\Connector\Models\User $old_identity