@@ -20,7 +20,7 @@ import { type CallMembership } from "./CallMembership.ts";
2020import  {  decodeBase64 ,  encodeBase64  }  from  "../base64.ts" ; 
2121import  {  type  IKeyTransport ,  type  KeyTransportEventListener ,  KeyTransportEvents  }  from  "./IKeyTransport.ts" ; 
2222import  {  logger  as  rootLogger ,  type  Logger  }  from  "../logger.ts" ; 
23- import  {  sleep  }  from  "../utils.ts" ; 
23+ import  {  defer ,   type   IDeferred ,   sleep  }  from  "../utils.ts" ; 
2424import  type  {  InboundEncryptionSession ,  ParticipantDeviceInfo ,  ParticipantId ,  Statistics  }  from  "./types.ts" ; 
2525import  {  getParticipantId ,  KeyBuffer  }  from  "./utils.ts" ; 
2626import  { 
@@ -75,6 +75,8 @@ export class RTCEncryptionManager implements IEncryptionManager {
7575
7676    private  logger : Logger ; 
7777
78+     private  currentRatchetRequest : IDeferred < {  key : ArrayBuffer ;  keyIndex : number  } >  |  null  =  null ; 
79+ 
7880    public  constructor ( 
7981        private  userId : string , 
8082        private  deviceId : string , 
@@ -86,9 +88,10 @@ export class RTCEncryptionManager implements IEncryptionManager {
8688            encryptionKeyIndex : number , 
8789            participantId : ParticipantId , 
8890        )  =>  void , 
91+         private  ratchetKey : ( participantId : ParticipantId ,  encryptionKeyIndex : number )  =>  void , 
8992        parentLogger ?: Logger , 
9093    )  { 
91-         this . logger  =  ( parentLogger  ??  rootLogger ) . getChild ( `[EncryptionManager ]` ) ; 
94+         this . logger  =  ( parentLogger  ??  rootLogger ) . getChild ( `[RTCEncryptionManager ]` ) ; 
9295    } 
9396
9497    public  getEncryptionKeys ( ) : Map < string ,  Array < {  key : Uint8Array ;  timestamp : number  } > >  { 
@@ -163,7 +166,9 @@ export class RTCEncryptionManager implements IEncryptionManager {
163166    } 
164167
165168    public  onNewKeyReceived : KeyTransportEventListener  =  ( userId ,  deviceId ,  keyBase64Encoded ,  index ,  timestamp )  =>  { 
166-         this . logger . debug ( `Received key over transport ${ userId } ${ deviceId } ${ index }  ) ; 
169+         this . logger . debug ( 
170+             `Received key over transport ${ userId } ${ deviceId } ${ index } ${ keyBase64Encoded }  , 
171+         ) ; 
167172
168173        // We received a new key, notify the video layer of this new key so that it can decrypt the frames properly. 
169174        const  participantId  =  getParticipantId ( userId ,  deviceId ) ; 
@@ -216,7 +221,13 @@ export class RTCEncryptionManager implements IEncryptionManager {
216221        // get current memberships 
217222        const  toShareWith : ParticipantDeviceInfo [ ]  =  this . getMemberships ( ) 
218223            . filter ( ( membership )  =>  { 
219-                 return  membership . sender  !=  undefined ; 
224+                 return  ( 
225+                     membership . sender  !=  undefined  && 
226+                     ! ( 
227+                         // filter me out 
228+                         ( membership . sender  ==  this . userId  &&  membership . deviceId  ==  this . deviceId ) 
229+                     ) 
230+                 ) ; 
220231            } ) 
221232            . map ( ( membership )  =>  { 
222233                return  { 
@@ -272,13 +283,37 @@ export class RTCEncryptionManager implements IEncryptionManager {
272283            toDistributeTo  =  toShareWith ; 
273284            outboundKey  =  newOutboundKey ; 
274285        }  else  if  ( anyJoined . length  >  0 )  { 
275-             // keep the same key 
276-             // XXX In the future we want to distribute a ratcheted key not the current one 
286+             if  ( this . outboundSession ! . sharedWith . length  >  0 )  { 
287+                 // This key was already shared with someone, we need to ratchet it 
288+                 // We want to ratchet the current key and only distribute the ratcheted key to the new joiners 
289+                 // This needs to send some async messages, so we need to wait for the ratchet to finish 
290+                 const  deferredKey  =  defer < {  key : ArrayBuffer ;  keyIndex : number  } > ( ) ; 
291+                 this . currentRatchetRequest  =  deferredKey ; 
292+                 this . logger . info ( `Query ratcheting key index:${ this . outboundSession ! . keyId }  ) ; 
293+                 this . ratchetKey ( getParticipantId ( this . userId ,  this . deviceId ) ,  this . outboundSession ! . keyId ) ; 
294+                 const  res  =  await  Promise . race ( [ deferredKey . promise ,  sleep ( 1000 ) ] ) ; 
295+                 if  ( res  ===  undefined )  { 
296+                     // TODO: we might want to rotate the key instead? 
297+                     this . logger . error ( "Ratchet key timed out sharing the same key for now :/" ) ; 
298+                 }  else  { 
299+                     const  {  key,  keyIndex }  =  await  deferredKey . promise ; 
300+                     this . logger . info ( 
301+                         `... Ratcheting done key index:${ keyIndex } ${ encodeBase64 ( new  Uint8Array ( key ) ) }  , 
302+                     ) ; 
303+                     this . outboundSession ! . key  =  new  Uint8Array ( key ) ; 
304+                     this . onEncryptionKeysChanged ( 
305+                         this . outboundSession ! . key , 
306+                         this . outboundSession ! . keyId , 
307+                         getParticipantId ( this . userId ,  this . deviceId ) , 
308+                     ) ; 
309+                 } 
310+             } 
277311            toDistributeTo  =  anyJoined ; 
278312            outboundKey  =  this . outboundSession ! ; 
279313        }  else  { 
280-             // no changes 
281-             return ; 
314+             // No one joined or left, it could just be the first key, keep going 
315+             toDistributeTo  =  [ ] ; 
316+             outboundKey  =  this . outboundSession ! ; 
282317        } 
283318
284319        try  { 
@@ -318,4 +353,10 @@ export class RTCEncryptionManager implements IEncryptionManager {
318353        globalThis . crypto . getRandomValues ( key ) ; 
319354        return  key ; 
320355    } 
356+ 
357+     public  onOwnKeyRatcheted ( key : ArrayBuffer ,  keyIndex : number  |  undefined ) : void { 
358+         this . logger . debug ( `Own key ratcheted for key index:${ keyIndex } ${ encodeBase64 ( new  Uint8Array ( key ) ) }  ) ; 
359+ 
360+         this . currentRatchetRequest ?. resolve ( {  key,  keyIndex : keyIndex !  } ) ; 
361+     } 
321362} 
0 commit comments