SocialiteController::getSocialAuthCallback()   B
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.439
c 0
b 0
f 0
cc 5
eloc 16
nc 5
nop 1
1
<?php
2
3
namespace App\Http\Controllers\Auth;
4
5
use App\Http\Requests\GetEmailFormRequest;
6
use App\Http\Requests\SocialiteUserSaveEmailRequest;
7
use App\Repositories\UserRepository;
8
use App\Services\SocialiteUser;
9
use App\User;
10
use Laravel\Socialite\Contracts\Factory as Socialite;
11
use App\Http\Controllers\Controller;
12
13
class SocialiteController extends Controller
14
{
15
    /**
16
     * @var Socialite
17
     */
18
    protected $socialite;
19
20
    /**
21
     * @var SocialiteUser
22
     */
23
    protected $service;
24
25
    /**
26
     * @var UserRepository
27
     */
28
    protected $users;
29
30
    /**
31
     * SocialiteController constructor.
32
     * @param Socialite $socialite
33
     * @param UserRepository $userRepository
34
     * @param SocialiteUser $socialiteUser
35
     */
36
    public function __construct(
37
        Socialite $socialite,
38
        UserRepository $userRepository,
39
        SocialiteUser $socialiteUser
40
    )
41
    {
42
        $this->socialite = $socialite;
43
        $this->users = $userRepository;
44
        $this->service = $socialiteUser;
45
        $this->middleware((new AuthController)->guestMiddleware());
46
    }
47
48
    /**
49
     * Redirect to social provider.
50
     *
51
     * @param $provider
52
     * @return mixed
53
     */
54
    public function getSocialAuth($provider)
55
    {
56
        return $this->socialite->driver($provider)->scopes([
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Laravel\Socialite\Contracts\Provider as the method scopes() does only exist in the following implementations of said interface: Laravel\Socialite\Two\AbstractProvider, Laravel\Socialite\Two\FacebookProvider, Laravel\Socialite\Two\GithubProvider, Laravel\Socialite\Two\GoogleProvider, Laravel\Socialite\Two\LinkedInProvider.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
57
            'email'
58
        ])->redirect();
59
    }
60
61
    /**
62
     * Email form.
63
     *
64
     * @param GetEmailFormRequest $request
65
     * @param $provider
66
     * @param $social
67
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
68
     */
69
    public function getEmailForm(GetEmailFormRequest $request, $provider, $social)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $provider is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
70
    {
71
        return view('auth.email', ['social' => $social]);
72
    }
73
74
    public function postEmailForm(
75
        SocialiteUserSaveEmailRequest $request,
76
        $provider,
77
        $social
78
    )
79
    {
80
        $callback = json_decode($social->callback);
81
        $this->service->init($provider, $callback);
82
        list($frst_n, $last_n) = $this->service->getFirstAndLustNames($callback->name);
83
        $user = $this->users->createSimpleUser([
84
            'email' => $request->get('email'),
85
            'password' => $this->users->hashPassword(str_random(45)),
86
            'firstname' => $frst_n,
87
            'lastname' => $last_n
88
        ], (int)true);
89
        $this->service->tryToAssociateUser($social, $request->get('email'));
90
91
        $this->service->login($user);
92
93
        $this->service->avatar($callback->avatar);
94
95
        return redirect()->route('home')->withStatus('Logged in success.');
0 ignored issues
show
Bug introduced by
The method withStatus() does not exist on Illuminate\Http\RedirectResponse. Did you maybe mean status()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
96
    }
97
98
    /**
99
     * Social provider callback.
100
     *
101
     * @param $provider
102
     * @return string
103
     */
104
    public function getSocialAuthCallback($provider)
105
    {
106
        if ($s_user = $this->getProvidedUser($provider)) {
107
            $user = $this->service
108
                ->init($provider, $s_user)
109
                ->register();
110
111
            if ($user instanceof SocialiteUser) {
112
                return redirect()->route('social_auth_email', [
113
                    'provider' => $user->getProvider(),
114
                    'social' => $user->getUser()->getId()
115
                ]);
116
            } elseif ($user instanceof User) {
117
                $this->service->login($user);
118
119
                if(! $user->checkAvatar())
120
                    $this->service->avatar($s_user->getAvatar());
121
122
                return redirect()->route('home');
123
            }
124
125
        } else {
126
            return redirect()->route('login')->withStatus('Something wrong. Try the default register.');
0 ignored issues
show
Bug introduced by
The method withStatus() does not exist on Illuminate\Http\RedirectResponse. Did you maybe mean status()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
127
        }
128
    }
129
130
    /**
131
     * @param $provider
132
     * @return \Laravel\Socialite\Contracts\User
133
     */
134
    private function getProvidedUser($provider)
135
    {
136
        return @$this->socialite->driver($provider)->user();
137
    }
138
}