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.

126 lines
3.6 KiB

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