From d8d4ade1b7707e6018b139c64ce509c95b28460e Mon Sep 17 00:00:00 2001 From: "DeepBlueV7.X" Date: Fri, 1 Jul 2022 12:43:42 +0000 Subject: [PATCH] Fix calls on homeservers without the unstable thirdparty endpoints (#8931) * Fix calls on homeservers without the unstable thirdparty endpoints Calling that endpoint throws an error and aborts the entire call. We do check if an empty list or null is returned by that endpoint everywhere, so returning an empty list simulates the thirdparty stuff just not being found. Checking for "this.supportsSipNativeVirtual" doesn't necessarily work, since that might not be set yet and as such breaks calls that rely on this functionality working. fixes https://github.com/vector-im/element-web/issues/21680 Signed-off-by: Nicolas Werner * Address review comments * Make log message a warning Signed-off-by: Nicolas Werner --- src/CallHandler.tsx | 51 +++++++++++++-------- test/CallHandler-test.ts | 95 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 123 insertions(+), 23 deletions(-) diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index 55c29c7a6f..733c9b8499 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -265,28 +265,43 @@ export default class CallHandler extends EventEmitter { return this.supportsSipNativeVirtual; } - public pstnLookup(phoneNumber: string): Promise { - return MatrixClientPeg.get().getThirdpartyUser( - this.pstnSupportPrefixed ? PROTOCOL_PSTN_PREFIXED : PROTOCOL_PSTN, { - 'm.id.phone': phoneNumber, - }, - ); + public async pstnLookup(phoneNumber: string): Promise { + try { + return await MatrixClientPeg.get().getThirdpartyUser( + this.pstnSupportPrefixed ? PROTOCOL_PSTN_PREFIXED : PROTOCOL_PSTN, { + 'm.id.phone': phoneNumber, + }, + ); + } catch (e) { + logger.warn('Failed to lookup user from phone number', e); + return Promise.resolve([]); + } } - public sipVirtualLookup(nativeMxid: string): Promise { - return MatrixClientPeg.get().getThirdpartyUser( - PROTOCOL_SIP_VIRTUAL, { - 'native_mxid': nativeMxid, - }, - ); + public async sipVirtualLookup(nativeMxid: string): Promise { + try { + return await MatrixClientPeg.get().getThirdpartyUser( + PROTOCOL_SIP_VIRTUAL, { + 'native_mxid': nativeMxid, + }, + ); + } catch (e) { + logger.warn('Failed to query SIP identity for user', e); + return Promise.resolve([]); + } } - public sipNativeLookup(virtualMxid: string): Promise { - return MatrixClientPeg.get().getThirdpartyUser( - PROTOCOL_SIP_NATIVE, { - 'virtual_mxid': virtualMxid, - }, - ); + public async sipNativeLookup(virtualMxid: string): Promise { + try { + return await MatrixClientPeg.get().getThirdpartyUser( + PROTOCOL_SIP_NATIVE, { + 'virtual_mxid': virtualMxid, + }, + ); + } catch (e) { + logger.warn('Failed to query identity for SIP user', e); + return Promise.resolve([]); + } } private onCallIncoming = (call: MatrixCall): void => { diff --git a/test/CallHandler-test.ts b/test/CallHandler-test.ts index 6a4f29aaa1..b7a047a9ef 100644 --- a/test/CallHandler-test.ts +++ b/test/CallHandler-test.ts @@ -79,7 +79,7 @@ class FakeCall extends EventEmitter { roomId: string; callId = "fake call id"; - constructor(roomId) { + constructor(roomId: string) { super(); this.roomId = roomId; @@ -104,14 +104,14 @@ function untilCallHandlerEvent(callHandler: CallHandler, event: CallHandlerEvent describe('CallHandler', () => { let dmRoomMap; let callHandler; - let audioElement; + let audioElement: HTMLAudioElement; let fakeCall; // what addresses the app has looked up via pstn and native lookup let pstnLookup: string; let nativeLookup: string; - beforeEach(() => { + beforeEach(async () => { stubClient(); MatrixClientPeg.get().createCall = roomId => { if (fakeCall && fakeCall.roomId !== roomId) { @@ -151,7 +151,7 @@ describe('CallHandler', () => { }; dmRoomMap = { - getUserIdForRoomId: roomId => { + getUserIdForRoomId: (roomId: string) => { if (roomId === NATIVE_ROOM_ALICE) { return NATIVE_ALICE; } else if (roomId === NATIVE_ROOM_BOB) { @@ -164,7 +164,7 @@ describe('CallHandler', () => { return null; } }, - getDMRoomsForUserId: userId => { + getDMRoomsForUserId: (userId: string) => { if (userId === NATIVE_ALICE) { return [NATIVE_ROOM_ALICE]; } else if (userId === NATIVE_BOB) { @@ -322,3 +322,88 @@ describe('CallHandler', () => { expect(callHandler.getCallForRoom(NATIVE_ROOM_CHARLIE)).toBe(fakeCall); }); }); + +describe('CallHandler without third party protocols', () => { + let dmRoomMap; + let callHandler: CallHandler; + let audioElement: HTMLAudioElement; + let fakeCall; + + beforeEach(() => { + stubClient(); + MatrixClientPeg.get().createCall = roomId => { + if (fakeCall && fakeCall.roomId !== roomId) { + throw new Error("Only one call is supported!"); + } + fakeCall = new FakeCall(roomId); + return fakeCall; + }; + + MatrixClientPeg.get().getThirdpartyProtocols = () => { + throw new Error("Endpoint unsupported."); + }; + + callHandler = new CallHandler(); + callHandler.start(); + + const nativeRoomAlice = mkStubDM(NATIVE_ROOM_ALICE, NATIVE_ALICE); + + MatrixClientPeg.get().getRoom = roomId => { + switch (roomId) { + case NATIVE_ROOM_ALICE: + return nativeRoomAlice; + } + }; + + dmRoomMap = { + getUserIdForRoomId: (roomId: string) => { + if (roomId === NATIVE_ROOM_ALICE) { + return NATIVE_ALICE; + } else { + return null; + } + }, + getDMRoomsForUserId: (userId: string) => { + if (userId === NATIVE_ALICE) { + return [NATIVE_ROOM_ALICE]; + } else { + return []; + } + }, + }; + DMRoomMap.setShared(dmRoomMap); + + MatrixClientPeg.get().getThirdpartyUser = (_proto, _params) => { + throw new Error("Endpoint unsupported."); + }; + + audioElement = document.createElement('audio'); + audioElement.id = "remoteAudio"; + document.body.appendChild(audioElement); + }); + + afterEach(() => { + callHandler.stop(); + DMRoomMap.setShared(null); + // @ts-ignore + window.mxCallHandler = null; + fakeCall = null; + MatrixClientPeg.unset(); + + document.body.removeChild(audioElement); + SdkConfig.unset(); + }); + + it('should still start a native call', async () => { + callHandler.placeCall(NATIVE_ROOM_ALICE, CallType.Voice); + + await untilCallHandlerEvent(callHandler, CallHandlerEvent.CallState); + + // Check that a call was started: its room on the protocol level + // should be the virtual room + expect(fakeCall.roomId).toEqual(NATIVE_ROOM_ALICE); + + // but it should appear to the user to be in thw native room for Bob + expect(callHandler.roomIdForCall(fakeCall)).toEqual(NATIVE_ROOM_ALICE); + }); +});