From 9590306d99f6db648617cf27704350f698982c35 Mon Sep 17 00:00:00 2001 From: helllllllder Date: Mon, 17 Jul 2023 12:34:15 -0300 Subject: [PATCH] feat: verify objects permission on external endpoint --- chats/apps/api/v1/external/permissions.py | 81 +++++++++++++++++++++-- chats/apps/dashboard/models.py | 4 ++ chats/apps/msgs/models.py | 8 +++ chats/apps/projects/models.py | 4 ++ chats/apps/queues/models.py | 8 +++ chats/apps/rooms/models.py | 4 ++ chats/apps/sectors/models.py | 8 +++ 7 files changed, 111 insertions(+), 6 deletions(-) diff --git a/chats/apps/api/v1/external/permissions.py b/chats/apps/api/v1/external/permissions.py index 64c06581..f43e569f 100644 --- a/chats/apps/api/v1/external/permissions.py +++ b/chats/apps/api/v1/external/permissions.py @@ -1,15 +1,84 @@ +from django.core.exceptions import ObjectDoesNotExist from rest_framework import permissions from chats.apps.projects.models import ProjectPermission class IsAdminPermission(permissions.BasePermission): - def has_permission(self, request, view): # pragma: no cover + def get_auth_permission(self, request): auth_header = request.META.get("HTTP_AUTHORIZATION") + auth_token = auth_header.split()[1] + permission = ProjectPermission.objects.get(pk=auth_token, role=1) + return permission + + def has_permission(self, request, view): # pragma: no cover + if view.action in ["list", "create"]: + try: + permission = self.get_auth_permission(request) + project = permission.project + + validation = ValidatePermissionRequest( + request_data=request.data or request.query_params, project=project + ) + + return validation.is_valid + except (AttributeError, IndexError, ProjectPermission.DoesNotExist): + return False + + return super().has_permission(request, view) + + def has_object_permission(self, request, view, obj): + """ + Return `True` if permission is granted, `False` otherwise. + """ + try: + permission = self.get_auth_permission(request) + project = obj.project + except ProjectPermission.DoesNotExist: + return False + return permission.project == project + + +LEVEL_NAME_MAPPING = { + "project_uuid": "project", + "project": "project", + "sector_uuid": "pk", + "sector": "pk", + "queue_uuid": "queues", + "queue": "queues", +} + + +class ValidatePermissionRequest: + def __init__(self, request_data, project) -> None: + self.project = project + self.data = request_data + self.queryset = {} + + # Get the instance type and pk + for key in [ + "project", + "sector", + "queue", + "project_uuid", + "sector_uuid", + "queue_uuid", + ]: + self.level_name = LEVEL_NAME_MAPPING[key] + self.level_id = self.data.get(key, None) + if self.level_name != "project" and self.level_id is not None: + self.queryset = {self.level_name: self.level_id} + break + elif self.level_name == "project" and self.level_id is not None: + break + + @property + def is_valid(self): try: - auth_token = auth_header.split()[1] - return ( - True if ProjectPermission.objects.get(pk=auth_token, role=1) else False - ) - except (AttributeError, IndexError, ProjectPermission.DoesNotExist): + if self.level_name == "project": + return str(self.project.pk) == self.level_id + if self.queryset != {}: + return self.project.sectors.filter(**self.queryset).exists() + except ObjectDoesNotExist: return False + return False diff --git a/chats/apps/dashboard/models.py b/chats/apps/dashboard/models.py index 14dfbdbf..2c269627 100644 --- a/chats/apps/dashboard/models.py +++ b/chats/apps/dashboard/models.py @@ -23,3 +23,7 @@ class Meta: def __str__(self): return self.room.queue.name + + @property + def project(self): + return self.room.project diff --git a/chats/apps/msgs/models.py b/chats/apps/msgs/models.py index 91385b1c..7373d345 100644 --- a/chats/apps/msgs/models.py +++ b/chats/apps/msgs/models.py @@ -87,6 +87,10 @@ def notify_room(self, action: str, callback: bool = False): headers={"content-type": "application/json"}, ) + @property + def project(self): + return self.room.project + class MessageMedia(BaseModel): message = models.ForeignKey( @@ -146,3 +150,7 @@ def callback(self): def notify_room(self, *args, **kwargs): """ """ self.message.notify_room(*args, **kwargs) + + @property + def project(self): + return self.message.project diff --git a/chats/apps/projects/models.py b/chats/apps/projects/models.py index 3025e3a5..7b145363 100644 --- a/chats/apps/projects/models.py +++ b/chats/apps/projects/models.py @@ -351,3 +351,7 @@ class Meta: def __str__(self): return self.receiver_type + ": " + self.external_id + + @property + def project(self): + return self.flow_start.project diff --git a/chats/apps/queues/models.py b/chats/apps/queues/models.py index a1643a7e..692abcfd 100644 --- a/chats/apps/queues/models.py +++ b/chats/apps/queues/models.py @@ -86,6 +86,10 @@ def set_queue_authorization(self, user, role: int): ) return sector_auth + @property + def project(self): + return self.sector.project + class QueueAuthorization(BaseModel): ROLE_NOT_SETTED = 0 @@ -132,6 +136,10 @@ def get_permission(self, user): def sector(self): return self.queue.sector + @property + def project(self): + return self.queue.project + @property def is_agent(self): return self.role == self.ROLE_AGENT diff --git a/chats/apps/rooms/models.py b/chats/apps/rooms/models.py index 5477b34c..d7472d3a 100644 --- a/chats/apps/rooms/models.py +++ b/chats/apps/rooms/models.py @@ -103,6 +103,10 @@ def get_is_waiting(self): check_flowstarts = self.flowstarts.filter(is_deleted=False).exists() return check_messages or check_flowstarts + @property + def project(self): + return self.queue.project + @property def last_contact_message(self): return ( diff --git a/chats/apps/sectors/models.py b/chats/apps/sectors/models.py index 20e3daec..31b094ee 100644 --- a/chats/apps/sectors/models.py +++ b/chats/apps/sectors/models.py @@ -225,6 +225,10 @@ def notify_user(self, action): action=f"sector_authorization.{action}", ) + @property + def project(self): + return self.sector.project + class SectorTag(BaseModel): name = models.CharField(_("Name"), max_length=120) @@ -251,3 +255,7 @@ class Meta: def __str__(self): return self.name + + @property + def project(self): + return self.sector.project