fix: call system bugs and security hardening
- CallEmbed: fix memory leak — mx event listeners were never removed because dispose() called .bind(this) again, creating new function objects. Now uses arrow class fields so start()/dispose() share the exact same reference. - callPreferences: toggleVideo is a no-op when cameraOnJoin=false, preventing internal state drift from the returned value. - CallControls: PTT key guard now blocks on SELECT elements and walks the DOM for inherited contentEditable to prevent key interception inside dropdowns and custom editors. - RoomInput: GIF fetch validates Giphy CDN domain allow-list, HTTP Content-Type header, and enforces 20 MB size cap.
This commit is contained in:
@@ -51,6 +51,12 @@ export class CallEmbed {
|
||||
|
||||
private styleRetryObserver?: MutationObserver;
|
||||
|
||||
// Arrow-function class fields so dispose() passes the exact same reference to mx.off()
|
||||
private readonly boundOnEvent = (ev: MatrixEvent) => this.onEvent(ev);
|
||||
private readonly boundOnEventDecrypted = (ev: MatrixEvent) => this.onEventDecrypted(ev);
|
||||
private readonly boundOnStateUpdate = (ev: MatrixEvent) => this.onStateUpdate(ev);
|
||||
private readonly boundOnToDeviceEvent = (ev: MatrixEvent) => this.onToDeviceEvent(ev);
|
||||
|
||||
static getIntent(dm: boolean, ongoing: boolean, video?: boolean): ElementCallIntent {
|
||||
if (dm && ongoing) {
|
||||
return video ? ElementCallIntent.JoinExistingDM : ElementCallIntent.JoinExistingDMVoice;
|
||||
@@ -252,10 +258,10 @@ export class CallEmbed {
|
||||
});
|
||||
|
||||
// Attach listeners for feeding events - the underlying widget classes handle permissions for us
|
||||
this.mx.on(ClientEvent.Event, this.onEvent.bind(this));
|
||||
this.mx.on(MatrixEventEvent.Decrypted, this.onEventDecrypted.bind(this));
|
||||
this.mx.on(RoomStateEvent.Events, this.onStateUpdate.bind(this));
|
||||
this.mx.on(ClientEvent.ToDeviceEvent, this.onToDeviceEvent.bind(this));
|
||||
this.mx.on(ClientEvent.Event, this.boundOnEvent);
|
||||
this.mx.on(MatrixEventEvent.Decrypted, this.boundOnEventDecrypted);
|
||||
this.mx.on(RoomStateEvent.Events, this.boundOnStateUpdate);
|
||||
this.mx.on(ClientEvent.ToDeviceEvent, this.boundOnToDeviceEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,10 +278,10 @@ export class CallEmbed {
|
||||
this.container.removeChild(this.iframe);
|
||||
this.control.dispose();
|
||||
|
||||
this.mx.off(ClientEvent.Event, this.onEvent.bind(this));
|
||||
this.mx.off(MatrixEventEvent.Decrypted, this.onEventDecrypted.bind(this));
|
||||
this.mx.off(RoomStateEvent.Events, this.onStateUpdate.bind(this));
|
||||
this.mx.off(ClientEvent.ToDeviceEvent, this.onToDeviceEvent.bind(this));
|
||||
this.mx.off(ClientEvent.Event, this.boundOnEvent);
|
||||
this.mx.off(MatrixEventEvent.Decrypted, this.boundOnEventDecrypted);
|
||||
this.mx.off(RoomStateEvent.Events, this.boundOnStateUpdate);
|
||||
this.mx.off(ClientEvent.ToDeviceEvent, this.boundOnToDeviceEvent);
|
||||
|
||||
// Clear internal state
|
||||
this.readUpToMap = {};
|
||||
|
||||
Reference in New Issue
Block a user