1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Longman\LaravelLodash\Middlewares; |
6
|
|
|
|
7
|
|
|
use Closure; |
8
|
|
|
use Illuminate\Http\Request; |
9
|
|
|
use Illuminate\Support\Str; |
10
|
|
|
use Psr\Log\LoggerInterface; |
11
|
|
|
use Symfony\Component\HttpFoundation\Response; |
12
|
|
|
|
13
|
|
|
use function implode; |
14
|
|
|
use function parse_url; |
15
|
|
|
use function str_replace; |
16
|
|
|
use function strpos; |
17
|
|
|
use function strtok; |
18
|
|
|
|
19
|
|
|
use const PHP_URL_HOST; |
20
|
|
|
|
21
|
|
|
class AllowCorsRequests |
22
|
|
|
{ |
23
|
|
|
protected $logger; |
24
|
|
|
|
25
|
5 |
|
public function __construct(LoggerInterface $logger) |
26
|
|
|
{ |
27
|
5 |
|
$this->logger = $logger; |
28
|
5 |
|
} |
29
|
|
|
|
30
|
5 |
|
public function handle(Request $request, Closure $next) |
31
|
|
|
{ |
32
|
5 |
|
if (! $request->headers->has('Origin')) { |
33
|
1 |
|
return $next($request); |
34
|
|
|
} |
35
|
|
|
|
36
|
4 |
|
$origin = $request->headers->get('Origin', ''); |
37
|
4 |
|
$host = $this->parseUrl($origin); |
38
|
4 |
View Code Duplication |
if (empty($host)) { |
|
|
|
|
39
|
1 |
|
$this->logRequest('Origin is invalid', [ |
40
|
1 |
|
'origin' => $origin, |
41
|
1 |
|
'parsed' => $host, |
42
|
|
|
]); |
43
|
|
|
|
44
|
1 |
|
return $this->response($request, 'Origin is invalid', Response::HTTP_BAD_REQUEST); |
45
|
|
|
} |
46
|
|
|
|
47
|
4 |
|
$allowedOrigins = config('lodash.cors.allow_origins', []); |
48
|
4 |
|
$currentApp = $this->parseUrl((string) config('app.url', '')); |
49
|
4 |
|
if (! empty($host)) { |
50
|
4 |
|
$allowedOrigins[] = $currentApp; |
51
|
|
|
} |
52
|
|
|
|
53
|
4 |
|
$found = false; |
54
|
4 |
|
foreach ($allowedOrigins as $allowedOrigin) { |
55
|
4 |
|
if ($host === $allowedOrigin || Str::endsWith($host, '.' . $allowedOrigin)) { |
56
|
3 |
|
$found = true; |
57
|
3 |
|
break; |
58
|
|
|
} |
59
|
|
|
} |
60
|
|
|
|
61
|
4 |
View Code Duplication |
if (! $found) { |
|
|
|
|
62
|
1 |
|
$this->logRequest('Origin is not allowed', [ |
63
|
1 |
|
'origin' => $origin, |
64
|
1 |
|
'parsed' => $host, |
65
|
|
|
]); |
66
|
|
|
|
67
|
1 |
|
return $this->response($request, 'Origin is not allowed', Response::HTTP_METHOD_NOT_ALLOWED); |
68
|
|
|
} |
69
|
|
|
|
70
|
3 |
|
if ($request->method() === Request::METHOD_OPTIONS) { |
71
|
1 |
|
$allowedHeaders = config('lodash.cors.allow_headers', []); |
72
|
1 |
|
$allowedMethods = config('lodash.cors.allow_methods', []); |
73
|
|
|
|
74
|
1 |
|
$response = $this->response($request, 'Allowed', Response::HTTP_OK); |
75
|
|
|
|
76
|
1 |
|
$response->headers->set('Access-Control-Allow-Origin', $origin); |
77
|
1 |
|
$response->headers->set('Access-Control-Allow-Credentials', 'true'); |
78
|
|
|
|
79
|
1 |
|
$response->headers->set('Access-Control-Allow-Methods', implode(',', $allowedMethods)); |
80
|
1 |
|
$response->headers->set('Access-Control-Allow-Headers', implode(',', $allowedHeaders)); |
81
|
1 |
|
$response->headers->set('Access-Control-Max-Age', '1728000'); |
82
|
|
|
|
83
|
1 |
|
return $response; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** @var \Illuminate\Http\Response $response */ |
87
|
2 |
|
$response = $next($request); |
88
|
|
|
|
89
|
2 |
|
$response->headers->set('Access-Control-Allow-Origin', $origin); |
90
|
2 |
|
$response->headers->set('Access-Control-Allow-Credentials', 'true'); |
91
|
|
|
|
92
|
2 |
|
return $response; |
93
|
|
|
} |
94
|
|
|
|
95
|
1 |
|
protected function logRequest(string $message, array $context = []): void |
96
|
|
|
{ |
97
|
1 |
|
$this->logger->warning($message, $context); |
98
|
1 |
|
} |
99
|
|
|
|
100
|
4 |
|
protected function parseUrl(string $url): string |
101
|
|
|
{ |
102
|
4 |
|
$host = (string) parse_url($url, PHP_URL_HOST); |
103
|
|
|
|
104
|
4 |
|
if (Str::startsWith($host, 'www.')) { |
105
|
|
|
$host = str_replace('www.', '', $host); |
106
|
|
|
} |
107
|
|
|
|
108
|
4 |
|
if (strpos($host, ':') !== false) { |
109
|
|
|
$host = strtok($host, ':'); |
110
|
|
|
} |
111
|
|
|
|
112
|
4 |
|
return $host; |
113
|
|
|
} |
114
|
|
|
|
115
|
2 |
|
protected function response(Request $request, string $message, int $code): Response |
116
|
|
|
{ |
117
|
2 |
|
if ($request->wantsJson()) { |
118
|
|
|
return response()->json(['message' => $message], $code); |
|
|
|
|
119
|
|
|
} |
120
|
|
|
|
121
|
2 |
|
return response($message, $code); |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.