Ensure the participant requesting a mute action is still present
in the room before processing the request.
This mitigates scenarios where a previously issued token could be
reused after the meeting has ended.
Current token lifetime is intentionally long-lived and will be
refactored in the future to better align with LiveKit session
constraints. In the meantime, add this extra validation step to
reduce the attack surface.
Extend the existing live synchronization mechanism beyond room
configuration to also include lobby access level changes.
This ensures that all owners and admins sharing a room maintain a
consistent and up-to-date view of room state in the frontend,
including configuration and access control updates.
Update room serialization to include room configuration for all
users fetching the API response, not only room owners.
This behavior was inherited from the original upstream project.
At the moment, exposing this configuration does not appear to
introduce meaningful security concerns or provide attackers with
additional capabilities.
The decision will continue to be reviewed from a security
perspective, but sharing the configuration improves frontend
consistency and synchronization.
Simplify source serialization and validation logic while improving
type safety around room configuration handling.
Introduce a dedicated TypeScript type matching the backend
Pydantic model more precisely.
Also harmonize track source casing between frontend and backend to
remove redundant conversion logic and resolve#1282.
Introduce synchronization of room configuration changes across
active participants.
When a room configuration is updated through a PUT operation, the
backend now performs an additional LiveKit API call to notify room
participants through a room metadata update event.
This ensures admins and owners quickly see up-to-date settings in
their administration panel. It also prepares the frontend for
automatic updates of unprivileged participants room’s data without
refetching it from the API.
An event-driven design was chosen instead of storing the full room
configuration in LiveKit metadata. While embedding the state
directly in metadata would provide immediate synchronization, it
would also require initializing and maintaining configuration
state during room creation or webhook handling, increasing the
risk of operational failures and regressions.
Instead, the backend emits lightweight synchronization events and
active clients update their React Query cache, which remains the
single source of truth for room configuration data.
Introduce a new room setting controlling whether all participants,
including non-privileged users, can mute others.
Update API validation accordingly and add the frontend controls
allowing administrators to toggle the option and persist the
configuration through the API.
Enable any participant to mute others when the room configuration
allows it. This is enabled by default for all meetings unless
explicitly disabled by an administrator.
Privileged users retain the ability to mute any participant
regardless of the room configuration.
Added a hyperlink to the "Open" text in step 1 of the recording
notification email instructions. Previously, "Open" was plain text
and users could only access their recording via the button below.
Now the text itself is a clickable link, improving accessibility
for email clients that may not render the button properly.
Updated MJML source template and all 4 locale files (en, fr, de, nl).
Introduce a new user assignment mechanism to for more friendly output
than the current (SPEAKER_0, SPEAKER_1, ...). Use the VAD metadata to
compare speech intervals with those returned by WhisperX. User with the
highest overlap score above a defined threshold is assigned to each segment.
This method allows for multi-speaker scenarios for a single account.
The tasks endpoint used non-timezone-aware date and time values and split
them into separate variables, which is unconventional. Refactor the
implementation to use timezone-aware datetime objects and align transcription
formatting with the user-declared timezone. Update the source of truth for
recording start time to FileInfo.started_at for improved precision. Adjust
the task signature in preparation for upcoming user assignment work, which
will require `started_at`, `ended_at`, and `metadata_filename`.
Expose RECORDING_ENCODING_* settings to override the default LiveKit
Egress preset (H264_720P_30). When RECORDING_ENCODING_ENABLED is True,
the provided width/height/framerate/bitrate/keyframe values are passed
as advanced EncodingOptions. Lowering framerate and bitrate reduces
recording file size and egress worker CPU load.
Disabled by default, preserving current behaviour.
Wrap Recording and RecordingAccess creation in a single transaction so a
partial failure does not leave orphan rows, and return 409 instead of 500
when a recording is already in progress for the room.
When the worker fails to start, transition the Recording to
FAILED_TO_START so the unique partial constraint on (room, status) no
longer blocks future recording attempts on the same room.
Room.configuration accepted arbitrary JSON without validation, allowing unsafe
or malformed payloads to be stored and creating a security risk. Define a
Pydantic schema to enforce structure and constraints, and add validation
at the serializer level to reject invalid inputs.
Integrate the add-ons authentication backend into the externalviewset.
This allows third-party integrations (e.g. calendar add-ins) to
obtain a JWT for a user and use it to call the API (e.g. create a
room) via a Bearer authorization header.
Introduce a configuration flag to enable or disable the
application token exchange (service account) mechanism.
This allows activating alternative authentication backends
without requiring full application token configuration.
Required to support the upcoming add-ons authentication backend.
The external viewset expected a plural "rooms:x" scope instead of
the incorrect singular "room:x".
Update it to accept the proper scope and emit tokens accordingly.
Add a new authentication backend for add-ons, with a core service
managing session state in cache and exposing three API endpoints.
Microsoft Add-ins recommend launching authentication from the
side panel via a dialog, then returning the JWT to the parent
context using postMessage. However, due to Django and SSO security
constraints (window.opener not preserved), this approach is not
viable.
Implement a three-step authentication flow:
- `/init`: create a session, return a short-lived transit token
and CSRF token. Store session ID in a secure HttpOnly cookie.
- `/poll`: allow the add-on to poll until authentication is
complete, then consume the session and clear the cookie.
- `/exchange`: exchange the transit token for a JWT, which is
later retrieved via the `/poll` endpoint.
The add-on opens an authentication dialog, stores the transit
token in sessionStorage, and performs the exchange after login.
This approach works within iframe constraints and provides a
sufficiently secure v0 despite known limitations.
Allow controlling when the metadata collector agent is started,
enabling users to try the feature and disable it if needed.
Introduce a user-level feature flag to toggle the agent for the
initial release.
Introduce MetadataCollector and MetadataCollectorService classes to
centralize the collection and storage of user connections, VAD events,
and chat messages. This creates a structured foundation for future speaker
assignment logic based on voice activity detection. Add tests for this new
feature.
Run `uv lock --upgrade` to update transitive dependencies and
resolve the vulnerability in Pillow.
Upgrade Pillow from 12.1.1 to 12.2.0 to address the FITS GZIP
decompression bomb issue.
Tests were incorrectly mocking Twirp errors using HTTP status
codes instead of the meaningful error codes returned by the
LiveKit SDK.
Update mocks to reflect actual SDK behavior.
Replace passing the LiveKit JWT in the request body with the
Authorization header, following standard authentication practices.
Extend the LiveKit authentication backend usage across additional
endpoints.
This also raises questions about how clients should securely
retrieve LiveKit tokens, to be addressed later.
Avoid mapping all Twirp errors to generic 500 responses.
Explicitly handle the case where a participant is no longer in
the room, as this may indicate suspicious behavior or a client
state issue.
Improve error discrimination to provide more accurate responses.
Introduce toggle-hand and rename endpoints in RoomViewSet,
secured with LiveKit token authentication.
Remove direct permission for clients to update their own metadata
via LiveKit tokens to prevent spoofing (e.g. faking admin status).
Proxy participant metadata updates through the backend to enforce
proper validation and authorization.
Signed-off-by: lebaudantoine <lebaud.antoine131@gmail.com>
Resolve warnings raised in jwt/api_jwt.py:365 by ensuring test
keys meet the required security length.
Align test configuration with expected cryptographic standards.
Serialization hardening introduced a breaking change between the
frontend and backend. Adjust the Pydantic model to restore
compatibility.
Reinstate support for can_subscribe_metric, which is passed by
default from the frontend.
Email addresses are PII and should not appear in technical or
error logs.
Sanitize logging to avoid exposing sensitive user data when
invitation sending fails.
Prevent invited participants from seeing each other's email
addresses when sending room invitations.
Ensure invitations are sent with proper isolation to avoid
mass PII disclosure.
This mitigates risks of email harvesting, spam, and phishing
through the platform.
After migrating to uv-build only the module matching the project name was
included in sdist/wheel packages. Without a src layout additional modules
need to be tracked manually to ship them in built packages.
Make SESSION_ENGINE configurable through environment variable,
following the same values.Value() pattern already used for
SESSION_COOKIE_AGE. This enables OIDC backchannel-logout by
allowing users to set SESSION_ENGINE to db backend.
Closes#1037