feat(discord): finish discord login/logout sequence

Signed-off-by: miguel456 <me@nogueira.codes>
This commit is contained in:
Miguel Nogueira 2022-10-15 02:18:41 +01:00
parent 0d749c4390
commit 0940ad715f
No known key found for this signature in database
GPG Key ID: 3C6A7E29AF26D370
5 changed files with 125 additions and 3 deletions

View File

@ -32,17 +32,20 @@ use App\Http\Requests\FlushSessionsRequest;
use App\Http\Requests\Remove2FASecretRequest;
use App\Http\Requests\Reset2FASecretRequest;
use App\Http\Requests\SearchPlayerRequest;
use App\Http\Requests\SetNewPasswordRequest;
use App\Http\Requests\UpdateUserRequest;
use App\Notifications\ChangedPassword;
use App\Notifications\EmailChanged;
use App\Notifications\PasswordAdminResetNotification;
use App\Notifications\TwoFactorResetNotification;
use App\Services\AccountSuspensionService;
use App\Services\DiscordService;
use App\Traits\DisablesFeatures;
use App\Traits\HandlesAccountDeletion;
use App\Traits\ReceivesAccountTokens;
use App\User;
use Google2FA;
use Illuminate\Http\Client\RequestException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
@ -245,6 +248,44 @@ class UserController extends Controller
}
/**
* Sets a user's password and removes their discord information from storage
*
* @param User $user
* @param SetNewPasswordRequest $request
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function setUnlinkPassword(SetNewPasswordRequest $request, DiscordService $discordService)
{
Auth::user()->password = Hash::make($request->newpass);
Auth::user()->save();
try {
$discordService->revokeAccountTokens(Auth::user());
Log::warning('Revoking social account tokens, user initiated', [
'user' => Auth::user()->email
]);
} catch (RequestException $requestException) {
if ($requestException->getCode() == 401) {
return redirect(route('discordRedirect'));
}
Log::error('Error while trying to revoke Discord credentials', [$requestException->getMessage()]);
return redirect()
->back()
->with('error', __('An unknown error ocurred. Please try again later.'));
}
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
$request->session()->flash('success', 'Discord account unlinked! You may now login with your Discord email and brand new password.');
return redirect(route('login'));
}
/**
* Change the current user's email address

View File

@ -0,0 +1,34 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class SetNewPasswordRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
if (\Auth::user()->hasDiscordConnection()) {
return true;
}
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'newpass' => 'required|string|min:10|confirmed'
];
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Services;
use App\User;
use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
class DiscordService
{
/**
* Sends a token revocation request to Discord to invalidate a specific $user's tokens.
* Please ensure you have the user set a password for their account after this, or request new tokens.
*
* @see https://www.rfc-editor.org/rfc/rfc7009
* @param User $user
* @return bool
* @throws RequestException
*/
public function revokeAccountTokens(User $user): bool
{
$req = Http::asForm()->post(config('services.discord.base_url') . '/oauth2/token/revoke', [
'client_id' => config('services.discord.client_id'),
'client_secret' => config('services.discord.client_secret'),
'token' => $user->discord_token,
])->throw();
$user->discord_token = null;
$user->discord_user_id = null;
$user->discord_refresh_token = null;
$user->discord_pfp = null;
$user->save();
return $req->ok();
}
}

View File

@ -271,7 +271,7 @@
<p>{{ __('Alternatively, you can unlink your Discord account and set a password which you can use to sign in. Please note that any roles and/or privileges you may have been given as a result of this integration may be automatically removed until you link your Discord account again.') }}</p>
<form method="POST" action="" id="setPassword">
<form method="POST" action="{{ route('addPassword') }}" id="setPassword">
@csrf
@method('PATCH')
@ -285,13 +285,15 @@
<div class="col">
<label for="unlinkConfirmNewPassword">{{ __('Confirm new password') }}</label>
<input type="password" name="newpass_confirm" if="unlinkConfirmNewPassword" class="form-control">
<input type="password" name="newpass_confirmation" if="unlinkConfirmNewPassword" class="form-control">
</div>
</div>
<button type="submit" class="btn btn-warning btn-md mt-4 mb-2"><i class="fas fa-check"></i> {{ __('Set password and unlink account') }}</button>
<button type="submit" class="btn btn-warning btn-md mt-4"><i class="fas fa-check"></i> {{ __('Set password and unlink account') }}</button>
<p class="text-sm"><i>{{ __('You will be logged out afterwards.') }}</i></p>
</form>
@else
<h5 class="card-title">{{__('Change Password')}}</h5>
<p class="card-text">{{__('Change your password here. This will log you out from all existing sessions for your security.')}}</p>

View File

@ -219,6 +219,9 @@ Route::group(['prefix' => LaravelLocalization::setLocale(), 'middleware' => ['lo
Route::patch('/settings/account/change-password', [UserController::class, 'changePassword'])
->name('changePassword');
Route::patch('/settings/account/add-password', [UserController::class, 'setUnlinkPassword'])
->name('addPassword');
Route::patch('/settings/account/change-email', [UserController::class, 'changeEmail'])