<?php
// HttpRequestHandler.php
// Copyright P.Kassel, M.Seliger, G.Trietsch, all Rights Reserved
namespace Docuform\Api;use Docuform\Api\Exception\ApiHttpException;use Docuform\Api\Exception\ApiHttpForbiddenException;use Docuform\Api\Exception\ApiHttpInvalidScopeException;use Docuform\Api\Exception\ApiHttpInvalidUserException;use Docuform\Database\DbException;use DI\Container;use Psr\Http\Message\ResponseInterface;use Psr\Http\Message\ServerRequestInterface;use function explode;abstract class HttpRequestHandler{private $m_container;public function __construct($container){$this->m_container=$container;}public static function onRequest(Container $container,string $handlerName,ServerRequestInterface $request,ResponseInterface $response,array $args):ResponseInterface{$code=500;$restApi=$container->get('RestApi');$cfactory=$container->get('classfactory');$handler=$cfactory->Create($handlerName);if($handler!==null){if($restApi->checkToken($request)){try{if($handler->checkUserType($request)){if($handler->checkScopes($request,$handlerName)){if($restApi->checkRouteArguments($request)){$code=$handler->handleRequest($request,$response,$args);self::checkDestroySession($container,$request,$response,$code);}}}}catch(DbException $e){throw new ApiHttpException($request,500,'Database exception',$e->getMessage());}}else{$code=403;}}$header=$response->getHeader('Content-Type');if(empty($header)||count($header)===0){$response=$response->withHeader('Content-Type','application/json');}return $response->withStatus($code);}private static function checkDestroySession(Container $container,ServerRequestInterface $request,ResponseInterface $response,int $code){$responseRedirectUri='';$restApi=$container->get('RestApi');if($restApi->getApiName()==='auth'){try{$redirectUri=$container->get('redirect_uri');}catch(\Exception $e){$redirectUri='';}if($code===302&&$response->hasHeader('Location')){$location=$response->getHeader('Location');$location=$location[0]?? '';$responseRedirectUri=strtok($location,'?');}if(($code!==302||(!empty($redirectUri)&&$redirectUri===$responseRedirectUri))&&($code!==200||strpos($request->getUri(),'auth/v2/authorize')!==false||strpos($request->getUri(),'auth/v2/token')!==false)){try{$session=$container->get('session');if(!empty($session)){$container->set('session',null);$session::destroy();}}catch(\Exception $e){}}}}private function checkScopes($request,$handlerName):bool{$result=false;$restApi=$this->m_container->get('RestApi');if($restApi->getApiName()!=='auth'){$requiredScopes=$this->getRequiredScopes($request);$methodScopes=$restApi->getRequiredMethodScopes($request->getMethod(),$handlerName);$allOfScopes=!empty($requiredScopes['allOf'])?$requiredScopes['allOf']:[];$anyOfScopes=!empty($requiredScopes['anyOf'])?$requiredScopes['anyOf']:[];if(!empty($methodScopes)){foreach($methodScopes as $scope){if(!array_key_exists($scope,$allOfScopes)){$allOfScopes[]=$scope;}}}if(!empty($requiredScopes)&&(count($allOfScopes)>0||count($anyOfScopes)>0)){$tokenData=$request->getAttribute('token_data');if(empty($tokenData['scopes'])){throw new ApiHttpInvalidUserException();}$tokenScopesArray=$tokenData['scopes'];if(!empty($tokenScopesArray)){if(!in_array('admin',$tokenScopesArray,true)){foreach(['server','client']as $scope){if(in_array($scope.'_write',$tokenScopesArray,true)&&!in_array($scope.'_read',$tokenScopesArray,true)){$tokenScopesArray[]=$scope.'_read';}}$scopesIntersect=array_values(array_intersect($tokenScopesArray,$allOfScopes));if(count($allOfScopes)>0){$result=count(array_diff($allOfScopes,$scopesIntersect))===0;}else{$result=true;}if($result===true&&count($anyOfScopes)>0){$scopesIntersect=array_values(array_intersect($tokenScopesArray,$anyOfScopes));$result=count($scopesIntersect)>0;}}else{$result=true;}}}elseif(isset($requiredScopes['allOf'])){$result=true;}if($result!==true){throw new ApiHttpInvalidScopeException($request);}}else{$result=true;}return $result;}private function checkUserType($request):bool{$result=true;if(!empty($this->getAllowedUserTypes($request))){$allowedUserTypesArray=$this->getAllowedUserTypes($request);$user=$this->getContainer()->get('user');if(!in_array($user->userType,$allowedUserTypesArray,true)){$result=false;}}if($result!==true){throw new ApiHttpForbiddenException($request);}return $result;}abstract public function getAllowedUserTypes($request):array;abstract public function getRequiredScopes($request):array;public function getLogger():Logger{return $this->getContainer()->get('logger');}public function getContainer():Container{return $this->m_container;}public function getToken():string{return $this->getContainer()->get('RestApi')->getToken();}abstract public function handleRequest($request,& $response,$arguments):int;}