]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/Auth/RegisterController.php
Adds autofocus on the email field of the standard login page.
[bookstack] / app / Http / Controllers / Auth / RegisterController.php
1 <?php
2
3 namespace BookStack\Http\Controllers\Auth;
4
5 use BookStack\Auth\Access\EmailConfirmationService;
6 use BookStack\Auth\Access\SocialAuthService;
7 use BookStack\Auth\SocialAccount;
8 use BookStack\Auth\User;
9 use BookStack\Auth\UserRepo;
10 use BookStack\Exceptions\SocialDriverNotConfigured;
11 use BookStack\Exceptions\SocialSignInAccountNotUsed;
12 use BookStack\Exceptions\SocialSignInException;
13 use BookStack\Exceptions\UserRegistrationException;
14 use BookStack\Http\Controllers\Controller;
15 use Exception;
16 use Illuminate\Foundation\Auth\RegistersUsers;
17 use Illuminate\Http\RedirectResponse;
18 use Illuminate\Http\Request;
19 use Illuminate\Http\Response;
20 use Illuminate\Routing\Redirector;
21 use Illuminate\View\View;
22 use Laravel\Socialite\Contracts\User as SocialUser;
23 use Validator;
24
25 class RegisterController extends Controller
26 {
27     /*
28     |--------------------------------------------------------------------------
29     | Register Controller
30     |--------------------------------------------------------------------------
31     |
32     | This controller handles the registration of new users as well as their
33     | validation and creation. By default this controller uses a trait to
34     | provide this functionality without requiring any additional code.
35     |
36     */
37
38     use RegistersUsers;
39
40     protected $socialAuthService;
41     protected $emailConfirmationService;
42     protected $userRepo;
43
44     /**
45      * Where to redirect users after login / registration.
46      *
47      * @var string
48      */
49     protected $redirectTo = '/';
50     protected $redirectPath = '/';
51
52     /**
53      * Create a new controller instance.
54      *
55      * @param SocialAuthService $socialAuthService
56      * @param \BookStack\Auth\EmailConfirmationService $emailConfirmationService
57      * @param UserRepo $userRepo
58      */
59     public function __construct(SocialAuthService $socialAuthService, EmailConfirmationService $emailConfirmationService, UserRepo $userRepo)
60     {
61         $this->middleware('guest')->only(['getRegister', 'postRegister', 'socialRegister']);
62         $this->socialAuthService = $socialAuthService;
63         $this->emailConfirmationService = $emailConfirmationService;
64         $this->userRepo = $userRepo;
65         $this->redirectTo = url('/');
66         $this->redirectPath = url('/');
67         parent::__construct();
68     }
69
70     /**
71      * Get a validator for an incoming registration request.
72      *
73      * @param  array $data
74      * @return \Illuminate\Contracts\Validation\Validator
75      */
76     protected function validator(array $data)
77     {
78         return Validator::make($data, [
79             'name' => 'required|min:2|max:255',
80             'email' => 'required|email|max:255|unique:users',
81             'password' => 'required|min:6',
82         ]);
83     }
84
85     /**
86      * Check whether or not registrations are allowed in the app settings.
87      * @throws UserRegistrationException
88      */
89     protected function checkRegistrationAllowed()
90     {
91         if (!setting('registration-enabled')) {
92             throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login');
93         }
94     }
95
96     /**
97      * Show the application registration form.
98      * @return Response
99      * @throws UserRegistrationException
100      */
101     public function getRegister()
102     {
103         $this->checkRegistrationAllowed();
104         $socialDrivers = $this->socialAuthService->getActiveDrivers();
105         return view('auth.register', ['socialDrivers' => $socialDrivers]);
106     }
107
108     /**
109      * Handle a registration request for the application.
110      * @param Request|Request $request
111      * @return RedirectResponse|Redirector
112      * @throws UserRegistrationException
113      */
114     public function postRegister(Request $request)
115     {
116         $this->checkRegistrationAllowed();
117         $this->validator($request->all())->validate();
118
119         $userData = $request->all();
120         return $this->registerUser($userData);
121     }
122
123     /**
124      * Create a new user instance after a valid registration.
125      * @param  array  $data
126      * @return User
127      */
128     protected function create(array $data)
129     {
130         return User::create([
131             'name' => $data['name'],
132             'email' => $data['email'],
133             'password' => bcrypt($data['password']),
134         ]);
135     }
136
137     /**
138      * The registrations flow for all users.
139      * @param array $userData
140      * @param bool|false|SocialAccount $socialAccount
141      * @param bool $emailVerified
142      * @return RedirectResponse|Redirector
143      * @throws UserRegistrationException
144      */
145     protected function registerUser(array $userData, $socialAccount = false, $emailVerified = false)
146     {
147         $registrationRestrict = setting('registration-restrict');
148
149         if ($registrationRestrict) {
150             $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
151             $userEmailDomain = $domain = mb_substr(mb_strrchr($userData['email'], "@"), 1);
152             if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
153                 throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register');
154             }
155         }
156
157         $newUser = $this->userRepo->registerNew($userData, $emailVerified);
158         if ($socialAccount) {
159             $newUser->socialAccounts()->save($socialAccount);
160         }
161
162         if ((setting('registration-confirmation') || $registrationRestrict) && !$emailVerified) {
163             $newUser->save();
164
165             try {
166                 $this->emailConfirmationService->sendConfirmation($newUser);
167             } catch (Exception $e) {
168                 session()->flash('error', trans('auth.email_confirm_send_error'));
169             }
170
171             return redirect('/register/confirm');
172         }
173
174         auth()->login($newUser);
175         session()->flash('success', trans('auth.register_success'));
176         return redirect($this->redirectPath());
177     }
178
179     /**
180      * Show the page to tell the user to check their email
181      * and confirm their address.
182      */
183     public function getRegisterConfirmation()
184     {
185         return view('auth.register-confirm');
186     }
187
188     /**
189      * Confirms an email via a token and logs the user into the system.
190      * @param $token
191      * @return RedirectResponse|Redirector
192      * @throws UserRegistrationException
193      */
194     public function confirmEmail($token)
195     {
196         $confirmation = $this->emailConfirmationService->getEmailConfirmationFromToken($token);
197         $user = $confirmation->user;
198         $user->email_confirmed = true;
199         $user->save();
200         auth()->login($user);
201         session()->flash('success', trans('auth.email_confirm_success'));
202         $this->emailConfirmationService->deleteConfirmationsByUser($user);
203         return redirect($this->redirectPath);
204     }
205
206     /**
207      * Shows a notice that a user's email address has not been confirmed,
208      * Also has the option to re-send the confirmation email.
209      * @return View
210      */
211     public function showAwaitingConfirmation()
212     {
213         return view('auth.user-unconfirmed');
214     }
215
216     /**
217      * Resend the confirmation email
218      * @param Request $request
219      * @return View
220      */
221     public function resendConfirmation(Request $request)
222     {
223         $this->validate($request, [
224             'email' => 'required|email|exists:users,email'
225         ]);
226         $user = $this->userRepo->getByEmail($request->get('email'));
227
228         try {
229             $this->emailConfirmationService->sendConfirmation($user);
230         } catch (Exception $e) {
231             session()->flash('error', trans('auth.email_confirm_send_error'));
232             return redirect('/register/confirm');
233         }
234
235         session()->flash('success', trans('auth.email_confirm_resent'));
236         return redirect('/register/confirm');
237     }
238
239     /**
240      * Redirect to the social site for authentication intended to register.
241      * @param $socialDriver
242      * @return mixed
243      * @throws UserRegistrationException
244      * @throws SocialDriverNotConfigured
245      */
246     public function socialRegister($socialDriver)
247     {
248         $this->checkRegistrationAllowed();
249         session()->put('social-callback', 'register');
250         return $this->socialAuthService->startRegister($socialDriver);
251     }
252
253     /**
254      * The callback for social login services.
255      * @param $socialDriver
256      * @param Request $request
257      * @return RedirectResponse|Redirector
258      * @throws SocialSignInException
259      * @throws UserRegistrationException
260      * @throws SocialDriverNotConfigured
261      */
262     public function socialCallback($socialDriver, Request $request)
263     {
264         if (!session()->has('social-callback')) {
265             throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login');
266         }
267
268         // Check request for error information
269         if ($request->has('error') && $request->has('error_description')) {
270             throw new SocialSignInException(trans('errors.social_login_bad_response', [
271                 'socialAccount' => $socialDriver,
272                 'error' => $request->get('error_description'),
273             ]), '/login');
274         }
275
276         $action = session()->pull('social-callback');
277
278         // Attempt login or fall-back to register if allowed.
279         $socialUser = $this->socialAuthService->getSocialUser($socialDriver);
280         if ($action == 'login') {
281             try {
282                 return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser);
283             } catch (SocialSignInAccountNotUsed $exception) {
284                 if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) {
285                     return $this->socialRegisterCallback($socialDriver, $socialUser);
286                 }
287                 throw $exception;
288             }
289         }
290
291         if ($action == 'register') {
292             return $this->socialRegisterCallback($socialDriver, $socialUser);
293         }
294
295         return redirect()->back();
296     }
297
298     /**
299      * Detach a social account from a user.
300      * @param $socialDriver
301      * @return RedirectResponse|Redirector
302      */
303     public function detachSocialAccount($socialDriver)
304     {
305         return $this->socialAuthService->detachSocialAccount($socialDriver);
306     }
307
308     /**
309      * Register a new user after a registration callback.
310      * @param string $socialDriver
311      * @param SocialUser $socialUser
312      * @return RedirectResponse|Redirector
313      * @throws UserRegistrationException
314      */
315     protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser)
316     {
317         $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser);
318         $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
319         $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver);
320
321         // Create an array of the user data to create a new user instance
322         $userData = [
323             'name' => $socialUser->getName(),
324             'email' => $socialUser->getEmail(),
325             'password' => str_random(30)
326         ];
327         return $this->registerUser($userData, $socialAccount, $emailVerified);
328     }
329 }