From d7e74cceee04347fc5f664ec504bfbb64d96326c Mon Sep 17 00:00:00 2001 From: Louise McMahon Date: Tue, 4 Feb 2025 17:29:21 +0000 Subject: [PATCH] Stop discord users from logging in using a password --- .../Auth/ConfirmablePasswordController.php | 41 ------------ .../Auth/PasswordResetLinkController.php | 11 +++- app/Http/Requests/Auth/LoginRequest.php | 9 ++- resources/js/Pages/Auth/ConfirmPassword.vue | 63 ------------------- resources/js/Pages/Auth/ForgotPassword.vue | 3 +- resources/js/Pages/Auth/Login.vue | 1 + resources/js/Pages/Auth/ResetPassword.vue | 3 +- routes/auth.php | 6 -- routes/web.php | 2 +- tests/Feature/Auth/AuthenticationTest.php | 19 ++++++ .../Feature/Auth/PasswordConfirmationTest.php | 47 -------------- tests/Feature/Auth/PasswordResetTest.php | 17 +++++ 12 files changed, 60 insertions(+), 162 deletions(-) delete mode 100644 app/Http/Controllers/Auth/ConfirmablePasswordController.php delete mode 100644 resources/js/Pages/Auth/ConfirmPassword.vue delete mode 100644 tests/Feature/Auth/PasswordConfirmationTest.php diff --git a/app/Http/Controllers/Auth/ConfirmablePasswordController.php b/app/Http/Controllers/Auth/ConfirmablePasswordController.php deleted file mode 100644 index d2b1f14..0000000 --- a/app/Http/Controllers/Auth/ConfirmablePasswordController.php +++ /dev/null @@ -1,41 +0,0 @@ -validate([ - 'email' => $request->user()->email, - 'password' => $request->password, - ])) { - throw ValidationException::withMessages([ - 'password' => __('auth.password'), - ]); - } - - $request->session()->put('auth.password_confirmed_at', time()); - - return redirect()->intended(route('dashboard', absolute: false)); - } -} diff --git a/app/Http/Controllers/Auth/PasswordResetLinkController.php b/app/Http/Controllers/Auth/PasswordResetLinkController.php index b22c544..83b71c2 100644 --- a/app/Http/Controllers/Auth/PasswordResetLinkController.php +++ b/app/Http/Controllers/Auth/PasswordResetLinkController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; +use App\Models\User; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Password; @@ -33,11 +34,19 @@ public function store(Request $request): RedirectResponse 'email' => 'required|email', ]); + $user = User::where('email', $request->get('email'))->first(); + + if ($user->discordUser !== null) { + throw ValidationException::withMessages([ + 'email' => [trans(Password::INVALID_USER)], + ]); + } + // We will send the password reset link to this user. Once we have attempted // to send the link, we will examine the response then see the message we // need to show to the user. Finally, we'll send out a proper response. $status = Password::sendResetLink( - $request->only('email') + $request->only('email'), ); if ($status == Password::RESET_LINK_SENT) { diff --git a/app/Http/Requests/Auth/LoginRequest.php b/app/Http/Requests/Auth/LoginRequest.php index 2574642..c40427f 100644 --- a/app/Http/Requests/Auth/LoginRequest.php +++ b/app/Http/Requests/Auth/LoginRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests\Auth; +use App\Models\User; use Illuminate\Auth\Events\Lockout; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Facades\Auth; @@ -41,7 +42,13 @@ public function authenticate(): void { $this->ensureIsNotRateLimited(); - if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) { + if (! Auth::attemptWhen( + $this->only('email', 'password'), + function (User $user) { + return $user->discordUser === null; + }, + $this->boolean('remember') + )) { RateLimiter::hit($this->throttleKey()); throw ValidationException::withMessages([ diff --git a/resources/js/Pages/Auth/ConfirmPassword.vue b/resources/js/Pages/Auth/ConfirmPassword.vue deleted file mode 100644 index 4d14374..0000000 --- a/resources/js/Pages/Auth/ConfirmPassword.vue +++ /dev/null @@ -1,63 +0,0 @@ - - - diff --git a/resources/js/Pages/Auth/ForgotPassword.vue b/resources/js/Pages/Auth/ForgotPassword.vue index 1962285..de71363 100644 --- a/resources/js/Pages/Auth/ForgotPassword.vue +++ b/resources/js/Pages/Auth/ForgotPassword.vue @@ -4,7 +4,7 @@ import InputError from '@/Components/InputError.vue'; import InputLabel from '@/Components/InputLabel.vue'; import PrimaryButton from '@/Components/PrimaryButton.vue'; import TextInput from '@/Components/TextInput.vue'; -import { Head, useForm } from '@inertiajs/vue3'; +import {Head, useForm} from '@inertiajs/vue3'; defineProps<{ status?: string; @@ -63,6 +63,7 @@ const submit = () => { Email Password Reset Link diff --git a/resources/js/Pages/Auth/Login.vue b/resources/js/Pages/Auth/Login.vue index 4ef22d4..c8842c0 100644 --- a/resources/js/Pages/Auth/Login.vue +++ b/resources/js/Pages/Auth/Login.vue @@ -153,6 +153,7 @@ const showEmailForm = ref(false); class="ms-4 bg-brand" :class="{ 'opacity-25': form.processing }" :disabled="form.processing" + type="submit" > Log in diff --git a/resources/js/Pages/Auth/ResetPassword.vue b/resources/js/Pages/Auth/ResetPassword.vue index b9e609d..4f90b61 100644 --- a/resources/js/Pages/Auth/ResetPassword.vue +++ b/resources/js/Pages/Auth/ResetPassword.vue @@ -4,7 +4,7 @@ import InputError from '@/Components/InputError.vue'; import InputLabel from '@/Components/InputLabel.vue'; import PrimaryButton from '@/Components/PrimaryButton.vue'; import TextInput from '@/Components/TextInput.vue'; -import { Head, useForm } from '@inertiajs/vue3'; +import {Head, useForm} from '@inertiajs/vue3'; const props = defineProps<{ @@ -101,6 +101,7 @@ const submit = () => { Reset Password diff --git a/routes/auth.php b/routes/auth.php index 12f9aa7..d20a445 100644 --- a/routes/auth.php +++ b/routes/auth.php @@ -1,7 +1,6 @@ middleware('throttle:6,1') ->name('verification.send'); - Route::get('confirm-password', [ConfirmablePasswordController::class, 'show']) - ->name('password.confirm'); - - Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']); - Route::put('password', [PasswordController::class, 'update'])->name('password.update'); Route::post('logout', [AuthenticatedSessionController::class, 'destroy']) diff --git a/routes/web.php b/routes/web.php index d77ba09..01bc7bc 100644 --- a/routes/web.php +++ b/routes/web.php @@ -8,7 +8,7 @@ Route::get('/', function () { return redirect()->route('login'); -}); +})->name('home'); Route::get('/dashboard', function () { return Inertia::render('Dashboard'); diff --git a/tests/Feature/Auth/AuthenticationTest.php b/tests/Feature/Auth/AuthenticationTest.php index e4ba7a9..1861652 100644 --- a/tests/Feature/Auth/AuthenticationTest.php +++ b/tests/Feature/Auth/AuthenticationTest.php @@ -3,6 +3,7 @@ namespace Tests\Feature\Auth; use App\Http\Controllers\Auth\AuthenticatedSessionController; +use App\Models\DiscordUser; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; use PHPUnit\Framework\Attributes\CoversClass; @@ -54,4 +55,22 @@ public function test_users_can_logout(): void $this->assertGuest(); $response->assertRedirect('/'); } + + public function test_user_with_discord_login_cannot_login_with_password(): void + { + $user = User::factory([ + 'password' => null, + 'remember_token' => null, + ]) + ->has(DiscordUser::factory()) + ->create(); + + $response = $this->post('/login', [ + 'email' => $user->email, + 'password' => 'password', + ]); + + $this->assertGuest(); + $response->assertRedirect(route('home')); + } } diff --git a/tests/Feature/Auth/PasswordConfirmationTest.php b/tests/Feature/Auth/PasswordConfirmationTest.php deleted file mode 100644 index 924b70f..0000000 --- a/tests/Feature/Auth/PasswordConfirmationTest.php +++ /dev/null @@ -1,47 +0,0 @@ -create(); - - $response = $this->actingAs($user)->get('/confirm-password'); - - $response->assertStatus(200); - } - - public function test_password_can_be_confirmed(): void - { - $user = User::factory()->create(); - - $response = $this->actingAs($user)->post('/confirm-password', [ - 'password' => 'password', - ]); - - $response->assertRedirect(); - $response->assertSessionHasNoErrors(); - } - - public function test_password_is_not_confirmed_with_invalid_password(): void - { - $user = User::factory()->create(); - - $response = $this->actingAs($user)->post('/confirm-password', [ - 'password' => 'wrong-password', - ]); - - $response->assertSessionHasErrors(); - } -} diff --git a/tests/Feature/Auth/PasswordResetTest.php b/tests/Feature/Auth/PasswordResetTest.php index 6c80f80..2ab1cd0 100644 --- a/tests/Feature/Auth/PasswordResetTest.php +++ b/tests/Feature/Auth/PasswordResetTest.php @@ -3,6 +3,7 @@ namespace Tests\Feature\Auth; use App\Http\Controllers\Auth\NewPasswordController; +use App\Models\DiscordUser; use App\Models\User; use Illuminate\Auth\Notifications\ResetPassword; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -33,6 +34,22 @@ public function test_reset_password_link_can_be_requested(): void Notification::assertSentTo($user, ResetPassword::class); } + public function test_reset_password_link_cannot_be_requested_for_user_with_discord_login(): void + { + Notification::fake(); + + $user = User::factory([ + 'password' => null, + 'remember_token' => null, + ]) + ->has(DiscordUser::factory()) + ->create(); + + $this->post('/forgot-password', ['email' => $user->email]); + + Notification::assertNotSentTo($user, ResetPassword::class); + } + public function test_reset_password_screen_can_be_rendered(): void { Notification::fake();