106 lines
3.5 KiB
Python
106 lines
3.5 KiB
Python
from secrets import compare_digest
|
|
|
|
from django.conf import settings
|
|
from rest_framework.permissions import BasePermission
|
|
from rest_framework.request import Request
|
|
|
|
from .core.models import Role
|
|
|
|
REQUEST_PERMISSION_TYPE_MAP = {
|
|
"GET": "view",
|
|
"HEAD": "view",
|
|
"OPTIONS": "view",
|
|
"POST": "change",
|
|
"PUT": "change",
|
|
"DELETE": "delete",
|
|
"PATCH": "change",
|
|
}
|
|
|
|
|
|
def get_own_obj(request, view):
|
|
user = request.user
|
|
if user is None or user.role != Role.HOST:
|
|
return ""
|
|
if request.method == "GET":
|
|
return ""
|
|
qs = view.queryset.all()
|
|
try:
|
|
model_owners = []
|
|
for model in qs:
|
|
owner = model.get_owner()
|
|
if owner not in model_owners:
|
|
model_owners.append(owner)
|
|
if len(model_owners) == 1 and user in model_owners:
|
|
return "own_"
|
|
except AttributeError:
|
|
return ""
|
|
return ""
|
|
|
|
|
|
def get_permission_for_view(request, view):
|
|
try:
|
|
permission_type = REQUEST_PERMISSION_TYPE_MAP[request.method]
|
|
if view.__class__.__name__ == "APIRootView":
|
|
return f"{permission_type}_apiroot"
|
|
model = view.model_permission_name
|
|
own_obj = get_own_obj(request, view)
|
|
return f"{permission_type}_{own_obj}{model}"
|
|
except AttributeError:
|
|
return None
|
|
|
|
|
|
def check_authorization_header(request: Request):
|
|
auth_header = request.headers.get("authorization", "")
|
|
if auth_header.startswith("Api-Key"):
|
|
token = auth_header.split()[1]
|
|
return compare_digest(token, settings.CONFIG.general.api_key)
|
|
return False
|
|
|
|
|
|
class IsAdminOrOwnUser(BasePermission):
|
|
"""
|
|
Implements Django Rest Framework permissions. This is separate from
|
|
Django's standard permission system. For details see
|
|
https://www.django-rest-framework.org/api-guide/permissions/#custom-permissions
|
|
"""
|
|
|
|
def has_permission(self, request, view):
|
|
if request.user.is_superuser():
|
|
return True
|
|
return False
|
|
|
|
def has_object_permission(self, request, view, obj):
|
|
if request.user.is_superuser():
|
|
return True
|
|
return obj.username == request.user
|
|
|
|
|
|
class IsSystemTokenOrUser(BasePermission):
|
|
"""
|
|
Implements Django Rest Framework permissions. This is separate from
|
|
Django's standard permission system. For details see
|
|
https://www.django-rest-framework.org/api-guide/permissions/#custom-permissions
|
|
|
|
This permission allows services (liquidsoap, 3rd-party, etc) to connect with
|
|
an API-Key header. All standard-users (i.e. not using the API-Key) have their
|
|
permissions checked against Django's standard permission system.
|
|
"""
|
|
|
|
def has_permission(self, request, view):
|
|
if request.user and request.user.is_authenticated:
|
|
perm = get_permission_for_view(request, view)
|
|
# Required as view_apiroot is a permission not linked to a specific
|
|
# model. This use-case allows users to view the base of the API
|
|
# explorer. Their assigned group permissions determine further access
|
|
# into the explorer.
|
|
if perm == "view_apiroot":
|
|
return True
|
|
return request.user.has_perm(perm)
|
|
return check_authorization_header(request)
|
|
|
|
def has_object_permission(self, request, view, obj):
|
|
if request.user and request.user.is_authenticated:
|
|
perm = get_permission_for_view(request, view)
|
|
return request.user.has_perm(perm, obj)
|
|
return check_authorization_header(request)
|