|
@ -1,17 +1,16 @@ |
|
|
import 'dart:convert'; |
|
|
import 'dart:convert'; |
|
|
import 'dart:typed_data'; |
|
|
import 'dart:typed_data'; |
|
|
|
|
|
|
|
|
import 'package:pointycastle/export.dart'; |
|
|
|
|
|
import 'package:uuid/uuid.dart'; |
|
|
|
|
|
|
|
|
import 'package:Envelope/models/conversation_users.dart'; |
|
|
|
|
|
import 'package:Envelope/models/my_profile.dart'; |
|
|
|
|
|
import 'package:Envelope/models/text_messages.dart'; |
|
|
|
|
|
import 'package:Envelope/utils/encryption/aes_helper.dart'; |
|
|
|
|
|
import 'package:Envelope/utils/encryption/crypto_utils.dart'; |
|
|
|
|
|
import 'package:Envelope/utils/strings.dart'; |
|
|
|
|
|
import 'package:pointycastle/pointycastle.dart'; |
|
|
|
|
|
|
|
|
import '/models/conversation_users.dart'; |
|
|
|
|
|
import '/models/conversations.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/storage/database.dart'; |
|
|
import '/utils/strings.dart'; |
|
|
|
|
|
|
|
|
|
|
|
const messageTypeReceiver = 'receiver'; |
|
|
const messageTypeReceiver = 'receiver'; |
|
|
const messageTypeSender = 'sender'; |
|
|
const messageTypeSender = 'sender'; |
|
@ -30,11 +29,11 @@ Future<List<Message>> getMessagesForThread(Conversation conversation) async { |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
return List.generate(maps.length, (i) { |
|
|
return List.generate(maps.length, (i) { |
|
|
return Message( |
|
|
|
|
|
|
|
|
return TextMessage( |
|
|
id: maps[i]['id'], |
|
|
id: maps[i]['id'], |
|
|
symmetricKey: maps[i]['symmetric_key'], |
|
|
symmetricKey: maps[i]['symmetric_key'], |
|
|
userSymmetricKey: maps[i]['user_symmetric_key'], |
|
|
userSymmetricKey: maps[i]['user_symmetric_key'], |
|
|
data: maps[i]['data'], |
|
|
|
|
|
|
|
|
text: maps[i]['data'], |
|
|
senderId: maps[i]['sender_id'], |
|
|
senderId: maps[i]['sender_id'], |
|
|
senderUsername: maps[i]['sender_username'], |
|
|
senderUsername: maps[i]['sender_username'], |
|
|
associationKey: maps[i]['association_key'], |
|
|
associationKey: maps[i]['association_key'], |
|
@ -42,24 +41,22 @@ Future<List<Message>> getMessagesForThread(Conversation conversation) async { |
|
|
failedToSend: maps[i]['failed_to_send'] == 1, |
|
|
failedToSend: maps[i]['failed_to_send'] == 1, |
|
|
); |
|
|
); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
class Message { |
|
|
class Message { |
|
|
String id; |
|
|
String id; |
|
|
String symmetricKey; |
|
|
String symmetricKey; |
|
|
String userSymmetricKey; |
|
|
String userSymmetricKey; |
|
|
String data; |
|
|
|
|
|
String senderId; |
|
|
String senderId; |
|
|
String senderUsername; |
|
|
String senderUsername; |
|
|
String associationKey; |
|
|
String associationKey; |
|
|
String createdAt; |
|
|
String createdAt; |
|
|
bool failedToSend; |
|
|
bool failedToSend; |
|
|
|
|
|
|
|
|
Message({ |
|
|
Message({ |
|
|
required this.id, |
|
|
required this.id, |
|
|
required this.symmetricKey, |
|
|
required this.symmetricKey, |
|
|
required this.userSymmetricKey, |
|
|
required this.userSymmetricKey, |
|
|
required this.data, |
|
|
|
|
|
required this.senderId, |
|
|
required this.senderId, |
|
|
required this.senderUsername, |
|
|
required this.senderUsername, |
|
|
required this.associationKey, |
|
|
required this.associationKey, |
|
@ -67,42 +64,13 @@ class Message { |
|
|
required this.failedToSend, |
|
|
required this.failedToSend, |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
Future<List<Map<String, String>>> payloadJsonBase( |
|
|
|
|
|
Uint8List symmetricKey, |
|
|
|
|
|
Conversation conversation, |
|
|
|
|
|
String messageId, |
|
|
|
|
|
String messageDataId, |
|
|
|
|
|
) async { |
|
|
|
|
|
|
|
|
factory Message.fromJson(Map<String, dynamic> json, RSAPrivateKey privKey) { |
|
|
|
|
|
var userSymmetricKey = CryptoUtils.rsaDecrypt( |
|
|
|
|
|
base64.decode(json['symmetric_key']), |
|
|
|
|
|
privKey, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
var symmetricKey = AesHelper.aesDecrypt( |
|
|
|
|
|
userSymmetricKey, |
|
|
|
|
|
base64.decode(json['message_data']['symmetric_key']), |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
var senderId = AesHelper.aesDecrypt( |
|
|
|
|
|
base64.decode(symmetricKey), |
|
|
|
|
|
base64.decode(json['message_data']['sender_id']), |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
var data = AesHelper.aesDecrypt( |
|
|
|
|
|
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, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Future<String> payloadJson(Conversation conversation, String messageId) async { |
|
|
|
|
|
MyProfile profile = await MyProfile.getProfile(); |
|
|
MyProfile profile = await MyProfile.getProfile(); |
|
|
if (profile.publicKey == null) { |
|
|
if (profile.publicKey == null) { |
|
|
throw Exception('Could not get profile.publicKey'); |
|
|
throw Exception('Could not get profile.publicKey'); |
|
@ -110,10 +78,7 @@ class Message { |
|
|
|
|
|
|
|
|
RSAPublicKey publicKey = profile.publicKey!; |
|
|
RSAPublicKey publicKey = profile.publicKey!; |
|
|
|
|
|
|
|
|
final String messageDataId = (const Uuid()).v4(); |
|
|
|
|
|
|
|
|
|
|
|
final userSymmetricKey = AesHelper.deriveKey(generateRandomString(32)); |
|
|
final userSymmetricKey = AesHelper.deriveKey(generateRandomString(32)); |
|
|
final symmetricKey = AesHelper.deriveKey(generateRandomString(32)); |
|
|
|
|
|
|
|
|
|
|
|
List<Map<String, String>> messages = []; |
|
|
List<Map<String, String>> messages = []; |
|
|
List<ConversationUser> conversationUsers = await getConversationUsers(conversation); |
|
|
List<ConversationUser> conversationUsers = await getConversationUsers(conversation); |
|
@ -150,48 +115,10 @@ class Message { |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
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), |
|
|
|
|
|
), |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
return jsonEncode(<String, dynamic>{ |
|
|
|
|
|
'message_data': messageData, |
|
|
|
|
|
'message': messages, |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
return messages; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Map<String, dynamic> toMap() { |
|
|
|
|
|
return { |
|
|
|
|
|
'id': id, |
|
|
|
|
|
'symmetric_key': symmetricKey, |
|
|
|
|
|
'user_symmetric_key': userSymmetricKey, |
|
|
|
|
|
'data': data, |
|
|
|
|
|
'sender_id': senderId, |
|
|
|
|
|
'sender_username': senderUsername, |
|
|
|
|
|
'association_key': associationKey, |
|
|
|
|
|
'created_at': createdAt, |
|
|
|
|
|
'failed_to_send': failedToSend ? 1 : 0, |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
String getContent() { |
|
|
|
|
|
return ''; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@override |
|
|
|
|
|
String toString() { |
|
|
|
|
|
return ''' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
id: $id |
|
|
|
|
|
data: $data |
|
|
|
|
|
senderId: $senderId |
|
|
|
|
|
senderUsername: $senderUsername |
|
|
|
|
|
associationKey: $associationKey |
|
|
|
|
|
createdAt: $createdAt |
|
|
|
|
|
'''; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
} |