Skip to content

Commit

Permalink
Unify logic of e_user_model::checkAdminPerms() and getperms()
Browse files Browse the repository at this point in the history
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: 44526b43

Reverts: 001799cb

Fixes: #5064
  • Loading branch information
Deltik committed Sep 9, 2023
1 parent 001799c commit dd36fbd
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 109 deletions.
91 changes: 37 additions & 54 deletions class2.php
Original file line number Diff line number Diff line change
Expand Up @@ -1309,33 +1309,54 @@ 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'))
{
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.
{
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -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;
}

Expand Down
76 changes: 76 additions & 0 deletions e107_handlers/user_handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
77 changes: 22 additions & 55 deletions e107_handlers/user_model.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down
4 changes: 4 additions & 0 deletions e107_tests/tests/unit/class2Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'");

Expand Down

0 comments on commit dd36fbd

Please sign in to comment.