mirror of
https://github.com/evennia/evennia.git
synced 2026-04-04 06:57:16 +02:00
Changed perm lockfunc to primarily use the Player-level permission and added the @quell command for managing permission downgrading.
This commit is contained in:
parent
78e7346962
commit
3ac44946c3
5 changed files with 148 additions and 32 deletions
|
|
@ -21,19 +21,32 @@ from src.commands.default.muxcommand import MuxCommand
|
|||
PERMISSION_HIERARCHY = settings.PERMISSION_HIERARCHY
|
||||
PERMISSION_HIERARCHY_LOWER = [perm.lower() for perm in PERMISSION_HIERARCHY]
|
||||
|
||||
class CmdQuell(MuxCommand):
|
||||
class CmdQuell(MuxPlayerCommand):
|
||||
"""
|
||||
Quelling permissions
|
||||
|
||||
Usage:
|
||||
quell <command> [=permission level]
|
||||
quell
|
||||
unquell
|
||||
quell/permlevel <command>
|
||||
|
||||
Normally the permission level of the Player is used when puppeting a
|
||||
Character/Object to determine access. Giving this command without
|
||||
arguments will instead switch the lock system to make use of the
|
||||
puppeted Object's permissions instead. Note that this only works DOWNWARDS -
|
||||
a Player cannot use a higher-permission Character to escalate their Player
|
||||
permissions for example. Use the unquell command to revert this state.
|
||||
|
||||
Note that the superuser character is unaffected by full quelling. Use a separate
|
||||
admin account for testing.
|
||||
|
||||
When given an argument, the argument is considered a command to execute with
|
||||
a different (lower) permission level than they currently have. This is useful
|
||||
for quick testing. If no permlevel switch is given, the command will be
|
||||
executed using the lowest permission level available in settings.PERMISSION_HIERARCHY.
|
||||
|
||||
Quelling singular commands will work also for the superuser.
|
||||
|
||||
This is an admin command that allows to execute another command as
|
||||
another (lower) permission level than what you currently
|
||||
have. This is useful for testing. Also superuser flag will be
|
||||
deactivated by this command. If no permission level is given,
|
||||
the command will be executed as the lowest level available in
|
||||
settings.PERMISSION_HIERARCHY.
|
||||
"""
|
||||
|
||||
key = "quell"
|
||||
|
|
@ -43,12 +56,30 @@ class CmdQuell(MuxCommand):
|
|||
def func(self):
|
||||
"Perform the command"
|
||||
|
||||
player = self.caller
|
||||
|
||||
if not self.args:
|
||||
self.caller.msg("Usage: quell <command> [=permission level]")
|
||||
return
|
||||
# try to fully quell player permissions
|
||||
if self.cmdstring == 'unquell':
|
||||
if player.get_attribute('_quell'):
|
||||
self.msg("You are not currently quelling you Player permissions.")
|
||||
else:
|
||||
player.del_attribute('_quell')
|
||||
self.msg("You are now using your Player permissions normally.")
|
||||
return
|
||||
else:
|
||||
if player.is_superuser:
|
||||
self.msg("Superusers cannot be quelled.")
|
||||
return
|
||||
if player.get_attribute('_quell'):
|
||||
self.msg("You are already quelling your Player permissions.")
|
||||
return
|
||||
player.set_attribute('_quell', True)
|
||||
self.msg("You quell your Player permissions.")
|
||||
return
|
||||
|
||||
cmd = self.lhs
|
||||
perm = self.rhs
|
||||
perm = self.switches and self.switches[0] or None
|
||||
|
||||
if not PERMISSION_HIERARCHY:
|
||||
self.caller.msg("settings.PERMISSION_HIERARCHY is not defined. Add a hierarchy to use this command.")
|
||||
|
|
|
|||
|
|
@ -1116,6 +1116,7 @@ class CmdSetAttribute(ObjManipCommand):
|
|||
@set <obj>/<attr> = <value>
|
||||
@set <obj>/<attr> =
|
||||
@set <obj>/<attr>
|
||||
@set *<player>/attr = <value>
|
||||
|
||||
Sets attributes on objects. The second form clears
|
||||
a previously set attribute while the last form
|
||||
|
|
@ -1214,7 +1215,10 @@ class CmdSetAttribute(ObjManipCommand):
|
|||
objname = self.lhs_objattr[0]['name']
|
||||
attrs = self.lhs_objattr[0]['attrs']
|
||||
|
||||
obj = caller.search(objname)
|
||||
if objname.startswith('*'):
|
||||
obj = caller.search_player(objname.lstrip('*'))
|
||||
else:
|
||||
obj = caller.search(objname)
|
||||
if not obj:
|
||||
return
|
||||
|
||||
|
|
@ -1682,7 +1686,7 @@ class CmdExamine(ObjManipCommand):
|
|||
|
||||
self.player_mode = "player" in self.switches or obj_name.startswith('*')
|
||||
if self.player_mode:
|
||||
obj = self.search_player(obj_name)
|
||||
obj = caller.search_player(obj_name.lstrip('*'))
|
||||
else:
|
||||
obj = caller.search(obj_name)
|
||||
if not obj:
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class PlayerCmdSet(CmdSet):
|
|||
self.add(player.CmdQuit())
|
||||
self.add(player.CmdPassword())
|
||||
self.add(player.CmdColorTest())
|
||||
self.add(player.CmdQuell())
|
||||
|
||||
# testing
|
||||
self.add(building.CmdExamine())
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ __all__ = ("CmdOOCLook", "CmdIC", "CmdOOC", "CmdPassword", "CmdQuit",
|
|||
MAX_NR_CHARACTERS = MULTISESSION_MODE < 2 and 1 or MAX_NR_CHARACTERS
|
||||
BASE_PLAYER_TYPECLASS = settings.BASE_PLAYER_TYPECLASS
|
||||
|
||||
PERMISSION_HIERARCHY = settings.PERMISSION_HIERARCHY
|
||||
PERMISSION_HIERARCHY_LOWER = [perm.lower() for perm in PERMISSION_HIERARCHY]
|
||||
|
||||
class CmdOOCLook(MuxPlayerCommand):
|
||||
"""
|
||||
ooc look
|
||||
|
|
@ -601,3 +604,51 @@ class CmdColorTest(MuxPlayerCommand):
|
|||
# malformed input
|
||||
self.msg("Usage: @color ansi|xterm256")
|
||||
|
||||
class CmdQuell(MuxPlayerCommand):
|
||||
"""
|
||||
Quelling permissions
|
||||
|
||||
Usage:
|
||||
quell
|
||||
unquell
|
||||
|
||||
Normally the permission level of the Player is used when puppeting a
|
||||
Character/Object to determine access. This command will switch the lock
|
||||
system to make use of the puppeted Object's permissions instead. This is
|
||||
useful mainly for testing.
|
||||
Hierarchical permission quelling only work downwards, thus a Player cannot
|
||||
use a higher-permission Character to escalate their permission level.
|
||||
Use the unquell command to revert back to normal operation.
|
||||
|
||||
Note that the superuser character cannot be quelled. Use a separate
|
||||
admin account for testing.
|
||||
"""
|
||||
|
||||
key = "@quell"
|
||||
aliases =["@unquell"]
|
||||
locks = "cmd:all()"
|
||||
help_category = "General"
|
||||
|
||||
def func(self):
|
||||
"Perform the command"
|
||||
player = self.caller
|
||||
permstr = " (%s)" % (", ".join(player.permissions))
|
||||
if player.is_superuser:
|
||||
self.msg("Superusers cannot be quelled.")
|
||||
return
|
||||
if self.cmdstring == '@unquell':
|
||||
if not player.get_attribute('_quell'):
|
||||
self.msg("Already using normal Player permissions%s." % permstr)
|
||||
else:
|
||||
player.del_attribute('_quell')
|
||||
self.msg("Player permissions restored%s." % permstr)
|
||||
return
|
||||
else:
|
||||
if player.get_attribute('_quell'):
|
||||
self.msg("Already quelling Player permissions")
|
||||
return
|
||||
player.set_attribute('_quell', True)
|
||||
self.msg("Quelling Player permissions%s." % permstr)
|
||||
return
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -128,24 +128,61 @@ def perm(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
perm(<permission>)
|
||||
|
||||
where <permission> is the permission accessing_obj must
|
||||
have in order to pass the lock. If the given permission
|
||||
is part of _PERMISSION_HIERARCHY, permission is also granted
|
||||
to all ranks higher up in the hierarchy.
|
||||
have in order to pass the lock.
|
||||
|
||||
If the given permission is part of settings.PERMISSION_HIERARCHY,
|
||||
permission is also granted to all ranks higher up in the hierarchy.
|
||||
|
||||
If accessing_object is an Object controlled by a Player, the
|
||||
permissions of the Player is used unless the PlayerAttribute _quell
|
||||
is set to True on the Object. In this case however, the
|
||||
LOWEST hieararcy-permission of the Player/Object-pair will be used
|
||||
(this is order to avoid Players potentially escalating their own permissions
|
||||
by use of a higher-level Object)
|
||||
|
||||
"""
|
||||
# this allows the perm_above lockfunc to make use of this function too
|
||||
gtmode = kwargs.pop("_greater_than", False)
|
||||
|
||||
try:
|
||||
perm = args[0].lower()
|
||||
permissions = [p.lower() for p in accessing_obj.permissions]
|
||||
perms_object = [p.lower() for p in accessing_obj.permissions]
|
||||
except (AttributeError, IndexError):
|
||||
return False
|
||||
|
||||
if perm in permissions:
|
||||
# simplest case - we have a direct match
|
||||
if utils.inherits_from(accessing_obj, "src.objects.objects.Object") and accessing_obj.player:
|
||||
player = accessing_obj.player
|
||||
perms_player = [p.lower() for p in player.permissions]
|
||||
is_quell = player.get_attribute("_quell")
|
||||
|
||||
if perm in _PERMISSION_HIERARCHY:
|
||||
# check hierarchy without allowing escalation obj->player
|
||||
hpos_target = _PERMISSION_HIERARCHY.index(perm)
|
||||
hpos_player = [hpos for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) if hperm in perms_player]
|
||||
hpos_player = hpos_player and hpos_player[-1] or -1
|
||||
if is_quell:
|
||||
hpos_object = [hpos for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) if hperm in perms_object]
|
||||
hpos_object = hpos_object and hpos_object[-1] or -1
|
||||
if gtmode:
|
||||
return hpos_target < min(hpos_player, hpos_object)
|
||||
else:
|
||||
return hpos_target <= min(hpos_player, hpos_object)
|
||||
elif gtmode:
|
||||
return gtmode and hpos_target < hpos_player
|
||||
else:
|
||||
return hpos_target <= hpos_player
|
||||
elif not is_quell and perm in perms_player:
|
||||
# if we get here, check player perms first, otherwise continue as normal
|
||||
return True
|
||||
|
||||
if perm in perms_object:
|
||||
# simplest case - we have direct match
|
||||
return True
|
||||
if perm in _PERMISSION_HIERARCHY:
|
||||
# check if we have a higher hierarchy position
|
||||
ppos = _PERMISSION_HIERARCHY.index(perm)
|
||||
hpos_target = _PERMISSION_HIERARCHY.index(perm)
|
||||
return any(1 for hpos, hperm in enumerate(_PERMISSION_HIERARCHY)
|
||||
if hperm in permissions and hpos > ppos)
|
||||
if hperm in perms_object and hpos_target < hpos)
|
||||
return False
|
||||
|
||||
def perm_above(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
|
|
@ -155,20 +192,12 @@ def perm_above(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
it's assumed we refer to superuser. If no hierarchy is defined,
|
||||
this function has no meaning and returns False.
|
||||
"""
|
||||
try:
|
||||
perm = args[0].lower()
|
||||
except (AttributeError, IndexError):
|
||||
return False
|
||||
|
||||
if perm in _PERMISSION_HIERARCHY:
|
||||
ppos = _PERMISSION_HIERARCHY.index(perm)
|
||||
return any(1 for hpos, hperm in enumerate(_PERMISSION_HIERARCHY)
|
||||
if hperm in [p.lower() for p in accessing_obj.permissions] and hpos > ppos)
|
||||
return False
|
||||
kwargs["_greater_than"] = True
|
||||
return perm(accessing_obj,accessed_obj, *args, **kwargs)
|
||||
|
||||
def pperm(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
"""
|
||||
The basic permission-checker for Player objects. Ignores case.
|
||||
The basic permission-checker only for Player objects. Ignores case.
|
||||
|
||||
Usage:
|
||||
pperm(<permission>)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue