Commit Graph

21 Commits

Author SHA1 Message Date
lebaudantoine c9fcc2ed60 (backend) draft initial Room viewset for external applications
From a security perspective, the list endpoint should be limited to return only
rooms created by the external application. Currently, there is a risk of
exposing public rooms through this endpoint.

I will address this in upcoming commits by updating the room model to track
the source of generation. This will also provide useful information
for analytics.

The API viewset was largely copied and adapted. The serializer was heavily
restricted to return a response more appropriate for external applications,
providing ready-to-use information for their users
(for example, a clickable link).

I plan to extend the room information further, potentially aligning it with the
Google Meet API format. This first draft serves as a solid foundation.

Although scopes for delete and update exist, these methods have not yet been
implemented in the viewset. They will be added in future commits.
2025-10-06 19:34:24 +02:00
lebaudantoine 3fd5a4404c (backend) add application model with secure secret handling
We need to integrate with external applications. Objective: enable them to
securely generate room links with proper ownership attribution.

Proposed solution: Following the OAuth2 Machine-to-Machine specification,
we expose an endpoint allowing external applications to exchange a client_id
and client_secret pair for a JWT. This JWT is valid only within a well-scoped,
isolated external API, served through a dedicated viewset.

This commit introduces a model to persist application records in the database.
The main challenge lies in generating a secure client_secret and ensuring
it is properly stored.

The restframework-apikey dependency was discarded, as its approach diverges
significantly from OAuth2. Instead, inspiration was taken from oauthlib and
django-oauth-toolkit. However, their implementations proved either too heavy or
not entirely suitable for the intended use case. To avoid pulling in large
dependencies for minimal utility, the necessary components were selectively
copied, adapted, and improved.

A generic SecretField was introduced, designed for reuse and potentially
suitable for upstream contribution to Django.

Secrets are exposed only once at object creation time in the Django admin.
Once the object is saved, the secret is immediately hashed, ensuring it can
never be retrieved again.

One limitation remains: enforcing client_id and client_secret as read-only
during edits. At object creation, marking them read-only excluded them from
the Django form, which unintentionally regenerated new values.
This area requires further refinement.

The design prioritizes configurability while adhering to the principle of least
privilege. By default, new applications are created without any assigned scopes,
preventing them from performing actions on the API until explicitly configured.

If no domain is specified, domain delegation is not applied, allowing tokens
to be issued for any email domain.
2025-10-06 19:34:24 +02:00
lebaudantoine 58722cab00 🔧(backend) set explicit user subscription permissions for other tracks
Configure LiveKit token to explicitly allow users to subscribe to other
participants' video and audio tracks instead of relying on default
permissions.
2025-09-08 17:16:52 +02:00
lebaudantoine 1268346405 ♻️(backend) replace LiveKit token metadata with attributes
Switch from metadata to attributes when generating LiveKit tokens for
more convenient dict-like structure handling during token creation and
client-side reading.

Attributes provide better data structure flexibility compared to
metadata, simplifying both server-side token generation and client-side
data access patterns.
2025-09-04 11:26:48 +02:00
lebaudantoine 6c633b1ecb ♻️(backend) sync lobby and LiveKit participant UUID generation
Refactor lobby system to use consistent UUID v4 across lobby
registration and LiveKit token participant identity instead of
generating separate UUIDs.

Maintains synchronized identifiers between lobby cache and LiveKit
participants, simplifying future participant removal operations by
using the same UUID reference across both systems.
2025-09-04 11:26:48 +02:00
lebaudantoine 0f76517957 💩(backend) pass room config and user role data to LiveKit token utility
Extend LiveKit token creation utility with additional room configuration
and user role parameters to properly adapt room_admin grants and
publish sources based on permission levels.

This creates technical debt in utility function design that should be
refactored into proper service architecture for token
generation operations in future iterations.
2025-09-04 11:26:48 +02:00
lebaudantoine 206babb20f 🔧(backend) extract LiveKit publishing sources to Django settings
Move hardcoded LiveKit publishing sources from backend code to
configurable Django settings for better reusability and self-hosting
flexibility.

Enables self-hosters to customize LiveKit token generation sources
without code modifications, improving deployment configurability.
2025-09-04 11:26:48 +02:00
lebaudantoine 17c486f7bf ♻️(backend) extract notify_participant to util function
Move from lobby service to utils for reuse across services. Method is
generic enough for utility status. Future: create dedicated LiveKit
service to encapsulate all LiveKit-related utilities.
2025-07-16 14:47:24 +02:00
lebaudantoine ae17fbdaa8 ♻️(backend) extract livekit API client creation to reusable utility
Create dedicated utility function for livekit API client initialization.
Centralizes configuration logic including custom session handling for SSL
verification. Improves code reuse across backend components that interact
with LiveKit.
2025-04-24 18:05:52 +02:00
lebaudantoine 41c1f41ed2 (backend) add authenticated recording file access method
Implement secure recording file access through authentication instead of
exposing S3 bucket or using temporary signed links with loose permissions.
Inspired by docs and @spaccoud's implementation, with comprehensive
viewset checks to prevent unauthorized recording downloads.

The ingress reserved to media intercept the original request, and thanks to
Nginx annotations, check with the backend if the user is allowed to donwload
this recording file. This might introduce a dependency to Nginx in the project
by the way.

