The original implementation, introduced two years ago, was incorrect
and exposed the API to an undesired authentication mode: any user
access token obtained for a given user was being accepted as valid
credentials on the external API.
Restrict authentication to the intended mode so that user access
tokens are no longer accepted on this API.
Thanks @lunika spotting this.
Recording lifecycle previously relied exclusively on the MinIO storage-hook
endpoint to transition from STOPPED to SAVED, which made the system dependent
on MinIO bucket notifications and lifecycle configuration. Introduce support
for LiveKit egress_ended webhook (EGRESS_COMPLETE, EGRESS_LIMIT_REACHED) as
an alternative finalization mechanism for self-hosted deployments that do
not use MinIO / S3 hooks.
Change behavior of existing configuation RECORDING_STORAGE_EVENT_ENABLE.
When the LiveKit mechanism is enabled (RECORDING_STORAGE_EVENT_ENABLE=False),
RecordingEventsService.handle_complete is triggered from
LiveKitEventsService._handle_egress_ended.
Since we have added custom backgrounds, they could be
soft deleted but were never really deleted.
This commits introduces a command to actually delete
this files.
In introduces also a command to purge pending upload
.
When joining a meeting that already has many participants, new
participants are now muted by default.
This is an empirical change, not directly requested by users but
informed by user experience: a lot of people joining large meetings
arrive with their microphone and/or camera open, which can be
painful for the host, who otherwise has to mute everyone or ask
everyone to mute. Many of these participants are inattentive but
still noisy.
If you are joining a room that is already at a certain size, you are
probably not the one expected to speak; presenters typically join
among the very first participants.
In particularly large rooms, with more than 5 or 10 participants,
the entry notification sound can quickly feel spammy.
A configuration to disable it exists, but new users do not discover
it easily. The sound notification is most useful while waiting for
the first few participants to arrive; once a few people are in, the
meeting usually starts and the sound becomes more disruptive than
helpful.
The visual notification remains in place, so users are still aware
when newcomers join. Roll this out and check whether users find the
change helpful.
Pin idna to >=3.15 via uv constraint-dependencies to fix a moderate
severity (CVSS 5.3) information disclosure vulnerability. The flaw is
network-exploitable with no authentication required.
With the addition of the ANALYSING state
files could be accessed in the short time they
were in that state.
We now require files to be in ready.
Also adds missing frontend types (no impact).
When analysing a file, the previous commit introduced a row level lock
to make sure we would analyse and promote a single file.
This commit changes the locking mechanism so that it happens with
the upload state which avoids long running db locks and potential
perf issues.
Before this commit, post a file check, the policy could be
reused to change the verified file.
Now, files are uplaoded to a temporary location, then inside
a transaction that prevents concurrent calls, the file is
copied to its final destination and the checks are run on that one.
A new file can still be updated with the policy but it will never be read, etc.
As part of this change, all files in the new tmp directory
on s3 should have an expiration policy.
Add an email substring filter to the user merge management command,
allowing selection of a subset of users concerned by the merge process.
This enables safer incremental execution of the command by testing it
on a controlled group of users before applying it globally.
The goal is to validate behavior and ensure the merge process does not
introduce unexpected side effects or inconsistencies at scale.
Add a management command to merge duplicate users and reassign all
granted resources to the most recent user account in the database.
Support a dry-run mode to estimate the impact of the operation before
applying any changes. This helps validate the command and identify
potential issues in environments where realistic testing is difficult.
Add unit tests to verify the command behavior and ensure database
integrity is preserved during the merge process.
Move user provisioning logic out of the external token viewset into a
dedicated service to keep the viewset lightweight and easier to
maintain.
While extracting the logic, refactor user object handling to improve
robustness and make the provisioning workflow easier to reason about.
Defend against race conditions when concurrent requests attempt to
provision the same user. Rely on the existing database constraints to
guarantee uniqueness and gracefully handle integrity errors raised by
concurrent creations.
Update the test to document the actual contract without modifying the
underlying model behavior.
These tests act as non-regression coverage and explicitly assert that
users may have a null sub or email. They are intended to document the
current behavior of the initial user model rather than evolve or
constrain it.
Ghost rows have not been reported as an operational issue. For the sake
of simplicity, avoid changing the model unless required by a concrete
issue or unless the benefits clearly outweigh the added complexity.
Fix a race condition in the external viewset where concurrent requests
could create multiple pending users with the same email address.
No database constraint enforced email uniqueness for pending users,
allowing duplicates to be created under load.
This caused issues during user reconciliation, which expects a single
matching pending user and raises a warning when multiple records are
found.
Add a narrowly scoped migration to enforce the uniqueness constraint
and address the identified issue.
Backport the logging configuration from docs to LaSuite Meet after
discussion with @lunika.
Add a proper base logging setup to restore usable logs in production.
The initial repository bootstrap lacked a complete logging
configuration, resulting in limited operational visibility.
Use the Python port of Google's phone number library on the backend
instead of the JS one on the client. Saves 140Kb of unnecessary JS
and avoids a complex dynamic import that would have been required to
optimize loading.
The transformation is static: the phone number lives in the Django
settings, so the backend can format it once and pass the result to
the client. This avoids every client loading the 140Kb library and
re-computing the same information.
Moreover, within a single client, the transformation was previously
re-computed several times during a webapp lifecycle.
Inspired by commit eb23aef in suitenumerique/docs. The same base
route path is used everywhere, which helps when the backend sits
behind an ingress serving it with a regex like `api/*`.
Allow passing configuration and access level when creating a room
through the external API.
Also add a few guardrails:
* control whether public rooms are accepted on the external API
* set the default access level when creating a new room
Ensure the new room configuration and access level are returned by
the serializer when listing rooms.
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.