JWTAuth::getHeaderDecodeJson()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace CodeBlog\JWT;
4
5
use CodeBlog\JWT\Helpers;
6
7
/**
8
 * Class CodeBlog JWTAuth
9
 *
10
 * @author Whallysson Avelino <https://github.com/whallysson>
11
 * @package CodeBlog\JWT
12
 */
13
14
class JWTAuth
15
{
16
17
    /**
18
     * @var array
19
     */
20
    public static $algorithms = [
21
        'HS256' => 'SHA256',
22
        'HS384' => 'SHA384',
23
        'HS512' => 'SHA512',
24
    ];
25
26
    /**
27
     * @var string
28
     */
29
    private $header;
30
    /**
31
     * @var string
32
     */
33
    private $payload;
34
    /**
35
     * @var string
36
     */
37
    private $signature;
38
    /**
39
     * @var string
40
     */
41
    private $hash;
42
43
    /**
44
     * Check the JWT token string has a valid structre and it into its three
45
     * component parts, header, payload and signature
46
     *
47
     * @param string $tokenString
48
     *
49
     * @return JWTAuth
50
     */
51
    public function splitToken(string $tokenString): JWTAuth
52
    {
53
        $tokenParts = explode('.', $tokenString);
54
        if (count($tokenParts) === 3) {
55
            $this->header = $tokenParts[0];
56
            $this->payload = $tokenParts[1];
57
            $this->signature = $tokenParts[2];
58
59
            return $this;
60
        }
61
62
        Helpers::throwError(401,
63
            'A string de Token possui estrutura inválida, assegure três strings separadas por pontos.');
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return CodeBlog\JWT\JWTAuth. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
64
    }
65
66
    /**
67
     * @return JWTAuth
68
     */
69
    public function validateHeader(): JWTAuth
70
    {
71
        $header = json_decode(Helpers::decode($this->header));
72
        if (empty($header)) {
73
            Helpers::throwError(401, 'Codificação de segmento inválida');
74
        }
75
76
        if (empty($header->alg)) {
77
            Helpers::throwError(401, 'Algoritmo vazio');
78
        }
79
80
        if (empty(self::$algorithms[$header->alg])) {
81
            Helpers::throwError(401, 'Algoritmo não suportado');
82
        }
83
84
        $this->hash = $header->alg;
85
86
        return $this;
87
    }
88
89
    /**
90
     * @return JWTAuth
91
     */
92
    public function validatePayload(): JWTAuth
93
    {
94
        if (empty(json_decode($this->getPayload()))) {
95
            Helpers::throwError(401, 'Codificação de segmento inválida');
96
        }
97
98
        return $this;
99
    }
100
101
    /**
102
     * Validate that the JWT expiration date is valid and has not expired.
103
     *
104
     * @return JWTAuth
105
     */
106
    public function validateExpiration(): JWTAuth
107
    {
108
        if ($this->hasOldExpiration()) {
109
            Helpers::throwError(401, 'Este token expirou!');
110
        }
111
        return $this;
112
    }
113
114
    /**
115
     * @return bool
116
     */
117
    private function hasOldExpiration(): bool
118
    {
119
        $diff = $this->getExpiration() - time();
120
        return ($diff < 0 ? true : false);
121
    }
122
123
    /**
124
     * Generate a new Signature object based on the header, payload and secret
125
     * then check that the signature matches the token signature
126
     *
127
     * @param string $secret
128
     *
129
     * @return bool
130
     */
131
    public function validateSignature(string $secret): bool
132
    {
133
        if (false === (Helpers::decode($this->signature))) {
134
            Helpers::throwError(401, 'Codificação de assinatura inválida');
135
        }
136
137
        $signature = $this->signature($this->header, $this->payload, $secret, $this->getHash());
138
        if (hash_equals($signature, $this->signature)) {
139
            return true;
140
        }
141
142
        Helpers::throwError(401, 'A assinatura do token é inválida!! Entrada: ' . $this->signature);
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
143
    }
144
145
    /**
146
     * Assine uma string com uma determinada chave e algoritmo
147
     *
148
     * @return string
149
     */
150
    public function signature(string $header, string $payload, string $secret, string $hash = 'HS256'): string
151
    {
152
        if (empty(static::$algorithms[$hash])) {
153
            Helpers::throwError(401, 'Algoritmo não suportado');
154
        }
155
156
        return Helpers::encode(hash_hmac(static::$algorithms[$hash], "{$header}.{$payload}", $secret, true));
157
    }
158
159
    /**
160
     * Json decode the JWT payload and return the expiration attribute
161
     *
162
     * @return string
163
     */
164
    public function getExpiration(): string
165
    {
166
        $payload = json_decode($this->getPayload());
167
        if (isset($payload->exp)) {
168
            return $payload->exp;
169
        }
170
171
        Helpers::throwError(401, 'Objeto inválido, nenhum conjunto de parâmetros de expiração');
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
172
    }
173
174
    /**
175
     * Base 64 decode and return the JWT payload
176
     *
177
     * @return string
178
     */
179
    public function getPayload(): string
180
    {
181
        return Helpers::decode($this->payload);
182
    }
183
184
    /**
185
     * Base 64 decode and return the JWT header
186
     *
187
     * @return string
188
     */
189
    public function getHeader(): string
190
    {
191
        return Helpers::decode($this->header);
192
    }
193
194
    /**
195
     * Return payload but decode JSON string to stdClass first
196
     *
197
     * @return stdClass
0 ignored issues
show
Bug introduced by
The type CodeBlog\JWT\stdClass was not found. Did you mean stdClass? If so, make sure to prefix the type with \.
Loading history...
198
     */
199
    public function getPayloadDecodeJson(): \stdClass
200
    {
201
        return json_decode($this->getPayload());
202
    }
203
204
    /**
205
     * Return header but decode JSON string to stdClass first
206
     *
207
     * @return stdClass
208
     */
209
    public function getHeaderDecodeJson(): \stdClass
210
    {
211
        return json_decode($this->getHeader());
212
    }
213
214
    /**
215
     * Return the hash type for the signature hashing
216
     *
217
     * @return string
218
     */
219
    public function getHash(): string
220
    {
221
        return $this->hash;
222
    }
223
224
}
225