Note: Tests are integration-based rather than unit tests, requiring minio in
the compose stack and CI environment. Implementation includes known botocore
deprecation warnings that per GitHub issues won't be resolved for months.
2025-04-16 12:13:42 +02:00
lebaudantoine 4d961ed162 🚧(backend) introduce a lobby system
Implement lobby service using cache as LiveKit doesn't natively support
secure lobby functionality. Their teams recommended to create our own
system in our app's backend.

The lobby system is totally independant of the DRF session IDs,
making the request_entry endpoint authentication agnostic.

This decoupling prevents future DRF changes from breaking lobby functionality
and makes participant tracking more explicit.

Security audit is needed as current LiveKit tokens have excessive privileges
for unprivileged users. I'll offer more option ASAP for the admin to control
participant privileges.

Race condition handling also requires improvements, but should not be critical
at this point.

A great enhancement, would be to add a webhook, notifying the backend when the
room is closed, to reset cache.

This commit makes redis a prerequesite to run the suite of tests. The readme
and CI will be updated in dedicated commits.
2025-03-03 21:48:22 +01:00
lebaudantoine 710d7964ee ♻️(backend) extract LiveKit connection info generation function
Extract serialization logic for LiveKit server connection data to make it
reusable across endpoints. Function naming will be improved in future
refactoring when utility functions are moved to a proper service.
2025-03-03 21:48:22 +01:00
lebaudantoine 053c4a40e9 🩹(backend) fix identity hash randomness
'hash' built-in function is randomly seed by Python process.
In staging or production, our backend runs over 3 pods, thus 3
Python processes. For a given identity, it was not prompting
the same hash across all pods.

Why 'hash' is randomly seed? For security reasons, there was
a vulnerability disclosure exploiting key collision. Since Python 3.2,
'hash' is by default randomly seed.

Fixed it! Thx @jonathanperret for your help.
2024-09-04 14:15:38 +02:00
lebaudantoine c8cc9909ba (backend) give every participant room admin permission
Participants need to be room admin to interact with LiveKit server
api. Until we offer private room, with moderation, all participants
will be considered as room admin.

note: room admin doesn't offer permission to record a room. please,
refer to LiveKit documentation to learn more.
2024-08-29 23:15:11 +02:00
lebaudantoine 8b2750c413 (backend) attribute a color to each participant
Color is stored in participant's metadata.
Using a hash of some participant's info allow to persist the color
for logged-in participant without storing the color in db.

Please feel free to tune the saturation and lightness range.
Code is inspired by a tutorial found online.
2024-08-28 10:24:20 +02:00
lebaudantoine 28f43fb2c0 ♻️(backend) refactor LiveKit access token handling
Switched to using query parameters instead of GET requests, enabling the
inclusion of additional parameters when calling the create endpoint via POST.

Simplified the access token generation process by removing redundant calls to
`with_identity` and consolidating token generation steps. This streamlines the
method flow by preparing all necessary data before generating the access token.
2024-08-08 14:34:18 +02:00
lebaudantoine fe8ed43aae (backend) allow LiveKit users to update their own metadata
This is required, if users need to update their names, or participant
information.
2024-08-08 14:34:18 +02:00
lebaudantoine daa125edf3 🚨(backend) fix linter warnings
Recent updates of dev/ruff and dev/pylint dependencies led
to new linting warnings.

Pylint 3.2.0 introduced a new check `possibly-used-before-assignment`,
which ensures variables are defined regardless of conditional statements.

Some if/else branches were missing defaults. These have been fixed.
2024-07-31 13:12:30 +02:00
lebaudantoine e17d42ebe3 🔥(backend) remove todo items
The Pylint job was failing due to those TODO items. In our make lint
command sequence, Pylint runs first. If it fails, Ruff won't run,
which is quite inconvenient.

I've extracted those TODOs into an issue for further review.
2024-07-22 14:15:49 +02:00
lebaudantoine ae95a00301 (backend) add 'username' query param when retrieving a room
Quick and dirty approach. It works, that's essential.
Frontend can pass a desired username for the user. This would
be the name displayed in the room to other participants.
Usernames don't need to be unique, but user identities do

If no username is passed, API will fall back to a default username.
Why? This serves as a security mechanism. If the API is called
incorrectly by a client, it maintains the previous behavior.
2024-07-22 14:15:49 +02:00
lebaudantoine 2deef12d05 🚧(backend) Add utility function to generate LiveKit access token
Introduce a utility function to issue a basic LiveKit access token  with the minimal
required video grants for videoconferencing.

/!\ This function is naive, and doesn’t handle properly all cases. It’s under construction.

Testing was conducted using the LiveKit  connection test tool https://livekit.io/connection-test,
which allows users to  input the address of their local LiveKit server and an access token.

** Upcoming improvements? **

- Unit tests should be added.
- User display name should be their full name instead of their email address.
- Anonymous users should be allowed to provide a full name when requesting access to the room.
- Video grants should be adapted based on the room  configuration and the user's role.

These improvements will be addressed in future  commits.

Nevertheless, with this draft, we should be able to address various situations, including
public rooms, permanent rooms, temporary rooms, logged-in users, and anonymous users.
2024-06-25 18:55:52 +02:00