mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-29 03:37:17 +00:00
fcb7087f4d
Some integrators render our videoconference inside an iframe, where our cookie-based authentication does not work: our cookies are SameSite=Lax/Strict, so the iframe drops them. We looked at what Jitsi offers: a shared secret used to sign JWTs that authenticate users coming from external services. Since we already expose an external API where third parties authenticate as a given user, it was simpler for us to add an exchange mechanism on top of that. Flow: * Through the external API, mint a short-lived, single-use exchange code for a user. * The third party hands that code to the frontend as a URL fragment. * The frontend exchanges the code for a longer-lived JWT that can be used to query the regular API viewsets. Known limitations and follow-ups: * At some point it would be nice to shorten the JWT lifetime and add a refresh mechanism. This will be handled in a follow-up PR when actually needed. * CSP rules to control which origins are allowed to embed the app in an iframe still need to be added. * This alternative authentication cannot easily be scoped to a subset of endpoints without adding a lot of complexity, so it is accepted globally on the API for now.
52 lines
1.5 KiB
Python
52 lines
1.5 KiB
Python
"""Feature flag handler for the Meet core app."""
|
|
|
|
from functools import wraps
|
|
|
|
from django.conf import settings
|
|
from django.http import Http404
|
|
|
|
|
|
class FeatureFlag:
|
|
"""Check if features are enabled and return error responses."""
|
|
|
|
FLAGS = {
|
|
"recording": "RECORDING_ENABLE",
|
|
"storage_event": "RECORDING_STORAGE_EVENT_ENABLE",
|
|
"subtitle": "ROOM_SUBTITLE_ENABLED",
|
|
"file_upload": "FILE_UPLOAD_ENABLED",
|
|
"addons": "ADDONS_ENABLED",
|
|
"application": "APPLICATION_ENABLED",
|
|
"roomkit": "ROOMKIT_ENABLED",
|
|
"connection_test": "CONNECTION_TEST_ENABLED",
|
|
"user_access_token": "USER_ACCESS_TOKEN_ENABLED",
|
|
}
|
|
|
|
@classmethod
|
|
def flag_is_active(cls, flag_name):
|
|
"""Check if a feature flag is active."""
|
|
|
|
setting_name = cls.FLAGS.get(flag_name)
|
|
|
|
if setting_name is None:
|
|
return False
|
|
|
|
return getattr(settings, setting_name, False)
|
|
|
|
@classmethod
|
|
def require(cls, flag_name):
|
|
"""Decorator to check feature at the beginning of endpoint methods."""
|
|
|
|
if flag_name not in cls.FLAGS:
|
|
raise ValueError(f"Unknown feature flag: {flag_name}")
|
|
|
|
def decorator(view_func):
|
|
@wraps(view_func)
|
|
def wrapper(self, request, *args, **kwargs):
|
|
if not cls.flag_is_active(flag_name):
|
|
raise Http404
|
|
return view_func(self, request, *args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
return decorator
|