1616
1717package  org.sdn.android.sdk.internal.crypto 
1818
19+ import  dagger.Lazy 
1920import  kotlinx.coroutines.CoroutineScope 
2021import  kotlinx.coroutines.SupervisorJob 
2122import  kotlinx.coroutines.asCoroutineDispatcher 
@@ -30,6 +31,7 @@ import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_RATCHET
3031import  org.sdn.android.sdk.api.crypto.MXCryptoConfig 
3132import  org.sdn.android.sdk.api.extensions.tryOrNull 
3233import  org.sdn.android.sdk.api.logger.LoggerTag 
34+ import  org.sdn.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState 
3335import  org.sdn.android.sdk.api.session.crypto.keyshare.GossipingRequestListener 
3436import  org.sdn.android.sdk.api.session.crypto.model.CryptoDeviceInfo 
3537import  org.sdn.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest 
@@ -39,9 +41,11 @@ import org.sdn.android.sdk.api.session.crypto.model.RoomKeyShareRequest
3941import  org.sdn.android.sdk.api.session.events.model.EventType 
4042import  org.sdn.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent 
4143import  org.sdn.android.sdk.api.session.events.model.content.WithHeldCode 
44+ import  org.sdn.android.sdk.api.session.events.model.toContent 
4245import  org.sdn.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction 
4346import  org.sdn.android.sdk.internal.crypto.actions.MessageEncrypter 
4447import  org.sdn.android.sdk.internal.crypto.store.IMXCryptoStore 
48+ import  org.sdn.android.sdk.internal.crypto.tasks.SendSimpleEventTask 
4549import  org.sdn.android.sdk.internal.crypto.tasks.SendToDeviceTask 
4650import  org.sdn.android.sdk.internal.session.SessionScope 
4751import  org.sdn.android.sdk.internal.task.SemaphoreCoroutineSequencer 
@@ -63,6 +67,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
6367    private  val  messageEncrypter :  MessageEncrypter ,
6468    private  val  coroutineDispatchers :  SDNCoroutineDispatchers ,
6569    private  val  sendToDeviceTask :  SendToDeviceTask ,
70+     private  val  sendSimpleEventTask :  SendSimpleEventTask ,
6671    private  val  clock :  Clock ,
6772) {
6873
@@ -83,6 +88,8 @@ internal class IncomingKeyRequestManager @Inject constructor(
8388            val  requestId :  String ,
8489            val  requestingUserId :  String ,
8590            val  requestingDeviceId :  String ,
91+             val  requestingDeviceKey :  String? ,
92+             val  requestingDeviceOtk :  String? ,
8693            val  roomId :  String ,
8794            val  senderKey :  String ,
8895            val  sessionId :  String ,
@@ -109,6 +116,8 @@ internal class IncomingKeyRequestManager @Inject constructor(
109116                requestId =  requestId,
110117                requestingUserId =  senderId,
111118                requestingDeviceId =  deviceId,
119+                 requestingDeviceKey =  this .requestingDeviceKey,
120+                 requestingDeviceOtk =  this .requestingDeviceOtk,
112121                roomId =  roomId,
113122                senderKey =  senderKey,
114123                sessionId =  sessionId,
@@ -209,11 +218,11 @@ internal class IncomingKeyRequestManager @Inject constructor(
209218
210219    private  suspend  fun  handleIncomingRequest (request :  ValidMegolmRequestBody ) {
211220        //  We don't want to download keys, if we don't know the device yet we won't share any how?
212-         val  requestingDevice = 
213-                 cryptoStore.getUserDevice(request.requestingUserId,  request.requestingDeviceId) 
214-                          ? :   return   Unit . also  { 
215-                              Timber .tag(loggerTag.value).d( " Ignoring key request:  ${request.shortDbgString()} " ) 
216-                          }
221+         val  requestingDevice =  cryptoStore.getUserDevice(request.requestingUserId, request.requestingDeviceId) 
222+         if  (requestingDevice  ==   null   ||  requestingDevice.identityKey()  !=   request.requestingDeviceKey) { 
223+             directShareMegolmKey(request) 
224+             return 
225+         }
217226
218227        cryptoStore.saveIncomingKeyRequestAuditTrail(
219228                request.requestId,
@@ -357,6 +366,8 @@ internal class IncomingKeyRequestManager @Inject constructor(
357366                requestId =  request.requestId,
358367                requestingDeviceId =  request.deviceId,
359368                requestingUserId =  request.userId,
369+                 requestingDeviceKey =  null ,
370+                 requestingDeviceOtk =  null ,
360371                roomId =  request.requestBody.roomId,
361372                senderKey =  request.requestBody.senderKey,
362373                sessionId =  request.requestBody.sessionId,
@@ -446,6 +457,85 @@ internal class IncomingKeyRequestManager @Inject constructor(
446457        }
447458    }
448459
460+     private  suspend  fun  directShareMegolmKey (validRequest :  ValidMegolmRequestBody ): Boolean  {
461+         val  requestingDeviceKey =  validRequest.requestingDeviceKey ? :  return  false .also  {
462+             Timber .tag(loggerTag.value).e(" directShareMegolmKey: no requestingDeviceKey from ${validRequest.requestingUserId}  | ${validRequest.requestingDeviceId} "  )
463+         }
464+         val  requestingDeviceInfo =  CryptoDeviceInfo (
465+             userId =  validRequest.requestingUserId,
466+             deviceId =  validRequest.requestingDeviceId,
467+             keys =  mapOf (" curve25519:${validRequest.requestingDeviceId} "   to requestingDeviceKey)
468+         )
469+         val  wasSessionSharedWithUser =  cryptoStore.getSharedSessionInfo(validRequest.roomId, validRequest.sessionId, requestingDeviceInfo)
470+         if  (wasSessionSharedWithUser.found &&  wasSessionSharedWithUser.chainIndex ==  0 ) {
471+             Timber .tag(loggerTag.value).e(" skip direct share Key for ${validRequest.shortDbgString()} "  )
472+             return  false 
473+         }
474+ 
475+         Timber .tag(loggerTag.value).d(" try to direct share Megolm Key for ${validRequest.shortDbgString()} "  )
476+         if  (validRequest.requestingDeviceKey ==  null  ||  validRequest.requestingDeviceOtk ==  null ) {
477+             Timber .tag(loggerTag.value).w(" fail to direct share Megolm Key for ${validRequest.shortDbgString()} : no device keys"  )
478+             return  false 
479+         }
480+ 
481+         val  sessionHolder =  try  {
482+             olmDevice.getInboundGroupSession(validRequest.sessionId, validRequest.senderKey, validRequest.roomId)
483+         } catch  (failure:  Throwable ) {
484+             Timber .tag(loggerTag.value)
485+                 .e(failure, " shareKeysWithDevice: failed to get session ${validRequest.requestingUserId} "  )
486+             //  It's unavailable
487+             sendWithheldForRequest(validRequest, WithHeldCode .UNAVAILABLE )
488+             return  false 
489+         }
490+ 
491+         val  export =  sessionHolder.mutex.withLock {
492+             sessionHolder.wrapper.exportKeys(0 )
493+         } ? :  return  false .also  {
494+             Timber .tag(loggerTag.value)
495+                 .e(" shareKeysWithDevice: failed to export group session ${validRequest.sessionId} "  )
496+         }
497+ 
498+         val  payloadJson =  mapOf (
499+             " type"   to EventType .FORWARDED_ROOM_KEY ,
500+             " content"   to export
501+         )
502+ 
503+         val  encryptedPayload =  messageEncrypter.directEncryptMessage(
504+             payloadJson, validRequest.requestingUserId, validRequest.requestingDeviceId, validRequest.requestingDeviceKey, validRequest.requestingDeviceOtk)
505+         encryptedPayload.traceId =  validRequest.sessionId
506+ 
507+         return  try  {
508+             sendSimpleEventTask.execute(SendSimpleEventTask .Params (
509+                 roomId =  validRequest.roomId,
510+                 eventType =  EventType .ROOM_KEY_REPLY ,
511+                 encryptedPayload.toContent()
512+             ))
513+             Timber .tag(loggerTag.value)
514+                 .i(" successfully direct shared session for ${validRequest.shortDbgString()} "  )
515+             cryptoStore.saveForwardKeyAuditTrail(
516+                 validRequest.roomId,
517+                 validRequest.sessionId,
518+                 validRequest.senderKey,
519+                 validRequest.algorithm,
520+                 validRequest.requestingUserId,
521+                 validRequest.requestingDeviceId,
522+                 0 ,
523+             )
524+             cryptoStore.markedSessionAsShared(
525+                 validRequest.roomId,
526+                 validRequest.sessionId,
527+                 validRequest.requestingUserId,
528+                 validRequest.requestingDeviceId,
529+                 validRequest.requestingDeviceKey,
530+                 0 )
531+             true 
532+         } catch  (failure:  Throwable ) {
533+             Timber .tag(loggerTag.value)
534+                 .e(failure, " fail to direct share session for ${validRequest.shortDbgString()} "  )
535+             false 
536+         }
537+     }
538+ 
449539    fun  addRoomKeysRequestListener (listener :  GossipingRequestListener ) {
450540        synchronized(gossipingRequestListeners) {
451541            gossipingRequestListeners.add(listener)
0 commit comments