From 532551263d65c8e9f483c60745d544df0297fce7 Mon Sep 17 00:00:00 2001 From: "Michael Kaufmann (d00p)" Date: Sun, 18 Feb 2018 10:19:17 +0100 Subject: [PATCH] add new api-module to output list of possible modules/functions Signed-off-by: Michael Kaufmann (d00p) --- lib/classes/api/abstract.ApiCommand.php | 10 - lib/classes/api/commands/class.Customers.php | 31 ++- lib/classes/api/commands/class.Domains.php | 24 ++- lib/classes/api/commands/class.Froxlor.php | 182 ++++++++++++++++++ .../api/commands/class.IpsAndPorts.php | 23 ++- lib/classes/api/interface.ResourceEntity.php | 15 ++ 6 files changed, 272 insertions(+), 13 deletions(-) create mode 100644 lib/classes/api/commands/class.Froxlor.php create mode 100644 lib/classes/api/interface.ResourceEntity.php diff --git a/lib/classes/api/abstract.ApiCommand.php b/lib/classes/api/abstract.ApiCommand.php index 25fa60f0..ec473fbb 100644 --- a/lib/classes/api/abstract.ApiCommand.php +++ b/lib/classes/api/abstract.ApiCommand.php @@ -213,16 +213,6 @@ abstract class ApiCommand return $json_response; } - public abstract function list(); - - public abstract function get(); - - public abstract function add(); - - public abstract function update(); - - public abstract function delete(); - private function readUserData($header = null) { $sel_stmt = Database::prepare("SELECT * FROM `api_keys` WHERE `apikey` = :ak AND `secret` = :as"); diff --git a/lib/classes/api/commands/class.Customers.php b/lib/classes/api/commands/class.Customers.php index eb1b1085..2065a1d7 100644 --- a/lib/classes/api/commands/class.Customers.php +++ b/lib/classes/api/commands/class.Customers.php @@ -1,8 +1,13 @@ isAdmin()) { @@ -32,6 +37,14 @@ class Customers extends ApiCommand throw new Exception("Not allowed to execute given command.", 403); } + /** + * return a customer entry by id + * + * @param int $id customer-id + * + * @throws Exception + * @return array + */ public function get() { if ($this->isAdmin()) { @@ -655,6 +668,14 @@ class Customers extends ApiCommand throw new Exception("Not allowed to execute given command.", 403); } + /** + * delete a customer entry by id + * + * @param int $id customer-id + * + * @throws Exception + * @return array + */ public function delete() { if ($this->isAdmin()) { @@ -880,6 +901,14 @@ class Customers extends ApiCommand throw new Exception("Not allowed to execute given command.", 403); } + /** + * unlock a locked customer by id + * + * @param int $id customer-id + * + * @throws Exception + * @return array + */ public function unlock() { if ($this->isAdmin()) { diff --git a/lib/classes/api/commands/class.Domains.php b/lib/classes/api/commands/class.Domains.php index 2d0eb4dd..d4f88f84 100644 --- a/lib/classes/api/commands/class.Domains.php +++ b/lib/classes/api/commands/class.Domains.php @@ -1,8 +1,13 @@ isAdmin()) { @@ -32,6 +37,15 @@ class Domains extends ApiCommand throw new Exception("Not allowed to execute given command.", 403); } + /** + * return a domain entry by id + * + * @param int $id domain-id + * @param boolean $no_std_subdomain optional, default false + * + * @throws Exception + * @return array + */ public function get() { if ($this->isAdmin()) { @@ -1503,6 +1517,14 @@ class Domains extends ApiCommand throw new Exception("Not allowed to execute given command.", 403); } + /** + * delete a domain entry by id + * + * @param int $id domain-id + * + * @throws Exception + * @return array + */ public function delete() { if ($this->isAdmin()) { diff --git a/lib/classes/api/commands/class.Froxlor.php b/lib/classes/api/commands/class.Froxlor.php new file mode 100644 index 00000000..01c316e5 --- /dev/null +++ b/lib/classes/api/commands/class.Froxlor.php @@ -0,0 +1,182 @@ +getParam('module'); + + $functions = array(); + if ($module != null) { + // check existence + $this->requireModules($module); + // now get all static functions + $reflection = new \ReflectionClass($module); + $_functions = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); + foreach ($_functions as $func) { + if ($func->class == $module && $func->isPublic()) { + array_push($functions, array_merge(array( + 'module' => $module, + 'function' => $func->name + ), $this->_getParamListFromDoc($module, $func->name))); + } + } + } else { + // check all the modules + $path = FROXLOR_INSTALL_DIR . '/lib/classes/api/commands/'; + // valid directory? + if (is_dir($path)) { + // create RecursiveIteratorIterator + $its = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path)); + // check every file + foreach ($its as $fullFileName => $it) { + // does it match the Filename pattern? + $matches = array(); + if (preg_match("/^class\.(.+)\.php$/i", $it->getFilename(), $matches)) { + // check for existence + try { + // set the module to be in our namespace + $mod = $matches[1]; + $this->requireModules($mod); + } catch (Exception $e) { + // @todo log? + continue; + } + // now get all static functions + $reflection = new \ReflectionClass($mod); + $_functions = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); + foreach ($_functions as $func) { + if ($func->class == $mod && $func->isPublic()) { + array_push($functions, array_merge(array( + 'module' => $matches[1], + 'function' => $func->name + ), $this->_getParamListFromDoc($matches[1], $func->name))); + } + } + } + } + } else { + // yikes - no valid directory to check + throw new Exception("Cannot search directory '" . $path . "'. No such directory.", 500); + } + } + + // return the list + return $this->response(200, "successfull", $functions); + } + + /** + * generate an api-response to list all parameters and the return-value of + * a given module.function-combination + * + * @param string $module + * @param string $function + * + * @throws Exception + * @return array|bool + */ + private function _getParamListFromDoc($module = null, $function = null) + { + try { + // set the module to be in our namespace + $cls = new \ReflectionMethod($module, $function); + $comment = $cls->getDocComment(); + if ($comment == false) { + return array( + 'head' => 'There is no comment-block for "' . $module . '.' . $function . '"' + ); + } + $clines = explode("\n", $comment); + $result = array(); + $result['params'] = array(); + foreach ($clines as $c) { + $c = trim($c); + // check param-section + if (strpos($c, '@param')) { + preg_match('/^\*\s\@param\s(.+)\s(\$\w+)(\s.*)?/', $c, $r); + // cut $ off the parameter-name as it is not wanted in the api-request + $result['params'][] = array( + 'parameter' => substr($r[2], 1), + 'type' => $r[1], + 'desc' => (isset($r[3]) ? trim($r['3']) : '') + ); + } // check return-section + elseif (strpos($c, '@return')) { + preg_match('/^\*\s\@return\s(\w+)(\s.*)?/', $c, $r); + if (! isset($r[0]) || empty($r[0])) { + $r[1] = 'null'; + $r[2] = 'This function has no return value given'; + } + $result['return'] = array( + 'type' => $r[1], + 'desc' => (isset($r[2]) ? trim($r[2]) : '') + ); + } else if (! empty($c) && strpos($c, '@throws') === false) { + if (substr($c, 0, 3) == "/**") + continue; + if (substr($c, 0, 2) == "*/") + continue; + if (substr($c, 0, 1) == "*") + $c = trim(substr($c, 1)); + if (empty($c)) + continue; + if (! isset($result['head']) || empty($result['head'])) { + $result['head'] = $c . " "; + } else { + $result['head'] .= $c . " "; + } + } + } + return $result; + } catch (\ReflectionException $e) { + return array(); + } + } + + /** + * this functions is used to check the availability + * of a given list of modules. + * If either one of + * them are not found, throw an Exception + * + * @param string|array $modules + * + * @throws Exception + */ + private function requireModules($modules = null) + { + if ($modules != null) { + // no array -> create one + if (! is_array($modules)) { + $modules = array( + $modules + ); + } + // check all the modules + foreach ($modules as $module) { + try { + // can we use the class? + if (class_exists($module)) { + continue; + } else { + throw new Exception('The required class "' . $module . '" could not be found but the module-file exists', 404); + } + } catch (Exception $e) { + // The autoloader will throw an Exception + // that the required class could not be found + // but we want a nicer error-message for this here + throw new Exception('The required module "' . $module . '" could not be found', 404); + } + } + } + } +} diff --git a/lib/classes/api/commands/class.IpsAndPorts.php b/lib/classes/api/commands/class.IpsAndPorts.php index f0b9d8e1..9baa0a64 100644 --- a/lib/classes/api/commands/class.IpsAndPorts.php +++ b/lib/classes/api/commands/class.IpsAndPorts.php @@ -1,8 +1,13 @@ isAdmin() && $this->getUserDetail('change_serversettings')) { @@ -23,6 +28,14 @@ class IpsAndPorts extends ApiCommand throw new Exception("Not allowed to execute given command.", 403); } + /** + * return an ip/port entry by id + * + * @param int $id ip-port-id + * + * @throws Exception + * @return array + */ public function get() { if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) { @@ -314,6 +327,14 @@ class IpsAndPorts extends ApiCommand throw new Exception("Not allowed to execute given command.", 403); } + /** + * delete an ip/port entry by id + * + * @param int $id ip-port-id + * + * @throws Exception + * @return array + */ public function delete() { if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) { diff --git a/lib/classes/api/interface.ResourceEntity.php b/lib/classes/api/interface.ResourceEntity.php new file mode 100644 index 00000000..6361eb46 --- /dev/null +++ b/lib/classes/api/interface.ResourceEntity.php @@ -0,0 +1,15 @@ +