Encrypted messaging app
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
5.2 KiB

  1. import 'dart:convert';
  2. import 'dart:typed_data';
  3. import 'package:Envelope/utils/encryption/aes_helper.dart';
  4. import 'package:Envelope/utils/encryption/crypto_utils.dart';
  5. import 'package:pointycastle/impl.dart';
  6. import '/models/conversations.dart';
  7. import '/utils/storage/database.dart';
  8. Future<ConversationUser> getConversationUser(Conversation conversation, String userId) async {
  9. final db = await getDatabaseConnection();
  10. final List<Map<String, dynamic>> maps = await db.query(
  11. 'conversation_users',
  12. where: 'conversation_id = ? AND user_id = ?',
  13. whereArgs: [conversation.id, userId],
  14. );
  15. if (maps.length != 1) {
  16. throw ArgumentError('Invalid conversation_id or username');
  17. }
  18. return ConversationUser(
  19. id: maps[0]['id'],
  20. userId: maps[0]['user_id'],
  21. conversationId: maps[0]['conversation_id'],
  22. username: maps[0]['username'],
  23. associationKey: maps[0]['association_key'],
  24. publicKey: CryptoUtils.rsaPublicKeyFromPem(maps[0]['asymmetric_public_key']),
  25. admin: maps[0]['admin'] == 1,
  26. );
  27. }
  28. // A method that retrieves all the dogs from the dogs table.
  29. Future<List<ConversationUser>> getConversationUsers(Conversation conversation) async {
  30. final db = await getDatabaseConnection();
  31. final List<Map<String, dynamic>> maps = await db.query(
  32. 'conversation_users',
  33. where: 'conversation_id = ?',
  34. whereArgs: [conversation.id],
  35. orderBy: 'username',
  36. );
  37. List<ConversationUser> conversationUsers = List.generate(maps.length, (i) {
  38. return ConversationUser(
  39. id: maps[i]['id'],
  40. userId: maps[i]['user_id'],
  41. conversationId: maps[i]['conversation_id'],
  42. username: maps[i]['username'],
  43. associationKey: maps[i]['association_key'],
  44. publicKey: CryptoUtils.rsaPublicKeyFromPem(maps[i]['asymmetric_public_key']),
  45. admin: maps[i]['admin'] == 1,
  46. );
  47. });
  48. int index = 0;
  49. List<ConversationUser> finalConversationUsers = [];
  50. for (ConversationUser conversationUser in conversationUsers) {
  51. if (!conversationUser.admin) {
  52. finalConversationUsers.add(conversationUser);
  53. continue;
  54. }
  55. finalConversationUsers.insert(index, conversationUser);
  56. index++;
  57. }
  58. return finalConversationUsers;
  59. }
  60. Future<List<Map<String, dynamic>>> getEncryptedConversationUsers(Conversation conversation, Uint8List symKey) async {
  61. final db = await getDatabaseConnection();
  62. final List<Map<String, dynamic>> maps = await db.query(
  63. 'conversation_users',
  64. where: 'conversation_id = ?',
  65. whereArgs: [conversation.id],
  66. orderBy: 'username',
  67. );
  68. List<Map<String, dynamic>> conversationUsers = List.generate(maps.length, (i) {
  69. return {
  70. 'id': maps[i]['id'],
  71. 'conversation_id': maps[i]['conversation_id'],
  72. 'user_id': AesHelper.aesEncrypt(symKey, Uint8List.fromList(maps[i]['user_id'].codeUnits)),
  73. 'username': AesHelper.aesEncrypt(symKey, Uint8List.fromList(maps[i]['username'].codeUnits)),
  74. 'association_key': AesHelper.aesEncrypt(symKey, Uint8List.fromList(maps[i]['association_key'].codeUnits)),
  75. 'public_key': AesHelper.aesEncrypt(symKey, Uint8List.fromList(maps[i]['asymmetric_public_key'].codeUnits)),
  76. 'admin': AesHelper.aesEncrypt(symKey, Uint8List.fromList((maps[i]['admin'] == 1 ? 'true' : 'false').codeUnits)),
  77. };
  78. });
  79. return conversationUsers;
  80. }
  81. class ConversationUser{
  82. String id;
  83. String userId;
  84. String conversationId;
  85. String username;
  86. String associationKey;
  87. RSAPublicKey publicKey;
  88. bool admin;
  89. ConversationUser({
  90. required this.id,
  91. required this.userId,
  92. required this.conversationId,
  93. required this.username,
  94. required this.associationKey,
  95. required this.publicKey,
  96. required this.admin,
  97. });
  98. factory ConversationUser.fromJson(Map<String, dynamic> json, Uint8List symmetricKey) {
  99. String userId = AesHelper.aesDecrypt(
  100. symmetricKey,
  101. base64.decode(json['user_id']),
  102. );
  103. String username = AesHelper.aesDecrypt(
  104. symmetricKey,
  105. base64.decode(json['username']),
  106. );
  107. String associationKey = AesHelper.aesDecrypt(
  108. symmetricKey,
  109. base64.decode(json['association_key']),
  110. );
  111. String admin = AesHelper.aesDecrypt(
  112. symmetricKey,
  113. base64.decode(json['admin']),
  114. );
  115. String publicKeyString = AesHelper.aesDecrypt(
  116. symmetricKey,
  117. base64.decode(json['public_key']),
  118. );
  119. RSAPublicKey publicKey = CryptoUtils.rsaPublicKeyFromPem(publicKeyString);
  120. return ConversationUser(
  121. id: json['id'],
  122. conversationId: json['conversation_detail_id'],
  123. userId: userId,
  124. username: username,
  125. associationKey: associationKey,
  126. publicKey: publicKey,
  127. admin: admin == 'true',
  128. );
  129. }
  130. Map<String, dynamic> toJson() {
  131. return {
  132. 'id': id,
  133. 'user_id': userId,
  134. 'username': username,
  135. 'association_key': associationKey,
  136. 'asymmetric_public_key': publicKeyPem(),
  137. 'admin': admin ? 'true' : 'false',
  138. };
  139. }
  140. Map<String, dynamic> toMap() {
  141. return {
  142. 'id': id,
  143. 'user_id': userId,
  144. 'conversation_id': conversationId,
  145. 'username': username,
  146. 'association_key': associationKey,
  147. 'asymmetric_public_key': publicKeyPem(),
  148. 'admin': admin ? 1 : 0,
  149. };
  150. }
  151. String publicKeyPem() {
  152. return CryptoUtils.encodeRSAPublicKeyToPem(publicKey);
  153. }
  154. }