From dd36fbd51db1cd80d775a82a9b53287ad0aa7223 Mon Sep 17 00:00:00 2001 From: Nick Liu Date: Sat, 9 Sep 2023 11:43:10 +0200 Subject: [PATCH] Unify logic of `e_user_model::checkAdminPerms()` and `getperms()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Along with extensive documentation, `getperms()` is now deprecated and its replacements now have first-class support: * `e_user_model::checkAdminPerms()` and `getperms()` both use `e_userperms::simulateHasAdminPerms()`. * `e_user_model::checkPluginAdminPerms()` and `getperms('P', …, …)` both use `e_userperms::simulateHasPluginAdminPerms()`. ---- Partially reverts: https://github.com/e107inc/e107/commit/44526b43 Reverts: https://github.com/e107inc/e107/commit/001799cb Fixes: https://github.com/e107inc/e107/issues/5064 --- class2.php | 91 +++++++++++----------------- e107_handlers/user_handler.php | 76 +++++++++++++++++++++++ e107_handlers/user_model.php | 77 +++++++---------------- e107_tests/tests/unit/class2Test.php | 4 ++ 4 files changed, 139 insertions(+), 109 deletions(-) diff --git a/class2.php b/class2.php index 79a893d735..653d08b5c2 100755 --- a/class2.php +++ b/class2.php @@ -1309,22 +1309,46 @@ function check_class($var, $userclass = null, $uid = 0) /** - * @param $arg - * @param bool|mixed|string $ap - * @param mixed $path - * @return bool + * Check a requested permission set against admin permissions or plugin admin permissions. + * + * The constant {@link ADMIN} must be truthy or this function will always return {@link false}. + * + * @param string $arg The serialized requested access code or codes which will match if any of the codes are + * in the admin user's admin permissions. + * This is a pipe-delimited (`|`) list of access codes. + * Example for admin permissions: `C|4`. + * Use this exact value to enter plugin admin permissions checking mode: `P`. + * @param string|int|null $ap The serialized admin permissions or plugin admin permissions to check against. + * Exclude or use {@link null} to use the global {@link ADMINPERMS} constant. + * This is a dot-delimited (`.`) list of access codes. + * Accepts an integer that will be cast to a string for backwards compatibility. + * Example: `C.F.G.1.U0.U1.U2.P3.P4.English`. + * @param string|null $path The path to the file requesting the permission check. + * This is only used when checking plugin admin permissions. + * Exclude or use {@link null} to use the current page, which auto-detects the plugin path. + * Example: `http://localhost/e107v2/e107_plugins/gallery/admin_config.php` along with the + * first argument set to `P` will check the plugin admin permissions for plugin `gallery`. + * @return bool true if the user has the requested admin permissions, false otherwise. + * @see class2Test::testGetPerms() for examples. + * @deprecated v2.3.3 Use one of the object-oriented alternatives: + * {@link e_user_model::checkAdminPerms()} to check a specific user's admin permissions. + * {@link e_user_model::checkPluginAdminPerms()} to check a specific user's plugin admin + * permissions. + * {@link e_userperms::simulateHasAdminPerms()} to simulate a user's admin permissions. + * {@link e_userperms::simulateHasPluginAdminPerms()} to simulate a user's plugin admin + * permissions. + * {@link e107::getUser()} can be used to get the current user. */ -function getperms($arg, $ap = ADMINPERMS, $path = e_SELF) +function getperms($arg, $ap = null, $path = null) { - // $ap = "4"; // Just for testing. - if(trim($ap) === '') + if(is_null($ap)) { - return false; + $ap = defset('ADMINPERMS', e107::getUser()->getAdminPerms()); } - if(deftrue('USE_NEW_GETPERMS')) // Add to e107_config.php. + if(is_null($path)) { - return e107::getUser()->checkAdminPerms($arg,$ap,$path); + $path = defset('e_SELF'); } if(!deftrue('ADMIN')) @@ -1332,10 +1356,7 @@ function getperms($arg, $ap = ADMINPERMS, $path = e_SELF) return false; } - if($arg === 0) // Common-error avoidance with getperms(0) - { - $arg = '0'; - } + $arg = trim((string) $arg); // Common-error avoidance with getperms(0) or getperms(' '). if ($ap === '0' || $ap === '0.') // BC fix. { @@ -1345,38 +1366,11 @@ function getperms($arg, $ap = ADMINPERMS, $path = e_SELF) if ($arg === 'P' && preg_match('#(.*?)/' .e107::getInstance()->getFolder('plugins'). '(.*?)/(.*?)#', $path, $matches)) { $sql = e107::getDb('psql'); - /* $id = e107::getPlug()->load($matches[2])->getId(); - $arg = 'P'.$id;*/ - - if ($sql->select('plugin', 'plugin_id', "plugin_path = '".$matches[2]."' LIMIT 1 ")) - { - $row = $sql->fetch(); - $arg = 'P'.$row['plugin_id']; - } - } - - $ap_array = explode('.',$ap); - - if (in_array($arg,$ap_array,false)) - { - return true; - } - if(strpos($arg, "|")) - { - $tmp = explode("|", $arg); - foreach($tmp as $val) - { - if(in_array($val,$ap_array)) - { - return true; - } - } + return e_userperms::simulateHasPluginAdminPerms($sql, $matches[2], $ap); } - - return false; - + return e_userperms::simulateHasAdminPerms($arg, $ap); } /** @@ -1639,17 +1633,6 @@ function init_session() define('USERJOINED', ''); define('e_CLASS_REGEXP', '(^|,)(253|254|250|251|0)(,|$)'); define('e_NOBODY_REGEXP', '(^|,)255(,|$)'); - - if(deftrue('USE_NEW_GETPERMS')) // Add to e107_config.php. - { - $user->set('user_id', 1); - $user->set('user_name','e107-cli'); - $user->set('user_admin', 1); - $user->set('user_perms', '0'); - $user->set('user_class', ''); - $user->set('user_join', ''); - } - return; } diff --git a/e107_handlers/user_handler.php b/e107_handlers/user_handler.php index 8e004f86a0..f56626738c 100644 --- a/e107_handlers/user_handler.php +++ b/e107_handlers/user_handler.php @@ -2460,4 +2460,80 @@ function updatePerms($uid, $permArray) e107::getLog()->add('ADMIN_01',$logMsg,E_LOG_INFORMATIVE,''); } + /** + * Simulate whether a user has admin permissions based on the requested access code(s) and admin's permissions. + * + * @param string $requestedAccess The serialized requested access code or codes which will match if any of the + * codes are in the admin user's admin permissions. + * This is a pipe-delimited (`|`) list of access codes. + * Example: `C|4` + * @param string $adminPermissions The serialized admin user's admin permissions. + * This is a dot-delimited (`.`) list of access codes. + * Example: `C.F.G.L.T.1.X.I.8.K.3.4.U0.U1.U2.U3.6.A.A1.A2.TMP.2.Z.P3.P4.English` + * @return bool true if the user has matching permissions, false otherwise. + */ + public static function simulateHasAdminPerms($requestedAccess, $adminPermissions) + { + if(trim($adminPermissions) === '') + { + return false; + } + + if($requestedAccess === 0) + { + $requestedAccess = '0'; + } + + if($adminPermissions === '0' || $adminPermissions === '0.') + { + return true; + } + + $adminPermissionsArray = explode('.', $adminPermissions); + + if(in_array($requestedAccess, $adminPermissionsArray, false)) + { + return true; + } + + if(strpos($requestedAccess, '|')) + { + $requestedAccessCodes = explode('|', $requestedAccess); + foreach($requestedAccessCodes as $requestedAccessCode) + { + if(in_array($requestedAccessCode, $adminPermissionsArray)) + { + return true; + } + } + } + + return false; + } + + /** + * Simulate whether a user has admin permissions to a plugin. + * + * @param e_db $db The database handle to query installed plugins. + * @param string $pluginName The plugin name, not the plugin path like in {@link getperms()}. + * @param string $adminPermissions The serialized admin user's admin permissions. + * This is a dot-delimited (`.`) list of access codes. + * Example: `C.F.G.L.T.1.X.I.8.K.3.4.U0.U1.U2.U3.6.A.A1.A2.TMP.2.Z.P3.P4.English` + * @return bool true if the user has matching permissions, false otherwise. + */ + public static function simulateHasPluginAdminPerms($db, $pluginName, $adminPermissions) + { + $arg = "0"; + if($db->select( + 'plugin', + 'plugin_id', + "plugin_path = :plugin_path LIMIT 1", + ["plugin_path" => $pluginName] + )) + { + $row = $db->fetch(); + $arg = 'P' . $row['plugin_id']; + } + return self::simulateHasAdminPerms($arg, $adminPermissions); + } } diff --git a/e107_handlers/user_model.php b/e107_handlers/user_model.php index 8da02d0575..397809815c 100644 --- a/e107_handlers/user_model.php +++ b/e107_handlers/user_model.php @@ -646,70 +646,37 @@ final public function checkClass($class, $allowMain = true) } /** - * @param str $arg - * @param str $ap - * @param str $path - * @return bool + * Check if this user has the provided admin permissions. + * + * @param string $perm_str The serialized requested access code or codes which will match if any of the codes are in + * the admin user's admin permissions. + * This is a pipe-delimited (`|`) list of access codes. + * Example: `C|4` + * @return bool true if the user has the matching admin permissions, false otherwise. */ - final public function checkAdminPerms($arg, $ap = null, $path = null) + final public function checkAdminPerms($perm_str) { - // FIXME - method to replace getperms() - if(!$this->isAdmin()) { return false; } - if($ap === null) - { - $ap = $this->getAdminPerms(); - } - - if($arg === 0) // Common-error avoidance with getperms(0) - { - $arg = '0'; - } - - if ($ap === '0' || $ap === '0.') // BC fix. - { - return true; - } - - if ($arg === 'P' && !empty($path) && preg_match('#(.*?)/' .e107::getInstance()->getFolder('plugins'). '(.*?)/(.*?)#', $path, $matches)) - { - $sql = e107::getDb('psql'); - /* $id = e107::getPlug()->load($matches[2])->getId(); - $arg = 'P'.$id;*/ - - if ($sql->select('plugin', 'plugin_id', "plugin_path = '".$matches[2]."' LIMIT 1 ")) - { - $row = $sql->fetch(); - $arg = 'P'.$row['plugin_id']; - } - } - - $ap_array = explode('.',$ap); - - if (in_array($arg,$ap_array,false)) - { - return true; - } - - if(strpos($arg, "|")) - { - $tmp = explode("|", $arg); - foreach($tmp as $val) - { - if(in_array($val,$ap_array)) - { - return true; - } - } - } + $ap = $this->getAdminPerms(); + return e_userperms::simulateHasAdminPerms($perm_str, $ap); + } - return false; - //return ($this->isAdmin() && getperms($perm_str, $this->getAdminPerms())); + /** + * Check if this user has permissions to administer the given plugin. + * + * @param string $plugin_name The name of the plugin, not the path like in {@see getperms()}. + * @return bool true if the user has admin permissions for the plugin, false otherwise. + */ + final public function checkPluginAdminPerms($plugin_name) + { + $sql = e107::getDb('psql'); + $ap = $this->getAdminPerms(); + return e_userperms::simulateHasPluginAdminPerms($sql, $plugin_name, $ap); } /** diff --git a/e107_tests/tests/unit/class2Test.php b/e107_tests/tests/unit/class2Test.php index 0a663c1ac0..1e682e5321 100644 --- a/e107_tests/tests/unit/class2Test.php +++ b/e107_tests/tests/unit/class2Test.php @@ -52,7 +52,11 @@ function testGetPerms() $result = getperms('U1|U2', '0.'); $this->assertTrue($result); + $result = getperms('0', ' '); + $this->assertFalse($result); + $result = getperms(0, '0'); + $this->assertTrue($result); $pid = e107::getDb()->retrieve('plugin', 'plugin_id', "plugin_path = 'gallery'");