| 
									
										
										
										
											2024-03-10 20:22:28 +01:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace NoccyLabs\Mercureact\Http\Middleware; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use NoccyLabs\Mercureact\Configuration; | 
					
						
							| 
									
										
										
										
											2024-03-12 02:21:42 +01:00
										 |  |  | use NoccyLabs\Mercureact\Exception\SecurityException; | 
					
						
							| 
									
										
										
										
											2024-03-10 20:22:28 +01:00
										 |  |  | use Psr\Http\Message\ResponseInterface; | 
					
						
							|  |  |  | use Psr\Http\Message\ServerRequestInterface; | 
					
						
							| 
									
										
										
										
											2024-03-11 01:20:45 +01:00
										 |  |  | use Psr\Log\LoggerInterface; | 
					
						
							| 
									
										
										
										
											2024-03-10 20:22:28 +01:00
										 |  |  | use React\Http\Message\Response; | 
					
						
							|  |  |  | use React\Promise\Promise; | 
					
						
							|  |  |  | use React\Promise\PromiseInterface; | 
					
						
							|  |  |  | use Throwable; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ResponseMiddleware | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function __construct( | 
					
						
							| 
									
										
										
										
											2024-03-11 01:20:45 +01:00
										 |  |  |         private Configuration $config, | 
					
						
							|  |  |  |         private LoggerInterface $logger, | 
					
						
							| 
									
										
										
										
											2024-03-10 20:22:28 +01:00
										 |  |  |     ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Wraps rejections into error messages, and also does some sanity checks on the returned | 
					
						
							|  |  |  |      * data, making sure it is a response. | 
					
						
							|  |  |  |      *  | 
					
						
							|  |  |  |      * @param ServerRequestInterface $request | 
					
						
							|  |  |  |      * @param callable $next | 
					
						
							|  |  |  |      * @return PromiseInterface | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function __invoke(ServerRequestInterface $request, callable $next): PromiseInterface | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $promise = new Promise( | 
					
						
							|  |  |  |             function (callable $resolve) use ($request, $next) { | 
					
						
							|  |  |  |                 $resolve($next($request)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         return $promise->then( | 
					
						
							|  |  |  |             function ($response) { | 
					
						
							|  |  |  |                 if ($response instanceof ResponseInterface) { | 
					
						
							|  |  |  |                     return $response; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (is_array($response)) { | 
					
						
							|  |  |  |                     return Response::json($response); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (is_string($response)) { | 
					
						
							|  |  |  |                     return Response::plaintext($response); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return Response::plaintext((string)$response); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             function (Throwable $t) { | 
					
						
							|  |  |  |                 if ($t instanceof SecurityException) { | 
					
						
							|  |  |  |                     return Response::plaintext("Access Denied")->withStatus(Response::STATUS_UNAUTHORIZED); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2024-03-11 01:40:05 +01:00
										 |  |  |                 $this->logger->warning(get_class($t).": ".$t->getMessage(), [ 'file'=>$t->getFile(), 'line'=>$t->getLine() ]); | 
					
						
							| 
									
										
										
										
											2024-03-10 20:22:28 +01:00
										 |  |  |                 return Response::plaintext("500: Internal Server Error (".$t->getMessage().")\n")->withStatus(500); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         )->then( | 
					
						
							|  |  |  |             function ($response) use ($request) { | 
					
						
							|  |  |  |                 assert("\$response instanceof ResponseInterface"); | 
					
						
							|  |  |  |                 $host = ($request->getServerParams()['SERVER_ADDR']??""); | 
					
						
							|  |  |  |                         //. ":" . ($request->getServerParams()['SERVER_PORT']??"80");
 | 
					
						
							| 
									
										
										
										
											2024-03-11 01:20:45 +01:00
										 |  |  |                 $this->logger->debug(sprintf("%s %s %s → %3d (%d)",  | 
					
						
							| 
									
										
										
										
											2024-03-10 20:22:28 +01:00
										 |  |  |                     $request->getServerParams()['REMOTE_ADDR'],  | 
					
						
							|  |  |  |                     $request->getMethod(),  | 
					
						
							|  |  |  |                     $request->getUri()->getPath(),  | 
					
						
							| 
									
										
										
										
											2024-03-11 01:20:45 +01:00
										 |  |  |                     $response->getStatusCode(),  | 
					
						
							| 
									
										
										
										
											2024-03-10 20:22:28 +01:00
										 |  |  |                     strlen($response->getBody()) | 
					
						
							| 
									
										
										
										
											2024-03-11 01:20:45 +01:00
										 |  |  |                 ), [ | 
					
						
							|  |  |  |                     'remote' => $request->getServerParams()['REMOTE_ADDR'],  | 
					
						
							|  |  |  |                     'status' => $response->getStatusCode(),  | 
					
						
							|  |  |  |                     'method' => $request->getMethod(),  | 
					
						
							|  |  |  |                     'path' => $request->getUri()->getPath(),  | 
					
						
							|  |  |  |                 ]); | 
					
						
							| 
									
										
										
										
											2024-03-13 01:28:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 20:22:28 +01:00
										 |  |  |                 return $response | 
					
						
							| 
									
										
										
										
											2024-03-11 00:36:34 +01:00
										 |  |  |                     // ->withAddedHeader('Link', '<https://'.$host.'/.well-known/mercure>; rel="mercure"')
 | 
					
						
							|  |  |  |                     // ->withAddedHeader('Link', '<wss://'.$host.'/.well-known/mercure>; rel="mercure+ws"')
 | 
					
						
							| 
									
										
										
										
											2024-03-13 01:28:14 +01:00
										 |  |  |                     ->withHeader('Access-Control-Allow-Origin',  | 
					
						
							|  |  |  |                         $this->config->get('server.cors.allow_origin', '*')) | 
					
						
							|  |  |  |                     ->withHeader('Content-Security-Policy',  | 
					
						
							|  |  |  |                         $this->config->get('server.cors.csp', "default-src * 'self' http: 'unsafe-eval' 'unsafe-inline'; connect-src * 'self'")) | 
					
						
							| 
									
										
										
										
											2024-03-10 20:22:28 +01:00
										 |  |  |                     ->withHeader('Cache-Control', 'must-revalidate') | 
					
						
							|  |  |  |                     ->withHeader('Server', 'Mercureact/0.1.0'); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |