Commit Graph

63 Commits

Author SHA1 Message Date
lebaudantoine 6742f5d19d (backend) monitor throttling rate failure through sentry
Use a mixin, introduced by @lunika in the shared
backend library to monitor throttling behavior.

The mixin tracks when throttling limits are reached, sending errors to Sentry
to trigger alerts when configured. This helps detect misconfigurations,
fine-tune throttling settings, and identify suspicious operations.

This enables safely increasing API throttling limits while ensuring stability,
providing confidence that higher limits won’t break the system.
2026-02-09 15:50:53 +01:00
lebaudantoine 23de7e52bc ♻️(backend) extract throttling classes into a module
Extract throttling classes into a dedicated Python module, following the
structure of suitenumerique/docs.

This is a preparatory refactor to ease upcoming changes to the throttling
implementation. No functional behavior change is introduced in this commit.
2026-02-09 15:50:53 +01:00
lebaudantoine 587a5bc574 (frontend) allow starting both a recording and a transcription
Major user feature request: allow starting recording and transcription
simultaneously. Inspired by Google Meet UX, add a subtle checkbox letting users
start a recording alongside transcription.

The backend support for this feature is not yet implemented and will come in
upcoming commits, I can only pass the options to the API. The update of the
notification service will be handled later.
We’re half way with a functional feature.

This is not enabled by default because screen recording is resource-intensive. I
prefer users opt in rather than making it their default choice until feature
usage and performance stabilize.
2026-01-04 20:22:15 +01:00
lebaudantoine b0e27b38e2 🔒️(backend) avoid serializing rooms's pin code when restricted
Prevent anonymous users waiting in the lobby, or attacker
to discover the room pin code, that would allow them to join a room.
2025-12-17 10:05:23 +01:00
lebaudantoine 8044e3d6d8 ♻️(backend) replace Django permissions with feature flag decorator
Refactor feature flag mechanism from Django permission classes to custom
decorator that returns 404 Not Found when features are disabled instead
of exposing API structure through permission errors.

Improves security by preventing information disclosure about disabled
features and provides more appropriate response semantics. Custom
decorator approach is better suited for feature toggling than Django's
permission system which is designed for authorization.
2025-09-08 17:17:45 +02:00
lebaudantoine 1f71bfc5d2 🎨(backend) use pylint error names instead of codes in disable comments
Replace pylint error codes with descriptive error names in disable comments
to make suppressed warnings explicit and improve code readability.
2025-09-04 11:26:48 +02:00
lebaudantoine 888fbbcd5f 🎨(backend) use object primary key instead of id attribute
Replace id attribute references with object primary key for better code
consistency and Django model conventions.

requested by @qbey
2025-09-04 11:26:48 +02:00
lebaudantoine 3e69a2380f ♻️(frontend) sync publishing sources with Django backend settings
Replace hardcoded default publishing source constants with values from
Django backend settings to prevent desynchronization between frontend
and backend configurations.
2025-09-04 11:26:48 +02:00
lebaudantoine 5f70840398 ♻️(backend) move LiveKit participant management to server-side API
Refactor client-side LiveKit API calls to server-side endpoints
following LiveKit documentation recommendations for participant
management operations.

Replaces hacky direct client calls with proper backend-mediated
requests, improving security and following official LiveKit
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 fd7a78e80e ♻️(backend) factorize validation-only serializers to reduce duplication
Eliminates code duplication across validation serializers, improving
maintainability and ensuring consistent validation behavior throughout
the API layer.
2025-09-04 11:26:48 +02:00
lebaudantoine f48dd5cea1 (backend) add start-subtitle endpoint
Allow any user, anonymous or authenticated, to start subtitling
in a room only if they are an active participant of it.

Subtitling a room consists of starting the multi-user transcriber agent.
This agent forwards all participants' audio to an STT server and returns
transcription segments for any active voice to the room.

User roles in the backend room system cannot be used
to determine subtitle permissions.

The transcriber agent can be triggered multiple times but will only join a
room once. Unicity is managed by the agent itself.
Any user with a valid LiveKit token can initiate subtitles. Feature flag
logic is implemented on the frontend. The frontend ensures the "start
subtitle" action is only available to users who should see it. The backend
does not enforce feature flags in this version.

