Files
ThreadNet-Web/src/VoipUserMapper.ts
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

151 lines
6.6 KiB
TypeScript
Raw Normal View History

2021-01-21 19:20:35 +00:00
/*
2024-09-09 14:57:16 +01:00
Copyright 2024 New Vector Ltd.
2021-01-21 19:20:35 +00:00
Copyright 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
2024-09-09 14:57:16 +01:00
Please see LICENSE files in the repository root for full details.
2021-01-21 19:20:35 +00:00
*/
2025-02-05 13:25:06 +00:00
import { type Room, EventType } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
2021-10-22 17:23:32 -05:00
import { logger } from "matrix-js-sdk/src/logger";
import { ensureVirtualRoomExists } from "./createRoom";
2021-01-21 19:20:35 +00:00
import { MatrixClientPeg } from "./MatrixClientPeg";
import DMRoomMap from "./utils/DMRoomMap";
import LegacyCallHandler from "./LegacyCallHandler";
2022-03-24 15:26:09 -06:00
import { VIRTUAL_ROOM_EVENT_TYPE } from "./call-types";
2022-07-25 10:17:40 +02:00
import { findDMForUser } from "./utils/dm/findDMForUser";
2021-02-12 20:55:54 +00:00
// Functions for mapping virtual users & rooms. Currently the only lookup
// is sip virtual: there could be others in the future.
2021-01-21 19:20:35 +00:00
2021-02-12 20:55:54 +00:00
export default class VoipUserMapper {
// We store mappings of virtual -> native room IDs here until the local echo for the
// account data arrives.
private virtualToNativeRoomIdCache = new Map<string, string>();
2021-02-12 20:55:54 +00:00
public static sharedInstance(): VoipUserMapper {
if (window.mxVoipUserMapper === undefined) window.mxVoipUserMapper = new VoipUserMapper();
return window.mxVoipUserMapper;
}
2021-01-21 19:20:35 +00:00
2023-02-10 18:11:57 +00:00
private async userToVirtualUser(userId: string): Promise<string | null> {
const results = await LegacyCallHandler.instance.sipVirtualLookup(userId);
if (results.length === 0 || !results[0].fields.lookup_success) return null;
2021-02-12 20:55:54 +00:00
return results[0].userid;
}
2021-01-21 19:20:35 +00:00
private async getVirtualUserForRoom(roomId: string): Promise<string | null> {
2021-02-12 20:55:54 +00:00
const userId = DMRoomMap.shared().getUserIdForRoomId(roomId);
if (!userId) return null;
2021-01-21 19:20:35 +00:00
2021-02-12 20:55:54 +00:00
const virtualUser = await this.userToVirtualUser(userId);
if (!virtualUser) return null;
2021-01-21 19:20:35 +00:00
return virtualUser;
}
public async getOrCreateVirtualRoomForRoom(roomId: string): Promise<string | null> {
const virtualUser = await this.getVirtualUserForRoom(roomId);
if (!virtualUser) return null;
const cli = MatrixClientPeg.safeGet();
const virtualRoomId = await ensureVirtualRoomExists(cli, virtualUser, roomId);
cli.setRoomAccountData(virtualRoomId!, VIRTUAL_ROOM_EVENT_TYPE, {
2021-02-17 18:51:21 +00:00
native_room: roomId,
});
2021-01-21 19:20:35 +00:00
2023-02-10 18:11:57 +00:00
this.virtualToNativeRoomIdCache.set(virtualRoomId!, roomId);
2021-02-17 18:51:21 +00:00
return virtualRoomId;
2021-02-12 20:55:54 +00:00
}
2021-01-21 19:20:35 +00:00
/**
* Gets the ID of the virtual room for a room, or null if the room has no
* virtual room
*/
public async getVirtualRoomForRoom(roomId: string): Promise<Room | undefined> {
const virtualUser = await this.getVirtualUserForRoom(roomId);
if (!virtualUser) return undefined;
return findDMForUser(MatrixClientPeg.safeGet(), virtualUser);
}
public nativeRoomForVirtualRoom(roomId: string): string | null {
const cachedNativeRoomId = this.virtualToNativeRoomIdCache.get(roomId);
if (cachedNativeRoomId) {
logger.log(
"Returning native room ID " + cachedNativeRoomId + " for virtual room ID " + roomId + " from cache",
);
return cachedNativeRoomId;
}
const cli = MatrixClientPeg.safeGet();
const virtualRoom = cli.getRoom(roomId);
2021-02-12 20:55:54 +00:00
if (!virtualRoom) return null;
const virtualRoomEvent = virtualRoom.getAccountData(VIRTUAL_ROOM_EVENT_TYPE);
if (!virtualRoomEvent || !virtualRoomEvent.getContent()) return null;
2021-04-19 20:30:51 +01:00
const nativeRoomID = virtualRoomEvent.getContent()["native_room"];
const nativeRoom = cli.getRoom(nativeRoomID);
if (!nativeRoom || nativeRoom.getMyMembership() !== KnownMembership.Join) return null;
2021-04-19 20:30:51 +01:00
return nativeRoomID;
2021-02-12 20:55:54 +00:00
}
2021-01-21 19:20:35 +00:00
public isVirtualRoom(room: Room): boolean {
2021-02-17 18:51:21 +00:00
if (this.nativeRoomForVirtualRoom(room.roomId)) return true;
2021-01-21 19:20:35 +00:00
if (this.virtualToNativeRoomIdCache.has(room.roomId)) return true;
2021-02-17 18:51:21 +00:00
// also look in the create event for the claimed native room ID, which is the only
// way we can recognise a virtual room we've created when it first arrives down
// our stream. We don't trust this in general though, as it could be faked by an
// inviter: our main source of truth is the DM state.
const roomCreateEvent = room.currentState.getStateEvents(EventType.RoomCreate, "");
2021-02-17 18:51:21 +00:00
if (!roomCreateEvent || !roomCreateEvent.getContent()) return false;
// we only look at this for rooms we created (so inviters can't just cause rooms
// to be invisible)
if (roomCreateEvent.getSender() !== MatrixClientPeg.safeGet().getUserId()) return false;
2021-02-17 18:51:21 +00:00
const claimedNativeRoomId = roomCreateEvent.getContent()[VIRTUAL_ROOM_EVENT_TYPE];
return Boolean(claimedNativeRoomId);
2021-02-12 20:55:54 +00:00
}
public async onNewInvitedRoom(invitedRoom: Room): Promise<void> {
if (!LegacyCallHandler.instance.getSupportsVirtualRooms()) return;
2021-02-12 20:55:54 +00:00
const inviterId = invitedRoom.getDMInviter();
2023-02-10 18:11:57 +00:00
if (!inviterId) {
logger.error("Could not find DM inviter for room id: " + invitedRoom.roomId);
}
logger.log(`Checking virtual-ness of room ID ${invitedRoom.roomId}, invited by ${inviterId}`);
2023-02-10 18:11:57 +00:00
const result = await LegacyCallHandler.instance.sipNativeLookup(inviterId!);
2021-02-12 20:55:54 +00:00
if (result.length === 0) {
return;
2021-02-12 20:55:54 +00:00
}
if (result[0].fields.is_virtual) {
const cli = MatrixClientPeg.safeGet();
2021-02-12 20:55:54 +00:00
const nativeUser = result[0].userid;
const nativeRoom = findDMForUser(cli, nativeUser);
2021-02-12 20:55:54 +00:00
if (nativeRoom) {
// It's a virtual room with a matching native room, so set the room account data. This
// will make sure we know where how to map calls and also allow us know not to display
// it in the future.
cli.setRoomAccountData(invitedRoom.roomId, VIRTUAL_ROOM_EVENT_TYPE, {
2021-02-12 20:55:54 +00:00
native_room: nativeRoom.roomId,
});
// also auto-join the virtual room if we have a matching native room
// (possibly we should only join if we've also joined the native room, then we'd also have
// to make sure we joined virtual rooms on joining a native one)
cli.joinRoom(invitedRoom.roomId);
2021-02-12 20:55:54 +00:00
// also put this room in the virtual room ID cache so isVirtualRoom return the right answer
// in however long it takes for the echo of setAccountData to come down the sync
this.virtualToNativeRoomIdCache.set(invitedRoom.roomId, nativeRoom.roomId);
}
2021-02-12 20:55:54 +00:00
}
2021-01-21 19:20:35 +00:00
}
}