3 namespace BookStack\Http\Controllers\Auth;
5 use BookStack\Exceptions\SocialSignInAccountNotUsed;
6 use BookStack\Exceptions\SocialSignInException;
7 use BookStack\Exceptions\UserRegistrationException;
8 use BookStack\Auth\UserRepo;
9 use BookStack\Auth\Access\EmailConfirmationService;
10 use BookStack\Auth\Access\SocialAuthService;
11 use BookStack\Auth\SocialAccount;
12 use BookStack\Auth\User;
14 use Illuminate\Http\Request;
15 use Illuminate\Http\Response;
17 use BookStack\Http\Controllers\Controller;
18 use Illuminate\Foundation\Auth\RegistersUsers;
19 use Laravel\Socialite\Contracts\User as SocialUser;
21 class RegisterController extends Controller
24 |--------------------------------------------------------------------------
26 |--------------------------------------------------------------------------
28 | This controller handles the registration of new users as well as their
29 | validation and creation. By default this controller uses a trait to
30 | provide this functionality without requiring any additional code.
36 protected $socialAuthService;
37 protected $emailConfirmationService;
41 * Where to redirect users after login / registration.
45 protected $redirectTo = '/';
46 protected $redirectPath = '/';
49 * Create a new controller instance.
51 * @param \BookStack\Auth\Access\SocialAuthService $socialAuthService
52 * @param \BookStack\Auth\EmailConfirmationService $emailConfirmationService
53 * @param \BookStack\Auth\UserRepo $userRepo
55 public function __construct(\BookStack\Auth\Access\SocialAuthService $socialAuthService, \BookStack\Auth\Access\EmailConfirmationService $emailConfirmationService, UserRepo $userRepo)
57 $this->middleware('guest')->only(['getRegister', 'postRegister', 'socialRegister']);
58 $this->socialAuthService = $socialAuthService;
59 $this->emailConfirmationService = $emailConfirmationService;
60 $this->userRepo = $userRepo;
61 $this->redirectTo = baseUrl('/');
62 $this->redirectPath = baseUrl('/');
63 parent::__construct();
67 * Get a validator for an incoming registration request.
70 * @return \Illuminate\Contracts\Validation\Validator
72 protected function validator(array $data)
74 return Validator::make($data, [
75 'name' => 'required|max:255',
76 'email' => 'required|email|max:255|unique:users',
77 'password' => 'required|min:6',
82 * Check whether or not registrations are allowed in the app settings.
83 * @throws UserRegistrationException
85 protected function checkRegistrationAllowed()
87 if (!setting('registration-enabled')) {
88 throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login');
93 * Show the application registration form.
95 * @throws UserRegistrationException
97 public function getRegister()
99 $this->checkRegistrationAllowed();
100 $socialDrivers = $this->socialAuthService->getActiveDrivers();
101 return view('auth.register', ['socialDrivers' => $socialDrivers]);
105 * Handle a registration request for the application.
106 * @param Request|\Illuminate\Http\Request $request
107 * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
108 * @throws UserRegistrationException
110 public function postRegister(Request $request)
112 $this->checkRegistrationAllowed();
113 $this->validator($request->all())->validate();
115 $userData = $request->all();
116 return $this->registerUser($userData);
120 * Create a new user instance after a valid registration.
122 * @return \BookStack\Auth\User
124 protected function create(array $data)
126 return User::create([
127 'name' => $data['name'],
128 'email' => $data['email'],
129 'password' => bcrypt($data['password']),
134 * The registrations flow for all users.
135 * @param array $userData
136 * @param bool|false|SocialAccount $socialAccount
137 * @param bool $emailVerified
138 * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
139 * @throws UserRegistrationException
141 protected function registerUser(array $userData, $socialAccount = false, $emailVerified = false)
143 $registrationRestrict = setting('registration-restrict');
145 if ($registrationRestrict) {
146 $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
147 $userEmailDomain = $domain = substr(strrchr($userData['email'], "@"), 1);
148 if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
149 throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register');
153 $newUser = $this->userRepo->registerNew($userData, $emailVerified);
154 if ($socialAccount) {
155 $newUser->socialAccounts()->save($socialAccount);
158 if ((setting('registration-confirmation') || $registrationRestrict) && !$emailVerified) {
162 $this->emailConfirmationService->sendConfirmation($newUser);
163 } catch (Exception $e) {
164 session()->flash('error', trans('auth.email_confirm_send_error'));
167 return redirect('/register/confirm');
170 auth()->login($newUser);
171 session()->flash('success', trans('auth.register_success'));
172 return redirect($this->redirectPath());
176 * Show the page to tell the user to check their email
177 * and confirm their address.
179 public function getRegisterConfirmation()
181 return view('auth/register-confirm');
185 * Confirms an email via a token and logs the user into the system.
187 * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
188 * @throws UserRegistrationException
190 public function confirmEmail($token)
192 $confirmation = $this->emailConfirmationService->getEmailConfirmationFromToken($token);
193 $user = $confirmation->user;
194 $user->email_confirmed = true;
196 auth()->login($user);
197 session()->flash('success', trans('auth.email_confirm_success'));
198 $this->emailConfirmationService->deleteConfirmationsByUser($user);
199 return redirect($this->redirectPath);
203 * Shows a notice that a user's email address has not been confirmed,
204 * Also has the option to re-send the confirmation email.
205 * @return \Illuminate\View\View
207 public function showAwaitingConfirmation()
209 return view('auth/user-unconfirmed');
213 * Resend the confirmation email
214 * @param Request $request
215 * @return \Illuminate\View\View
217 public function resendConfirmation(Request $request)
219 $this->validate($request, [
220 'email' => 'required|email|exists:users,email'
222 $user = $this->userRepo->getByEmail($request->get('email'));
225 $this->emailConfirmationService->sendConfirmation($user);
226 } catch (Exception $e) {
227 session()->flash('error', trans('auth.email_confirm_send_error'));
228 return redirect('/register/confirm');
231 session()->flash('success', trans('auth.email_confirm_resent'));
232 return redirect('/register/confirm');
236 * Redirect to the social site for authentication intended to register.
237 * @param $socialDriver
239 * @throws UserRegistrationException
240 * @throws \BookStack\Exceptions\SocialDriverNotConfigured
242 public function socialRegister($socialDriver)
244 $this->checkRegistrationAllowed();
245 session()->put('social-callback', 'register');
246 return $this->socialAuthService->startRegister($socialDriver);
250 * The callback for social login services.
251 * @param $socialDriver
252 * @param Request $request
253 * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
254 * @throws SocialSignInException
255 * @throws UserRegistrationException
256 * @throws \BookStack\Exceptions\SocialDriverNotConfigured
258 public function socialCallback($socialDriver, Request $request)
260 if (!session()->has('social-callback')) {
261 throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login');
264 // Check request for error information
265 if ($request->has('error') && $request->has('error_description')) {
266 throw new SocialSignInException(trans('errors.social_login_bad_response', [
267 'socialAccount' => $socialDriver,
268 'error' => $request->get('error_description'),
272 $action = session()->pull('social-callback');
274 // Attempt login or fall-back to register if allowed.
275 $socialUser = $this->socialAuthService->getSocialUser($socialDriver);
276 if ($action == 'login') {
278 return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser);
279 } catch (SocialSignInAccountNotUsed $exception) {
280 if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) {
281 return $this->socialRegisterCallback($socialDriver, $socialUser);
287 if ($action == 'register') {
288 return $this->socialRegisterCallback($socialDriver, $socialUser);
291 return redirect()->back();
295 * Detach a social account from a user.
296 * @param $socialDriver
297 * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
299 public function detachSocialAccount($socialDriver)
301 return $this->socialAuthService->detachSocialAccount($socialDriver);
305 * Register a new user after a registration callback.
306 * @param string $socialDriver
307 * @param SocialUser $socialUser
308 * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
309 * @throws UserRegistrationException
311 protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser)
313 $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser);
314 $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
315 $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver);
317 // Create an array of the user data to create a new user instance
319 'name' => $socialUser->getName(),
320 'email' => $socialUser->getEmail(),
321 'password' => str_random(30)
323 return $this->registerUser($userData, $socialAccount, $emailVerified);