Skip to content

Commit f14f087

Browse files
committed
✨(backend,frontend) add configurable recording permissions
Add two new environment variables to control who can start/stop recordings: - RECORDING_SCREEN_PERMISSION: controls screen recording access - RECORDING_TRANSCRIPT_PERMISSION: controls transcript access Each variable accepts two values: - admin_owner (default): only room administrators or owners - authenticated: any authenticated user Includes backend permissions, frontend UI logic, tests, and documentation.
1 parent 89031ab commit f14f087

18 files changed

Lines changed: 574 additions & 12 deletions

File tree

docs/features/recording.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ sequenceDiagram
9292
| Option | Type | Default | Description |
9393
| --------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
9494
| **RECORDING_ENABLE** | Boolean | `False` | Enable or disable the room recording feature. |
95+
| **RECORDING_SCREEN_PERMISSION** | String | `"admin_owner"` | Permission level for screen recording: `admin_owner` (only room admins/owners) or `authenticated` (any authenticated user). |
96+
| **RECORDING_TRANSCRIPT_PERMISSION** | String | `"admin_owner"` | Permission level for transcript: `admin_owner` (only room admins/owners) or `authenticated` (any authenticated user). |
9597
| **RECORDING_OUTPUT_FOLDER** | String | `"recordings"` | Folder/prefix where recordings are stored in the object storage. |
9698
| **RECORDING_WORKER_CLASSES** | Dict | `{ "screen_recording": "core.recording.worker.services.VideoCompositeEgressService", "transcript": "core.recording.worker.services.AudioCompositeEgressService" }` | Maps recording types to their worker service classes. |
9799
| **RECORDING_EVENT_PARSER_CLASS** | String | `"core.recording.event.parsers.MinioParser"` | Class responsible for parsing storage events and updating the backend. |

docs/installation/kubernetes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ These are the environmental options available on meet backend.
340340
| RESOURCE_DEFAULT_ACCESS_LEVEL | Default resource access level for rooms | public |
341341
| ALLOW_UNREGISTERED_ROOMS | Allow usage of unregistered rooms | true |
342342
| RECORDING_ENABLE | Record meeting option | false |
343+
| RECORDING_SCREEN_PERMISSION | Permission level for screen recording: `admin_owner` or `authenticated` | admin_owner |
344+
| RECORDING_TRANSCRIPT_PERMISSION | Permission level for transcript: `admin_owner` or `authenticated` | admin_owner |
343345
| RECORDING_OUTPUT_FOLDER | Folder to store meetings | recordings |
344346
| RECORDING_WORKER_CLASSES | Worker classes for recording | {"screen_recording": "core.recording.worker.services.VideoCompositeEgressService","transcript": "core.recording.worker.services.AudioCompositeEgressService"} |
345347
| RECORDING_EVENT_PARSER_CLASS | Storage event engine for recording | core.recording.event.parsers.MinioParser |

env.d/development/common.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ ALLOW_UNREGISTERED_ROOMS=False
5959

6060
# Recording
6161
RECORDING_ENABLE=True
62+
# Recording permissions: admin_owner (default) | authenticated
63+
RECORDING_SCREEN_PERMISSION=admin_owner
64+
RECORDING_TRANSCRIPT_PERMISSION=admin_owner
6265
RECORDING_STORAGE_EVENT_ENABLE=True
6366
RECORDING_STORAGE_EVENT_TOKEN=password
6467
SUMMARY_SERVICE_ENDPOINT=http://app-summary-dev:8000/api/v1/tasks/

src/backend/core/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ def get_frontend_configuration(request):
4242
"available_modes": settings.RECORDING_WORKER_CLASSES.keys(),
4343
"expiration_days": settings.RECORDING_EXPIRATION_DAYS,
4444
"max_duration": settings.RECORDING_MAX_DURATION,
45+
"screen_recording_permission": settings.RECORDING_SCREEN_PERMISSION,
46+
"transcript_permission": settings.RECORDING_TRANSCRIPT_PERMISSION,
4547
},
4648
"telephony": {
4749
"enabled": settings.ROOM_TELEPHONY_ENABLED,

src/backend/core/api/permissions.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Permission handlers for the Meet core app."""
22

3+
from django.conf import settings
4+
35
from rest_framework import permissions
46

5-
from ..models import RoleChoices
7+
from ..models import Recording, RecordingStatusChoices, RoleChoices
68

79
ACTION_FOR_METHOD_TO_PERMISSION = {
810
"versions_detail": {"DELETE": "versions_destroy", "GET": "versions_retrieve"}
@@ -99,6 +101,43 @@ def has_object_permission(self, request, view, obj):
99101
return obj.is_administrator_or_owner(request.user)
100102

101103

104+
class HasRecordingPermission(IsAuthenticated):
105+
"""Check if user has permission to start/stop recording based on mode and settings."""
106+
107+
message = "You do not have permission to perform this recording action."
108+
109+
def _get_permission_level(self, mode):
110+
"""Return the permission level for the given mode."""
111+
if mode == "screen_recording":
112+
return getattr(settings, "RECORDING_SCREEN_PERMISSION", "admin_owner")
113+
if mode == "transcript":
114+
return getattr(settings, "RECORDING_TRANSCRIPT_PERMISSION", "admin_owner")
115+
return "admin_owner"
116+
117+
def has_object_permission(self, request, view, obj):
118+
"""Check object-level permissions based on recording mode."""
119+
mode = request.data.get("mode")
120+
121+
# For stop-recording, get mode from active recording
122+
if not mode:
123+
try:
124+
recording = Recording.objects.get(
125+
room=obj, status=RecordingStatusChoices.ACTIVE
126+
)
127+
mode = recording.mode
128+
except Recording.DoesNotExist:
129+
# No active recording, let the view handle the error
130+
return True
131+
132+
permission_level = self._get_permission_level(mode)
133+
134+
if permission_level == "authenticated":
135+
# Already authenticated via IsAuthenticated.has_permission
136+
return True
137+
# admin_owner
138+
return obj.is_administrator_or_owner(request.user)
139+
140+
102141
class HasLiveKitRoomAccess(permissions.BasePermission):
103142
"""Check if authenticated user's LiveKit token is for the specific room."""
104143

src/backend/core/api/viewsets.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ def perform_create(self, serializer):
281281
methods=["post"],
282282
url_path="start-recording",
283283
permission_classes=[
284-
permissions.HasPrivilegesOnRoom,
284+
permissions.HasRecordingPermission,
285285
],
286286
)
287287
@FeatureFlag.require("recording")
@@ -329,7 +329,7 @@ def start_room_recording(self, request, pk=None): # pylint: disable=unused-argu
329329
methods=["post"],
330330
url_path="stop-recording",
331331
permission_classes=[
332-
permissions.HasPrivilegesOnRoom,
332+
permissions.HasRecordingPermission,
333333
],
334334
)
335335
@FeatureFlag.require("recording")

0 commit comments

Comments
 (0)