Authentication in our system does not imply access to a room. The only
valid proof of access is the LiveKit API token issued by the backend.
Security consideration: A LiveKit API token is valid for 6 hours and
cannot be revoked at the end of a meeting. It is important to verify
that the token was issued for the correct room.

Calls to the agent dispatch endpoint must be server-initiated. The backend
proxies these calls, as clients cannot securely contact the agent dispatch
endpoint directly (per LiveKit documentation).

Room ID is passed as a query parameter. There is currently no validation
ensuring that the room exists prior to agent dispatch.
TODO: implement validation or error handling for non-existent rooms.

The backend does not forward LiveKit tokens to the agent. Default API
rate limiting is applied to prevent abuse.
2025-09-03 18:09:00 +02:00
lebaudantoine 162896c93c 🩹(backend) allow enforcing WSS protocol to resolve browser compatibility
The LiveKit API URL is necessary to interact with the API. It uses https
protocol.

Eplicit wss protocol is necessary in Websocket constructor for some
older browsers.

This resolves critical compatibility issues with legacy browsers
(notably Firefox <124, Chrome <125, Edge <125) that lack support
for HTTPS URLs in the WebSocket() constructor. Without explicit WSS
URLs, WebSocket signaling connections may fail, crash, or be blocked
entirely in these environments.

The setting is optional and defaults to the current behavior when
not specified, ensuring zero breaking changes for existing deployments.
2025-08-01 16:23:22 +02:00
lebaudantoine be63993ba2 🩹(frontend) fix connection warmup with WebSocket pre-authentication
Connection warmup wasn't working properly - only works when trying to
establish WebSocket first, then workaround kicks in. Call WebSocket
endpoint without auth info expecting 401 error, but enough to initiate
cache for subsequent WebSocket functionality.

Scope this **dirty** trick to Firefox users only. Haven't figured out
how to detect proxy from JS code simply.

Tested in staging and works on our constrained WiFi.
2025-07-25 08:50:33 +02:00
lebaudantoine 387bc2e1f4 🐛(frontend) add LiveKit connection warmup for Firefox+proxy fixes
Implement HTTPS prefetch before joining rooms to resolve WebSocket
handshake failures where Firefox+proxy returns HTTP 200 instead of 101.

Reproduced locally with Squid container. No proxy configuration fixes
found - HTTPS warmup is only working workaround. Issue doesn't occur
when signaling server shares webapp domain, making warmup unnecessary.

Use HEAD request to minimize bandwidth.
2025-07-24 14:32:51 +02:00
lebaudantoine 85bde9633f 🔧(frontend) pass recording max duration to frontend for user alerts
Send backend recording duration limit to frontend to display warning
messages when recordings approach or reach maximum allowed length.

This configuration needs to be synced with the egres. I chose to keep
this duration in ms to be consistent with other settings.
2025-07-16 14:47:24 +02:00
lebaudantoine 70d250cc9c 🔧(frontend) add telephony feature configuration from backend
Pass telephony service availability and settings to frontend to enable
conditional UI rendering based on SIP functionality status.
2025-07-07 19:21:39 +02:00
lebaudantoine d3178eff5d (backend) serialize room pin code for frontend access
Add pin code to API response to enable frontend display of room access
codes. UI implementation will follow in upcoming commits.
2025-07-07 19:21:39 +02:00
lebaudantoine 3e315e92fa 🎨(backend) simplify boolean comparisons by using opposite operators
Replace inverted boolean comparisons (not ... ==) with direct opposite
operators (!=) to improve code readability and reduce unnecessary
complexity in conditional statements.
2025-06-30 17:55:55 +02:00
lebaudantoine 1cd8fd2fc6 🔒️(backend) enhance participant ID serialization in lobby per audit
Improve participant ID handling in lobby serialization following security
auditor recommendations to prevent potential data exposure.
2025-06-24 13:57:53 +02:00
lebaudantoine 64eadadaef 🔒️(backend) clarify administrator role checking function names
Rename vague functions to explicitly indicate administrator permission checks,
or owner ones. Prevents developer confusion and potential security misuse
per auditor recommendations.
2025-06-24 13:57:53 +02:00
lebaudantoine 7038f2a85d 🐛(backend) fix KeyError crash when role is undefined in request data
Use dict.get() instead of direct key access to prevent server crashes when
role field is missing. Fix inherited from magnify project codebase.
2025-05-27 16:20:36 +02:00
lebaudantoine 422f838899 🔒️(backend) remove accesses list from room serializer for non-admins
Restrict access to room user permissions data by excluding this information
from room serializer response for non-admin/owner users. Previously all
members could see complete access lists. Change enforces stricter information
access control based on user role.

