@ -1,17 +1,48 @@  
			
		
	
		
			
				
					import  ' dart:convert ' ;  
			
		
	
		
			
				
					import  ' dart:typed_data ' ;  
			
		
	
		
			
				
					import  ' package:Envelope/models/conversation_users.dart ' ;  
			
		
	
		
			
				
					import  ' package:Envelope/models/conversations.dart ' ;  
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					import  ' package:pointycastle/export.dart ' ;  
			
		
	
		
			
				
					import  ' package:shared_preferences/shared_preferences.dart ' ;  
			
		
	
		
			
				
					import  ' /utils/encryption/crypto_utils.dart ' ;  
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					import  ' /models/conversation_users.dart ' ;  
			
		
	
		
			
				
					import  ' /models/conversations.dart ' ;  
			
		
	
		
			
				
					import  ' /models/my_profile.dart ' ;  
			
		
	
		
			
				
					import  ' /models/friends.dart ' ;  
			
		
	
		
			
				
					import  ' /utils/encryption/aes_helper.dart ' ;  
			
		
	
		
			
				
					import  ' /utils/encryption/crypto_utils.dart ' ;  
			
		
	
		
			
				
					import  ' /utils/storage/database.dart ' ;  
			
		
	
		
			
				
					import  ' /utils/strings.dart ' ;  
			
		
	
		
			
				
					import  ' /models/friends.dart ' ;  
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					const  messageTypeSender  =  ' sender ' ;  
			
		
	
		
			
				
					const  messageTypeReceiver  =  ' receiver ' ;  
			
		
	
		
			
				
					const  messageTypeSender  =  ' sender ' ;  
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					Future < List < Message > >  getMessagesForThread ( Conversation  conversation )  async  {  
			
		
	
		
			
				
					  final  db  =  await  getDatabaseConnection ( ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					  final  List < Map < String ,  dynamic > >  maps  =  await  db . rawQuery (   
			
		
	
		
			
				
					    '''   
			
		
	
		
			
				
					    SELECT  *  FROM  messages  WHERE  association_key  IN  (   
			
		
	
		
			
				
					      SELECT  association_key  FROM  conversation_users  WHERE  conversation_id  =  ?   
			
		
	
		
			
				
					    )   
			
		
	
		
			
				
					    ORDER  BY  created_at  DESC ;   
			
		
	
		
			
				
					    ''' ,   
			
		
	
		
			
				
					    [ conversation . id ]   
			
		
	
		
			
				
					  ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					  return  List . generate ( maps . length ,  ( i )  {   
			
		
	
		
			
				
					    return  Message (   
			
		
	
		
			
				
					      id:  maps [ i ] [ ' id ' ] ,   
			
		
	
		
			
				
					      symmetricKey:  maps [ i ] [ ' symmetric_key ' ] ,   
			
		
	
		
			
				
					      userSymmetricKey:  maps [ i ] [ ' user_symmetric_key ' ] ,   
			
		
	
		
			
				
					      data:  maps [ i ] [ ' data ' ] ,   
			
		
	
		
			
				
					      senderId:  maps [ i ] [ ' sender_id ' ] ,   
			
		
	
		
			
				
					      senderUsername:  maps [ i ] [ ' sender_username ' ] ,   
			
		
	
		
			
				
					      associationKey:  maps [ i ] [ ' association_key ' ] ,   
			
		
	
		
			
				
					      createdAt:  maps [ i ] [ ' created_at ' ] ,   
			
		
	
		
			
				
					      failedToSend:  maps [ i ] [ ' failed_to_send ' ]  = =  1 ,   
			
		
	
		
			
				
					    ) ;   
			
		
	
		
			
				
					  } ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					class  Message  {  
			
		
	
		
			
				
					  String  id ;   
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -38,109 +69,99 @@ class Message {  
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					  factory  Message . fromJson ( Map < String ,  dynamic >  json ,  RSAPrivateKey  privKey )  {   
			
		
	
		
			
				
					    var  userSymmetricKey  =  CryptoUtils . rsaDecrypt (   
			
		
	
		
			
				
					         base64 . decode ( json [ ' symmetric_key ' ] ) ,   
			
		
	
		
			
				
					         privKey ,   
			
		
	
		
			
				
					      base64 . decode ( json [ ' symmetric_key ' ] ) ,   
			
		
	
		
			
				
					      privKey ,   
			
		
	
		
			
				
					    ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					    var  symmetricKey  =  AesHelper . aesDecrypt (   
			
		
	
		
			
				
					         userSymmetricKey ,   
			
		
	
		
			
				
					         base64 . decode ( json [ ' message_data ' ] [ ' symmetric_key ' ] ) ,   
			
		
	
		
			
				
					      userSymmetricKey ,   
			
		
	
		
			
				
					      base64 . decode ( json [ ' message_data ' ] [ ' symmetric_key ' ] ) ,   
			
		
	
		
			
				
					    ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					    var  senderId  =  AesHelper . aesDecrypt (   
			
		
	
		
			
				
					         base64 . decode ( symmetricKey ) ,   
			
		
	
		
			
				
					         base64 . decode ( json [ ' message_data ' ] [ ' sender_id ' ] ) ,   
			
		
	
		
			
				
					      base64 . decode ( symmetricKey ) ,   
			
		
	
		
			
				
					      base64 . decode ( json [ ' message_data ' ] [ ' sender_id ' ] ) ,   
			
		
	
		
			
				
					    ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					    var  data  =  AesHelper . aesDecrypt (   
			
		
	
		
			
				
					         base64 . decode ( symmetricKey ) ,   
			
		
	
		
			
				
					         base64 . decode ( json [ ' message_data ' ] [ ' data ' ] ) ,   
			
		
	
		
			
				
					      base64 . decode ( symmetricKey ) ,   
			
		
	
		
			
				
					      base64 . decode ( json [ ' message_data ' ] [ ' data ' ] ) ,   
			
		
	
		
			
				
					    ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					    return  Message (   
			
		
	
		
			
				
					         id:  json [ ' id ' ] ,   
			
		
	
		
			
				
					         symmetricKey:  symmetricKey ,   
			
		
	
		
			
				
					         userSymmetricKey:  base64 . encode ( userSymmetricKey ) ,   
			
		
	
		
			
				
					         data:  data ,   
			
		
	
		
			
				
					         senderId:  senderId ,   
			
		
	
		
			
				
					         senderUsername:  ' Unknown ' ,   
			
		
	
		
			
				
					         associationKey:  json [ ' association_key ' ] ,   
			
		
	
		
			
				
					         createdAt:  json [ ' created_at ' ] ,   
			
		
	
		
			
				
					         failedToSend:  false ,   
			
		
	
		
			
				
					      id:  json [ ' id ' ] ,   
			
		
	
		
			
				
					      symmetricKey:  symmetricKey ,   
			
		
	
		
			
				
					      userSymmetricKey:  base64 . encode ( userSymmetricKey ) ,   
			
		
	
		
			
				
					      data:  data ,   
			
		
	
		
			
				
					      senderId:  senderId ,   
			
		
	
		
			
				
					      senderUsername:  ' Unknown ' ,   
			
		
	
		
			
				
					      associationKey:  json [ ' association_key ' ] ,   
			
		
	
		
			
				
					      createdAt:  json [ ' created_at ' ] ,   
			
		
	
		
			
				
					      failedToSend:  false ,   
			
		
	
		
			
				
					    ) ;   
			
		
	
		
			
				
					  }   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					  Future < String >  toJson ( Conversation  conversation ,  String  messageDataId )  async  {   
			
		
	
		
			
				
					      final  preferences  =  await  SharedPreferences . getInstance ( ) ;   
			
		
	
		
			
				
					      RSAPublicKey  publicKey  =  CryptoUtils . rsaPublicKeyFromPem ( preferences . getString ( ' asymmetricPublicKey ' ) ! ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					      final  userSymmetricKey  =  AesHelper . deriveKey ( generateRandomString ( 32 ) ) ;   
			
		
	
		
			
				
					      final  symmetricKey  =  AesHelper . deriveKey ( generateRandomString ( 32 ) ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					      List < Map < String ,  String > >  messages  =  [ ] ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					      String  id  =  ' ' ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					      List < ConversationUser >  conversationUsers  =  await  getConversationUsers ( conversation ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					      for  ( var  i  =  0 ;  i  <  conversationUsers . length ;  i + + )  {   
			
		
	
		
			
				
					          ConversationUser  user  =  conversationUsers [ i ] ;   
			
		
	
		
			
				
					          if  ( preferences . getString ( ' username ' )  = =  user . username )  {   
			
		
	
		
			
				
					            id  =  user . id ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					            messages . add ( {   
			
		
	
		
			
				
					              ' message_data_id ' :  messageDataId ,   
			
		
	
		
			
				
					              ' symmetric_key ' :  base64 . encode ( CryptoUtils . rsaEncrypt (   
			
		
	
		
			
				
					                  userSymmetricKey ,   
			
		
	
		
			
				
					                  publicKey ,   
			
		
	
		
			
				
					              ) ) ,   
			
		
	
		
			
				
					              ' association_key ' :  user . associationKey ,   
			
		
	
		
			
				
					            } ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					            continue ;   
			
		
	
		
			
				
					          }   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					          Friend  friend  =  await  getFriendByFriendId ( user . id ) ;   
			
		
	
		
			
				
					          RSAPublicKey  friendPublicKey  =  CryptoUtils . rsaPublicKeyFromPem ( friend . asymmetricPublicKey ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					          messages . add ( {   
			
		
	
		
			
				
					              ' message_data_id ' :  messageDataId ,   
			
		
	
		
			
				
					              ' symmetric_key ' :  base64 . encode ( CryptoUtils . rsaEncrypt (   
			
		
	
		
			
				
					                  userSymmetricKey ,   
			
		
	
		
			
				
					                  friendPublicKey ,   
			
		
	
		
			
				
					              ) ) ,   
			
		
	
		
			
				
					              ' association_key ' :  user . associationKey ,   
			
		
	
		
			
				
					          } ) ;   
			
		
	
		
			
				
					      }   
			
		
	
		
			
				
					    MyProfile  profile  =  await  MyProfile . getProfile ( ) ;   
			
		
	
		
			
				
					    if  ( profile . publicKey  = =  null )  {   
			
		
	
		
			
				
					      throw  Exception ( ' Could not get profile.publicKey ' ) ;   
			
		
	
		
			
				
					    }   
			
		
	
		
			
				
					    RSAPublicKey  publicKey  =  profile . publicKey ! ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					    final  userSymmetricKey  =  AesHelper . deriveKey ( generateRandomString ( 32 ) ) ;   
			
		
	
		
			
				
					    final  symmetricKey  =  AesHelper . deriveKey ( generateRandomString ( 32 ) ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					    List < Map < String ,  String > >  messages  =  [ ] ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					    String  id  =  ' ' ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					    List < ConversationUser >  conversationUsers  =  await  getConversationUsers ( conversation ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					      Map < String ,  String >  messageData  =  {   
			
		
	
		
			
				
					        ' id ' :  messageDataId ,   
			
		
	
		
			
				
					        ' data ' :  AesHelper . aesEncrypt ( symmetricKey ,  Uint8List . fromList ( data . codeUnits ) ) ,   
			
		
	
		
			
				
					        ' sender_id ' :  AesHelper . aesEncrypt ( symmetricKey ,  Uint8List . fromList ( id . codeUnits ) ) ,   
			
		
	
		
			
				
					        ' symmetric_key ' :  AesHelper . aesEncrypt (   
			
		
	
		
			
				
					    for  ( var  i  =  0 ;  i  <  conversationUsers . length ;  i + + )  {   
			
		
	
		
			
				
					      ConversationUser  user  =  conversationUsers [ i ] ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					      if  ( profile . id  = =  user . userId )  {   
			
		
	
		
			
				
					        id  =  user . id ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					        messages . add ( {   
			
		
	
		
			
				
					          ' message_data_id ' :  messageDataId ,   
			
		
	
		
			
				
					          ' symmetric_key ' :  base64 . encode ( CryptoUtils . rsaEncrypt (   
			
		
	
		
			
				
					            userSymmetricKey ,   
			
		
	
		
			
				
					            Uint8List . fromList ( base64 . encode ( symmetricKey ) . codeUnits ) ,   
			
		
	
		
			
				
					        ) ,   
			
		
	
		
			
				
					      } ;   
			
		
	
		
			
				
					            publicKey ,   
			
		
	
		
			
				
					          ) ) ,   
			
		
	
		
			
				
					          ' association_key ' :  user . associationKey ,   
			
		
	
		
			
				
					        } ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					      return  jsonEncode ( < String ,  dynamic > {   
			
		
	
		
			
				
					        ' message_data ' :  messageData ,   
			
		
	
		
			
				
					        ' message ' :  messages ,   
			
		
	
		
			
				
					      } ) ;   
			
		
	
		
			
				
					  }   
			
		
	
		
			
				
					        continue ;   
			
		
	
		
			
				
					      }   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					  @ override   
			
		
	
		
			
				
					  String  toString ( )  {   
			
		
	
		
			
				
					    return  '''   
			
		
	
		
			
				
					      Friend  friend  =  await  getFriendByFriendId ( user . userId ) ;   
			
		
	
		
			
				
					      RSAPublicKey  friendPublicKey  =  CryptoUtils . rsaPublicKeyFromPem ( friend . asymmetricPublicKey ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					      messages . add ( {   
			
		
	
		
			
				
					        ' message_data_id ' :  messageDataId ,   
			
		
	
		
			
				
					        ' symmetric_key ' :  base64 . encode ( CryptoUtils . rsaEncrypt (   
			
		
	
		
			
				
					          userSymmetricKey ,   
			
		
	
		
			
				
					          friendPublicKey ,   
			
		
	
		
			
				
					        ) ) ,   
			
		
	
		
			
				
					        ' association_key ' :  user . associationKey ,   
			
		
	
		
			
				
					      } ) ;   
			
		
	
		
			
				
					    }   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					    Map < String ,  String >  messageData  =  {   
			
		
	
		
			
				
					      ' id ' :  messageDataId ,   
			
		
	
		
			
				
					      ' data ' :  AesHelper . aesEncrypt ( symmetricKey ,  Uint8List . fromList ( data . codeUnits ) ) ,   
			
		
	
		
			
				
					      ' sender_id ' :  AesHelper . aesEncrypt ( symmetricKey ,  Uint8List . fromList ( senderId . codeUnits ) ) ,   
			
		
	
		
			
				
					      ' symmetric_key ' :  AesHelper . aesEncrypt (   
			
		
	
		
			
				
					        userSymmetricKey ,   
			
		
	
		
			
				
					        Uint8List . fromList ( base64 . encode ( symmetricKey ) . codeUnits ) ,   
			
		
	
		
			
				
					      ) ,   
			
		
	
		
			
				
					    } ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					        id:  $id   
			
		
	
		
			
				
					        data:  $data   
			
		
	
		
			
				
					        senderId:  $senderId   
			
		
	
		
			
				
					        senderUsername:  $senderUsername   
			
		
	
		
			
				
					        associationKey:  $associationKey   
			
		
	
		
			
				
					        createdAt:  $createdAt   
			
		
	
		
			
				
					''' ;  
			
		
	
		
			
				
					    return  jsonEncode ( < String ,  dynamic > {   
			
		
	
		
			
				
					      ' message_data ' :  messageData ,   
			
		
	
		
			
				
					      ' message ' :  messages ,   
			
		
	
		
			
				
					    } ) ;   
			
		
	
		
			
				
					  }   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					  Map < String ,  dynamic >  toMap ( )  {   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -157,33 +178,18 @@ class Message {  
			
		
	
		
			
				
					    } ;   
			
		
	
		
			
				
					  }   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					Future < List < Message > >  getMessagesForThread ( Conversation  conversation )  async  {  
			
		
	
		
			
				
					  final  db  =  await  getDatabaseConnection ( ) ;   
			
		
	
		
			
				
					  @ override   
			
		
	
		
			
				
					  String  toString ( )  {   
			
		
	
		
			
				
					    return  '''   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					  final  List < Map < String ,  dynamic > >  maps  =  await  db . rawQuery (   
			
		
	
		
			
				
					      '''   
			
		
	
		
			
				
					        SELECT  *  FROM  messages  WHERE  association_key  IN  (   
			
		
	
		
			
				
					          SELECT  association_key  FROM  conversation_users  WHERE  conversation_id  =  ?   
			
		
	
		
			
				
					        )   
			
		
	
		
			
				
					        ORDER  BY  created_at  DESC ;   
			
		
	
		
			
				
					      ''' ,   
			
		
	
		
			
				
					      [ conversation . id ]   
			
		
	
		
			
				
					  ) ;   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					  return  List . generate ( maps . length ,  ( i )  {   
			
		
	
		
			
				
					    return  Message (   
			
		
	
		
			
				
					        id:  maps [ i ] [ ' id ' ] ,   
			
		
	
		
			
				
					        symmetricKey:  maps [ i ] [ ' symmetric_key ' ] ,   
			
		
	
		
			
				
					        userSymmetricKey:  maps [ i ] [ ' user_symmetric_key ' ] ,   
			
		
	
		
			
				
					        data:  maps [ i ] [ ' data ' ] ,   
			
		
	
		
			
				
					        senderId:  maps [ i ] [ ' sender_id ' ] ,   
			
		
	
		
			
				
					        senderUsername:  maps [ i ] [ ' sender_username ' ] ,   
			
		
	
		
			
				
					        associationKey:  maps [ i ] [ ' association_key ' ] ,   
			
		
	
		
			
				
					        createdAt:  maps [ i ] [ ' created_at ' ] ,   
			
		
	
		
			
				
					        failedToSend:  maps [ i ] [ ' failed_to_send ' ]  = =  1 ,   
			
		
	
		
			
				
					    ) ;   
			
		
	
		
			
				
					  } ) ;   
			
		
	
		
			
				
					      id:  $id   
			
		
	
		
			
				
					      data:  $data   
			
		
	
		
			
				
					      senderId:  $senderId   
			
		
	
		
			
				
					      senderUsername:  $senderUsername   
			
		
	
		
			
				
					      associationKey:  $associationKey   
			
		
	
		
			
				
					      createdAt:  $createdAt   
			
		
	
		
			
				
					      ''' ;   
			
		
	
		
			
				
					  }   
			
		
	
		
			
				
					
  
			
		
	
		
			
				
					}