Completed
Push — graphql-auth ( 67a3fb...eab2f1 )
by
unknown
03:31
created

TokenAuth::encode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of laravel.su package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types = 1);
9
10
namespace App\Services;
11
12
13
use App\Models\User;
14
use Carbon\Carbon;
15
use Illuminate\Contracts\Auth\Guard;
16
use Illuminate\Contracts\Encryption\DecryptException;
17
use Illuminate\Encryption\Encrypter;
18
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
19
use Tymon\JWTAuth\Providers\JWT\JWTInterface;
20
21
class TokenAuth
22
{
23
    /**
24
     * @var JWTInterface
25
     */
26
    private $jwt;
27
    /**
28
     * @var Encrypter
29
     */
30
    private $encrypter;
31
    /**
32
     * @var Guard
33
     */
34
    private $guard;
35
36
    public function __construct(JWTInterface $jwt, Encrypter $encrypter, Guard $guard)
37
    {
38
39
        $this->jwt = $jwt;
40
        $this->encrypter = $encrypter;
41
        $this->guard = $guard;
42
    }
43
44
    /**
45
     * @param string $token
46
     * @return bool
47
     */
48
    public function attempt(string $token) : bool
49
    {
50
        $credentials = $this->decode($token);
51
        if (!isset($credentials['id']) || !isset($credentials['password'])) {
52
            return false;
53
        }
54
        $exists = User::whereId($credentials['id'])->wherePassword($credentials['password'])->exists();
55
        if (!$exists) {
56
            return false;
57
        }
58
        $this->guard->onceUsingId($credentials['id']);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Auth\Guard as the method onceUsingId() does only exist in the following implementations of said interface: Illuminate\Auth\SessionGuard.

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...
59
        return true;
60
    }
61
62
    /**
63
     * @param string $token
64
     * @throws TokenInvalidException
65
     * @throws DecryptException
66
     * @return array
67
     */
68
    public function decode(string $token) : array
69
    {
70
        $massive = $this->jwt->decode($token);
71
        foreach ($massive as &$item) {
72
            $item = $this->encrypter->decrypt($item);
73
        }
74
        return $massive;
75
    }
76
77
    /**
78
     * @return bool
79
     */
80
    public function check(): bool
81
    {
82
        return $this->guard->check();
83
    }
84
85
    /**
86
     * @return User
87
     */
88
    public function user() : User
89
    {
90
        return $this->guard->user();
91
    }
92
93
    /**
94
     * @return mixed
95
     */
96
    public function logout()
97
    {
98
        return $this->guard->logout();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Auth\Guard as the method logout() does only exist in the following implementations of said interface: Illuminate\Auth\SessionGuard.

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...
99
    }
100
101
    /**
102
     * @param array $credentials
103
     * @return mixed
104
     */
105
    public function once(array $credentials)
106
    {
107
        return $this->guard->once($credentials);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Auth\Guard as the method once() does only exist in the following implementations of said interface: Illuminate\Auth\SessionGuard.

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...
108
    }
109
110
    /**
111
     * @param User $user
112
     * @return string
113
     */
114
    public function fromUser(User $user) : string
115
    {
116
        $credentials = ['id' => $user->id,
117
            'password' => $user->password,
118
            'create' => Carbon::now()->toRfc3339String()];
119
        return $this->encode($credentials);
120
    }
121
122
    /**
123
     * @param array $inputs
124
     * @return string
125
     */
126
    public function encode(array $inputs) : string
127
    {
128
        foreach ($inputs as &$item) {
129
            $item = $this->encrypter->encrypt($item);
130
        }
131
        return $this->jwt->encode($inputs);
132
    }
133
}