Spotted in #YWH-PGM14336-5.
2025-04-30 14:13:30 +02:00
lebaudantoine 63565b38c3 ♻️(backend) simplify ResourceAccess viewset implementation
Restructure ResourceAccess viewset to align with Room and Recording viewset
patterns. Clean up implementation while preserving identical behavior and
API contract. Improves code consistency and maintainability across related
viewsets.

ResourceAccessPermission inherits from IsAuthenticated.
2025-04-30 14:13:30 +02:00
lebaudantoine 1a0051a90b (backend) implement recording expiration mechanism
Add expiration system for recordings.

Include option for users to set recordings as permanent (no expiration)
which is the default behavior.

System only calculates expiration dates and tracks status - actual deletion
is handled by Minio bucket lifecycle policies, not by application code.
2025-04-23 18:53:42 +02:00
lebaudantoine 8e0e286bc4 (backend) serialize user language and timezone for frontend use
Add user language and timezone to serialized user data to enable frontend
customization. Allows backend email notifications to respect user's
localization preferences for improved communication relevance.
2025-04-23 14:17:09 +02:00
lebaudantoine b927be9f16 (frontend) serialize recording key for frontend download links
Add recording key to serialized API response to enable frontend to generate
proper download links without additional backend calls. Simplifies media
access workflow across the application.
2025-04-17 16:58:33 +02:00
lebaudantoine 2092d586ab 🎨(backend) harmonize decorator actions to lowercase format
Standardize all method decorator actions to lowercase format following DRF
documentation conventions. Creates consistent style across codebase.
2025-04-17 11:22:34 +02:00
lebaudantoine 132a1fbac7 🩹(backend) update HasPrivilegesOnRoom permission error message
Generalize error message in HasPrivilegesOnRoom permission class to reflect
its broader usage beyond just recording contexts. Improves clarity when
this permission check fails in various application scenarios.
2025-04-17 11:22:34 +02:00
lebaudantoine 90b4449040 (backend) add email invitation endpoint for meeting participants
Implement new endpoint allowing admin/owner to invite participants via email.
Provides explicit way to search users and send meeting invitations with
direct links.

In upcoming commits, frontend will call ResourceAccess endpoint to add
invited people as members if they exist in visio, bypassing waiting room
for a smoother experience.
2025-04-17 11:22:34 +02:00
lebaudantoine acbc5dba73 🩹(backend) fix exception messages
Oopsie, badly copy-pasted code when creating new serializer.
Not critical.
2025-04-17 11:22:34 +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 dc06b55693 (backend) enable retrieve viewset on recording model
Add Django built-in mixins to recording viewset to support individual record
retrieval. Enables frontend to access single recording details needed for
the upcoming download page implementation.
2025-04-16 12:13:42 +02:00
lebaudantoine 3a4f4e7016 (backend) add recording mode to serialized fields
Include recording mode in serialized data to enable conditional UI elements
in frontend. Allows download controls to be dynamically enabled or disabled
based on the specific recording type being used.

Screen recording will be downloadable when transcript won't.
2025-04-16 12:13:42 +02:00
lebaudantoine 4e1a4be650 (backend) introduce a creation callback endpoint
Necessary in cross browser context situation, where we need to
pass data of a room newly created between two different windows.

This happens in Calendar integration.
2025-04-02 12:31:04 +02:00
lebaudantoine fbee41f5dd ♻️(backend) avoid repeating 'service' in python modules
These modules are already stored under the 'service' folder, it was redundant.
Renamed these files based on @lunika feedbacks.
2025-03-07 18:36:30 +01:00
lebaudantoine 11c2c2dea8 (backend) expose event-handler matching service via dedicated endpoint
Add new endpoint to access the event-handler matching service. Route is
protected by LiveKit authentication, handle at the service level.

Enables webhook event processing through standardized API.
2025-03-07 17:05:06 +01:00
lebaudantoine 0aa4f6389b (backend) add trusted user access level for rooms
Introduce new intermediate access level between public and restricted that
allows authenticated users to join rooms without admin approval. Not making
this the default level yet as current 12hr sessions would create painful
user experience for accessing rooms. Will reconsider default settings after
improving session management.

