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.

163 lines
4.1 KiB

import 'dart:convert';
import 'dart:typed_data';
import 'package:Envelope/models/conversation_users.dart';
import 'package:Envelope/models/friends.dart';
import 'package:Envelope/models/my_profile.dart';
import 'package:pointycastle/export.dart';
import 'package:sqflite/sqflite.dart';
import 'package:uuid/uuid.dart';
import '/utils/encryption/crypto_utils.dart';
import '/utils/encryption/aes_helper.dart';
import '/utils/storage/database.dart';
import '/utils/strings.dart';
Conversation findConversationByDetailId(List<Conversation> conversations, String id) {
for (var conversation in conversations) {
if (conversation.conversationDetailId == id) {
return conversation;
}
}
// Or return `null`.
throw ArgumentError.value(id, "id", "No element with that id");
}
class Conversation {
String id;
String userId;
String conversationDetailId;
String symmetricKey;
bool admin;
String name;
Conversation({
required this.id,
required this.userId,
required this.conversationDetailId,
required this.symmetricKey,
required this.admin,
required this.name,
});
factory Conversation.fromJson(Map<String, dynamic> json, RSAPrivateKey privKey) {
var symmetricKeyDecrypted = CryptoUtils.rsaDecrypt(
base64.decode(json['symmetric_key']),
privKey,
);
var detailId = AesHelper.aesDecrypt(
symmetricKeyDecrypted,
base64.decode(json['conversation_detail_id']),
);
var admin = AesHelper.aesDecrypt(
symmetricKeyDecrypted,
base64.decode(json['admin']),
);
return Conversation(
id: json['id'],
userId: json['user_id'],
conversationDetailId: detailId,
symmetricKey: base64.encode(symmetricKeyDecrypted),
admin: admin == 'true',
name: 'Unknown',
);
}
@override
String toString() {
return '''
id: $id
userId: $userId
name: $name
admin: $admin''';
}
Map<String, dynamic> toMap() {
return {
'id': id,
'user_id': userId,
'conversation_detail_id': conversationDetailId,
'symmetric_key': symmetricKey,
'admin': admin ? 1 : 0,
'name': name,
};
}
}
Future<Conversation> createConversation(String title, List<Friend> friends) async {
final db = await getDatabaseConnection();
MyProfile profile = await MyProfile.getProfile();
var uuid = const Uuid();
final String conversationId = uuid.v4();
Uint8List symmetricKey = AesHelper.deriveKey(generateRandomString(32));
String associationKey = generateRandomString(32);
Conversation conversation = Conversation(
id: conversationId,
userId: profile.id,
conversationDetailId: '',
symmetricKey: base64.encode(symmetricKey),
admin: true,
name: title,
);
await db.insert(
'conversations',
conversation.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
await db.insert(
'conversation_users',
ConversationUser(
id: uuid.v4(),
conversationId: conversationId,
username: profile.username,
associationKey: associationKey,
admin: false,
).toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
for (Friend friend in friends) {
await db.insert(
'conversation_users',
ConversationUser(
id: uuid.v4(),
conversationId: conversationId,
username: friend.username,
associationKey: associationKey,
admin: false,
).toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
return conversation;
}
// A method that retrieves all the dogs from the dogs table.
Future<List<Conversation>> getConversations() async {
final db = await getDatabaseConnection();
final List<Map<String, dynamic>> maps = await db.query('conversations');
return List.generate(maps.length, (i) {
return Conversation(
id: maps[i]['id'],
userId: maps[i]['user_id'],
conversationDetailId: maps[i]['conversation_detail_id'],
symmetricKey: maps[i]['symmetric_key'],
admin: maps[i]['admin'] == 1,
name: maps[i]['name'],
);
});
}