]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/Auth/RegisterController.php
83bd307e4171a503d86cdd8186ffb2040b69cbfa
[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\Support\Facades\Hash;
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 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' => Hash::make($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 ($this->emailConfirmationService->confirmationRequired() && !$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      * Redirect to the social site for authentication intended to register.
181      * @param $socialDriver
182      * @return mixed
183      * @throws UserRegistrationException
184      * @throws SocialDriverNotConfigured
185      */
186     public function socialRegister($socialDriver)
187     {
188         $this->checkRegistrationAllowed();
189         session()->put('social-callback', 'register');
190         return $this->socialAuthService->startRegister($socialDriver);
191     }
192
193     /**
194      * The callback for social login services.
195      * @param $socialDriver
196      * @param Request $request
197      * @return RedirectResponse|Redirector
198      * @throws SocialSignInException
199      * @throws UserRegistrationException
200      * @throws SocialDriverNotConfigured
201      */
202     public function socialCallback($socialDriver, Request $request)
203     {
204         if (!session()->has('social-callback')) {
205             throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login');
206         }
207
208         // Check request for error information
209         if ($request->has('error') && $request->has('error_description')) {
210             throw new SocialSignInException(trans('errors.social_login_bad_response', [
211                 'socialAccount' => $socialDriver,
212                 'error' => $request->get('error_description'),
213             ]), '/login');
214         }
215
216         $action = session()->pull('social-callback');
217
218         // Attempt login or fall-back to register if allowed.
219         $socialUser = $this->socialAuthService->getSocialUser($socialDriver);
220         if ($action == 'login') {
221             try {
222                 return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser);
223             } catch (SocialSignInAccountNotUsed $exception) {
224                 if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) {
225                     return $this->socialRegisterCallback($socialDriver, $socialUser);
226                 }
227                 throw $exception;
228             }
229         }
230
231         if ($action == 'register') {
232             return $this->socialRegisterCallback($socialDriver, $socialUser);
233         }
234
235         return redirect()->back();
236     }
237
238     /**
239      * Detach a social account from a user.
240      * @param $socialDriver
241      * @return RedirectResponse|Redirector
242      */
243     public function detachSocialAccount($socialDriver)
244     {
245         return $this->socialAuthService->detachSocialAccount($socialDriver);
246     }
247
248     /**
249      * Register a new user after a registration callback.
250      * @param string $socialDriver
251      * @param SocialUser $socialUser
252      * @return RedirectResponse|Redirector
253      * @throws UserRegistrationException
254      */
255     protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser)
256     {
257         $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser);
258         $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
259         $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver);
260
261         // Create an array of the user data to create a new user instance
262         $userData = [
263             'name' => $socialUser->getName(),
264             'email' => $socialUser->getEmail(),
265             'password' => str_random(30)
266         ];
267         return $this->registerUser($userData, $socialAccount, $emailVerified);
268     }
269 }