Support MSC3086 asserted identity
							parent
							
								
									249a0faa76
								
							
						
					
					
						commit
						59c5ab31de
					
				|  | @ -86,6 +86,9 @@ import { Action } from './dispatcher/actions'; | |||
| import VoipUserMapper from './VoipUserMapper'; | ||||
| import { addManagedHybridWidget, isManagedHybridWidgetEnabled } from './widgets/ManagedHybrid'; | ||||
| import { randomUppercaseString, randomLowercaseString } from "matrix-js-sdk/src/randomstring"; | ||||
| import SdkConfig from './SdkConfig'; | ||||
| import DMRoomMap from './utils/DMRoomMap'; | ||||
| import { ensureDMExists, findDMForUser } from './createRoom'; | ||||
| 
 | ||||
| export const PROTOCOL_PSTN = 'm.protocol.pstn'; | ||||
| export const PROTOCOL_PSTN_PREFIXED = 'im.vector.protocol.pstn'; | ||||
|  | @ -167,6 +170,11 @@ export default class CallHandler { | |||
|     private invitedRoomsAreVirtual = new Map<string, boolean>(); | ||||
|     private invitedRoomCheckInProgress = false; | ||||
| 
 | ||||
|     // Map of the asserted identiy users after we've looked them up using the API.
 | ||||
|     // We need to be be able to determine the mapped room synchronously, so we
 | ||||
|     // do the async lookup when we get new information and then store these mappings here
 | ||||
|     private assertedIdentityNativeUsers = new Map<string, string>(); | ||||
| 
 | ||||
|     static sharedInstance() { | ||||
|         if (!window.mxCallHandler) { | ||||
|             window.mxCallHandler = new CallHandler() | ||||
|  | @ -179,8 +187,17 @@ export default class CallHandler { | |||
|      * Gets the user-facing room associated with a call (call.roomId may be the call "virtual room" | ||||
|      * if a voip_mxid_translate_pattern is set in the config) | ||||
|      */ | ||||
|     public static roomIdForCall(call: MatrixCall): string { | ||||
|     public roomIdForCall(call: MatrixCall): string { | ||||
|         if (!call) return null; | ||||
| 
 | ||||
|         if (SdkConfig.get()['voipObeyAssertedIdentity']) { | ||||
|             const nativeUser = this.assertedIdentityNativeUsers[call.callId]; | ||||
|             if (nativeUser) { | ||||
|                 const room = findDMForUser(MatrixClientPeg.get(), nativeUser); | ||||
|                 if (room) return room.roomId | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return VoipUserMapper.sharedInstance().nativeRoomForVirtualRoom(call.roomId) || call.roomId; | ||||
|     } | ||||
| 
 | ||||
|  | @ -379,14 +396,14 @@ export default class CallHandler { | |||
|         // We don't allow placing more than one call per room, but that doesn't mean there
 | ||||
|         // can't be more than one, eg. in a glare situation. This checks that the given call
 | ||||
|         // is the call we consider 'the' call for its room.
 | ||||
|         const mappedRoomId = CallHandler.roomIdForCall(call); | ||||
|         const mappedRoomId = CallHandler.sharedInstance().roomIdForCall(call); | ||||
| 
 | ||||
|         const callForThisRoom = this.getCallForRoom(mappedRoomId); | ||||
|         return callForThisRoom && call.callId === callForThisRoom.callId; | ||||
|     } | ||||
| 
 | ||||
|     private setCallListeners(call: MatrixCall) { | ||||
|         const mappedRoomId = CallHandler.roomIdForCall(call); | ||||
|         let mappedRoomId = CallHandler.sharedInstance().roomIdForCall(call); | ||||
| 
 | ||||
|         call.on(CallEvent.Error, (err: CallError) => { | ||||
|             if (!this.matchesCallForThisRoom(call)) return; | ||||
|  | @ -500,6 +517,37 @@ export default class CallHandler { | |||
|             this.setCallListeners(newCall); | ||||
|             this.setCallState(newCall, newCall.state); | ||||
|         }); | ||||
|         call.on(CallEvent.AssertedIdentityChanged, async () => { | ||||
|             if (!this.matchesCallForThisRoom(call)) return; | ||||
| 
 | ||||
|             console.log(`Call ID ${call.callId} got new asserted identity:`, call.getRemoteAssertedIdentity()); | ||||
| 
 | ||||
|             const newAssertedIdentity = call.getRemoteAssertedIdentity().id; | ||||
|             let newNativeAssertedIdentity = newAssertedIdentity; | ||||
|             if (newAssertedIdentity) { | ||||
|                 const response = await this.sipNativeLookup(newAssertedIdentity); | ||||
|                 if (response.length) newNativeAssertedIdentity = response[0].userid; | ||||
|             } | ||||
|             console.log(`Asserted identity ${newAssertedIdentity} mapped to ${newNativeAssertedIdentity}`); | ||||
| 
 | ||||
|             if (newNativeAssertedIdentity) { | ||||
|                 this.assertedIdentityNativeUsers[call.callId] = newNativeAssertedIdentity; | ||||
| 
 | ||||
|                 await ensureDMExists(MatrixClientPeg.get(), newNativeAssertedIdentity); | ||||
| 
 | ||||
|                 const newMappedRoomId = CallHandler.sharedInstance().roomIdForCall(call); | ||||
|                 console.log(`Old room ID: ${mappedRoomId}, new room ID: ${newMappedRoomId}`); | ||||
|                 if (newMappedRoomId !== mappedRoomId) { | ||||
|                     this.removeCallForRoom(mappedRoomId); | ||||
|                     mappedRoomId = newMappedRoomId; | ||||
|                     this.calls.set(mappedRoomId, call); | ||||
|                     dis.dispatch({ | ||||
|                         action: Action.CallChangeRoom, | ||||
|                         call, | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     private async logCallStats(call: MatrixCall, mappedRoomId: string) { | ||||
|  | @ -551,7 +599,7 @@ export default class CallHandler { | |||
|     } | ||||
| 
 | ||||
|     private setCallState(call: MatrixCall, status: CallState) { | ||||
|         const mappedRoomId = CallHandler.roomIdForCall(call); | ||||
|         const mappedRoomId = CallHandler.sharedInstance().roomIdForCall(call); | ||||
| 
 | ||||
|         console.log( | ||||
|             `Call state in ${mappedRoomId} changed to ${status}`, | ||||
|  | @ -772,7 +820,7 @@ export default class CallHandler { | |||
| 
 | ||||
|                     const call = payload.call as MatrixCall; | ||||
| 
 | ||||
|                     const mappedRoomId = CallHandler.roomIdForCall(call); | ||||
|                     const mappedRoomId = CallHandler.sharedInstance().roomIdForCall(call); | ||||
|                     if (this.getCallForRoom(mappedRoomId)) { | ||||
|                         // ignore multiple incoming calls to the same room
 | ||||
|                         return; | ||||
|  |  | |||
|  | @ -57,7 +57,11 @@ export default class VoipUserMapper { | |||
|         if (!virtualRoom) return null; | ||||
|         const virtualRoomEvent = virtualRoom.getAccountData(VIRTUAL_ROOM_EVENT_TYPE); | ||||
|         if (!virtualRoomEvent || !virtualRoomEvent.getContent()) return null; | ||||
|         return virtualRoomEvent.getContent()['native_room'] || null; | ||||
|         const nativeRoomID = virtualRoomEvent.getContent()['native_room']; | ||||
|         const nativeRoom = MatrixClientPeg.get().getRoom(nativeRoomID); | ||||
|         if (!nativeRoom || nativeRoom.getMyMembership() !== 'join') return null; | ||||
| 
 | ||||
|         return nativeRoomID; | ||||
|     } | ||||
| 
 | ||||
|     public isVirtualRoom(room: Room): boolean { | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ import SettingsStore from "../../../settings/SettingsStore"; | |||
| import { CallEvent, CallState, MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; | ||||
| import { MatrixClientPeg } from '../../../MatrixClientPeg'; | ||||
| import {replaceableComponent} from "../../../utils/replaceableComponent"; | ||||
| import { Action } from '../../../dispatcher/actions'; | ||||
| 
 | ||||
| const SHOW_CALL_IN_STATES = [ | ||||
|     CallState.Connected, | ||||
|  | @ -142,6 +143,7 @@ export default class CallPreview extends React.Component<IProps, IState> { | |||
|         switch (payload.action) { | ||||
|             // listen for call state changes to prod the render method, which
 | ||||
|             // may hide the global CallView if the call it is tracking is dead
 | ||||
|             case Action.CallChangeRoom: | ||||
|             case 'call_state': { | ||||
|                 const [primaryCall, secondaryCalls] = getPrimarySecondaryCalls( | ||||
|                     CallHandler.sharedInstance().getAllActiveCallsNotInRoom(this.state.roomId), | ||||
|  |  | |||
|  | @ -208,7 +208,7 @@ export default class CallView extends React.Component<IProps, IState> { | |||
|     }; | ||||
| 
 | ||||
|     private onExpandClick = () => { | ||||
|         const userFacingRoomId = CallHandler.roomIdForCall(this.props.call); | ||||
|         const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call); | ||||
|         dis.dispatch({ | ||||
|             action: 'view_room', | ||||
|             room_id: userFacingRoomId, | ||||
|  | @ -337,7 +337,7 @@ export default class CallView extends React.Component<IProps, IState> { | |||
|     }; | ||||
| 
 | ||||
|     private onRoomAvatarClick = () => { | ||||
|         const userFacingRoomId = CallHandler.roomIdForCall(this.props.call); | ||||
|         const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call); | ||||
|         dis.dispatch({ | ||||
|             action: 'view_room', | ||||
|             room_id: userFacingRoomId, | ||||
|  | @ -345,7 +345,7 @@ export default class CallView extends React.Component<IProps, IState> { | |||
|     } | ||||
| 
 | ||||
|     private onSecondaryRoomAvatarClick = () => { | ||||
|         const userFacingRoomId = CallHandler.roomIdForCall(this.props.secondaryCall); | ||||
|         const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.secondaryCall); | ||||
| 
 | ||||
|         dis.dispatch({ | ||||
|             action: 'view_room', | ||||
|  | @ -354,7 +354,7 @@ export default class CallView extends React.Component<IProps, IState> { | |||
|     } | ||||
| 
 | ||||
|     private onCallResumeClick = () => { | ||||
|         const userFacingRoomId = CallHandler.roomIdForCall(this.props.call); | ||||
|         const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call); | ||||
|         CallHandler.sharedInstance().setActiveCallRoomId(userFacingRoomId); | ||||
|     } | ||||
| 
 | ||||
|  | @ -365,8 +365,8 @@ export default class CallView extends React.Component<IProps, IState> { | |||
| 
 | ||||
|     public render() { | ||||
|         const client = MatrixClientPeg.get(); | ||||
|         const callRoomId = CallHandler.roomIdForCall(this.props.call); | ||||
|         const secondaryCallRoomId = CallHandler.roomIdForCall(this.props.secondaryCall); | ||||
|         const callRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call); | ||||
|         const secondaryCallRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.secondaryCall); | ||||
|         const callRoom = client.getRoom(callRoomId); | ||||
|         const secCallRoom = this.props.secondaryCall ? client.getRoom(secondaryCallRoomId) : null; | ||||
| 
 | ||||
|  | @ -482,11 +482,13 @@ export default class CallView extends React.Component<IProps, IState> { | |||
|         const isOnHold = this.state.isLocalOnHold || this.state.isRemoteOnHold; | ||||
|         let holdTransferContent; | ||||
|         if (transfereeCall) { | ||||
|             const transferTargetRoom = MatrixClientPeg.get().getRoom(CallHandler.roomIdForCall(this.props.call)); | ||||
|             const transferTargetRoom = MatrixClientPeg.get().getRoom( | ||||
|                 CallHandler.sharedInstance().roomIdForCall(this.props.call), | ||||
|             ); | ||||
|             const transferTargetName = transferTargetRoom ? transferTargetRoom.name : _t("unknown person"); | ||||
| 
 | ||||
|             const transfereeRoom = MatrixClientPeg.get().getRoom( | ||||
|                 CallHandler.roomIdForCall(transfereeCall), | ||||
|                 CallHandler.sharedInstance().roomIdForCall(transfereeCall), | ||||
|             ); | ||||
|             const transfereeName = transfereeRoom ? transfereeRoom.name : _t("unknown person"); | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import dis from '../../../dispatcher/dispatcher'; | |||
| import {Resizable} from "re-resizable"; | ||||
| import ResizeNotifier from "../../../utils/ResizeNotifier"; | ||||
| import {replaceableComponent} from "../../../utils/replaceableComponent"; | ||||
| import { Action } from '../../../dispatcher/actions'; | ||||
| 
 | ||||
| interface IProps { | ||||
|     // What room we should display the call for
 | ||||
|  | @ -62,6 +63,7 @@ export default class CallViewForRoom extends React.Component<IProps, IState> { | |||
| 
 | ||||
|     private onAction = (payload) => { | ||||
|         switch (payload.action) { | ||||
|             case Action.CallChangeRoom: | ||||
|             case 'call_state': { | ||||
|                 const newCall = this.getCall(); | ||||
|                 if (newCall !== this.state.call) { | ||||
|  |  | |||
|  | @ -72,7 +72,7 @@ export default class IncomingCallBox extends React.Component<IProps, IState> { | |||
|         e.stopPropagation(); | ||||
|         dis.dispatch({ | ||||
|             action: 'answer', | ||||
|             room_id: CallHandler.roomIdForCall(this.state.incomingCall), | ||||
|             room_id: CallHandler.sharedInstance().roomIdForCall(this.state.incomingCall), | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|  | @ -80,7 +80,7 @@ export default class IncomingCallBox extends React.Component<IProps, IState> { | |||
|         e.stopPropagation(); | ||||
|         dis.dispatch({ | ||||
|             action: 'reject', | ||||
|             room_id: CallHandler.roomIdForCall(this.state.incomingCall), | ||||
|             room_id: CallHandler.sharedInstance().roomIdForCall(this.state.incomingCall), | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|  | @ -91,7 +91,7 @@ export default class IncomingCallBox extends React.Component<IProps, IState> { | |||
| 
 | ||||
|         let room = null; | ||||
|         if (this.state.incomingCall) { | ||||
|             room = MatrixClientPeg.get().getRoom(CallHandler.roomIdForCall(this.state.incomingCall)); | ||||
|             room = MatrixClientPeg.get().getRoom(CallHandler.sharedInstance().roomIdForCall(this.state.incomingCall)); | ||||
|         } | ||||
| 
 | ||||
|         const caller = room ? room.name : _t("Unknown caller"); | ||||
|  |  | |||
|  | @ -114,6 +114,9 @@ export enum Action { | |||
|      */ | ||||
|     VirtualRoomSupportUpdated = "virtual_room_support_updated", | ||||
| 
 | ||||
|     // Probably would be better to have a VoIP states in a store and have the store emit changes
 | ||||
|     CallChangeRoom = "call_change_room", | ||||
| 
 | ||||
|     /** | ||||
|      * Fired when an upload has started. Should be used with UploadStartedPayload. | ||||
|      */ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 David Baker
						David Baker