Changed perm lockfunc to primarily use the Player-level permission and added the @quell command for managing permission downgrading.

This commit is contained in:
Griatch 2013-05-12 13:45:46 +02:00
parent 78e7346962
commit 3ac44946c3
5 changed files with 148 additions and 32 deletions

View file

@ -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.")

View file

@ -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:

View file

@ -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())

View file

@ -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

View file

@ -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>)