]> BookStack Code Mirror - bookstack/blob - tests/Auth/RegistrationTest.php
Updated email confirmation flow so confirmation is done via POST
[bookstack] / tests / Auth / RegistrationTest.php
1 <?php
2
3 namespace Tests\Auth;
4
5 use BookStack\Auth\Role;
6 use BookStack\Auth\User;
7 use BookStack\Notifications\ConfirmEmail;
8 use Illuminate\Support\Facades\DB;
9 use Illuminate\Support\Facades\Notification;
10 use Tests\TestCase;
11
12 class RegistrationTest extends TestCase
13 {
14     public function test_confirmed_registration()
15     {
16         // Fake notifications
17         Notification::fake();
18
19         // Set settings and get user instance
20         $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
21         $user = User::factory()->make();
22
23         // Go through registration process
24         $resp = $this->post('/register', $user->only('name', 'email', 'password'));
25         $resp->assertRedirect('/register/confirm');
26         $this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
27
28         // Ensure notification sent
29         /** @var User $dbUser */
30         $dbUser = User::query()->where('email', '=', $user->email)->first();
31         Notification::assertSentTo($dbUser, ConfirmEmail::class);
32
33         // Test access and resend confirmation email
34         $resp = $this->post('/login', ['email' => $user->email, 'password' => $user->password]);
35         $resp->assertRedirect('/register/confirm/awaiting');
36
37         $resp = $this->get('/register/confirm/awaiting');
38         $this->withHtml($resp)->assertElementContains('form[action="' . url('/register/confirm/resend') . '"]', 'Resend');
39
40         $this->get('/books')->assertRedirect('/login');
41         $this->post('/register/confirm/resend', $user->only('email'));
42
43         // Get confirmation and confirm notification matches
44         $emailConfirmation = DB::table('email_confirmations')->where('user_id', '=', $dbUser->id)->first();
45         Notification::assertSentTo($dbUser, ConfirmEmail::class, function ($notification, $channels) use ($emailConfirmation) {
46             return $notification->token === $emailConfirmation->token;
47         });
48
49         // Check confirmation email confirmation accept page.
50         $resp = $this->get('/register/confirm/' . $emailConfirmation->token);
51         $acceptPage = $this->withHtml($resp);
52         $resp->assertOk();
53         $resp->assertSee('Thanks for confirming!');
54         $acceptPage->assertElementExists('form[method="post"][action$="/register/confirm/accept"][component="auto-submit"] button');
55         $acceptPage->assertFieldHasValue('token', $emailConfirmation->token);
56
57         // Check acceptance confirm
58         $this->post('/register/confirm/accept', ['token' => $emailConfirmation->token])->assertRedirect('/login');
59
60         // Check state on login redirect
61         $this->get('/login')->assertSee('Your email has been confirmed! You should now be able to login using this email address.');
62         $this->assertDatabaseMissing('email_confirmations', ['token' => $emailConfirmation->token]);
63         $this->assertDatabaseHas('users', ['name' => $dbUser->name, 'email' => $dbUser->email, 'email_confirmed' => true]);
64     }
65
66     public function test_restricted_registration()
67     {
68         $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true', 'registration-restrict' => 'example.com']);
69         $user = User::factory()->make();
70
71         // Go through registration process
72         $this->post('/register', $user->only('name', 'email', 'password'))
73             ->assertRedirect('/register');
74         $resp = $this->get('/register');
75         $resp->assertSee('That email domain does not have access to this application');
76         $this->assertDatabaseMissing('users', $user->only('email'));
77
78         $user->email = '[email protected]';
79
80         $this->post('/register', $user->only('name', 'email', 'password'))
81             ->assertRedirect('/register/confirm');
82         $this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
83
84         $this->assertNull(auth()->user());
85
86         $this->get('/')->assertRedirect('/login');
87         $resp = $this->followingRedirects()->post('/login', $user->only('email', 'password'));
88         $resp->assertSee('Email Address Not Confirmed');
89         $this->assertNull(auth()->user());
90     }
91
92     public function test_restricted_registration_with_confirmation_disabled()
93     {
94         $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'false', 'registration-restrict' => 'example.com']);
95         $user = User::factory()->make();
96
97         // Go through registration process
98         $this->post('/register', $user->only('name', 'email', 'password'))
99             ->assertRedirect('/register');
100         $this->assertDatabaseMissing('users', $user->only('email'));
101         $this->get('/register')->assertSee('That email domain does not have access to this application');
102
103         $user->email = '[email protected]';
104
105         $this->post('/register', $user->only('name', 'email', 'password'))
106             ->assertRedirect('/register/confirm');
107         $this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
108
109         $this->assertNull(auth()->user());
110
111         $this->get('/')->assertRedirect('/login');
112         $resp = $this->post('/login', $user->only('email', 'password'));
113         $resp->assertRedirect('/register/confirm/awaiting');
114         $this->get('/register/confirm/awaiting')->assertSee('Email Address Not Confirmed');
115         $this->assertNull(auth()->user());
116     }
117
118     public function test_registration_role_unset_by_default()
119     {
120         $this->assertFalse(setting('registration-role'));
121
122         $resp = $this->asAdmin()->get('/settings/registration');
123         $this->withHtml($resp)->assertElementContains('select[name="setting-registration-role"] option[value="0"][selected]', '-- None --');
124     }
125
126     public function test_registration_showing()
127     {
128         // Ensure registration form is showing
129         $this->setSettings(['registration-enabled' => 'true']);
130         $resp = $this->get('/login');
131         $this->withHtml($resp)->assertElementContains('a[href="' . url('/register') . '"]', 'Sign up');
132     }
133
134     public function test_normal_registration()
135     {
136         // Set settings and get user instance
137         /** @var Role $registrationRole */
138         $registrationRole = Role::query()->first();
139         $this->setSettings(['registration-enabled' => 'true', 'registration-role' => $registrationRole->id]);
140         /** @var User $user */
141         $user = User::factory()->make();
142
143         // Test form and ensure user is created
144         $resp = $this->get('/register')
145             ->assertSee('Sign Up');
146         $this->withHtml($resp)->assertElementContains('form[action="' . url('/register') . '"]', 'Create Account');
147
148         $resp = $this->post('/register', $user->only('password', 'name', 'email'));
149         $resp->assertRedirect('/');
150
151         $resp = $this->get('/');
152         $resp->assertOk();
153         $resp->assertSee($user->name);
154
155         $this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email]);
156
157         $user = User::query()->where('email', '=', $user->email)->first();
158         $this->assertEquals(1, $user->roles()->count());
159         $this->assertEquals($registrationRole->id, $user->roles()->first()->id);
160     }
161
162     public function test_empty_registration_redirects_back_with_errors()
163     {
164         // Set settings and get user instance
165         $this->setSettings(['registration-enabled' => 'true']);
166
167         // Test form and ensure user is created
168         $this->get('/register');
169         $this->post('/register', [])->assertRedirect('/register');
170         $this->get('/register')->assertSee('The name field is required');
171     }
172
173     public function test_registration_validation()
174     {
175         $this->setSettings(['registration-enabled' => 'true']);
176
177         $this->get('/register');
178         $resp = $this->followingRedirects()->post('/register', [
179             'name'     => '1',
180             'email'    => '1',
181             'password' => '1',
182         ]);
183         $resp->assertSee('The name must be at least 2 characters.');
184         $resp->assertSee('The email must be a valid email address.');
185         $resp->assertSee('The password must be at least 8 characters.');
186     }
187 }