|
9 | 9 | use Illuminate\Foundation\Testing\RefreshDatabase; |
10 | 10 | use Illuminate\Support\Facades\Config; |
11 | 11 | use Illuminate\Support\Facades\Crypt; |
| 12 | +use Illuminate\Support\Facades\DB; |
12 | 13 | use Illuminate\Support\Facades\Hash; |
13 | 14 | use Illuminate\Support\Once; |
14 | 15 | use Visus\Cuid2\Cuid2; |
@@ -77,6 +78,55 @@ function createInvitationLinkFixture(array $invitationAttributes = []): array |
77 | 78 | $this->assertGuest(); |
78 | 79 | }); |
79 | 80 |
|
| 81 | +it('accepts a magic link when opened from a different public origin', function () { |
| 82 | + [$team, $user, $password, $token] = createInvitationLinkFixture(); |
| 83 | + |
| 84 | + $this->get('https://coolify.example.com/auth/link?token='.urlencode($token)) |
| 85 | + ->assertRedirect(route('dashboard')); |
| 86 | + |
| 87 | + $this->assertAuthenticatedAs($user); |
| 88 | + $this->assertDatabaseMissing('team_invitations', ['email' => $user->email]); |
| 89 | + expect($user->teams()->where('team_id', $team->id)->exists())->toBeTrue(); |
| 90 | + |
| 91 | + $user->refresh(); |
| 92 | + expect(Hash::check($password, $user->password))->toBeFalse(); |
| 93 | +}); |
| 94 | + |
| 95 | +it('keeps the invited user authenticated after rotating the temporary password with database sessions', function () { |
| 96 | + $this->withMiddleware([CheckForcePasswordReset::class, DecideWhatToDoWithUser::class]); |
| 97 | + Config::set('session.driver', 'database'); |
| 98 | + |
| 99 | + [$team, $user, $password, $token] = createInvitationLinkFixture(); |
| 100 | + |
| 101 | + $this->get(route('auth.link', ['token' => $token])) |
| 102 | + ->assertRedirect(route('dashboard')); |
| 103 | + |
| 104 | + expect(DB::table('sessions')->where('user_id', $user->id)->exists())->toBeTrue(); |
| 105 | + |
| 106 | + $this->get(route('dashboard')) |
| 107 | + ->assertRedirect(route('auth.force-password-reset')); |
| 108 | + |
| 109 | + $this->assertAuthenticatedAs($user); |
| 110 | + expect($user->teams()->where('team_id', $team->id)->exists())->toBeTrue(); |
| 111 | + |
| 112 | + $user->refresh(); |
| 113 | + expect(Hash::check($password, $user->password))->toBeFalse(); |
| 114 | +}); |
| 115 | + |
| 116 | +it('rejects a magic link when the stored invitation token differs', function () { |
| 117 | + [, $user, , $token, $invitation] = createInvitationLinkFixture(); |
| 118 | + $differentToken = Crypt::encryptString("{$user->email}@@@{$invitation->uuid}@@@different-password"); |
| 119 | + |
| 120 | + $invitation->forceFill([ |
| 121 | + 'link' => route('auth.link', ['token' => $differentToken]), |
| 122 | + ])->save(); |
| 123 | + |
| 124 | + $this->get(route('auth.link', ['token' => $token])) |
| 125 | + ->assertRedirect(route('login')); |
| 126 | + |
| 127 | + $this->assertGuest(); |
| 128 | +}); |
| 129 | + |
80 | 130 | it('rejects a magic link when the invitation was revoked', function () { |
81 | 131 | [, $user, , $token, $invitation] = createInvitationLinkFixture(); |
82 | 132 | $invitation->delete(); |
|
0 commit comments