Skip to content

Commit ebfcf9e

Browse files
authored
Merge branch 'main' into feat/add_two_factor_auth
2 parents 429e5ec + 974a427 commit ebfcf9e

File tree

13 files changed

+168
-16
lines changed

13 files changed

+168
-16
lines changed

resources/js/components/delete-user.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { destroy } from '@/actions/App/Http/Controllers/Settings/ProfileController';
1+
import ProfileController from '@/actions/App/Http/Controllers/Settings/ProfileController';
22
import HeadingSmall from '@/components/heading-small';
33
import InputError from '@/components/input-error';
44
import { Button } from '@/components/ui/button';
@@ -32,7 +32,7 @@ export default function DeleteUser() {
3232
</DialogDescription>
3333

3434
<Form
35-
{...destroy.form()}
35+
{...ProfileController.destroy.form()}
3636
options={{
3737
preserveScroll: true,
3838
}}

resources/js/pages/auth/forgot-password.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Components
2-
import { store } from '@/actions/App/Http/Controllers/Auth/PasswordResetLinkController';
2+
import PasswordResetLinkController from '@/actions/App/Http/Controllers/Auth/PasswordResetLinkController';
33
import { login } from '@/routes';
44
import { Form, Head } from '@inertiajs/react';
55
import { LoaderCircle } from 'lucide-react';
@@ -19,7 +19,7 @@ export default function ForgotPassword({ status }: { status?: string }) {
1919
{status && <div className="mb-4 text-center text-sm font-medium text-green-600">{status}</div>}
2020

2121
<div className="space-y-6">
22-
<Form {...store.form()}>
22+
<Form {...PasswordResetLinkController.store.form()}>
2323
{({ processing, errors }) => (
2424
<>
2525
<div className="grid gap-2">

resources/js/pages/auth/login.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { store } from '@/actions/App/Http/Controllers/Auth/AuthenticatedSessionController';
1+
import AuthenticatedSessionController from '@/actions/App/Http/Controllers/Auth/AuthenticatedSessionController';
22
import InputError from '@/components/input-error';
33
import TextLink from '@/components/text-link';
44
import { Button } from '@/components/ui/button';
@@ -21,7 +21,7 @@ export default function Login({ status, canResetPassword }: LoginProps) {
2121
<AuthLayout title="Log in to your account" description="Enter your email and password below to log in">
2222
<Head title="Log in" />
2323

24-
<Form {...store.form()} resetOnSuccess={['password']} className="flex flex-col gap-6">
24+
<Form {...AuthenticatedSessionController.store.form()} resetOnSuccess={['password']} className="flex flex-col gap-6">
2525
{({ processing, errors }) => (
2626
<>
2727
<div className="grid gap-6">

resources/js/pages/auth/register.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { store } from '@/actions/App/Http/Controllers/Auth/RegisteredUserController';
1+
import RegisteredUserController from '@/actions/App/Http/Controllers/Auth/RegisteredUserController';
22
import { login } from '@/routes';
33
import { Form, Head } from '@inertiajs/react';
44
import { LoaderCircle } from 'lucide-react';
@@ -14,7 +14,12 @@ export default function Register() {
1414
return (
1515
<AuthLayout title="Create an account" description="Enter your details below to create your account">
1616
<Head title="Register" />
17-
<Form {...store.form()} resetOnSuccess={['password', 'password_confirmation']} disableWhileProcessing className="flex flex-col gap-6">
17+
<Form
18+
{...RegisteredUserController.store.form()}
19+
resetOnSuccess={['password', 'password_confirmation']}
20+
disableWhileProcessing
21+
className="flex flex-col gap-6"
22+
>
1823
{({ processing, errors }) => (
1924
<>
2025
<div className="grid gap-6">

resources/js/pages/auth/reset-password.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { store } from '@/actions/App/Http/Controllers/Auth/NewPasswordController';
1+
import NewPasswordController from '@/actions/App/Http/Controllers/Auth/NewPasswordController';
22
import { Form, Head } from '@inertiajs/react';
33
import { LoaderCircle } from 'lucide-react';
44

@@ -18,7 +18,11 @@ export default function ResetPassword({ token, email }: ResetPasswordProps) {
1818
<AuthLayout title="Reset password" description="Please enter your new password below">
1919
<Head title="Reset password" />
2020

21-
<Form {...store.form()} transform={(data) => ({ ...data, token, email })} resetOnSuccess={['password', 'password_confirmation']}>
21+
<Form
22+
{...NewPasswordController.store.form()}
23+
transform={(data) => ({ ...data, token, email })}
24+
resetOnSuccess={['password', 'password_confirmation']}
25+
>
2226
{({ processing, errors }) => (
2327
<div className="grid gap-6">
2428
<div className="grid gap-2">

resources/js/pages/auth/verify-email.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Components
2-
import { store } from '@/actions/App/Http/Controllers/Auth/EmailVerificationNotificationController';
2+
import EmailVerificationNotificationController from '@/actions/App/Http/Controllers/Auth/EmailVerificationNotificationController';
33
import { logout } from '@/routes';
44
import { Form, Head } from '@inertiajs/react';
55
import { LoaderCircle } from 'lucide-react';
@@ -19,7 +19,7 @@ export default function VerifyEmail({ status }: { status?: string }) {
1919
</div>
2020
)}
2121

22-
<Form {...store.form()} className="space-y-6 text-center">
22+
<Form {...EmailVerificationNotificationController.store.form()} className="space-y-6 text-center">
2323
{({ processing }) => (
2424
<>
2525
<Button disabled={processing} variant="secondary">

resources/js/pages/settings/password.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { update } from '@/actions/App/Http/Controllers/Settings/PasswordController';
1+
import PasswordController from '@/actions/App/Http/Controllers/Settings/PasswordController';
22
import InputError from '@/components/input-error';
33
import AppLayout from '@/layouts/app-layout';
44
import SettingsLayout from '@/layouts/settings/layout';
@@ -33,7 +33,7 @@ export default function Password() {
3333
<HeadingSmall title="Update password" description="Ensure your account is using a long, random password to stay secure" />
3434

3535
<Form
36-
{...update.form()}
36+
{...PasswordController.update.form()}
3737
options={{
3838
preserveScroll: true,
3939
}}

resources/js/pages/settings/profile.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { update } from '@/actions/App/Http/Controllers/Settings/ProfileController';
1+
import ProfileController from '@/actions/App/Http/Controllers/Settings/ProfileController';
22
import { send } from '@/routes/verification';
33
import { type BreadcrumbItem, type SharedData } from '@/types';
44
import { Transition } from '@headlessui/react';
@@ -33,7 +33,7 @@ export default function Profile({ mustVerifyEmail, status }: { mustVerifyEmail:
3333
<HeadingSmall title="Profile information" description="Update your name and email address" />
3434

3535
<Form
36-
{...update.form()}
36+
{...ProfileController.update.form()}
3737
options={{
3838
preserveScroll: true,
3939
}}

tests/Feature/Auth/AuthenticationTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,29 @@ public function test_users_can_logout()
5151
$this->assertGuest();
5252
$response->assertRedirect('/');
5353
}
54+
55+
public function test_users_are_rate_limited()
56+
{
57+
$user = User::factory()->create();
58+
59+
for ($i = 0; $i < 5; $i++) {
60+
$this->post('/login', [
61+
'email' => $user->email,
62+
'password' => 'wrong-password',
63+
])->assertStatus(302)->assertSessionHasErrors([
64+
'email' => 'These credentials do not match our records.',
65+
]);
66+
}
67+
68+
$response = $this->post('/login', [
69+
'email' => $user->email,
70+
'password' => 'wrong-password',
71+
]);
72+
73+
$response->assertSessionHasErrors('email');
74+
75+
$errors = session('errors');
76+
77+
$this->assertStringContainsString('Too many login attempts', $errors->first('email'));
78+
}
5479
}

tests/Feature/Auth/EmailVerificationTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,53 @@ public function test_email_is_not_verified_with_invalid_hash()
5555

5656
$this->assertFalse($user->fresh()->hasVerifiedEmail());
5757
}
58+
59+
public function test_email_is_not_verified_with_invalid_user_id(): void
60+
{
61+
$user = User::factory()->create([
62+
'email_verified_at' => null,
63+
]);
64+
65+
$verificationUrl = URL::temporarySignedRoute(
66+
'verification.verify',
67+
now()->addMinutes(60),
68+
['id' => 123, 'hash' => sha1($user->email)]
69+
);
70+
71+
$this->actingAs($user)->get($verificationUrl);
72+
73+
$this->assertFalse($user->fresh()->hasVerifiedEmail());
74+
}
75+
76+
public function test_verified_user_is_redirected_to_dashboard_from_verification_prompt(): void
77+
{
78+
$user = User::factory()->create([
79+
'email_verified_at' => now(),
80+
]);
81+
82+
$response = $this->actingAs($user)->get('/verify-email');
83+
84+
$response->assertRedirect(route('dashboard', absolute: false));
85+
}
86+
87+
public function test_already_verified_user_visiting_verification_link_is_redirected_without_firing_event_again(): void
88+
{
89+
$user = User::factory()->create([
90+
'email_verified_at' => now(),
91+
]);
92+
93+
Event::fake();
94+
95+
$verificationUrl = URL::temporarySignedRoute(
96+
'verification.verify',
97+
now()->addMinutes(60),
98+
['id' => $user->id, 'hash' => sha1($user->email)]
99+
);
100+
101+
$this->actingAs($user)->get($verificationUrl)
102+
->assertRedirect(route('dashboard', absolute: false).'?verified=1');
103+
104+
$this->assertTrue($user->fresh()->hasVerifiedEmail());
105+
Event::assertNotDispatched(Verified::class);
106+
}
58107
}

0 commit comments

Comments
 (0)