| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace BookStack\Auth\Access; | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-21 03:33:11 +08:00
										 |  |  | use BookStack\Actions\ActivityType; | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  | use BookStack\Auth\SocialAccount; | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  | use BookStack\Auth\User; | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  | use BookStack\Auth\UserRepo; | 
					
						
							|  |  |  | use BookStack\Exceptions\UserRegistrationException; | 
					
						
							| 
									
										
										
										
											2020-11-21 03:33:11 +08:00
										 |  |  | use BookStack\Facades\Activity; | 
					
						
							| 
									
										
										
										
											2021-03-20 05:54:50 +08:00
										 |  |  | use BookStack\Facades\Theme; | 
					
						
							|  |  |  | use BookStack\Theming\ThemeEvents; | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  | use Exception; | 
					
						
							| 
									
										
										
										
											2021-10-07 06:05:26 +08:00
										 |  |  | use Illuminate\Support\Str; | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class RegistrationService | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     protected $userRepo; | 
					
						
							|  |  |  |     protected $emailConfirmationService; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * RegistrationService constructor. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function __construct(UserRepo $userRepo, EmailConfirmationService $emailConfirmationService) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->userRepo = $userRepo; | 
					
						
							|  |  |  |         $this->emailConfirmationService = $emailConfirmationService; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Check whether or not registrations are allowed in the app settings. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |      * @throws UserRegistrationException | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |     public function ensureRegistrationAllowed() | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |         if (!$this->registrationAllowed()) { | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |             throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Check if standard BookStack User registrations are currently allowed. | 
					
						
							|  |  |  |      * Does not prevent external-auth based registration. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function registrationAllowed(): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $authMethod = config('auth.method'); | 
					
						
							|  |  |  |         $authMethodsWithRegistration = ['standard']; | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |         return in_array($authMethod, $authMethodsWithRegistration) && setting('registration-enabled'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 06:05:26 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Attempt to find a user in the system otherwise register them as a new | 
					
						
							|  |  |  |      * user. For use with external auth systems since password is auto-generated. | 
					
						
							| 
									
										
										
										
											2021-10-16 23:01:59 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2021-10-07 06:05:26 +08:00
										 |  |  |      * @throws UserRegistrationException | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function findOrRegister(string $name, string $email, string $externalId): User | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $user = User::query() | 
					
						
							|  |  |  |             ->where('external_auth_id', '=', $externalId) | 
					
						
							|  |  |  |             ->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (is_null($user)) { | 
					
						
							|  |  |  |             $userData = [ | 
					
						
							|  |  |  |                 'name'             => $name, | 
					
						
							|  |  |  |                 'email'            => $email, | 
					
						
							|  |  |  |                 'password'         => Str::random(32), | 
					
						
							|  |  |  |                 'external_auth_id' => $externalId, | 
					
						
							|  |  |  |             ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $user = $this->registerUser($userData, null, false); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $user; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * The registrations flow for all users. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |      * @throws UserRegistrationException | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |     public function registerUser(array $userData, ?SocialAccount $socialAccount = null, bool $emailConfirmed = false): User | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |         $userEmail = $userData['email']; | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |         // Email restriction
 | 
					
						
							|  |  |  |         $this->ensureEmailDomainAllowed($userEmail); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Ensure user does not already exist
 | 
					
						
							|  |  |  |         $alreadyUser = !is_null($this->userRepo->getByEmail($userEmail)); | 
					
						
							|  |  |  |         if ($alreadyUser) { | 
					
						
							| 
									
										
										
										
											2020-09-26 23:43:06 +08:00
										 |  |  |             throw new UserRegistrationException(trans('errors.error_user_exists_different_creds', ['email' => $userEmail]), '/login'); | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |         // Create the user
 | 
					
						
							| 
									
										
										
										
											2022-02-04 08:26:19 +08:00
										 |  |  |         $newUser = $this->userRepo->createWithoutActivity($userData, $emailConfirmed); | 
					
						
							|  |  |  |         $newUser->attachDefaultRole(); | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |         // Assign social account if given
 | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |         if ($socialAccount) { | 
					
						
							|  |  |  |             $newUser->socialAccounts()->save($socialAccount); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-21 03:33:11 +08:00
										 |  |  |         Activity::add(ActivityType::AUTH_REGISTER, $socialAccount ?? $newUser); | 
					
						
							| 
									
										
										
										
											2021-03-20 05:54:50 +08:00
										 |  |  |         Theme::dispatch(ThemeEvents::AUTH_REGISTER, $socialAccount ? $socialAccount->driver : auth()->getDefaultDriver(), $newUser); | 
					
						
							| 
									
										
										
										
											2020-11-21 03:33:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |         // Start email confirmation flow if required
 | 
					
						
							|  |  |  |         if ($this->emailConfirmationService->confirmationRequired() && !$emailConfirmed) { | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |             $newUser->save(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try { | 
					
						
							|  |  |  |                 $this->emailConfirmationService->sendConfirmation($newUser); | 
					
						
							| 
									
										
										
										
											2020-09-06 00:26:48 +08:00
										 |  |  |                 session()->flash('sent-email-confirmation', true); | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |             } catch (Exception $e) { | 
					
						
							|  |  |  |                 $message = trans('auth.email_confirm_send_error'); | 
					
						
							| 
									
										
										
										
											2021-08-21 22:49:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-05 00:54:50 +08:00
										 |  |  |                 throw new UserRegistrationException($message, '/register/confirm'); | 
					
						
							| 
									
										
										
										
											2020-01-26 22:42:50 +08:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |         return $newUser; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Ensure that the given email meets any active email domain registration restrictions. | 
					
						
							|  |  |  |      * Throws if restrictions are active and the email does not match an allowed domain. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |      * @throws UserRegistrationException | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function ensureEmailDomainAllowed(string $userEmail): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $registrationRestrict = setting('registration-restrict'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!$registrationRestrict) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict)); | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |         $userEmailDomain = $domain = mb_substr(mb_strrchr($userEmail, '@'), 1); | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |         if (!in_array($userEmailDomain, $restrictedEmailDomains)) { | 
					
						
							|  |  |  |             $redirect = $this->registrationAllowed() ? '/register' : '/login'; | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |             throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), $redirect); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-03-08 06:24:05 +08:00
										 |  |  | } |