]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/Auth/RegisterController.php
Updated to Laravel 5.8
[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 Illuminate\Support\Str;
23 use Laravel\Socialite\Contracts\User as SocialUser;
24 use Validator;
25
26 class RegisterController extends Controller
27 {
28     /*
29     |--------------------------------------------------------------------------
30     | Register Controller
31     |--------------------------------------------------------------------------
32     |
33     | This controller handles the registration of new users as well as their
34     | validation and creation. By default this controller uses a trait to
35     | provide this functionality without requiring any additional code.
36     |
37     */
38
39     use RegistersUsers;
40
41     protected $socialAuthService;
42     protected $emailConfirmationService;
43     protected $userRepo;
44
45     /**
46      * Where to redirect users after login / registration.
47      *
48      * @var string
49      */
50     protected $redirectTo = '/';
51     protected $redirectPath = '/';
52
53     /**
54      * Create a new controller instance.
55      *
56      * @param SocialAuthService $socialAuthService
57      * @param EmailConfirmationService $emailConfirmationService
58      * @param UserRepo $userRepo
59      */
60     public function __construct(SocialAuthService $socialAuthService, EmailConfirmationService $emailConfirmationService, UserRepo $userRepo)
61     {
62         $this->middleware('guest')->only(['getRegister', 'postRegister', 'socialRegister']);
63         $this->socialAuthService = $socialAuthService;
64         $this->emailConfirmationService = $emailConfirmationService;
65         $this->userRepo = $userRepo;
66         $this->redirectTo = url('/');
67         $this->redirectPath = url('/');
68         parent::__construct();
69     }
70
71     /**
72      * Get a validator for an incoming registration request.
73      *
74      * @param  array $data
75      * @return \Illuminate\Contracts\Validation\Validator
76      */
77     protected function validator(array $data)
78     {
79         return Validator::make($data, [
80             'name' => 'required|min:2|max:255',
81             'email' => 'required|email|max:255|unique:users',
82             'password' => 'required|min:8',
83         ]);
84     }
85
86     /**
87      * Check whether or not registrations are allowed in the app settings.
88      * @throws UserRegistrationException
89      */
90     protected function checkRegistrationAllowed()
91     {
92         if (!setting('registration-enabled')) {
93             throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login');
94         }
95     }
96
97     /**
98      * Show the application registration form.
99      * @return Response
100      * @throws UserRegistrationException
101      */
102     public function getRegister()
103     {
104         $this->checkRegistrationAllowed();
105         $socialDrivers = $this->socialAuthService->getActiveDrivers();
106         return view('auth.register', ['socialDrivers' => $socialDrivers]);
107     }
108
109     /**
110      * Handle a registration request for the application.
111      * @param Request|Request $request
112      * @return RedirectResponse|Redirector
113      * @throws UserRegistrationException
114      */
115     public function postRegister(Request $request)
116     {
117         $this->checkRegistrationAllowed();
118         $this->validator($request->all())->validate();
119
120         $userData = $request->all();
121         return $this->registerUser($userData);
122     }
123
124     /**
125      * Create a new user instance after a valid registration.
126      * @param  array  $data
127      * @return User
128      */
129     protected function create(array $data)
130     {
131         return User::create([
132             'name' => $data['name'],
133             'email' => $data['email'],
134             'password' => Hash::make($data['password']),
135         ]);
136     }
137
138     /**
139      * The registrations flow for all users.
140      * @param array $userData
141      * @param bool|false|SocialAccount $socialAccount
142      * @param bool $emailVerified
143      * @return RedirectResponse|Redirector
144      * @throws UserRegistrationException
145      */
146     protected function registerUser(array $userData, $socialAccount = false, $emailVerified = false)
147     {
148         $registrationRestrict = setting('registration-restrict');
149
150         if ($registrationRestrict) {
151             $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
152             $userEmailDomain = $domain = mb_substr(mb_strrchr($userData['email'], "@"), 1);
153             if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
154                 throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register');
155             }
156         }
157
158         $newUser = $this->userRepo->registerNew($userData, $emailVerified);
159         if ($socialAccount) {
160             $newUser->socialAccounts()->save($socialAccount);
161         }
162
163         if ($this->emailConfirmationService->confirmationRequired() && !$emailVerified) {
164             $newUser->save();
165
166             try {
167                 $this->emailConfirmationService->sendConfirmation($newUser);
168             } catch (Exception $e) {
169                 session()->flash('error', trans('auth.email_confirm_send_error'));
170             }
171
172             return redirect('/register/confirm');
173         }
174
175         auth()->login($newUser);
176         session()->flash('success', trans('auth.register_success'));
177         return redirect($this->redirectPath());
178     }
179
180     /**
181      * Redirect to the social site for authentication intended to register.
182      * @param $socialDriver
183      * @return mixed
184      * @throws UserRegistrationException
185      * @throws SocialDriverNotConfigured
186      */
187     public function socialRegister($socialDriver)
188     {
189         $this->checkRegistrationAllowed();
190         session()->put('social-callback', 'register');
191         return $this->socialAuthService->startRegister($socialDriver);
192     }
193
194     /**
195      * The callback for social login services.
196      * @param $socialDriver
197      * @param Request $request
198      * @return RedirectResponse|Redirector
199      * @throws SocialSignInException
200      * @throws UserRegistrationException
201      * @throws SocialDriverNotConfigured
202      */
203     public function socialCallback($socialDriver, Request $request)
204     {
205         if (!session()->has('social-callback')) {
206             throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login');
207         }
208
209         // Check request for error information
210         if ($request->has('error') && $request->has('error_description')) {
211             throw new SocialSignInException(trans('errors.social_login_bad_response', [
212                 'socialAccount' => $socialDriver,
213                 'error' => $request->get('error_description'),
214             ]), '/login');
215         }
216
217         $action = session()->pull('social-callback');
218
219         // Attempt login or fall-back to register if allowed.
220         $socialUser = $this->socialAuthService->getSocialUser($socialDriver);
221         if ($action == 'login') {
222             try {
223                 return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser);
224             } catch (SocialSignInAccountNotUsed $exception) {
225                 if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) {
226                     return $this->socialRegisterCallback($socialDriver, $socialUser);
227                 }
228                 throw $exception;
229             }
230         }
231
232         if ($action == 'register') {
233             return $this->socialRegisterCallback($socialDriver, $socialUser);
234         }
235
236         return redirect()->back();
237     }
238
239     /**
240      * Detach a social account from a user.
241      * @param $socialDriver
242      * @return RedirectResponse|Redirector
243      */
244     public function detachSocialAccount($socialDriver)
245     {
246         return $this->socialAuthService->detachSocialAccount($socialDriver);
247     }
248
249     /**
250      * Register a new user after a registration callback.
251      * @param string $socialDriver
252      * @param SocialUser $socialUser
253      * @return RedirectResponse|Redirector
254      * @throws UserRegistrationException
255      */
256     protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser)
257     {
258         $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser);
259         $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
260         $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver);
261
262         // Create an array of the user data to create a new user instance
263         $userData = [
264             'name' => $socialUser->getName(),
265             'email' => $socialUser->getEmail(),
266             'password' => Str::random(30)
267         ];
268         return $this->registerUser($userData, $socialAccount, $emailVerified);
269     }
270 }