diff --git a/app/Actions/Fortify/CreateNewUser.php b/app/Actions/Fortify/CreateNewUser.php index b65e3816..935a1716 100644 --- a/app/Actions/Fortify/CreateNewUser.php +++ b/app/Actions/Fortify/CreateNewUser.php @@ -35,7 +35,7 @@ class CreateNewUser implements CreatesNewUsers Rule::unique(User::class), ], 'password' => $this->passwordRules(), - 'timezone' => ['nullable', 'string', 'timezone'], + 'timezone' => ['nullable', 'string', 'max:255'], ])->validate(); $user = User::create([ @@ -43,7 +43,7 @@ class CreateNewUser implements CreatesNewUsers 'email' => $input['email'], 'password' => $input['password'], 'locale' => $this->detectLocaleFromRequest(), - 'timezone' => $input['timezone'] ?? null, + 'timezone' => $this->normalizeTimezone($input['timezone'] ?? null), ]); if (! config('mail.email_verification_enabled')) { @@ -53,6 +53,23 @@ class CreateNewUser implements CreatesNewUsers return $user; } + /** + * Normalize a browser-detected timezone, discarding identifiers PHP does + * not recognize so a hidden auto-detected field can never block registration. + */ + protected function normalizeTimezone(?string $timezone): ?string + { + if ($timezone === null || $timezone === '') { + return null; + } + + if (! in_array($timezone, timezone_identifiers_list(\DateTimeZone::ALL_WITH_BC), true)) { + return null; + } + + return $timezone; + } + /** * Detect locale from Accept-Language header. */ diff --git a/resources/js/pages/auth/register.tsx b/resources/js/pages/auth/register.tsx index 10a38854..4fe59325 100644 --- a/resources/js/pages/auth/register.tsx +++ b/resources/js/pages/auth/register.tsx @@ -69,6 +69,8 @@ export default function Register({ value={detectedTimezone} /> + +
diff --git a/tests/Feature/Auth/RegistrationTest.php b/tests/Feature/Auth/RegistrationTest.php index 8d57f7cf..26a21248 100644 --- a/tests/Feature/Auth/RegistrationTest.php +++ b/tests/Feature/Auth/RegistrationTest.php @@ -93,6 +93,42 @@ test('new users store their detected timezone on registration', function () { expect($user->timezone)->toBe('America/New_York'); }); +test('new users can register with a legacy timezone alias', function () { + Queue::fake(); + + $response = $this->post(route('register.store'), [ + 'name' => 'Test User', + 'email' => 'test@example.com', + 'password' => 'password', + 'password_confirmation' => 'password', + 'timezone' => 'Asia/Calcutta', + ]); + + $this->assertAuthenticated(); + $response->assertRedirect(route('onboarding', absolute: false)); + + expect(User::where('email', 'test@example.com')->first()->timezone) + ->toBe('Asia/Calcutta'); +}); + +test('new users can register when the browser sends an unrecognized timezone', function () { + Queue::fake(); + + $response = $this->post(route('register.store'), [ + 'name' => 'Test User', + 'email' => 'test@example.com', + 'password' => 'password', + 'password_confirmation' => 'password', + 'timezone' => 'Not/AZone', + ]); + + $this->assertAuthenticated(); + $response->assertRedirect(route('onboarding', absolute: false)); + + expect(User::where('email', 'test@example.com')->first()->timezone) + ->toBeNull(); +}); + test('new users can register without a timezone', function () { Queue::fake();