jwtValidate   C
last analyzed

Complexity

Total Complexity 56

Size/Duplication

Total Lines 316
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 106
c 5
b 0
f 0
dl 0
loc 316
rs 5.5199
wmc 56

15 Methods

Rating   Name   Duplication   Size   Complexity  
A iss() 0 17 5
A payload() 0 14 3
A header() 0 8 4
A signature() 0 23 6
A nbf() 0 17 5
A exp() 0 14 5
A leeway() 0 3 1
A typ() 0 8 4
B sub() 0 33 8
A isAnonymousScope() 0 3 2
A alg() 0 10 5
A unauthorised() 0 3 1
A iat() 0 17 5
A timestamp() 0 3 1
A getTimestamp() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like jwtValidate often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use jwtValidate, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * ==================================
4
 * Responsible PHP API
5
 * ==================================
6
 *
7
 * @link Git https://github.com/vince-scarpa/responsibleAPI.git
8
 *
9
 * @api Responible API
10
 * @package responsible\core\oauth
11
 *
12
 * @author Vince scarpa <[email protected]>
13
 *
14
 */
15
namespace responsible\core\auth;
16
17
use responsible\core\server;
18
use responsible\core\encoder;
19
use responsible\core\exception;
20
use responsible\core\route;
21
use responsible\core\user;
22
use responsible\core\headers\header;
23
24
class jwtValidate extends jwt
25
{
26
    /**
27
     * [$TIMESTAMP]
28
     * @var int
29
     */
30
    protected static $TIMESTAMP;
31
32
    /**
33
     * [$LEEWAY]
34
     * @var int
35
     */
36
    protected static $LEEWAY = 0;
37
38
    /**
39
     * [$ALGORITHM]
40
     * @var string
41
     */
42
    private static $ALGORITHM;
0 ignored issues
show
introduced by
The private property $ALGORITHM is not used, and could be removed.
Loading history...
43
44
    /**
45
     * [$isPayloadValid Validation placeholders]
46
     * @var array
47
     */
48
    protected static $isPayloadValid = [
49
        "iss" => false,
50
        "sub" => false,
51
        "iat" => false,
52
        "nbf" => false,
53
        "exp" => false,
54
    ];
55
56
    /**
57
     * [unauthorised Set unauthorized headers]
58
     * @throws responsibleException
59
     * @return void
60
     */
61
    private static function unauthorised()
62
    {
63
        (new jwt)->setUnauthorised();
64
        // @codeCoverageIgnoreStart
65
    }
66
    // @codeCoverageIgnoreEnd
67
68
    /**
69
     * [header Validate the header object]
70
     * First segment of the token
71
     * @return bool
72
     */
73
    public static function header(array $headObject = [])
74
    {
75
        if (
76
            empty($headObject) ||
77
            !self::typ($headObject) ||
78
            !self::alg($headObject)
79
        ) {
80
            self::unauthorised();
81
        }
82
    }
83
84
    /**
85
     * [payload Validate the payload object]
86
     * Second segment of the token
87
     * @return boolean
88
     */
89
    public static function payload(array $payloadObject = [])
90
    {
91
        if( self::isAnonymousScope($payloadObject) ) {
92
            return true;
93
        }
94
95
        self::iss($payloadObject);
96
        self::sub($payloadObject);
97
        self::iat($payloadObject);
98
        self::nbf($payloadObject);
99
        self::exp($payloadObject);
100
101
        if ((true === in_array(false, self::$isPayloadValid))) {
102
            self::unauthorised();
103
        }
104
    }
105
106
    /**
107
     * Check if the scope is anonymous
108
     * @return boolean
109
     */
110
    private static function isAnonymousScope($payloadObject)
111
    {
112
        return (isset($payloadObject['scope']) && $payloadObject['scope'] == 'anonymous');
113
    }
114
115
    /**
116
     * [signature - Validate the signature object]
117
     * Third segment of the token
118
     * @return bool
119
     */
120
    public static function signature($jwtHead, $jwtPayload, $signature, $key)
121
    {
122
        if (empty($jwtHead) ||
123
            empty($jwtPayload) ||
124
            empty($signature) ||
125
            empty($key)
126
        ) {
127
            self::unauthorised();
128
        }
129
130
        $cipher = new encoder\cipher;
131
        $algo = parent::getAlgorithm();
132
133
        $hashed = $cipher->encode(
134
            $cipher->hash(
135
                $algo['hash'],
136
                $jwtHead . '.' . $jwtPayload,
137
                $key
138
            )
139
        );
140
141
        if (!$cipher->hashCompare($signature, $hashed)) {
142
            self::unauthorised();
143
        }
144
    }
145
146
    /**
147
     * [typ Issuer claim]
148
     *
149
     * @return bool
150
     */
151
    public static function typ($headObject)
152
    {
153
        if (!isset($headObject['typ']) ||
154
            (isset($headObject['typ']) && empty($headObject))
155
        ) {
156
            return;
157
        }
158
        return true;
159
    }
160
161
    /**
162
     * [alg Issuer claim]
163
     *
164
     * @return bool
165
     */
166
    public static function alg($headObject)
167
    {
168
        if (!isset($headObject['alg']) ||
169
            (isset($headObject['alg']) && empty($headObject)) &&
170
            (self::getAlgorithm()['header'] === $headObject['alg'])
171
        ) {
172
            return;
173
        }
174
175
        return true;
176
    }
177
178
    /**
179
     * [iss Issuer claim]
180
     *
181
     * @return bool
182
     */
183
    public static function iss($payloadObject)
184
    {
185
        if (!isset($payloadObject['iss']) ||
186
            (isset($payloadObject['iss']) && empty($payloadObject))
187
        ) {
188
            return;
189
        }
190
191
        $router = new route\router;
192
        $router->route();
193
194
        if ($payloadObject['iss'] !== $router->getIssuer(true)) {
195
            return;
196
        }
197
198
        self::$isPayloadValid['iss'] = true;
199
        return true;
200
    }
201
202
    /**
203
     * [sub Subject claim]
204
     * The Responsible API uses the "Subject" claim as a placeholder for account Ids
205
     *
206
     * @return bool
207
     */
208
    public static function sub($payloadObject)
209
    {
210
        $server = new server([], parent::$options);
211
        if ($server->isMockTest()) {
212
            return self::$isPayloadValid['sub'] = true;
213
        }
214
215
        // @codeCoverageIgnoreStart
216
        if (!isset($payloadObject['sub']) ||
217
            (isset($payloadObject['sub']) && empty($payloadObject))
218
        ) {
219
            return;
220
        }
221
222
        $account = (object) (new user\user)
223
            ->setOptions(parent::$options)
224
            ->load($payloadObject['sub'], ['refreshToken' => false])
225
        ;
226
227
        if (empty($account)) {
228
            return;
229
        } else {
230
            if (!isset($account->account_id)) {
231
                return;
232
            }
233
234
            if ((int) $account->account_id !== (int) $payloadObject['sub']) {
235
                return;
236
            }
237
        }
238
239
        self::$isPayloadValid['sub'] = true;
240
        return true;
241
        // @codeCoverageIgnoreEnd
242
    }
243
244
    /**
245
     * [iat Issued at claim]
246
     *
247
     * @return bool
248
     */
249
    public static function iat($payloadObject)
250
    {
251
        if (!isset($payloadObject['iat']) ||
252
            (isset($payloadObject['iat']) && empty($payloadObject))
253
        ) {
254
            return;
255
        }
256
257
        if ($payloadObject['iat'] > self::getTimestamp()) {
258
            (new exception\errorException)
259
                ->setOptions(parent::$options)
260
                ->message(self::messages('not_ready'))
261
                ->error('NO_CONTENT');
262
        }
263
264
        self::$isPayloadValid['iat'] = true;
265
        return true;
266
    }
267
268
    /**
269
     * [nbf Not before claim]
270
     *
271
     * @return bool
272
     */
273
    public static function nbf($payloadObject)
274
    {
275
        if (!isset($payloadObject['nbf']) ||
276
            (isset($payloadObject['nbf']) && empty($payloadObject))
277
        ) {
278
            return;
279
        }
280
281
        if ($payloadObject['nbf'] > self::getTimestamp()) {
282
            (new exception\errorException)
283
                ->setOptions(parent::$options)
284
                ->message(self::messages('not_ready'))
285
                ->error('NO_CONTENT');
286
        }
287
288
        self::$isPayloadValid['nbf'] = true;
289
        return true;
290
    }
291
292
    /**
293
     * [exp Expiration claim this optional so if its not set return true]
294
     *
295
     * @return bool
296
     */
297
    public static function exp($payloadObject)
298
    {
299
        if (!isset($payloadObject['exp']) ||
300
            (isset($payloadObject['exp']) && empty($payloadObject))
301
        ) {
302
            return;
303
        }
304
305
        if ($payloadObject['exp'] <= (int) (self::$TIMESTAMP - self::$LEEWAY)) {
306
            self::unauthorised();
307
        }
308
309
        self::$isPayloadValid['exp'] = true;
310
        return true;
311
    }
312
313
    /**
314
     * [leeway Inherit the leeway offset]
315
     * @param  int $leeway [integer in seconds]
316
     * @return void
317
     */
318
    public static function leeway($leeway)
319
    {
320
        self::$LEEWAY = $leeway;
321
    }
322
323
    /**
324
     * [timestamp Inherit the current timestamp (now)]
325
     * @param  int $timestamp [integer in seconds]
326
     * @return void
327
     */
328
    public static function timestamp($timestamp)
329
    {
330
        self::$TIMESTAMP = $timestamp;
331
    }
332
333
    /**
334
     * [getTimestamp Add both the timestamp (now) and the leeway]
335
     * @return int
336
     */
337
    private static function getTimestamp()
338
    {
339
        return (int) (self::$TIMESTAMP + self::$LEEWAY);
340
    }
341
}
342