libretime/api/libretime_api/permissions.py

106 lines
3.5 KiB
Python
Raw Permalink Normal View History

from secrets import compare_digest
2020-01-30 14:47:36 +01:00
from django.conf import settings
from rest_framework.permissions import BasePermission
from rest_framework.request import Request
from .core.models import Role
2020-01-30 14:47:36 +01:00
REQUEST_PERMISSION_TYPE_MAP = {
2021-05-27 16:23:02 +02:00
"GET": "view",
"HEAD": "view",
"OPTIONS": "view",
"POST": "change",
"PUT": "change",
"DELETE": "delete",
"PATCH": "change",
2020-01-30 14:47:36 +01:00
}
2021-05-27 16:23:02 +02:00
2020-01-30 14:47:36 +01:00
def get_own_obj(request, view):
user = request.user
2022-06-27 17:13:05 +02:00
if user is None or user.role != Role.HOST:
2021-05-27 16:23:02 +02:00
return ""
if request.method == "GET":
return ""
2020-01-30 14:47:36 +01:00
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:
2021-05-27 16:23:02 +02:00
return "own_"
2020-01-30 14:47:36 +01:00
except AttributeError:
2021-05-27 16:23:02 +02:00
return ""
return ""
2020-01-30 14:47:36 +01:00
def get_permission_for_view(request, view):
try:
permission_type = REQUEST_PERMISSION_TYPE_MAP[request.method]
2021-05-27 16:23:02 +02:00
if view.__class__.__name__ == "APIRootView":
return f"{permission_type}_apiroot"
2020-01-30 14:47:36 +01:00
model = view.model_permission_name
own_obj = get_own_obj(request, view)
2022-04-01 17:29:11 +02:00
return f"{permission_type}_{own_obj}{model}"
2020-01-30 14:47:36 +01:00
except AttributeError:
return None
2021-05-27 16:23:02 +02:00
def check_authorization_header(request: Request):
auth_header = request.headers.get("authorization", "")
2021-05-27 16:23:02 +02:00
if auth_header.startswith("Api-Key"):
2020-01-30 14:47:36 +01:00
token = auth_header.split()[1]
return compare_digest(token, settings.CONFIG.general.api_key)
2020-01-30 14:47:36 +01:00
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
"""
2021-05-27 16:23:02 +02:00
2020-01-30 14:47:36 +01:00
def has_permission(self, request, view):
if request.user.is_superuser():
2020-01-30 14:47:36 +01:00
return True
return False
def has_object_permission(self, request, view, obj):
if request.user.is_superuser():
2020-01-30 14:47:36 +01:00
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.
"""
2021-05-27 16:23:02 +02:00
2020-01-30 14:47:36 +01:00
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.
2021-05-27 16:23:02 +02:00
if perm == "view_apiroot":
2020-01-30 14:47:36 +01:00
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)