Completed
Push — master ( cd6aa3...db07f0 )
by Jitendra
13s
created

Cors::before()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 2
1
<?php
2
3
namespace PhalconExt\Http\Middleware;
4
5
use Phalcon\Http\Request;
1 ignored issue
show
Bug introduced by
The type Phalcon\Http\Request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Phalcon\Http\Response;
1 ignored issue
show
Bug introduced by
The type Phalcon\Http\Response was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use PhalconExt\Http\BaseMiddleware;
8
9
class Cors extends BaseMiddleware
10
{
11
    /** @var string */
12
    protected $origin;
13
14
    protected $configKey = 'cors';
15
16
    /**
17
     * Handle the cors.
18
     *
19
     * @param Request  $request
20
     * @param Response $response
21
     *
22
     * @return bool
23
     */
24
    public function before(Request $request, Response $response): bool
25
    {
26
        $this->origin = $request->getHeader('Origin');
27
28
        if (!$this->isApplicable($request)) {
29
            return true;
30
        }
31
32
        if ($this->canPreflight($request)) {
33
            return $this->preflight($request, $response);
34
        }
35
36
        return $this->serve($response);
37
    }
38
39
    /**
40
     * If cors is applicable for this request.
41
     *
42
     * Not applicable if origin is empty or same as current host.
43
     *
44
     * @param Request $request
45
     *
46
     * @return bool
47
     */
48
    protected function isApplicable(Request $request): bool
49
    {
50
        if (empty($this->origin)) {
51
            return false;
52
        }
53
54
        return $this->origin !== $request->getScheme() . '://' . $request->getHttpHost();
55
    }
56
57
    /**
58
     * Check if request can be served as preflight.
59
     *
60
     * @param Request $request
61
     *
62
     * @return bool
63
     */
64
    protected function canPreflight(Request $request) : bool
65
    {
66
        if (empty($request->getHeader('Access-Control-Request-Method')) ||
67
            $request->getMethod() !== 'OPTIONS'
68
        ) {
69
            return false;
70
        }
71
72
        return true;
73
    }
74
75
    /**
76
     * Handle preflight.
77
     *
78
     * @param Request  $request
79
     * @param Response $response
80
     *
81
     * @return bool
82
     */
83
    protected function preflight(Request $request, Response $response): bool
84
    {
85
        if (!\in_array($request->getHeader('Access-Control-Request-Method'), $this->config['allowedMethods'])) {
86
            return $this->abort(405);
87
        }
88
89
        if (!$this->areHeadersAllowed($request->getHeader('Access-Control-Request-Headers'))) {
90
            return $this->abort(403);
91
        }
92
93
        $this->disableView();
94
95
        $response
96
            ->setHeader('Access-Control-Allow-Origin', $this->origin)
97
            ->setHeader('Access-Control-Allow-Credentials', 'true')
98
            ->setHeader('Access-Control-Allow-Methods', \implode(', ', $this->config['allowedMethods']))
99
            ->setHeader('Access-Control-Allow-Headers', \implode(', ', $this->config['allowedHeaders']))
100
            ->setHeader('Access-Control-Max-Age', $this->config['maxAge'])
101
            ->setContent('')
102
            ->send();
103
104
        return false;
105
    }
106
107
    /**
108
     * Check if cors headers from client are allowed.
109
     *
110
     * @param string|null $corsRequestHeaders
111
     *
112
     * @return bool
113
     */
114
    protected function areHeadersAllowed(string $corsRequestHeaders = null)
115
    {
116
        if ('' === \trim($corsRequestHeaders)) {
117
            return true;
118
        }
119
120
        // Normalize request headers for comparison.
121
        $corsRequestHeaders = \array_map(
122
            'strtolower',
123
            \explode(',', \str_replace(' ', '', $corsRequestHeaders))
124
        );
125
126
        return empty(\array_diff($corsRequestHeaders, $this->config['allowedHeaders']));
127
    }
128
129
    /**
130
     * Serve cors headers.
131
     *
132
     * @param Response $response
133
     *
134
     * @return bool
135
     */
136
    public function serve(Response $response): bool
137
    {
138
        if (!$this->isOriginAllowed()) {
139
            return $this->abort(403);
140
        }
141
142
        $response
143
            ->setHeader('Access-Control-Allow-Origin', $this->origin)
144
            ->setHeader('Access-Control-Allow-Credentials', 'true');
145
146
        // Optionally set expose headers.
147
        if ($this->config['exposedHeaders'] ?? null) {
148
            $response->setHeader('Access-Control-Expose-Headers', \implode(', ', $this->config['exposedHeaders']));
149
        }
150
151
        return true;
152
    }
153
154
    /**
155
     * If origin is white listed.
156
     *
157
     * @return bool
158
     */
159
    protected function isOriginAllowed(): bool
160
    {
161
        if (\in_array('*', $this->config['allowedOrigins'])) {
162
            return true;
163
        }
164
165
        return \in_array($this->origin, $this->config['allowedOrigins']);
166
    }
167
}
168