Make use of the new jwt service endpoint (with delayed event delegation)

This also does all the compatibility work. When to use which endpoint to
authenticate agains a jwt service.
This commit is contained in:
Timo K
2025-12-17 09:53:49 +01:00
parent 9bd51fdfc4
commit ab7e3486b3
17 changed files with 294 additions and 74 deletions

View File

@@ -7,9 +7,11 @@ Please see LICENSE in the repository root for full details.
import { type IOpenIDToken, type MatrixClient } from "matrix-js-sdk";
import { logger } from "matrix-js-sdk/lib/logger";
import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/EncryptionManager";
import { FailToGetOpenIdToken } from "../utils/errors";
import { doNetworkOperationWithRetry } from "../utils/matrix";
import { Config } from "../config/Config";
export interface SFUConfig {
url: string;
@@ -33,8 +35,12 @@ export type OpenIDClientParts = Pick<
*/
export async function getSFUConfigWithOpenID(
client: OpenIDClientParts,
membership: CallMembershipIdentityParts,
serviceUrl: string,
matrixRoomId: string,
livekitRoomAlias: string,
matrix2jwt: boolean,
delayEndpointBaseUrl?: string,
delayId?: string,
): Promise<SFUConfig> {
let openIdToken: IOpenIDToken;
try {
@@ -49,21 +55,31 @@ export async function getSFUConfigWithOpenID(
logger.debug("Got openID token", openIdToken);
logger.info(`Trying to get JWT for focus ${serviceUrl}...`);
const sfuConfig = await getLiveKitJWT(
client,
const args: [CallMembershipIdentityParts, string, string, IOpenIDToken] = [
membership,
serviceUrl,
matrixRoomId,
livekitRoomAlias,
openIdToken,
);
logger.info(`Got JWT from call's active focus URL.`);
return sfuConfig;
];
if (matrix2jwt) {
const sfuConfig = await getLiveKitJWTWithDelayDelegation(
...args,
delayEndpointBaseUrl,
delayId,
);
logger.info(`Got JWT from call's active focus URL.`);
return sfuConfig;
} else {
const sfuConfig = await getLiveKitJWT(...args);
logger.info(`Got JWT from call's active focus URL.`);
return sfuConfig;
}
}
async function getLiveKitJWT(
client: OpenIDClientParts,
membership: CallMembershipIdentityParts,
livekitServiceURL: string,
roomName: string,
livekitRoomAlias: string,
openIDToken: IOpenIDToken,
): Promise<SFUConfig> {
try {
@@ -73,9 +89,9 @@ async function getLiveKitJWT(
"Content-Type": "application/json",
},
body: JSON.stringify({
room: roomName,
room: livekitRoomAlias,
openid_token: openIDToken,
device_id: client.getDeviceId(),
device_id: membership.deviceId,
}),
});
if (!res.ok) {
@@ -86,3 +102,53 @@ async function getLiveKitJWT(
throw new Error("SFU Config fetch failed with exception " + e);
}
}
export async function getLiveKitJWTWithDelayDelegation(
membership: CallMembershipIdentityParts,
livekitServiceURL: string,
livekitRoomAlias: string,
openIDToken: IOpenIDToken,
delayEndpointBaseUrl?: string,
delayId?: string,
): Promise<SFUConfig> {
const { userId, deviceId, memberId } = membership;
const body = {
room_id: livekitRoomAlias,
slot_id: "m.call#ROOM",
openid_token: openIDToken,
member: {
id: memberId,
claimed_user_id: userId,
claimed_device_id: deviceId,
},
};
let bodyDalayParts = {};
// Also check for empty string
if (delayId && delayEndpointBaseUrl) {
const delayTimeoutMs =
Config.get().matrix_rtc_session?.delayed_leave_event_delay_ms ?? 1000;
bodyDalayParts = {
delay_id: delayId,
delay_timeout: delayTimeoutMs,
delay_cs_api_url: delayEndpointBaseUrl,
};
}
try {
const res = await fetch(livekitServiceURL + "/get_token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ ...body, ...bodyDalayParts }),
});
if (!res.ok) {
throw new Error("SFU Config fetch failed with status code " + res.status);
}
return await res.json();
} catch (e) {
throw new Error("SFU Config fetch failed with exception " + e);
}
}