|
@ -1,6 +1,7 @@ |
|
|
import 'dart:convert'; |
|
|
import 'dart:convert'; |
|
|
import 'dart:typed_data'; |
|
|
import 'dart:typed_data'; |
|
|
|
|
|
|
|
|
|
|
|
import 'package:Envelope/models/messages.dart'; |
|
|
import 'package:pointycastle/export.dart'; |
|
|
import 'package:pointycastle/export.dart'; |
|
|
import 'package:sqflite/sqflite.dart'; |
|
|
import 'package:sqflite/sqflite.dart'; |
|
|
import 'package:uuid/uuid.dart'; |
|
|
import 'package:uuid/uuid.dart'; |
|
@ -20,6 +21,7 @@ Future<Conversation> createConversation(String title, List<Friend> friends) asyn |
|
|
|
|
|
|
|
|
var uuid = const Uuid(); |
|
|
var uuid = const Uuid(); |
|
|
final String conversationId = uuid.v4(); |
|
|
final String conversationId = uuid.v4(); |
|
|
|
|
|
final String conversationDetailId = uuid.v4(); |
|
|
|
|
|
|
|
|
Uint8List symmetricKey = AesHelper.deriveKey(generateRandomString(32)); |
|
|
Uint8List symmetricKey = AesHelper.deriveKey(generateRandomString(32)); |
|
|
|
|
|
|
|
@ -28,11 +30,12 @@ Future<Conversation> createConversation(String title, List<Friend> friends) asyn |
|
|
Conversation conversation = Conversation( |
|
|
Conversation conversation = Conversation( |
|
|
id: conversationId, |
|
|
id: conversationId, |
|
|
userId: profile.id, |
|
|
userId: profile.id, |
|
|
conversationDetailId: '', |
|
|
|
|
|
|
|
|
conversationDetailId: conversationDetailId, |
|
|
symmetricKey: base64.encode(symmetricKey), |
|
|
symmetricKey: base64.encode(symmetricKey), |
|
|
admin: true, |
|
|
admin: true, |
|
|
name: title, |
|
|
name: title, |
|
|
status: ConversationStatus.pending, |
|
|
status: ConversationStatus.pending, |
|
|
|
|
|
isRead: true, |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
await db.insert( |
|
|
await db.insert( |
|
@ -51,7 +54,7 @@ Future<Conversation> createConversation(String title, List<Friend> friends) asyn |
|
|
associationKey: associationKey, |
|
|
associationKey: associationKey, |
|
|
admin: true, |
|
|
admin: true, |
|
|
).toMap(), |
|
|
).toMap(), |
|
|
conflictAlgorithm: ConflictAlgorithm.replace, |
|
|
|
|
|
|
|
|
conflictAlgorithm: ConflictAlgorithm.fail, |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
for (Friend friend in friends) { |
|
|
for (Friend friend in friends) { |
|
@ -103,6 +106,7 @@ Future<Conversation> getConversationById(String id) async { |
|
|
admin: maps[0]['admin'] == 1, |
|
|
admin: maps[0]['admin'] == 1, |
|
|
name: maps[0]['name'], |
|
|
name: maps[0]['name'], |
|
|
status: ConversationStatus.values[maps[0]['status']], |
|
|
status: ConversationStatus.values[maps[0]['status']], |
|
|
|
|
|
isRead: maps[0]['is_read'] == 1, |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -121,6 +125,7 @@ Future<List<Conversation>> getConversations() async { |
|
|
admin: maps[i]['admin'] == 1, |
|
|
admin: maps[i]['admin'] == 1, |
|
|
name: maps[i]['name'], |
|
|
name: maps[i]['name'], |
|
|
status: ConversationStatus.values[maps[i]['status']], |
|
|
status: ConversationStatus.values[maps[i]['status']], |
|
|
|
|
|
isRead: maps[i]['is_read'] == 1, |
|
|
); |
|
|
); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
@ -134,6 +139,7 @@ class Conversation { |
|
|
bool admin; |
|
|
bool admin; |
|
|
String name; |
|
|
String name; |
|
|
ConversationStatus status; |
|
|
ConversationStatus status; |
|
|
|
|
|
bool isRead; |
|
|
|
|
|
|
|
|
Conversation({ |
|
|
Conversation({ |
|
|
required this.id, |
|
|
required this.id, |
|
@ -143,6 +149,7 @@ class Conversation { |
|
|
required this.admin, |
|
|
required this.admin, |
|
|
required this.name, |
|
|
required this.name, |
|
|
required this.status, |
|
|
required this.status, |
|
|
|
|
|
required this.isRead, |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -170,6 +177,7 @@ class Conversation { |
|
|
admin: admin == 'true', |
|
|
admin: admin == 'true', |
|
|
name: 'Unknown', |
|
|
name: 'Unknown', |
|
|
status: ConversationStatus.complete, |
|
|
status: ConversationStatus.complete, |
|
|
|
|
|
isRead: true, |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -181,41 +189,28 @@ class Conversation { |
|
|
List<ConversationUser> users = await getConversationUsers(this); |
|
|
List<ConversationUser> users = await getConversationUsers(this); |
|
|
List<Object> userConversations = []; |
|
|
List<Object> userConversations = []; |
|
|
|
|
|
|
|
|
for (var x in users) { |
|
|
|
|
|
print(x.toMap()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (ConversationUser user in users) { |
|
|
for (ConversationUser user in users) { |
|
|
if (profile.id == user.userId) { |
|
|
|
|
|
userConversations.add({ |
|
|
|
|
|
'id': user.id, |
|
|
|
|
|
'user_id': profile.id, |
|
|
|
|
|
'conversation_detail_id': AesHelper.aesEncrypt(symKey, Uint8List.fromList(id.codeUnits)), |
|
|
|
|
|
'admin': AesHelper.aesEncrypt(symKey, Uint8List.fromList((admin ? 'true' : 'false').codeUnits)), |
|
|
|
|
|
'symmetric_key': base64.encode(CryptoUtils.rsaEncrypt(symKey, profile.publicKey!)), |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Friend friend = await getFriendByFriendId(user.userId); |
|
|
|
|
|
RSAPublicKey pubKey = CryptoUtils.rsaPublicKeyFromPem(friend.asymmetricPublicKey); |
|
|
|
|
|
|
|
|
RSAPublicKey pubKey = profile.publicKey!; |
|
|
|
|
|
String newId = id; |
|
|
|
|
|
|
|
|
|
|
|
if (profile.id != user.userId) { |
|
|
|
|
|
Friend friend = await getFriendByFriendId(user.userId); |
|
|
|
|
|
pubKey = CryptoUtils.rsaPublicKeyFromPem(friend.asymmetricPublicKey); |
|
|
|
|
|
newId = (const Uuid()).v4(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
userConversations.add({ |
|
|
userConversations.add({ |
|
|
'id': user.id, |
|
|
|
|
|
'user_id': friend.userId, |
|
|
|
|
|
'conversation_detail_id': AesHelper.aesEncrypt(symKey, Uint8List.fromList(id.codeUnits)), |
|
|
|
|
|
|
|
|
'id': newId, |
|
|
|
|
|
'user_id': user.userId, |
|
|
|
|
|
'conversation_detail_id': AesHelper.aesEncrypt(symKey, Uint8List.fromList(conversationDetailId.codeUnits)), |
|
|
'admin': AesHelper.aesEncrypt(symKey, Uint8List.fromList((admin ? 'true' : 'false').codeUnits)), |
|
|
'admin': AesHelper.aesEncrypt(symKey, Uint8List.fromList((admin ? 'true' : 'false').codeUnits)), |
|
|
'symmetric_key': base64.encode(CryptoUtils.rsaEncrypt(symKey, pubKey)), |
|
|
'symmetric_key': base64.encode(CryptoUtils.rsaEncrypt(symKey, pubKey)), |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (var x in userConversations) { |
|
|
|
|
|
print(x); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
return { |
|
|
'id': id, |
|
|
|
|
|
|
|
|
'id': conversationDetailId, |
|
|
'name': AesHelper.aesEncrypt(symKey, Uint8List.fromList(name.codeUnits)), |
|
|
'name': AesHelper.aesEncrypt(symKey, Uint8List.fromList(name.codeUnits)), |
|
|
'users': AesHelper.aesEncrypt(symKey, Uint8List.fromList(jsonEncode(users).codeUnits)), |
|
|
'users': AesHelper.aesEncrypt(symKey, Uint8List.fromList(jsonEncode(users).codeUnits)), |
|
|
'user_conversations': userConversations, |
|
|
'user_conversations': userConversations, |
|
@ -231,6 +226,7 @@ class Conversation { |
|
|
'admin': admin ? 1 : 0, |
|
|
'admin': admin ? 1 : 0, |
|
|
'name': name, |
|
|
'name': name, |
|
|
'status': status.index, |
|
|
'status': status.index, |
|
|
|
|
|
'is_read': isRead ? 1 : 0, |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -244,6 +240,37 @@ class Conversation { |
|
|
name: $name |
|
|
name: $name |
|
|
admin: $admin'''; |
|
|
admin: $admin'''; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Future<Message?> getRecentMessage() 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 |
|
|
|
|
|
LIMIT 1; |
|
|
|
|
|
''', |
|
|
|
|
|
[id], |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (maps.isEmpty) { |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return Message( |
|
|
|
|
|
id: maps[0]['id'], |
|
|
|
|
|
symmetricKey: maps[0]['symmetric_key'], |
|
|
|
|
|
userSymmetricKey: maps[0]['user_symmetric_key'], |
|
|
|
|
|
data: maps[0]['data'], |
|
|
|
|
|
senderId: maps[0]['sender_id'], |
|
|
|
|
|
senderUsername: maps[0]['sender_username'], |
|
|
|
|
|
associationKey: maps[0]['association_key'], |
|
|
|
|
|
createdAt: maps[0]['created_at'], |
|
|
|
|
|
failedToSend: maps[0]['failed_to_send'] == 1, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|