| 
							- <?php
 - 
 - namespace dokuwiki\Remote;
 - 
 - /**
 -  * Provide the Remote XMLRPC API as a JSON based API
 -  */
 - class JsonRpcServer
 - {
 -     protected $remote;
 - 
 -     /** @var float The XML-RPC Version. 0 is our own simplified variant */
 -     protected $version = 0;
 - 
 -     /**
 -      * JsonRpcServer constructor.
 -      */
 -     public function __construct()
 -     {
 -         $this->remote = new Api();
 -     }
 - 
 -     /**
 -      * Serve the request
 -      *
 -      * @param string $body Should only be set for testing, otherwise the request body is read from php://input
 -      * @return mixed
 -      * @throws RemoteException
 -      */
 -     public function serve($body = '')
 -     {
 -         global $conf;
 -         global $INPUT;
 - 
 -         if (!$conf['remote']) {
 -             http_status(404);
 -             throw new RemoteException("JSON-RPC server not enabled.", -32605);
 -         }
 -         if (!empty($conf['remotecors'])) {
 -             header('Access-Control-Allow-Origin: ' . $conf['remotecors']);
 -         }
 -         if ($INPUT->server->str('REQUEST_METHOD') !== 'POST') {
 -             http_status(405);
 -             header('Allow: POST');
 -             throw new RemoteException("JSON-RPC server only accepts POST requests.", -32606);
 -         }
 -         if ($INPUT->server->str('CONTENT_TYPE') !== 'application/json') {
 -             http_status(415);
 -             throw new RemoteException("JSON-RPC server only accepts application/json requests.", -32606);
 -         }
 - 
 -         try {
 -             if ($body === '') {
 -                 $body = file_get_contents('php://input');
 -             }
 -             if ($body !== '') {
 -                 $data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
 -             } else {
 -                 $data = [];
 -             }
 -         } catch (\Exception $e) {
 -             http_status(400);
 -             throw new RemoteException("JSON-RPC server only accepts valid JSON.", -32700);
 -         }
 - 
 -         return $this->createResponse($data);
 -     }
 - 
 -     /**
 -      * This executes the method and returns the result
 -      *
 -      * This should handle all JSON-RPC versions and our simplified version
 -      *
 -      * @link https://en.wikipedia.org/wiki/JSON-RPC
 -      * @link https://www.jsonrpc.org/specification
 -      * @param array $data
 -      * @return array
 -      * @throws RemoteException
 -      */
 -     protected function createResponse($data)
 -     {
 -         global $INPUT;
 -         $return = [];
 - 
 -         if (isset($data['method'])) {
 -             // this is a standard conform request (at least version 1.0)
 -             $method = $data['method'];
 -             $params = $data['params'] ?? [];
 -             $this->version = 1;
 - 
 -             // always return the same ID
 -             if (isset($data['id'])) $return['id'] = $data['id'];
 - 
 -             // version 2.0 request
 -             if (isset($data['jsonrpc'])) {
 -                 $return['jsonrpc'] = $data['jsonrpc'];
 -                 $this->version = (float)$data['jsonrpc'];
 -             }
 - 
 -             // version 1.1 request
 -             if (isset($data['version'])) {
 -                 $return['version'] = $data['version'];
 -                 $this->version = (float)$data['version'];
 -             }
 -         } else {
 -             // this is a simplified request
 -             $method = $INPUT->server->str('PATH_INFO');
 -             $method = trim($method, '/');
 -             $params = $data;
 -             $this->version = 0;
 -         }
 - 
 -         // excute the method
 -         $return['result'] = $this->call($method, $params);
 -         $this->addErrorData($return); // handles non-error info
 -         return $return;
 -     }
 - 
 -     /**
 -      * Create an error response
 -      *
 -      * @param \Exception $exception
 -      * @return array
 -      */
 -     public function returnError($exception)
 -     {
 -         $return = [];
 -         $this->addErrorData($return, $exception);
 -         return $return;
 -     }
 - 
 -     /**
 -      * Depending on the requested version, add error data to the response
 -      *
 -      * @param array $response
 -      * @param \Exception|null $e
 -      * @return void
 -      */
 -     protected function addErrorData(&$response, $e = null)
 -     {
 -         if ($e !== null) {
 -             // error occured, add to response
 -             $response['error'] = [
 -                 'code' => $e->getCode(),
 -                 'message' => $e->getMessage()
 -             ];
 -         } else {
 -             // no error, act according to version
 -             if ($this->version > 0 && $this->version < 2) {
 -                 // version 1.* wants null
 -                 $response['error'] = null;
 -             } elseif ($this->version < 1) {
 -                 // simplified version wants success
 -                 $response['error'] = [
 -                     'code' => 0,
 -                     'message' => 'success'
 -                 ];
 -             }
 -             // version 2 wants no error at all
 -         }
 -     }
 - 
 -     /**
 -      * Call an API method
 -      *
 -      * @param string $methodname
 -      * @param array $args
 -      * @return mixed
 -      * @throws RemoteException
 -      */
 -     public function call($methodname, $args)
 -     {
 -         try {
 -             return $this->remote->call($methodname, $args);
 -         } catch (AccessDeniedException $e) {
 -             if (!isset($_SERVER['REMOTE_USER'])) {
 -                 http_status(401);
 -                 throw new RemoteException("server error. not authorized to call method $methodname", -32603);
 -             } else {
 -                 http_status(403);
 -                 throw new RemoteException("server error. forbidden to call the method $methodname", -32604);
 -             }
 -         } catch (RemoteException $e) {
 -             http_status(400);
 -             throw $e;
 -         }
 -     }
 - }
 
 
  |