3 namespace dokuwiki\Remote
;
5 use dokuwiki\Extension\RemotePlugin
;
7 use dokuwiki\test\Remote\Mock\ApiCore
as MockApiCore
;
10 * This class provides information about remote access to the wiki.
12 * == Types of methods ==
13 * There are two types of remote methods. The first is the core methods.
14 * These are always available and provided by dokuwiki.
15 * The other is plugin methods. These are provided by remote plugins.
17 * == Information structure ==
18 * The information about methods will be given in an array with the following structure:
20 * 'method.remoteName' => array(
22 * 'type eg. string|int|...|date|file',
24 * 'name' => 'method name in class',
26 * 'public' => 1/0 - method bypass default group check (used by login)
27 * ['doc' = 'method documentation'],
31 * plugin names are formed the following:
32 * core methods begin by a 'dokuwiki' or 'wiki' followed by a . and the method name itself.
33 * i.e.: dokuwiki.version or wiki.getPage
35 * plugin methods are formed like 'plugin.<plugin name>.<method name>'.
36 * i.e.: plugin.clock.getTime or plugin.clock_gmt.getTime
40 /** @var ApiCall[] core methods provided by dokuwiki */
41 protected $coreMethods;
43 /** @var ApiCall[] remote methods provided by dokuwiki plugins */
44 protected $pluginMethods;
47 * Get all available methods with remote access.
49 * @return ApiCall[] with information to all available methods
51 public function getMethods()
53 return array_merge($this->getCoreMethods(), $this->getPluginMethods());
57 * Collects all the core methods
59 * @param ApiCore|MockApiCore $apiCore this parameter is used for testing.
60 * Here you can pass a non-default RemoteAPICore instance. (for mocking)
61 * @return ApiCall[] all core methods.
63 public function getCoreMethods($apiCore = null)
65 if (!$this->coreMethods
) {
66 if ($apiCore === null) {
67 $this->coreMethods
= (new ApiCore())->getMethods();
69 $this->coreMethods
= $apiCore->getMethods();
72 return $this->coreMethods
;
76 * Collects all the methods of the enabled Remote Plugins
78 * @return ApiCall[] all plugin methods.
80 public function getPluginMethods()
82 if ($this->pluginMethods
) return $this->pluginMethods
;
84 $plugins = plugin_list('remote');
85 foreach ($plugins as $pluginName) {
86 /** @var RemotePlugin $plugin */
87 $plugin = plugin_load('remote', $pluginName);
88 if (!is_subclass_of($plugin, RemotePlugin
::class)) {
89 Logger
::error("Remote Plugin $pluginName does not implement dokuwiki\Extension\RemotePlugin");
94 $methods = $plugin->getMethods();
95 } catch (\ReflectionException
$e) {
97 "Remote Plugin $pluginName failed to return methods",
105 foreach ($methods as $method => $call) {
106 $this->pluginMethods
["plugin.$pluginName.$method"] = $call;
110 return $this->pluginMethods
;
114 * Call a method via remote api.
116 * @param string $method name of the method to call.
117 * @param array $args arguments to pass to the given method
118 * @return mixed result of method call, must be a primitive type.
119 * @throws RemoteException
121 public function call($method, $args = [])
123 if ($args === null) {
128 $this->ensureApiIsEnabled();
129 $methods = $this->getMethods();
130 if (!isset($methods[$method])) {
131 throw new RemoteException('Method does not exist', -32603);
133 $this->ensureAccessIsAllowed($methods[$method]);
135 // invoke the ApiCall
137 return $methods[$method]($args);
138 } catch (\InvalidArgumentException
$e) {
139 throw new RemoteException($e->getMessage(), -32602);
140 } catch (\ArgumentCountError
$e) {
141 throw new RemoteException($e->getMessage(), -32602);
146 * Check that the API is generally enabled
149 * @throws RemoteException thrown when the API is disabled
151 public function ensureApiIsEnabled()
154 if (!$conf['remote'] ||
trim($conf['remoteuser']) == '!!not set!!') {
155 throw new AccessDeniedException('Server Error. API is not enabled in config.', -32604);
160 * Check if the current user is allowed to call the given method
162 * @param ApiCall $method
164 * @throws AccessDeniedException Thrown when the user is not allowed to call the method
166 public function ensureAccessIsAllowed(ApiCall
$method)
172 if ($method->isPublic()) return; // public methods are always allowed
173 if (!$conf['useacl']) return; // ACL is not enabled, so we can't check users
174 if (trim($conf['remoteuser']) === '') return; // all users are allowed
175 if (auth_isMember($conf['remoteuser'], $INPUT->server
->str('REMOTE_USER'), (array)($USERINFO['grps'] ??
[]))) {
176 return; // user is allowed
179 // still here? no can do
180 throw new AccessDeniedException('server error. not authorized to call method', -32604);