2023-10-16 17:45:06 +01:00
/*
2024-09-06 10:22:13 +02:00
Copyright 2023, 2024 New Vector Ltd.
2023-10-16 17:45:06 +01:00
2025-02-18 17:59:58 +00:00
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
2024-09-06 10:22:13 +02:00
Please see LICENSE in the repository root for full details.
2023-10-16 17:45:06 +01:00
*/
2025-05-19 18:04:07 +02:00
import { BaseKeyProvider } from "livekit-client" ;
2025-03-13 13:58:43 +01:00
import { logger } from "matrix-js-sdk/lib/logger" ;
2023-10-16 17:45:06 +01:00
import {
2024-12-11 09:27:55 +00:00
type MatrixRTCSession ,
2023-10-16 17:45:06 +01:00
MatrixRTCSessionEvent ,
2025-03-13 13:58:43 +01:00
} from "matrix-js-sdk/lib/matrixrtc" ;
2025-12-15 18:23:30 +01:00
import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/EncryptionManager" ;
2025-12-16 12:18:00 +01:00
import { firstValueFrom } from "rxjs" ;
2025-12-15 18:23:30 +01:00
import {
2025-12-16 12:18:00 +01:00
computeLivekitParticipantIdentity$ ,
2025-12-15 18:23:30 +01:00
livekitIdentityInput ,
2025-12-16 12:18:00 +01:00
} from "../state/CallViewModel/remoteMembers/LivekitParticipantIdentity" ;
2023-10-16 17:45:06 +01:00
export class MatrixKeyProvider extends BaseKeyProvider {
private rtcSession? : MatrixRTCSession ;
2023-10-19 16:50:29 +01:00
public constructor () {
2025-04-23 09:22:54 +02:00
super ({ ratchetWindowSize : 10 , keyringSize : 256 });
2023-10-19 16:50:29 +01:00
}
2023-10-16 17:45:06 +01:00
public setRTCSession ( rtcSession : MatrixRTCSession ) : void {
if ( this . rtcSession ) {
this . rtcSession . off (
MatrixRTCSessionEvent . EncryptionKeyChanged ,
this . onEncryptionKeyChanged ,
);
}
this . rtcSession = rtcSession ;
this . rtcSession . on (
MatrixRTCSessionEvent . EncryptionKeyChanged ,
this . onEncryptionKeyChanged ,
);
// The new session could be aware of keys of which the old session wasn't,
2024-10-11 16:34:45 +01:00
// so emit key changed events
this . rtcSession . reemitEncryptionKeys ();
2023-10-16 17:45:06 +01:00
}
2024-09-10 09:49:35 +02:00
private onEncryptionKeyChanged = (
2023-10-20 17:31:15 +01:00
encryptionKey : Uint8Array ,
2023-10-16 17:45:06 +01:00
encryptionKeyIndex : number ,
2025-12-15 18:23:30 +01:00
membership : CallMembershipIdentityParts ,
2024-09-10 09:49:35 +02:00
) : void => {
2025-12-15 18:23:30 +01:00
const unhashedIdentity = livekitIdentityInput ( membership );
// This is the only way we can get the kind of the membership event we just received the key for.
// best case we want to recompute this once the memberships change (you can receive the key before the participant...)
//
// TODO change this to `?? "rtc"` for newer versions.
const kind =
this . rtcSession ? . memberships . find (
( m ) =>
m . userId === membership . userId &&
m . deviceId === membership . deviceId &&
m . memberId === membership . memberId ,
) ? . kind ?? "session" ;
Promise . all ([
crypto . subtle . importKey ( "raw" , encryptionKey , "HKDF" , false , [
2025-05-19 18:04:07 +02:00
"deriveBits" ,
"deriveKey" ,
2025-12-15 18:23:30 +01:00
]),
2025-12-16 12:18:00 +01:00
firstValueFrom ( computeLivekitParticipantIdentity$ ( membership , kind )),
2025-12-15 18:23:30 +01:00
]). then (
([ keyMaterial , livekitParticipantId ]) => {
this . onSetEncryptionKey (
keyMaterial ,
livekitParticipantId ,
encryptionKeyIndex ,
);
2025-05-19 18:04:07 +02:00
2025-12-15 18:23:30 +01:00
logger . debug (
`Sent new key to livekit room= ${ this . rtcSession ? . room . roomId } participantId= ${ livekitParticipantId } (before hash: ${ unhashedIdentity } ) encryptionKeyIndex= ${ encryptionKeyIndex } ` ,
);
},
( e ) => {
logger . error (
`Failed to create key material from buffer for livekit room= ${ this . rtcSession ? . room . roomId } participantId before hash= ${ unhashedIdentity } encryptionKeyIndex= ${ encryptionKeyIndex } ` ,
e ,
);
},
);
2023-10-16 17:45:06 +01:00
};
}