]> BookStack Code Mirror - bookstack/blob - app/Access/Controllers/SocialController.php
Cleaned up namespacing in routes
[bookstack] / app / Access / Controllers / SocialController.php
1 <?php
2
3 namespace BookStack\Access\Controllers;
4
5 use BookStack\Access\LoginService;
6 use BookStack\Access\RegistrationService;
7 use BookStack\Access\SocialAuthService;
8 use BookStack\Exceptions\SocialDriverNotConfigured;
9 use BookStack\Exceptions\SocialSignInAccountNotUsed;
10 use BookStack\Exceptions\SocialSignInException;
11 use BookStack\Exceptions\UserRegistrationException;
12 use BookStack\Http\Controller;
13 use Illuminate\Http\Request;
14 use Illuminate\Support\Str;
15 use Laravel\Socialite\Contracts\User as SocialUser;
16
17 class SocialController extends Controller
18 {
19     protected SocialAuthService $socialAuthService;
20     protected RegistrationService $registrationService;
21     protected LoginService $loginService;
22
23     /**
24      * SocialController constructor.
25      */
26     public function __construct(
27         SocialAuthService $socialAuthService,
28         RegistrationService $registrationService,
29         LoginService $loginService
30     ) {
31         $this->middleware('guest')->only(['register']);
32         $this->socialAuthService = $socialAuthService;
33         $this->registrationService = $registrationService;
34         $this->loginService = $loginService;
35     }
36
37     /**
38      * Redirect to the relevant social site.
39      *
40      * @throws SocialDriverNotConfigured
41      */
42     public function login(string $socialDriver)
43     {
44         session()->put('social-callback', 'login');
45
46         return $this->socialAuthService->startLogIn($socialDriver);
47     }
48
49     /**
50      * Redirect to the social site for authentication intended to register.
51      *
52      * @throws SocialDriverNotConfigured
53      * @throws UserRegistrationException
54      */
55     public function register(string $socialDriver)
56     {
57         $this->registrationService->ensureRegistrationAllowed();
58         session()->put('social-callback', 'register');
59
60         return $this->socialAuthService->startRegister($socialDriver);
61     }
62
63     /**
64      * The callback for social login services.
65      *
66      * @throws SocialSignInException
67      * @throws SocialDriverNotConfigured
68      * @throws UserRegistrationException
69      */
70     public function callback(Request $request, string $socialDriver)
71     {
72         if (!session()->has('social-callback')) {
73             throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login');
74         }
75
76         // Check request for error information
77         if ($request->has('error') && $request->has('error_description')) {
78             throw new SocialSignInException(trans('errors.social_login_bad_response', [
79                 'socialAccount' => $socialDriver,
80                 'error'         => $request->get('error_description'),
81             ]), '/login');
82         }
83
84         $action = session()->pull('social-callback');
85
86         // Attempt login or fall-back to register if allowed.
87         $socialUser = $this->socialAuthService->getSocialUser($socialDriver);
88         if ($action === 'login') {
89             try {
90                 return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser);
91             } catch (SocialSignInAccountNotUsed $exception) {
92                 if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) {
93                     return $this->socialRegisterCallback($socialDriver, $socialUser);
94                 }
95
96                 throw $exception;
97             }
98         }
99
100         if ($action === 'register') {
101             return $this->socialRegisterCallback($socialDriver, $socialUser);
102         }
103
104         return redirect()->back();
105     }
106
107     /**
108      * Detach a social account from a user.
109      */
110     public function detach(string $socialDriver)
111     {
112         $this->socialAuthService->detachSocialAccount($socialDriver);
113         session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => Str::title($socialDriver)]));
114
115         return redirect(user()->getEditUrl());
116     }
117
118     /**
119      * Register a new user after a registration callback.
120      *
121      * @throws UserRegistrationException
122      */
123     protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser)
124     {
125         $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser);
126         $socialAccount = $this->socialAuthService->newSocialAccount($socialDriver, $socialUser);
127         $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver);
128
129         // Create an array of the user data to create a new user instance
130         $userData = [
131             'name'     => $socialUser->getName(),
132             'email'    => $socialUser->getEmail(),
133             'password' => Str::random(32),
134         ];
135
136         // Take name from email address if empty
137         if (!$userData['name']) {
138             $userData['name'] = explode('@', $userData['email'])[0];
139         }
140
141         $user = $this->registrationService->registerUser($userData, $socialAccount, $emailVerified);
142         $this->showSuccessNotification(trans('auth.register_success'));
143         $this->loginService->login($user, $socialDriver);
144
145         return redirect('/');
146     }
147 }