Removal of permission defaults (in favour of permission cascading) (#3937)

This commit is contained in:
Dylan T 2020-12-01 17:13:54 +00:00 committed by GitHub
parent 1eabc3fe75
commit 6d8833ccd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 215 additions and 241 deletions

View File

@ -682,7 +682,7 @@ class Server{
$this->operators->set(strtolower($name), true);
if(($player = $this->getPlayerExact($name)) !== null){
$player->onOpStatusChange(true);
$player->setBasePermission(DefaultPermissions::ROOT_OPERATOR, true);
}
$this->operators->save();
}
@ -691,7 +691,7 @@ class Server{
$this->operators->remove(strtolower($name));
if(($player = $this->getPlayerExact($name)) !== null){
$player->onOpStatusChange(false);
$player->unsetBasePermission(DefaultPermissions::ROOT_OPERATOR);
}
$this->operators->save();
}

View File

@ -76,10 +76,6 @@ class ConsoleCommandSender implements CommandSender{
return "CONSOLE";
}
public function onOpStatusChange(bool $value) : void{
}
public function getScreenLineHeight() : int{
return $this->lineHeight ?? PHP_INT_MAX;
}

View File

@ -95,6 +95,7 @@ use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use pocketmine\network\NetworkSessionManager;
use pocketmine\permission\DefaultPermissions;
use pocketmine\player\GameMode;
use pocketmine\player\Player;
use pocketmine\player\PlayerInfo;
@ -722,8 +723,9 @@ class NetworkSession{
//TODO: permission flags
$pk->commandPermission = ($for->isOp() ? AdventureSettingsPacket::PERMISSION_OPERATOR : AdventureSettingsPacket::PERMISSION_NORMAL);
$pk->playerPermission = ($for->isOp() ? PlayerPermissions::OPERATOR : PlayerPermissions::MEMBER);
$isOp = $for->hasPermission(DefaultPermissions::ROOT_OPERATOR);
$pk->commandPermission = ($isOp ? AdventureSettingsPacket::PERMISSION_OPERATOR : AdventureSettingsPacket::PERMISSION_NORMAL);
$pk->playerPermission = ($isOp ? PlayerPermissions::OPERATOR : PlayerPermissions::MEMBER);
$pk->entityUniqueId = $for->getId();
$this->sendDataPacket($pk);

View File

@ -26,98 +26,103 @@ namespace pocketmine\permission;
abstract class DefaultPermissions{
public const ROOT = "pocketmine";
public static function registerPermission(Permission $perm, ?Permission $parent = null) : Permission{
if($parent instanceof Permission){
$parent->addChild($perm->getName(), true);
}
PermissionManager::getInstance()->addPermission($perm);
public const ROOT_OPERATOR = "pocketmine.group.operator";
public const ROOT_USER = "pocketmine.group.user";
return PermissionManager::getInstance()->getPermission($perm->getName());
/**
* @param Permission[] $grantedBy
* @param Permission[] $deniedBy
*/
public static function registerPermission(Permission $candidate, array $grantedBy = [], array $deniedBy = []) : Permission{
foreach($grantedBy as $permission){
$permission->addChild($candidate->getName(), true);
}
foreach($deniedBy as $permission){
$permission->addChild($candidate->getName(), false);
}
PermissionManager::getInstance()->addPermission($candidate);
return PermissionManager::getInstance()->getPermission($candidate->getName());
}
public static function registerCorePermissions() : void{
$parent = self::registerPermission(new Permission(self::ROOT, "Allows using all PocketMine commands and utilities"));
$broadcasts = self::registerPermission(new Permission(self::ROOT . ".broadcast", "Allows the user to receive all broadcast messages"), $parent);
self::registerPermission(new Permission(self::ROOT . ".broadcast.admin", "Allows the user to receive administrative broadcasts", Permission::DEFAULT_OP), $broadcasts);
self::registerPermission(new Permission(self::ROOT . ".broadcast.user", "Allows the user to receive user broadcasts", Permission::DEFAULT_TRUE), $broadcasts);
$broadcasts->recalculatePermissibles();
$operatorRoot = self::registerPermission(new Permission(self::ROOT_OPERATOR, "Grants all operator permissions"), [$parent]);
$everyoneRoot = self::registerPermission(new Permission(self::ROOT_USER, "Grants all non-sensitive permissions that everyone gets by default"), [$operatorRoot]);
$commands = self::registerPermission(new Permission(self::ROOT . ".command", "Allows using all PocketMine commands"), $parent);
$broadcastRoot = self::registerPermission(new Permission(self::ROOT . ".broadcast", "Allows the user to receive all broadcast messages"), [$parent]);
$whitelist = self::registerPermission(new Permission(self::ROOT . ".command.whitelist", "Allows the user to modify the server whitelist", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.add", "Allows the user to add a player to the server whitelist"), $whitelist);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.remove", "Allows the user to remove a player from the server whitelist"), $whitelist);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.reload", "Allows the user to reload the server whitelist"), $whitelist);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.enable", "Allows the user to enable the server whitelist"), $whitelist);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.disable", "Allows the user to disable the server whitelist"), $whitelist);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.list", "Allows the user to list all players on the server whitelist"), $whitelist);
$whitelist->recalculatePermissibles();
self::registerPermission(new Permission(self::ROOT . ".broadcast.admin", "Allows the user to receive administrative broadcasts"), [$operatorRoot, $broadcastRoot]);
self::registerPermission(new Permission(self::ROOT . ".broadcast.user", "Allows the user to receive user broadcasts"), [$everyoneRoot, $broadcastRoot]);
$ban = self::registerPermission(new Permission(self::ROOT . ".command.ban", "Allows the user to ban people", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.ban.player", "Allows the user to ban players"), $ban);
self::registerPermission(new Permission(self::ROOT . ".command.ban.ip", "Allows the user to ban IP addresses"), $ban);
self::registerPermission(new Permission(self::ROOT . ".command.ban.list", "Allows the user to list banned players"), $ban);
$ban->recalculatePermissibles();
//this allows using ALL commands if assigned, irrespective of what group the player is in
$commandRoot = self::registerPermission(new Permission(self::ROOT . ".command", "Allows using all PocketMine commands"), [$parent]);
$operatorCommand = [$commandRoot, $operatorRoot];
$everyoneCommand = [$commandRoot, $everyoneRoot];
$unban = self::registerPermission(new Permission(self::ROOT . ".command.unban", "Allows the user to unban people", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.unban.player", "Allows the user to unban players"), $unban);
self::registerPermission(new Permission(self::ROOT . ".command.unban.ip", "Allows the user to unban IP addresses"), $unban);
$unban->recalculatePermissibles();
$whitelist = self::registerPermission(new Permission(self::ROOT . ".command.whitelist", "Allows the user to modify the server whitelist"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.add", "Allows the user to add a player to the server whitelist"), [$whitelist]);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.remove", "Allows the user to remove a player from the server whitelist"), [$whitelist]);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.reload", "Allows the user to reload the server whitelist"), [$whitelist]);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.enable", "Allows the user to enable the server whitelist"), [$whitelist]);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.disable", "Allows the user to disable the server whitelist"), [$whitelist]);
self::registerPermission(new Permission(self::ROOT . ".command.whitelist.list", "Allows the user to list all players on the server whitelist"), [$whitelist]);
$op = self::registerPermission(new Permission(self::ROOT . ".command.op", "Allows the user to change operators", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.op.give", "Allows the user to give a player operator status"), $op);
self::registerPermission(new Permission(self::ROOT . ".command.op.take", "Allows the user to take a player's operator status"), $op);
$op->recalculatePermissibles();
$ban = self::registerPermission(new Permission(self::ROOT . ".command.ban", "Allows the user to ban people"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.ban.player", "Allows the user to ban players"), [$ban]);
self::registerPermission(new Permission(self::ROOT . ".command.ban.ip", "Allows the user to ban IP addresses"), [$ban]);
self::registerPermission(new Permission(self::ROOT . ".command.ban.list", "Allows the user to list banned players"), [$ban]);
$save = self::registerPermission(new Permission(self::ROOT . ".command.save", "Allows the user to save the worlds", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.save.enable", "Allows the user to enable automatic saving"), $save);
self::registerPermission(new Permission(self::ROOT . ".command.save.disable", "Allows the user to disable automatic saving"), $save);
self::registerPermission(new Permission(self::ROOT . ".command.save.perform", "Allows the user to perform a manual save"), $save);
$save->recalculatePermissibles();
$unban = self::registerPermission(new Permission(self::ROOT . ".command.unban", "Allows the user to unban people"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.unban.player", "Allows the user to unban players"), [$unban]);
self::registerPermission(new Permission(self::ROOT . ".command.unban.ip", "Allows the user to unban IP addresses"), [$unban]);
$time = self::registerPermission(new Permission(self::ROOT . ".command.time", "Allows the user to alter the time", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.time.add", "Allows the user to fast-forward time"), $time);
self::registerPermission(new Permission(self::ROOT . ".command.time.set", "Allows the user to change the time"), $time);
self::registerPermission(new Permission(self::ROOT . ".command.time.start", "Allows the user to restart the time"), $time);
self::registerPermission(new Permission(self::ROOT . ".command.time.stop", "Allows the user to stop the time"), $time);
self::registerPermission(new Permission(self::ROOT . ".command.time.query", "Allows the user query the time"), $time);
$time->recalculatePermissibles();
$op = self::registerPermission(new Permission(self::ROOT . ".command.op", "Allows the user to change operators"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.op.give", "Allows the user to give a player operator status"), [$op]);
self::registerPermission(new Permission(self::ROOT . ".command.op.take", "Allows the user to take a player's operator status"), [$op]);
$kill = self::registerPermission(new Permission(self::ROOT . ".command.kill", "Allows the user to kill players", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.kill.self", "Allows the user to commit suicide", Permission::DEFAULT_TRUE), $kill);
self::registerPermission(new Permission(self::ROOT . ".command.kill.other", "Allows the user to kill other players"), $kill);
$kill->recalculatePermissibles();
$save = self::registerPermission(new Permission(self::ROOT . ".command.save", "Allows the user to save the worlds"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.save.enable", "Allows the user to enable automatic saving"), [$save]);
self::registerPermission(new Permission(self::ROOT . ".command.save.disable", "Allows the user to disable automatic saving"), [$save]);
self::registerPermission(new Permission(self::ROOT . ".command.save.perform", "Allows the user to perform a manual save"), [$save]);
self::registerPermission(new Permission(self::ROOT . ".command.me", "Allows the user to perform a chat action", Permission::DEFAULT_TRUE), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.tell", "Allows the user to privately message another player", Permission::DEFAULT_TRUE), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.say", "Allows the user to talk as the console", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.give", "Allows the user to give items to players", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.effect", "Allows the user to give/take potion effects", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.enchant", "Allows the user to enchant items", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.particle", "Allows the user to create particle effects", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.teleport", "Allows the user to teleport players", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.kick", "Allows the user to kick players", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.stop", "Allows the user to stop the server", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.list", "Allows the user to list all online players", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.help", "Allows the user to view the help menu", Permission::DEFAULT_TRUE), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.plugins", "Allows the user to view the list of plugins", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.version", "Allows the user to view the version of the server", Permission::DEFAULT_TRUE), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.gamemode", "Allows the user to change the gamemode of players", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.defaultgamemode", "Allows the user to change the default gamemode", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.seed", "Allows the user to view the seed of the world", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.status", "Allows the user to view the server performance", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.gc", "Allows the user to fire garbage collection tasks", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.dumpmemory", "Allows the user to dump memory contents", Permission::DEFAULT_FALSE), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.timings", "Allows the user to records timings for all plugin events", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.spawnpoint", "Allows the user to change player's spawnpoint", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.setworldspawn", "Allows the user to change the world spawn", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.transferserver", "Allows the user to transfer self to another server", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.title", "Allows the user to send a title to the specified player", Permission::DEFAULT_OP), $commands);
self::registerPermission(new Permission(self::ROOT . ".command.difficulty", "Allows the user to change the game difficulty", Permission::DEFAULT_OP), $commands);
$time = self::registerPermission(new Permission(self::ROOT . ".command.time", "Allows the user to alter the time"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.time.add", "Allows the user to fast-forward time"), [$time]);
self::registerPermission(new Permission(self::ROOT . ".command.time.set", "Allows the user to change the time"), [$time]);
self::registerPermission(new Permission(self::ROOT . ".command.time.start", "Allows the user to restart the time"), [$time]);
self::registerPermission(new Permission(self::ROOT . ".command.time.stop", "Allows the user to stop the time"), [$time]);
self::registerPermission(new Permission(self::ROOT . ".command.time.query", "Allows the user query the time"), [$time]);
$commands->recalculatePermissibles();
$kill = self::registerPermission(new Permission(self::ROOT . ".command.kill", "Allows the user to kill players"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.kill.self", "Allows the user to commit suicide"), [$kill, $everyoneRoot]);
self::registerPermission(new Permission(self::ROOT . ".command.kill.other", "Allows the user to kill other players"), [$kill]);
$parent->recalculatePermissibles();
self::registerPermission(new Permission(self::ROOT . ".command.me", "Allows the user to perform a chat action"), $everyoneCommand);
self::registerPermission(new Permission(self::ROOT . ".command.tell", "Allows the user to privately message another player"), $everyoneCommand);
self::registerPermission(new Permission(self::ROOT . ".command.say", "Allows the user to talk as the console"), [$commandRoot, $operatorRoot]);
self::registerPermission(new Permission(self::ROOT . ".command.give", "Allows the user to give items to players"), [$commandRoot, $operatorRoot]);
self::registerPermission(new Permission(self::ROOT . ".command.effect", "Allows the user to give/take potion effects"), [$commandRoot, $operatorRoot]);
self::registerPermission(new Permission(self::ROOT . ".command.enchant", "Allows the user to enchant items"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.particle", "Allows the user to create particle effects"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.teleport", "Allows the user to teleport players"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.kick", "Allows the user to kick players"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.stop", "Allows the user to stop the server"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.list", "Allows the user to list all online players"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.help", "Allows the user to view the help menu"), $everyoneCommand);
self::registerPermission(new Permission(self::ROOT . ".command.plugins", "Allows the user to view the list of plugins"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.version", "Allows the user to view the version of the server"), $everyoneCommand);
self::registerPermission(new Permission(self::ROOT . ".command.gamemode", "Allows the user to change the gamemode of players"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.defaultgamemode", "Allows the user to change the default gamemode"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.seed", "Allows the user to view the seed of the world"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.status", "Allows the user to view the server performance"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.gc", "Allows the user to fire garbage collection tasks"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.dumpmemory", "Allows the user to dump memory contents"), [$commandRoot]); //TODO: this should be exclusively granted to CONSOLE
self::registerPermission(new Permission(self::ROOT . ".command.timings", "Allows the user to records timings for all plugin events"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.spawnpoint", "Allows the user to change player's spawnpoint"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.setworldspawn", "Allows the user to change the world spawn"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.transferserver", "Allows the user to transfer self to another server"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.title", "Allows the user to send a title to the specified player"), $operatorCommand);
self::registerPermission(new Permission(self::ROOT . ".command.difficulty", "Allows the user to change the game difficulty"), $operatorCommand);
}
}

View File

@ -27,9 +27,25 @@ use pocketmine\plugin\Plugin;
interface Permissible{
public function isOp() : bool;
/**
* Assigns a baseline permission to the permissible. This is **always** calculated before anything else, which means
* that permissions set using addAttachment() will always override base permissions.
* You probably don't want to use this if you're not assigning (denying) operator permissions.
*
* @internal
* @see Permissible::addAttachment() for normal permission assignments
* @param Permission|string $name
*/
public function setBasePermission($name, bool $grant) : void;
public function onOpStatusChange(bool $value) : void;
/**
* Unsets a baseline permission previously set. If it wasn't already set, this will have no effect.
* Note that this might have different results than setting the permission to false.
*
* @internal
* @param Permission|string $name
*/
public function unsetBasePermission($name) : void;
/**
* Checks if this instance has a permission overridden

View File

@ -29,12 +29,17 @@ use pocketmine\timings\Timings;
use function spl_object_id;
class PermissibleBase implements Permissible{
/** @var bool */
private $op;
/** @var Permissible|null */
private $parent;
/**
* @var bool[]
* @phpstan-var array<string, bool>
*/
private $rootPermissions = [
DefaultPermissions::ROOT_USER => true
];
/** @var PermissionAttachment[] */
private $attachments = [];
@ -43,7 +48,12 @@ class PermissibleBase implements Permissible{
public function __construct(?Permissible $permissible, bool $isOp){
$this->parent = $permissible;
$this->op = $isOp;
//TODO: we can't setBasePermission here directly due to bad architecture that causes recalculatePermissions to explode
//so, this hack has to be done here to prevent permission recalculations until it's fixed...
if($isOp){
$this->rootPermissions[DefaultPermissions::ROOT_OPERATOR] = true;
}
//TODO: permissions need to be recalculated here, or inherited permissions won't work
}
@ -51,12 +61,16 @@ class PermissibleBase implements Permissible{
return $this->parent ?? $this;
}
public function isOp() : bool{
return $this->op;
public function setBasePermission($name, bool $grant) : void{
if($name instanceof Permission){
$name = $name->getName();
}
$this->rootPermissions[$name] = $grant;
$this->getRootPermissible()->recalculatePermissions();
}
public function onOpStatusChange(bool $value) : void{
$this->op = $value;
public function unsetBasePermission($name) : void{
unset($this->rootPermissions[$name instanceof Permission ? $name->getName() : $name]);
$this->getRootPermissible()->recalculatePermissions();
}
@ -117,14 +131,16 @@ class PermissibleBase implements Permissible{
public function recalculatePermissions() : void{
Timings::$permissibleCalculationTimer->startTiming();
$this->clearPermissions();
$permManager = PermissionManager::getInstance();
$defaults = $permManager->getDefaultPermissions($this->isOp());
$permManager->subscribeToDefaultPerms($this->isOp(), $this->getRootPermissible());
$permManager->unsubscribeFromAllPermissions($this->getRootPermissible());
$this->permissions = [];
foreach($defaults as $perm){
$name = $perm->getName();
$this->permissions[$name] = new PermissionAttachmentInfo($this->getRootPermissible(), $name, null, true);
foreach($this->rootPermissions as $name => $isGranted){
$perm = $permManager->getPermission($name);
if($perm === null){
throw new \InvalidStateException("Unregistered root permission $name");
}
$this->permissions[$name] = new PermissionAttachmentInfo($this->getRootPermissible(), $name, null, $isGranted);
$permManager->subscribeToPermission($name, $this->getRootPermissible());
$this->calculateChildPermissions($perm->getChildren(), false, null);
}
@ -137,11 +153,7 @@ class PermissibleBase implements Permissible{
}
public function clearPermissions() : void{
$permManager = PermissionManager::getInstance();
$permManager->unsubscribeFromAllPermissions($this->getRootPermissible());
$permManager->unsubscribeFromDefaultPerms(false, $this->getRootPermissible());
$permManager->unsubscribeFromDefaultPerms(true, $this->getRootPermissible());
PermissionManager::getInstance()->unsubscribeFromAllPermissions($this->getRootPermissible());
$this->permissions = [];
}

View File

@ -30,12 +30,18 @@ trait PermissibleDelegateTrait{
/** @var PermissibleBase */
private $perm;
public function isOp() : bool{
return $this->perm->isOp();
/**
* @param Permission|string $name
*/
public function setBasePermission($name, bool $value) : void{
$this->perm->setBasePermission($name, $value);
}
public function onOpStatusChange(bool $value) : void{
$this->perm->onOpStatusChange($value);
/**
* @param Permission|string $name
*/
public function unsetBasePermission($name) : void{
$this->perm->unsetBasePermission($name);
}
/**

View File

@ -31,14 +31,6 @@ namespace pocketmine\permission;
* Represents a permission
*/
class Permission{
public const DEFAULT_OP = "op";
public const DEFAULT_NOT_OP = "notop";
public const DEFAULT_TRUE = "true";
public const DEFAULT_FALSE = "false";
/** @var string */
public static $DEFAULT_PERMISSION = self::DEFAULT_OP;
/** @var string */
private $name;
@ -51,19 +43,15 @@ class Permission{
*/
private $children;
/** @var string */
private $defaultValue;
/**
* Creates a new Permission object to be attached to Permissible objects
*
* @param bool[] $children
* @phpstan-param array<string, bool> $children
*/
public function __construct(string $name, ?string $description = null, ?string $defaultValue = null, array $children = []){
public function __construct(string $name, ?string $description = null, array $children = []){
$this->name = $name;
$this->description = $description ?? "";
$this->defaultValue = $defaultValue ?? self::$DEFAULT_PERMISSION;
$this->children = $children;
$this->recalculatePermissibles();
@ -81,17 +69,6 @@ class Permission{
return $this->children;
}
public function getDefault() : string{
return $this->defaultValue;
}
public function setDefault(string $value) : void{
if($value !== $this->defaultValue){
$this->defaultValue = $value;
$this->recalculatePermissibles();
}
}
public function getDescription() : string{
return $this->description;
}
@ -110,8 +87,6 @@ class Permission{
public function recalculatePermissibles() : void{
$perms = $this->getPermissibles();
PermissionManager::getInstance()->recalculatePermissionDefaults($this);
foreach($perms as $p){
$p->recalculatePermissions();
}

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\permission;
use pocketmine\timings\Timings;
use function count;
use function spl_object_id;
@ -41,16 +40,8 @@ class PermissionManager{
/** @var Permission[] */
protected $permissions = [];
/** @var Permission[] */
protected $defaultPerms = [];
/** @var Permission[] */
protected $defaultPermsOp = [];
/** @var Permissible[][] */
protected $permSubs = [];
/** @var Permissible[] */
protected $defSubs = [];
/** @var Permissible[] */
protected $defSubsOp = [];
public function getPermission(string $name) : ?Permission{
return $this->permissions[$name] ?? null;
@ -59,7 +50,6 @@ class PermissionManager{
public function addPermission(Permission $permission) : bool{
if(!isset($this->permissions[$permission->getName()])){
$this->permissions[$permission->getName()] = $permission;
$this->calculatePermissionDefault($permission);
return true;
}
@ -78,45 +68,6 @@ class PermissionManager{
}
}
/**
* @return Permission[]
*/
public function getDefaultPermissions(bool $op) : array{
if($op){
return $this->defaultPermsOp;
}else{
return $this->defaultPerms;
}
}
public function recalculatePermissionDefaults(Permission $permission) : void{
if(isset($this->permissions[$permission->getName()])){
unset($this->defaultPermsOp[$permission->getName()]);
unset($this->defaultPerms[$permission->getName()]);
$this->calculatePermissionDefault($permission);
}
}
private function calculatePermissionDefault(Permission $permission) : void{
Timings::$permissionDefaultTimer->startTiming();
if($permission->getDefault() === Permission::DEFAULT_OP or $permission->getDefault() === Permission::DEFAULT_TRUE){
$this->defaultPermsOp[$permission->getName()] = $permission;
$this->dirtyPermissibles(true);
}
if($permission->getDefault() === Permission::DEFAULT_NOT_OP or $permission->getDefault() === Permission::DEFAULT_TRUE){
$this->defaultPerms[$permission->getName()] = $permission;
$this->dirtyPermissibles(false);
}
Timings::$permissionDefaultTimer->stopTiming();
}
private function dirtyPermissibles(bool $op) : void{
foreach($this->getDefaultPermSubscriptions($op) as $p){
$p->recalculatePermissions();
}
}
public function subscribeToPermission(string $permission, Permissible $permissible) : void{
if(!isset($this->permSubs[$permission])){
$this->permSubs[$permission] = [];
@ -149,33 +100,6 @@ class PermissionManager{
return $this->permSubs[$permission] ?? [];
}
public function subscribeToDefaultPerms(bool $op, Permissible $permissible) : void{
if($op){
$this->defSubsOp[spl_object_id($permissible)] = $permissible;
}else{
$this->defSubs[spl_object_id($permissible)] = $permissible;
}
}
public function unsubscribeFromDefaultPerms(bool $op, Permissible $permissible) : void{
if($op){
unset($this->defSubsOp[spl_object_id($permissible)]);
}else{
unset($this->defSubs[spl_object_id($permissible)]);
}
}
/**
* @return Permissible[]
*/
public function getDefaultPermSubscriptions(bool $op) : array{
if($op){
return $this->defSubsOp;
}
return $this->defSubs;
}
/**
* @return Permission[]
*/
@ -185,7 +109,5 @@ class PermissionManager{
public function clearPermissions() : void{
$this->permissions = [];
$this->defaultPerms = [];
$this->defaultPermsOp = [];
}
}

View File

@ -23,31 +23,34 @@ declare(strict_types=1);
namespace pocketmine\permission;
use function count;
use function is_array;
use function is_bool;
use function ksort;
use function strtolower;
class PermissionParser{
public const DEFAULT_OP = "op";
public const DEFAULT_NOT_OP = "notop";
public const DEFAULT_TRUE = "true";
public const DEFAULT_FALSE = "false";
public const DEFAULT_STRING_MAP = [
"op" => Permission::DEFAULT_OP,
"isop" => Permission::DEFAULT_OP,
"operator" => Permission::DEFAULT_OP,
"isoperator" => Permission::DEFAULT_OP,
"admin" => Permission::DEFAULT_OP,
"isadmin" => Permission::DEFAULT_OP,
"op" => self::DEFAULT_OP,
"isop" => self::DEFAULT_OP,
"operator" => self::DEFAULT_OP,
"isoperator" => self::DEFAULT_OP,
"admin" => self::DEFAULT_OP,
"isadmin" => self::DEFAULT_OP,
"!op" => Permission::DEFAULT_NOT_OP,
"notop" => Permission::DEFAULT_NOT_OP,
"!operator" => Permission::DEFAULT_NOT_OP,
"notoperator" => Permission::DEFAULT_NOT_OP,
"!admin" => Permission::DEFAULT_NOT_OP,
"notadmin" => Permission::DEFAULT_NOT_OP,
"!op" => self::DEFAULT_NOT_OP,
"notop" => self::DEFAULT_NOT_OP,
"!operator" => self::DEFAULT_NOT_OP,
"notoperator" => self::DEFAULT_NOT_OP,
"!admin" => self::DEFAULT_NOT_OP,
"notadmin" => self::DEFAULT_NOT_OP,
"true" => Permission::DEFAULT_TRUE,
"false" => Permission::DEFAULT_FALSE,
"true" => self::DEFAULT_TRUE,
"false" => self::DEFAULT_FALSE,
];
/**
@ -75,25 +78,27 @@ class PermissionParser{
* @param mixed[][] $data
* @phpstan-param array<string, array<string, mixed>> $data
*
* @return Permission[]
* @return Permission[][]
* @phpstan-return array<string, list<Permission>>
*/
public static function loadPermissions(array $data, string $default = Permission::DEFAULT_OP) : array{
public static function loadPermissions(array $data, string $default = self::DEFAULT_OP) : array{
$result = [];
foreach($data as $key => $entry){
$result[] = self::loadPermission($key, $entry, $default, $result);
self::loadPermission($key, $entry, $default, $result);
}
return $result;
}
/**
* @param mixed[] $data
* @param Permission[] $output reference parameter
* @param mixed[] $data
* @param Permission[][] $output reference parameter
* @phpstan-param array<string, mixed> $data
* @phpstan-param array<string, list<Permission>> $output
*
* @throws \Exception
*/
public static function loadPermission(string $name, array $data, string $default = Permission::DEFAULT_OP, array &$output = []) : Permission{
public static function loadPermission(string $name, array $data, string $default = self::DEFAULT_OP, array &$output = []) : void{
$desc = null;
$children = [];
if(isset($data["default"])){
@ -104,7 +109,7 @@ class PermissionParser{
if(is_array($data["children"])){
foreach($data["children"] as $k => $v){
if(is_array($v)){
$output[] = self::loadPermission($k, $v, $default, $output);
self::loadPermission($k, $v, $default, $output);
}
$children[$k] = true;
}
@ -117,6 +122,6 @@ class PermissionParser{
$desc = $data["description"];
}
return new Permission($name, $desc, $default, $children);
$output[$default][] = new Permission($name, $desc, $children);
}
}

View File

@ -83,7 +83,10 @@ class PluginDescription{
/** @var PluginEnableOrder */
private $order;
/** @var Permission[] */
/**
* @var Permission[][]
* @phpstan-var array<string, list<Permission>>
*/
private $permissions = [];
/**
@ -286,7 +289,8 @@ class PluginDescription{
}
/**
* @return Permission[]
* @return Permission[][]
* @phpstan-return array<string, list<Permission>>
*/
public function getPermissions() : array{
return $this->permissions;

View File

@ -31,7 +31,9 @@ use pocketmine\event\plugin\PluginDisableEvent;
use pocketmine\event\plugin\PluginEnableEvent;
use pocketmine\event\RegisteredListener;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\permission\DefaultPermissions;
use pocketmine\permission\PermissionManager;
use pocketmine\permission\PermissionParser;
use pocketmine\Server;
use pocketmine\timings\TimingsHandler;
use pocketmine\utils\AssumptionFailedError;
@ -162,8 +164,32 @@ class PluginManager{
}
$permManager = PermissionManager::getInstance();
foreach($description->getPermissions() as $perm){
$permManager->addPermission($perm);
$opRoot = $permManager->getPermission(DefaultPermissions::ROOT_OPERATOR);
$everyoneRoot = $permManager->getPermission(DefaultPermissions::ROOT_USER);
foreach($description->getPermissions() as $default => $perms){
foreach($perms as $perm){
$permManager->addPermission($perm);
switch($default){
case PermissionParser::DEFAULT_TRUE:
$everyoneRoot->addChild($perm->getName(), true);
break;
case PermissionParser::DEFAULT_OP:
$opRoot->addChild($perm->getName(), true);
break;
case PermissionParser::DEFAULT_NOT_OP:
//TODO: I don't think anyone uses this, and it currently relies on some magic inside PermissibleBase
//to ensure that the operator override actually applies.
//Explore getting rid of this.
//The following grants this permission to anyone who has the "everyone" root permission.
//However, if the operator root node (which has higher priority) is present, the
//permission will be denied instead.
$everyoneRoot->addChild($perm->getName(), true);
$opRoot->addChild($perm->getName(), false);
break;
default:
break;
}
}
}
/**

View File

@ -445,6 +445,11 @@ parameters:
count: 1
path: ../../../src/plugin/PluginBase.php
-
message: "#^Cannot call method addChild\\(\\) on pocketmine\\\\permission\\\\Permission\\|null\\.$#"
count: 4
path: ../../../src/plugin/PluginManager.php
-
message: "#^Parameter \\#1 \\$closure of static method pocketmine\\\\utils\\\\Utils\\:\\:getNiceClosureName\\(\\) expects Closure, Closure\\|null given\\.$#"
count: 2