| 
									
										
										
										
											2022-06-23 09:33:43 +02:00
										 |  |  | <?php | 
					
						
							| 
									
										
										
										
											2022-10-16 19:29:53 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * AcceptHeaders.php | 
					
						
							|  |  |  |  * Copyright (c) 2022 james@firefly-iii.org | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file is part of Firefly III (https://github.com/firefly-iii). | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU Affero General Public License as | 
					
						
							|  |  |  |  * published by the Free Software Foundation, either version 3 of the | 
					
						
							|  |  |  |  * License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU Affero General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  |  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-16 09:25:10 +02:00
										 |  |  | declare(strict_types=1); | 
					
						
							| 
									
										
										
										
											2022-06-23 09:33:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace FireflyIII\Http\Middleware; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use FireflyIII\Exceptions\BadHttpHeaderException; | 
					
						
							|  |  |  | use Illuminate\Http\Request; | 
					
						
							|  |  |  | use Illuminate\Http\Response; | 
					
						
							|  |  |  | use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-24 06:24:17 +02:00
										 |  |  | use function Safe\preg_match; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-23 09:33:43 +02:00
										 |  |  | class AcceptHeaders | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Handle the incoming requests. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return Response | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2022-06-23 09:33:43 +02:00
										 |  |  |      * @throws BadHttpHeaderException | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-06-04 06:30:22 +02:00
										 |  |  |     public function handle(Request $request, callable $next): mixed | 
					
						
							| 
									
										
										
										
											2022-06-23 09:33:43 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-10 19:56:38 +01:00
										 |  |  |         $method       = $request->getMethod(); | 
					
						
							| 
									
										
										
										
											2023-04-06 15:07:35 +08:00
										 |  |  |         $accepts      = ['application/x-www-form-urlencoded', 'application/json', 'application/vnd.api+json', 'application/octet-stream', '*/*']; | 
					
						
							|  |  |  |         $contentTypes = ['application/x-www-form-urlencoded', 'application/json', 'application/vnd.api+json', 'application/octet-stream']; | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |         $submitted    = (string) $request->header('Content-Type'); | 
					
						
							| 
									
										
										
										
											2022-06-23 09:33:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 19:56:38 +01:00
										 |  |  |         // if bad Accept header, send error.
 | 
					
						
							|  |  |  |         if (!$request->accepts($accepts)) { | 
					
						
							|  |  |  |             throw new BadHttpHeaderException(sprintf('Accept header "%s" is not something this server can provide.', $request->header('Accept'))); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // if bad 'Content-Type' header, refuse service.
 | 
					
						
							| 
									
										
										
										
											2025-03-09 10:35:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // some routes are exempt from this.
 | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $exempt       = [ | 
					
						
							|  |  |  |             'api.v1.data.bulk.transactions', | 
					
						
							| 
									
										
										
										
											2025-03-09 10:35:12 +01:00
										 |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (('POST' === $method || 'PUT' === $method) && !$request->hasHeader('Content-Type') && !in_array($request->route()->getName(), $exempt, true)) { | 
					
						
							| 
									
										
										
										
											2023-03-05 17:07:27 +01:00
										 |  |  |             $error             = new BadHttpHeaderException('Content-Type header cannot be empty.'); | 
					
						
							| 
									
										
										
										
											2023-01-10 19:56:38 +01:00
										 |  |  |             $error->statusCode = 415; | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 19:56:38 +01:00
										 |  |  |             throw $error; | 
					
						
							| 
									
										
										
										
											2022-06-23 09:33:43 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-03-09 10:35:12 +01:00
										 |  |  |         if (('POST' === $method || 'PUT' === $method) && !$this->acceptsHeader($submitted, $contentTypes) && !in_array($request->route()->getName(), $exempt, true)) { | 
					
						
							| 
									
										
										
										
											2022-11-06 18:14:21 +01:00
										 |  |  |             $error             = new BadHttpHeaderException(sprintf('Content-Type cannot be "%s"', $submitted)); | 
					
						
							| 
									
										
										
										
											2022-06-23 09:33:43 +02:00
										 |  |  |             $error->statusCode = 415; | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-23 09:33:43 +02:00
										 |  |  |             throw $error; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // throw bad request if trace id is not a UUID
 | 
					
						
							| 
									
										
										
										
											2024-01-01 14:43:56 +01:00
										 |  |  |         $uuid         = $request->header('X-Trace-Id'); | 
					
						
							| 
									
										
										
										
											2025-05-24 05:40:20 +02:00
										 |  |  |         if (is_string($uuid) && '' !== trim($uuid) && (1 !== preg_match('/^[a-f\d]{8}(-[a-f\d]{4}){4}[a-f\d]{8}$/i', trim($uuid)))) { | 
					
						
							| 
									
										
										
										
											2022-06-23 09:33:43 +02:00
										 |  |  |             throw new BadRequestHttpException('Bad X-Trace-Id header.'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $next($request); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-05 17:07:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private function acceptsHeader(string $content, array $accepted): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (str_contains($content, ';')) { | 
					
						
							|  |  |  |             $content = trim(explode(';', $content)[0]); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-05 17:07:27 +01:00
										 |  |  |         return in_array($content, $accepted, true); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-07-16 09:25:10 +02:00
										 |  |  | } |