This access level definition may evolve to become stricter in the future,
potentially limiting access to authenticated users who share the same
organization as the room admin.
2025-03-05 11:26:14 +01:00
lebaudantoine e20acfa5a9 🔒️(backend) limit user listing endpoint with security flag
Deactivate inherited user listing capability that allows authenticated users
to retrieve all application users in JSON format. This potentially unsecure
endpoint exposes user database to scraping and isn't currently used in the
application.

Implement security flag to disable access until properly refactored for
upcoming invitation feature. Will revisit and adapt endpoint behavior when
developing user invitation functionality.
2025-03-05 10:45:50 +01: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 01f4d05d6b ♻️(backend) replace is_public with access_level field
Replace unused is_public boolean field with access_level to allow for more
granular control. Initially maintains public/restricted functionality while
enabling future addition of "trusted" access level.
2025-03-03 21:48:22 +01:00
lebaudantoine 4fe01ae2bf 💩(backend) notify the summary service when a new recording is available
Draft a piece of code to try the feature in staging. I'll consolidate this
implementation ASAP, as soon we have a first implementation functional.

What's missing?
- when owners are multiple
- retry when the backend cannot reach the summary service
- factorize the key oneliner, duplicated from the egress service
- optimize SQL query
- unit tests
2024-12-02 14:33:54 +01:00
lebaudantoine bd4dec6f27 (backend) serialize user name-related fields
Needed in the frontend. Updated existing tests accordingly.
Names are not yet saved while logging the user, it will be
added in the upcomming commits.
2024-11-15 23:38:31 +01:00
lebaudantoine 7afa165013 (backend) offer an endpoint to save recording
I've protected this endpoint with a feature flag, and an authentication
class, as it will be exposed on the public internet.

I've tried to keep the viewset logic as minimal as possible, I've
to ship smth and will continue iterating on this piece of code.

At some point, abstracting webhook endpoint and authentication class
might be beneficial for the project. YAGNI as of today.
2024-11-13 19:36:17 +01:00
lebaudantoine 28ca2d6c37 (backend) expose recording configurations to the client
Inform frontend code, if recording a room is enabled, and which recordings modes
are available. Frontend should adapt its behavior based on this data.
2024-11-13 19:23:34 +01:00
lebaudantoine d4532eeb64 ♻️(backend) remove unnecessary manipulation of the room name
Avoided unnecessary manipulation of the room name to prevent issues when
starting an egress worker. Previously, hyphens were stripped from the room
name, likely inherited from the legacy setup with Jitsi in Magnify, though
the purpose of this change is unclear and might be an undesired legacy
feature.

To ensure accurate room matching during egress worker requests, this update
removes any manipulation of the room name. This approach minimizes the risk
of errors when initiating recordings and maintains the integrity of the
original room name throughout the process.
2024-11-13 18:34:16 +01:00
lebaudantoine b84628ee95 (backend) add two new endpoints to start and stop a recording
The LiveKit egress worker interactions are proxied through the backend for
security reasons. Allowing clients to directly use tokens with sufficient
grants to start recordings could lead to misuse, enabling users to spam the
egress worker API and potentially initiate a DDOS attack on the egress
service. To prevent this, only users with room-specific privileges can
initiate recordings.

We make sure only one recording at the time can be made on a room.

The requested recording mode is stored so it can be referenced later when
the recording is saved, triggering a callback action as needed.

A feature flag was also introduced for this capability; while this is a simple
approach, a more robust system for managing feature flags could be valuable
long-term. For now, KISS (Keep It Simple, Stupid) applies.

The viewset endpoints were designed to be as straightforward as possible—
let me know if anything can be improved.
2024-11-13 18:34:16 +01:00
lebaudantoine cb4c058c5d (backend) add minimal Recording viewset for room recordings
Implements routes to manage recordings within rooms, following the patterns
established in Impress. The viewset exposes targeted endpoints rather than
full CRUD operations, with recordings being created (soon) through
room-specific routes (e.g. room/123/start-recording).

The implementation draws from @sampaccoud's initial work and advices.

Review focus areas:
- Permission implementation choices
- Serializer design and structure

Credit: Initial work by @sampaccoud
2024-11-08 10:36:31 +01:00