From 43d678d8ca698f6c8da19f8822bd05eabbce0bcb Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 23 May 2021 00:42:30 +0200 Subject: [PATCH] Fix bugs in API perm checking --- evennia/locks/lockfuncs.py | 3 ++- evennia/locks/lockhandler.py | 23 +++++++++++++++++++++++ evennia/web/api/README.md | 3 ++- evennia/web/api/permissions.py | 19 +++++++++++++------ evennia/web/api/urls.py | 1 + 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/evennia/locks/lockfuncs.py b/evennia/locks/lockfuncs.py index a55b442dcc..7adf710479 100644 --- a/evennia/locks/lockfuncs.py +++ b/evennia/locks/lockfuncs.py @@ -167,7 +167,8 @@ def perm(accessing_obj, accessed_obj, *args, **kwargs): try: permission = args[0].lower() perms_object = accessing_obj.permissions.all() - except (AttributeError, IndexError): + except (AttributeError, IndexError) as err: + print("accessing_obj err:", err) return False gtmode = kwargs.pop("_greater_than", False) diff --git a/evennia/locks/lockhandler.py b/evennia/locks/lockhandler.py index 25b2f2be45..843a709ff4 100644 --- a/evennia/locks/lockhandler.py +++ b/evennia/locks/lockhandler.py @@ -693,6 +693,29 @@ def check_lockstring( access_type=access_type, ) +def check_perm( + obj, permission, no_superuser_bypass=False): + """ + Shortcut for checking if an object has the given `permission`. If the + permission is in `settings.PERMISSION_HIERARCHY`, the check passes + if the object has this permission or higher. + + This is equivalent to calling the perm() lockfunc, but without needing + an accessed object. + + Args: + obj (Object, Account): The object to check access. If this has a linked + Account, the account is checked instead (same rules as per perm()). + permission (str): The permission string to check. + no_superuser_bypass (bool, optional): If unset, the superuser + will always pass this check. + + """ + from evennia.locks.lockfuncs import perm + if not no_superuser_bypass and obj.is_superuser: + return True + return perm(obj, None, permission) + def validate_lockstring(lockstring): """ diff --git a/evennia/web/api/README.md b/evennia/web/api/README.md index d06838fbf4..efa5cd0596 100644 --- a/evennia/web/api/README.md +++ b/evennia/web/api/README.md @@ -1,6 +1,7 @@ # Evennia API ## Synopsis + An API, or [Application Programming Interface][wiki-api], is a way of establishing rules through which external services can use your program. In web development, it's often that case that the 'frontend' of a web app is written in HTML and Javascript @@ -141,4 +142,4 @@ the native [Fetch][fetch]. [rest]: https://en.wikipedia.org/wiki/Representational_state_transfer [requests]: https://requests.readthedocs.io/en/master/ [axios]: https://github.com/axios/axios -[fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API \ No newline at end of file +[fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API diff --git a/evennia/web/api/permissions.py b/evennia/web/api/permissions.py index 87efe07a23..6ed9521629 100644 --- a/evennia/web/api/permissions.py +++ b/evennia/web/api/permissions.py @@ -1,13 +1,20 @@ -from rest_framework import permissions +""" +Sets up an api-access permission check using the in-game permission hierarchy. +""" + + +from rest_framework import permissions from django.conf import settings +from evennia.locks.lockhandler import check_perm class EvenniaPermission(permissions.BasePermission): """ - A Django Rest Framework permission class that allows us to use - Evennia's permission structure. Based on the action in a given - view, we'll check a corresponding Evennia access/lock check. + A Django Rest Framework permission class that allows us to use Evennia's + permission structure. Based on the action in a given view, we'll check a + corresponding Evennia access/lock check. + """ # subclass this to change these permissions @@ -40,9 +47,9 @@ class EvenniaPermission(permissions.BasePermission): return True # these actions don't support object-level permissions, so use the above definitions if view.action == "list": - return request.user.has_permistring(self.MINIMUM_LIST_PERMISSION) + return check_perm(request.user, self.MINIMUM_LIST_PERMISSION) if view.action == "create": - return request.user.has_permistring(self.MINIMUM_CREATE_PERMISSION) + return check_perm(request.user, self.MINIMUM_CREATE_PERMISSION) return True # this means we'll check object-level permissions @staticmethod diff --git a/evennia/web/api/urls.py b/evennia/web/api/urls.py index 70c18c43c8..3b42bf9ec6 100644 --- a/evennia/web/api/urls.py +++ b/evennia/web/api/urls.py @@ -7,6 +7,7 @@ actions that it detects for a viewset. For example, below we create a DefaultRou We then register ObjectDBViewSet, a viewset for CRUD operations for ObjectDB instances, to the 'objects' base endpoint. That will generate a number of URLs like the following: + list objects: action: GET, url: /objects/, view name: object-list create object: action: POST, url: /objects/, view name: object-list retrieve object: action: GET, url: /objects/<:pk>, view name: object-detail