]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/Auth/RegisterController.php
Added crude example of captcha usage
[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 GuzzleHttp\Client;
17 use Illuminate\Foundation\Auth\RegistersUsers;
18 use Illuminate\Http\RedirectResponse;
19 use Illuminate\Http\Request;
20 use Illuminate\Http\Response;
21 use Illuminate\Routing\Redirector;
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         $captcha = $request->get('g-recaptcha-response');
120         $resp = (new Client())->post('https://www.google.com/recaptcha/api/siteverify', [
121             'form_params' => [
122                 'response' => $captcha,
123                 'secret' => '%%secret_key%%',
124             ]
125         ]);
126         $respBody = json_decode($resp->getBody());
127         if (!$respBody->success) {
128             return redirect()->back()->withInput()->withErrors([
129                 'g-recaptcha-response' => 'Did not pass captcha',
130             ]);
131         }
132
133         $userData = $request->all();
134         return $this->registerUser($userData);
135     }
136
137     /**
138      * Create a new user instance after a valid registration.
139      * @param  array  $data
140      * @return User
141      */
142     protected function create(array $data)
143     {
144         return User::create([
145             'name' => $data['name'],
146             'email' => $data['email'],
147             'password' => bcrypt($data['password']),
148         ]);
149     }
150
151     /**
152      * The registrations flow for all users.
153      * @param array $userData
154      * @param bool|false|SocialAccount $socialAccount
155      * @param bool $emailVerified
156      * @return RedirectResponse|Redirector
157      * @throws UserRegistrationException
158      */
159     protected function registerUser(array $userData, $socialAccount = false, $emailVerified = false)
160     {
161         $registrationRestrict = setting('registration-restrict');
162
163         if ($registrationRestrict) {
164             $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
165             $userEmailDomain = $domain = mb_substr(mb_strrchr($userData['email'], "@"), 1);
166             if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
167                 throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register');
168             }
169         }
170
171         $newUser = $this->userRepo->registerNew($userData, $emailVerified);
172         if ($socialAccount) {
173             $newUser->socialAccounts()->save($socialAccount);
174         }
175
176         if ($this->emailConfirmationService->confirmationRequired() && !$emailVerified) {
177             $newUser->save();
178
179             try {
180                 $this->emailConfirmationService->sendConfirmation($newUser);
181             } catch (Exception $e) {
182                 session()->flash('error', trans('auth.email_confirm_send_error'));
183             }
184
185             return redirect('/register/confirm');
186         }
187
188         auth()->login($newUser);
189         session()->flash('success', trans('auth.register_success'));
190         return redirect($this->redirectPath());
191     }
192
193     /**
194      * Redirect to the social site for authentication intended to register.
195      * @param $socialDriver
196      * @return mixed
197      * @throws UserRegistrationException
198      * @throws SocialDriverNotConfigured
199      */
200     public function socialRegister($socialDriver)
201     {
202         $this->checkRegistrationAllowed();
203         session()->put('social-callback', 'register');
204         return $this->socialAuthService->startRegister($socialDriver);
205     }
206
207     /**
208      * The callback for social login services.
209      * @param $socialDriver
210      * @param Request $request
211      * @return RedirectResponse|Redirector
212      * @throws SocialSignInException
213      * @throws UserRegistrationException
214      * @throws SocialDriverNotConfigured
215      */
216     public function socialCallback($socialDriver, Request $request)
217     {
218         if (!session()->has('social-callback')) {
219             throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login');
220         }
221
222         // Check request for error information
223         if ($request->has('error') && $request->has('error_description')) {
224             throw new SocialSignInException(trans('errors.social_login_bad_response', [
225                 'socialAccount' => $socialDriver,
226                 'error' => $request->get('error_description'),
227             ]), '/login');
228         }
229
230         $action = session()->pull('social-callback');
231
232         // Attempt login or fall-back to register if allowed.
233         $socialUser = $this->socialAuthService->getSocialUser($socialDriver);
234         if ($action == 'login') {
235             try {
236                 return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser);
237             } catch (SocialSignInAccountNotUsed $exception) {
238                 if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) {
239                     return $this->socialRegisterCallback($socialDriver, $socialUser);
240                 }
241                 throw $exception;
242             }
243         }
244
245         if ($action == 'register') {
246             return $this->socialRegisterCallback($socialDriver, $socialUser);
247         }
248
249         return redirect()->back();
250     }
251
252     /**
253      * Detach a social account from a user.
254      * @param $socialDriver
255      * @return RedirectResponse|Redirector
256      */
257     public function detachSocialAccount($socialDriver)
258     {
259         return $this->socialAuthService->detachSocialAccount($socialDriver);
260     }
261
262     /**
263      * Register a new user after a registration callback.
264      * @param string $socialDriver
265      * @param SocialUser $socialUser
266      * @return RedirectResponse|Redirector
267      * @throws UserRegistrationException
268      */
269     protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser)
270     {
271         $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser);
272         $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
273         $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver);
274
275         // Create an array of the user data to create a new user instance
276         $userData = [
277             'name' => $socialUser->getName(),
278             'email' => $socialUser->getEmail(),
279             'password' => str_random(30)
280         ];
281         return $this->registerUser($userData, $socialAccount, $emailVerified);
282     }
283 }