ov-components: Avoid unnecessary encryption decryption data channels

Livekit client now encrypt and decrypt data channels
Updated imports
master
Carlos Santos 2025-12-17 17:38:28 +01:00
parent 47253bbda1
commit ddc7226b64
3 changed files with 32 additions and 63 deletions

View File

@ -13,27 +13,17 @@ import {
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import { ILogger } from '../../models/logger.model';
import { animate, style, transition, trigger } from '@angular/animations'; import { animate, style, transition, trigger } from '@angular/animations';
import { MatDrawerContainer, MatSidenav } from '@angular/material/sidenav'; import { MatDrawerContainer, MatSidenav } from '@angular/material/sidenav';
import { skip, Subject, takeUntil } from 'rxjs'; import { skip, Subject, takeUntil } from 'rxjs';
import { SidenavMode } from '../../models/layout.model';
import { PanelStatusInfo, PanelType } from '../../models/panel.model';
import { DataTopic } from '../../models/data-topic.model'; import { DataTopic } from '../../models/data-topic.model';
import { SidenavMode } from '../../models/layout.model';
import { ILogger } from '../../models/logger.model';
import { PanelStatusInfo, PanelType } from '../../models/panel.model';
import { RoomStatusData } from '../../models/room.model'; import { RoomStatusData } from '../../models/room.model';
import { ActionService } from '../../services/action/action.service'; import { ActionService } from '../../services/action/action.service';
import { BroadcastingService } from '../../services/broadcasting/broadcasting.service'; import { BroadcastingService } from '../../services/broadcasting/broadcasting.service';
// import { CaptionService } from '../../services/caption/caption.service'; // import { CaptionService } from '../../services/caption/caption.service';
import { ChatService } from '../../services/chat/chat.service';
import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service';
import { LayoutService } from '../../services/layout/layout.service';
import { LoggerService } from '../../services/logger/logger.service';
import { OpenViduService } from '../../services/openvidu/openvidu.service';
import { PanelService } from '../../services/panel/panel.service';
import { ParticipantService } from '../../services/participant/participant.service';
import { RecordingService } from '../../services/recording/recording.service';
import { TranslateService } from '../../services/translate/translate.service';
import { VirtualBackgroundService } from '../../services/virtual-background/virtual-background.service';
import { import {
DataPacket_Kind, DataPacket_Kind,
DisconnectReason, DisconnectReason,
@ -48,9 +38,18 @@ import {
} from 'livekit-client'; } from 'livekit-client';
import { ParticipantLeftEvent, ParticipantLeftReason, ParticipantModel } from '../../models/participant.model'; import { ParticipantLeftEvent, ParticipantLeftReason, ParticipantModel } from '../../models/participant.model';
import { RecordingStatus } from '../../models/recording.model'; import { RecordingStatus } from '../../models/recording.model';
import { TemplateManagerService, SessionTemplateConfiguration } from '../../services/template/template-manager.service'; import { ChatService } from '../../services/chat/chat.service';
import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service';
import { LayoutService } from '../../services/layout/layout.service';
import { LoggerService } from '../../services/logger/logger.service';
import { OpenViduService } from '../../services/openvidu/openvidu.service';
import { PanelService } from '../../services/panel/panel.service';
import { ParticipantService } from '../../services/participant/participant.service';
import { RecordingService } from '../../services/recording/recording.service';
import { SessionTemplateConfiguration, TemplateManagerService } from '../../services/template/template-manager.service';
import { TranslateService } from '../../services/translate/translate.service';
import { ViewportService } from '../../services/viewport/viewport.service'; import { ViewportService } from '../../services/viewport/viewport.service';
import { E2eeService } from '../../services/e2ee/e2ee.service'; import { VirtualBackgroundService } from '../../services/virtual-background/virtual-background.service';
import { safeJsonParse } from '../../utils/utils'; import { safeJsonParse } from '../../utils/utils';
/** /**
@ -141,7 +140,6 @@ export class SessionComponent implements OnInit, OnDestroy {
private cd: ChangeDetectorRef, private cd: ChangeDetectorRef,
private templateManagerService: TemplateManagerService, private templateManagerService: TemplateManagerService,
protected viewportService: ViewportService, protected viewportService: ViewportService,
private e2eeService: E2eeService
) { ) {
this.log = this.loggerSrv.get('SessionComponent'); this.log = this.loggerSrv.get('SessionComponent');
this.setupTemplates(); this.setupTemplates();
@ -445,23 +443,6 @@ export class SessionComponent implements OnInit, OnDestroy {
); );
} }
// private subscribeToCaptionLanguage() {
// this.captionLanguageSubscription = this.captionService.captionLangObs.subscribe(async (langOpt) => {
// if (this.captionService.areCaptionsEnabled()) {
// // Unsubscribe all streams from speech to text and re-subscribe with new language
// this.log.d('Re-subscribe from STT because of language changed to ', langOpt.lang);
// await this.openviduService.unsubscribeRemotesFromSTT();
// await this.openviduService.subscribeRemotesToSTT(langOpt.lang);
// }
// });
// }
// private subscribeToParticipantNameChanged() {
// this.room.on(RoomEvent.ParticipantNameChanged, (name: string, participant: RemoteParticipant | LocalParticipant) => {
// console.log('ParticipantNameChanged', participant);
// });
// }
private subscribeToDataMessage() { private subscribeToDataMessage() {
this.room.on( this.room.on(
RoomEvent.DataReceived, RoomEvent.DataReceived,
@ -485,10 +466,6 @@ export class SessionComponent implements OnInit, OnDestroy {
const participantIdentity = storedParticipant?.identity || ''; const participantIdentity = storedParticipant?.identity || '';
const participantName = storedParticipant?.name || ''; const participantName = storedParticipant?.name || '';
if (this.e2eeService.isEnabled) {
payload = await this.decryptIfNeeded(topic, payload, participantIdentity);
}
const rawText = decoder.decode(payload); const rawText = decoder.decode(payload);
this.log.d('DataReceived (raw)', { topic }); this.log.d('DataReceived (raw)', { topic });
@ -580,18 +557,18 @@ export class SessionComponent implements OnInit, OnDestroy {
} }
} }
private async decryptIfNeeded(topic: string | undefined, payload: Uint8Array, identity: string): Promise<Uint8Array> { // private async decryptIfNeeded(topic: string | undefined, payload: Uint8Array, identity: string): Promise<Uint8Array> {
if (topic === DataTopic.CHAT && this.e2eeService.isEnabled) { // if (topic === DataTopic.CHAT && this.e2eeService.isEnabled) {
try { // try {
return await this.e2eeService.decryptOrMask(payload, identity, JSON.stringify({ message: '******' })); // return await this.e2eeService.decryptOrMask(payload, identity, JSON.stringify({ message: '******' }));
} catch (e) { // } catch (e) {
this.log.e('Error decrypting payload, using masked fallback', e); // this.log.e('Error decrypting payload, using masked fallback', e);
// In case of decryption error, return a masked JSON so subsequent parsing won't crash // // In case of decryption error, return a masked JSON so subsequent parsing won't crash
return new TextEncoder().encode(JSON.stringify({ message: '******' })); // return new TextEncoder().encode(JSON.stringify({ message: '******' }));
} // }
} // }
return payload; // return payload;
} // }
private subscribeToReconnection() { private subscribeToReconnection() {
this.room.on(RoomEvent.Reconnecting, () => { this.room.on(RoomEvent.Reconnecting, () => {

View File

@ -1,19 +1,18 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/internal/Observable';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { Observable } from 'rxjs/internal/Observable';
import { ILogger } from '../../models/logger.model';
import { ChatMessage } from '../../models/chat.model'; import { ChatMessage } from '../../models/chat.model';
import { ILogger } from '../../models/logger.model';
import { INotificationOptions } from '../../models/notification-options.model'; import { INotificationOptions } from '../../models/notification-options.model';
import { DataTopic } from '../../models/data-topic.model';
import { PanelType } from '../../models/panel.model';
import { ActionService } from '../action/action.service'; import { ActionService } from '../action/action.service';
import { LoggerService } from '../logger/logger.service'; import { LoggerService } from '../logger/logger.service';
import { DataTopic } from '../../models/data-topic.model';
import { PanelService } from '../panel/panel.service'; import { PanelService } from '../panel/panel.service';
import { ParticipantService } from '../participant/participant.service'; import { ParticipantService } from '../participant/participant.service';
import { PanelType } from '../../models/panel.model';
import { TranslateService } from '../translate/translate.service'; import { TranslateService } from '../translate/translate.service';
import { E2eeService } from '../e2ee/e2ee.service';
/** /**
* @internal * @internal
@ -33,7 +32,6 @@ export class ChatService {
private panelService: PanelService, private panelService: PanelService,
private actionService: ActionService, private actionService: ActionService,
private translateService: TranslateService, private translateService: TranslateService,
private e2eeService: E2eeService
) { ) {
this.log = this.loggerSrv.get('ChatService'); this.log = this.loggerSrv.get('ChatService');
this.chatMessages$ = this._messageList.asObservable(); this.chatMessages$ = this._messageList.asObservable();
@ -64,7 +62,6 @@ export class ChatService {
/** /**
* Sends a chat message through the data channel. * Sends a chat message through the data channel.
* If E2EE is enabled, the message will be encrypted before sending.
* *
* @param message The message text to send * @param message The message text to send
*/ */
@ -74,13 +71,10 @@ export class ChatService {
try { try {
// Create message payload // Create message payload
const payload = JSON.stringify({ message: plainTextMessage }); const payload = JSON.stringify({ message: plainTextMessage });
const plainData: Uint8Array = new TextEncoder().encode(payload); const data: Uint8Array = new TextEncoder().encode(payload);
// Encrypt data if E2EE is enabled (Uint8Array → Uint8Array)
const dataToSend: Uint8Array = await this.e2eeService.encrypt(plainData);
// Send through data channel // Send through data channel
await this.participantService.publishData(dataToSend, { topic: DataTopic.CHAT, reliable: true }); await this.participantService.publishData(data, { topic: DataTopic.CHAT, reliable: true });
// Add to local message list // Add to local message list
this.addMessage(plainTextMessage, true, this.participantService.getMyName()!); this.addMessage(plainTextMessage, true, this.participantService.getMyName()!);

View File

@ -124,8 +124,6 @@ export class OpenViduService {
if (needsE2EEConfig) { if (needsE2EEConfig) {
// Create worker using the copied livekit-client e2ee worker from assets // Create worker using the copied livekit-client e2ee worker from assets
roomOptions.encryption = this.buildE2EEOptions(); roomOptions.encryption = this.buildE2EEOptions();
// !This config enables the data channel encryption
// (roomOptions as any).encryption = this.buildE2EEOptions();
} }
this.room = new Room(roomOptions); this.room = new Room(roomOptions);