JWTHelper::qsh()   B
last analyzed

Complexity

Conditions 4
Paths 2

Size

Total Lines 36
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 23
nc 2
nop 2
dl 0
loc 36
rs 8.5806
c 0
b 0
f 0
1
<?php
2
3
namespace AtlassianConnectCore\Helpers;
4
5
/**
6
 * Class JWTHelper
7
 *
8
 * @package AtlassianConnectCore\Helpers
9
 */
10
class JWTHelper
11
{
12
    /**
13
     * Decode JWT token
14
     *
15
     * @param string $token
16
     *
17
     * @return array|null
18
     */
19
    public static function decode($token)
20
    {
21
        $parts = explode('.', $token);
22
23
        if(count($parts) !== 3) {
24
            return null;
25
        }
26
27
        return [
28
            'header' => json_decode(base64_decode($parts[0]), true),
29
            'body' => json_decode(base64_decode($parts[1]), true),
30
            'signature' => $parts[2]
31
        ];
32
    }
33
34
    /**
35
     * Create JWT token used by Atlassian REST API request
36
     *
37
     * @param string $url URL of the request
38
     * @param string $method HTTP method
39
     * @param string $addOnKey Key of the add-on
40
     * @param string $secret Shared secret of the Tenant
41
     *
42
     * @return string
43
     */
44
    public static function create($url, $method, $addOnKey, $secret)
45
    {
46
        $payload = [
47
            'iss' => $addOnKey,
48
            'iat' => time(),
49
            'exp' => time() + 86400,
50
            'qsh' => static::qsh($url, $method)
51
        ];
52
53
        return \Firebase\JWT\JWT::encode($payload, $secret);
54
    }
55
56
    /**
57
     * Create Query String Hash
58
     *
59
     * More details:
60
     * https://developer.atlassian.com/static/connect/docs/latest/concepts/understanding-jwt.html#creating-token
61
     *
62
     * @param string $url URL of the request
63
     * @param string $method HTTP method
64
     *
65
     * @return string
66
     */
67
    public static function qsh($url, $method)
68
    {
69
        $method = strtoupper($method);
70
        $parts = parse_url($url);
71
        $path = $parts['path'];
72
73
        $canonicalQuery = '';
74
75
        if (!empty($parts['query'])) {
76
            $query = $parts['query'];
77
            $queryParts = explode('&', $query);
78
            $queryArray = [];
79
80
            foreach ($queryParts as $queryPart) {
81
                $pieces = explode('=', $queryPart);
82
                $key = array_shift($pieces);
83
                $key = rawurlencode($key);
84
                $value = substr($queryPart, strlen($key) + 1);
85
                $value = rawurlencode($value);
86
                $queryArray[$key][] = $value;
87
            }
88
89
            ksort($queryArray);
90
91
            foreach ($queryArray as $key => $pieceOfQuery) {
92
                $pieceOfQuery = implode(',', $pieceOfQuery);
93
                $canonicalQuery .= $key . '=' . $pieceOfQuery . '&';
94
            }
95
96
            $canonicalQuery = rtrim($canonicalQuery, '&');
97
        }
98
99
        $qshString = implode('&', [$method, $path, $canonicalQuery]);
100
        $qsh = hash('sha256', $qshString);
101
102
        return $qsh;
103
    }
104
}