Authentication::getPublicRoutesByMethod()   A
last analyzed

Complexity

Conditions 2
Paths 1

Size

Total Lines 16
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 1
nop 1
dl 0
loc 16
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Controlabs\Handler\Slim;
4
5
use Controlabs\Http\Exception\Unauthorized;
6
use Slim\Http\Request;
7
use Slim\Http\Response;
8
use Controlabs\Helper\JWT as JWTHelper;
9
10
class Authentication
11
{
12
    private $jwtHelper;
13
    private $public;
14
15
    public function __construct(JWTHelper $jwtHelper, array $public = [])
16
    {
17
        $this->jwtHelper = $jwtHelper;
18
        $this->public = $public;
19
    }
20
21
    public function __invoke(Request $request, Response $response, $next)
22
    {
23
        try {
24
            $token = $this->token($request);
25
            $payload = $this->decodeToken($token);
26
27
            unset($payload['iss']);
28
            unset($payload['aud']);
29
            unset($payload['sub']);
30
            unset($payload['exp']);
31
32
            $request = $request->withAttributes($payload);
33
        } catch (Unauthorized $exception) {
34
            $this->handleException($request, $exception);
35
        }
36
37
        return $next($request, $response);
38
    }
39
40
    protected function token(Request $request)
41
    {
42
        $token = $request->getHeader('Authorization')[0] ?? null;
43
44
        if (!$token) {
45
            throw new Unauthorized();
46
        }
47
48
        return $token;
49
    }
50
51
    protected function decodeToken($token)
52
    {
53
        $payload = $this->jwtHelper->decode($token, true);
54
55
        if (!$payload) {
56
            throw new Unauthorized();
57
        }
58
59
        return $payload;
60
    }
61
62
    protected function handleException(Request $request, Unauthorized $unauthorized)
63
    {
64
        if (!$this->isPublic($request)) {
65
            throw $unauthorized;
66
        }
67
    }
68
69
    protected function isPublic(Request $request)
70
    {
71
        $route = $this->route($request);
72
73
        $patterns = $this->getPublicRoutesByMethod($request->getMethod());
74
75
        foreach ($patterns as $pattern) {
76
            if ($this->match($pattern, $route)) {
77
                return true;
78
            }
79
        }
80
81
        return false;
82
    }
83
84
    protected function route(Request $request)
85
    {
86
        $route = $request->getAttribute('route');
87
88
        if (!$route) {
89
            return '';
90
        }
91
92
        return $route->getPattern();
93
    }
94
95
    protected function getPublicRoutesByMethod($method)
96
    {
97
        /*
98
         * 0 - Method
99
         * 1 - Pattern
100
         */
101
102
        $map = function (array $public) use ($method) {
103
            return $this->match($public[0], $method) ? $public[1] : '';
104
        };
105
106
        $patterns = array_map($map, $this->public);
107
        $patterns = array_filter($patterns);
108
        $patterns = array_values($patterns);
109
110
        return $patterns;
111
    }
112
113
    protected function match($pattern, $str)
114
    {
115
        $pattern = str_replace("/", "\/", $pattern);
116
        $pattern = "/{$pattern}/";
117
118
        try {
119
            return !!preg_match($pattern, $str);
120
        } catch (\Exception $exception) {
121
            throw new \Exception('Invalid RegExp: ' . $pattern, 0, $exception);
122
        }
123
    }
124
}
125