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.

128 lines
3.8 KiB

  1. import 'dart:convert';
  2. import 'package:uuid/uuid.dart';
  3. import 'package:Envelope/models/conversation_users.dart';
  4. import 'package:intl/intl.dart';
  5. import 'package:http/http.dart' as http;
  6. import 'package:flutter_dotenv/flutter_dotenv.dart';
  7. import 'package:pointycastle/export.dart';
  8. import 'package:sqflite/sqflite.dart';
  9. import 'package:shared_preferences/shared_preferences.dart';
  10. import '/utils/storage/session_cookie.dart';
  11. import '/utils/storage/encryption_keys.dart';
  12. import '/utils/storage/database.dart';
  13. import '/models/conversations.dart';
  14. import '/models/messages.dart';
  15. Future<void> updateMessageThread(Conversation conversation, {RSAPrivateKey? privKey}) async {
  16. privKey ??= await getPrivateKey();
  17. final preferences = await SharedPreferences.getInstance();
  18. String username = preferences.getString('username')!;
  19. ConversationUser currentUser = await getConversationUserByUsername(conversation, username);
  20. var resp = await http.get(
  21. Uri.parse('${dotenv.env["SERVER_URL"]}api/v1/auth/messages/${currentUser.associationKey}'),
  22. headers: {
  23. 'cookie': await getSessionCookie(),
  24. }
  25. );
  26. if (resp.statusCode != 200) {
  27. throw Exception(resp.body);
  28. }
  29. List<dynamic> messageThreadJson = jsonDecode(resp.body);
  30. final db = await getDatabaseConnection();
  31. for (var i = 0; i < messageThreadJson.length; i++) {
  32. Message message = Message.fromJson(
  33. messageThreadJson[i] as Map<String, dynamic>,
  34. privKey,
  35. );
  36. ConversationUser messageUser = await getConversationUserById(conversation, message.senderId);
  37. message.senderUsername = messageUser.username;
  38. await db.insert(
  39. 'messages',
  40. message.toMap(),
  41. conflictAlgorithm: ConflictAlgorithm.replace,
  42. );
  43. }
  44. }
  45. Future<void> updateMessageThreads({List<Conversation>? conversations}) async {
  46. try {
  47. RSAPrivateKey privKey = await getPrivateKey();
  48. conversations ??= await getConversations();
  49. for (var i = 0; i < conversations.length; i++) {
  50. await updateMessageThread(conversations[i], privKey: privKey);
  51. }
  52. } catch(SocketException) {
  53. return;
  54. }
  55. }
  56. Future<void> sendMessage(Conversation conversation, String data) async {
  57. final preferences = await SharedPreferences.getInstance();
  58. final userId = preferences.getString('userId');
  59. final username = preferences.getString('username');
  60. if (userId == null || username == null) {
  61. throw Exception('Invalid user id');
  62. }
  63. var uuid = const Uuid();
  64. final String messageDataId = uuid.v4();
  65. ConversationUser currentUser = await getConversationUserByUsername(conversation, username);
  66. Message message = Message(
  67. id: messageDataId,
  68. symmetricKey: '',
  69. userSymmetricKey: '',
  70. senderId: userId,
  71. senderUsername: username,
  72. data: data,
  73. associationKey: currentUser.associationKey,
  74. createdAt: DateTime.now().toIso8601String(),
  75. failedToSend: false,
  76. );
  77. final db = await getDatabaseConnection();
  78. await db.insert(
  79. 'messages',
  80. message.toMap(),
  81. conflictAlgorithm: ConflictAlgorithm.replace,
  82. );
  83. String sessionCookie = await getSessionCookie();
  84. message.toJson(conversation, messageDataId)
  85. .then((messageJson) {
  86. return http.post(
  87. Uri.parse('${dotenv.env["SERVER_URL"]}api/v1/auth/message'),
  88. headers: <String, String>{
  89. 'Content-Type': 'application/json; charset=UTF-8',
  90. 'cookie': sessionCookie,
  91. },
  92. body: messageJson,
  93. );
  94. })
  95. .then((resp) {
  96. if (resp.statusCode != 200) {
  97. throw Exception('Unable to send message');
  98. }
  99. })
  100. .catchError((exception) {
  101. message.failedToSend = true;
  102. db.update(
  103. 'messages',
  104. message.toMap(),
  105. where: 'id = ?',
  106. whereArgs: [message.id],
  107. );
  108. });
  109. }