context->getUser(); if (!$user || !$user->hasGroup(Group::ADMIN)) { return $this->createError("Permission denied."); } return true; } protected function isRestricted(string $method): bool { return in_array(strtolower($method), ["permission/update", "permission/delete"]); // TODO: access the "hasConfigurablePermissions" here. } } } namespace Core\API\Permission { use Core\API\Parameter\ArrayType; use Core\API\Parameter\Parameter; use Core\API\Parameter\StringType; use Core\API\PermissionAPI; use Core\Driver\SQL\Column\Column; use Core\Driver\SQL\Condition\CondIn; use Core\Driver\SQL\Condition\CondLike; use Core\Driver\SQL\Strategy\UpdateStrategy; use Core\Objects\Context; use Core\Objects\DatabaseEntity\Group; class Check extends PermissionAPI { public function __construct(Context $context, bool $externalCall = false) { parent::__construct($context, $externalCall, array( 'method' => new StringType('method', 323) )); $this->isPublic = false; } public function _execute(): bool { $method = $this->getParam("method"); $sql = $this->context->getSQL(); $res = $sql->select("groups") ->from("ApiPermission") ->where(new CondLike($method, new Column("method"))) ->execute(); $this->success = ($res !== FALSE); $this->lastError = $sql->getLastError(); if ($this->success) { if (empty($res) || !is_array($res)) { return true; } $groups = json_decode($res[0]["groups"]); if (empty($groups)) { return true; } $currentUser = $this->context->getUser(); $userGroups = $currentUser ? $currentUser->getGroups() : []; if (empty($userGroups) || empty(array_intersect($groups, array_keys($userGroups)))) { if (!$currentUser) { $this->result["loggedIn"] = false; } http_response_code(401); return $this->createError("Permission denied."); } // user would have required groups, check for 2fa-state if ($currentUser && !$this->check2FA()) { http_response_code(401); return false; } } return $this->success; } public static function getDescription(): string { return "Checks whether a user is permitted to access a given API-method"; } public static function hasConfigurablePermissions(): bool { return false; } } class Fetch extends PermissionAPI { private ?array $groups; public function __construct(Context $context, bool $externalCall = false) { parent::__construct($context, $externalCall, array()); } private function fetchGroups(): bool { $sql = $this->context->getSQL(); $this->groups = Group::findAll($sql); $this->success = ($this->groups !== FALSE); $this->lastError = $sql->getLastError(); return $this->success; } public function _execute(): bool { if (!$this->fetchGroups()) { return false; } $sql = $this->context->getSQL(); $res = $sql->select("method", "groups", "description", "is_core") ->from("ApiPermission") ->execute(); $this->success = ($res !== FALSE); $this->lastError = $sql->getLastError(); if ($this->success) { $permissions = []; foreach ($res as $row) { $method = $row["method"]; $description = $row["description"]; $groups = json_decode($row["groups"]); $isCore = $row["is_core"]; $permissions[] = [ "method" => $method, "groups" => $groups, "description" => $description, "is_core" => $isCore ]; } $this->result["permissions"] = $permissions; $this->result["groups"] = $this->groups; } return $this->success; } public static function getDescription(): string { return "Allows users to fetch API permissions"; } public static function getDefaultPermittedGroups(): array { return [Group::ADMIN]; } } class Update extends PermissionAPI { public function __construct(Context $context, bool $externalCall = false) { parent::__construct($context, $externalCall, [ "method" => new StringType("method", 32, false), "groups" => new ArrayType("groups", Parameter::TYPE_INT, true, false), "description" => new StringType("description", 128, true, null), ]); } protected function _execute(): bool { if (!$this->checkStaticPermission()) { return false; } $sql = $this->context->getSQL(); $method = $this->getParam("method"); $description = $this->getParam("description"); if ($this->isRestricted($method)) { return $this->createError("This method cannot be updated."); } $groupIds = array_unique($this->getParam("groups")); if (!empty($groupIds)) { sort($groupIds); $availableGroups = Group::findAll($sql, new CondIn(new Column("id"), $groupIds)); foreach ($groupIds as $groupId) { if (!isset($availableGroups[$groupId])) { return $this->createError("Group with id=$groupId does not exist."); } } } if ($description === null) { $updateQuery = $sql->insert("ApiPermission", ["method", "groups", "is_core"]) ->onDuplicateKeyStrategy(new UpdateStrategy(["method"], ["groups" => $groupIds])) ->addRow($method, $groupIds, false); } else { $updateQuery = $sql->insert("ApiPermission", ["method", "groups", "is_core", "description"]) ->onDuplicateKeyStrategy(new UpdateStrategy(["method"], ["groups" => $groupIds, "description" => $description])) ->addRow($method, $groupIds, false, $description); } $this->success = $updateQuery->execute() !== false; $this->lastError = $sql->getLastError(); return $this->success; } public static function getDescription(): string { return "Allows users to modify API permissions. This is restricted to the administrator and cannot be changed"; } public static function getDefaultPermittedGroups(): array { return [Group::ADMIN]; } public static function hasConfigurablePermissions(): bool { return false; } } class Delete extends PermissionAPI { public function __construct(Context $context, bool $externalCall = false) { parent::__construct($context, $externalCall, [ "method" => new StringType("method", 32, false), ]); } protected function _execute(): bool { if (!$this->checkStaticPermission()) { return false; } $sql = $this->context->getSQL(); $method = $this->getParam("method"); if ($this->isRestricted($method)) { return $this->createError("This method cannot be deleted."); } $res = $sql->select("method") ->from("ApiPermission") ->whereEq("method", $method) ->execute(); $this->success = $res !== false; $this->lastError = $sql->getLastError(); if ($this->success) { if (!$res) { return $this->createError("This method was not configured yet"); } else { $res = $sql->delete("ApiPermission") ->whereEq("method", $method) ->execute(); $this->success = $res !== false; $this->lastError = $sql->getLastError(); } } return $this->success; } public static function getDescription(): string { return "Allows users to delete API permissions. This is restricted to the administrator and cannot be changed"; } public static function getDefaultPermittedGroups(): array { return [Group::ADMIN]; } public static function hasConfigurablePermissions(): bool { return false; } } }