import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:pointycastle/export.dart';
|
|
|
|
import '/utils/encryption/aes_helper.dart';
|
|
import '/utils/encryption/crypto_utils.dart';
|
|
import '/utils/storage/database.dart';
|
|
|
|
Friend findFriendByFriendId(List<Friend> friends, String id) {
|
|
for (var friend in friends) {
|
|
if (friend.friendId == id) {
|
|
return friend;
|
|
}
|
|
}
|
|
// Or return `null`.
|
|
throw ArgumentError.value(id, 'id', 'No element with that id');
|
|
}
|
|
|
|
Future<Friend> getFriendByFriendId(String userId) async {
|
|
final db = await getDatabaseConnection();
|
|
|
|
final List<Map<String, dynamic>> maps = await db.query(
|
|
'friends',
|
|
where: 'friend_id = ?',
|
|
whereArgs: [userId],
|
|
);
|
|
|
|
if (maps.length != 1) {
|
|
throw ArgumentError('Invalid user id');
|
|
}
|
|
|
|
return Friend(
|
|
id: maps[0]['id'],
|
|
userId: maps[0]['user_id'],
|
|
friendId: maps[0]['friend_id'],
|
|
friendSymmetricKey: maps[0]['symmetric_key'],
|
|
publicKey: CryptoUtils.rsaPublicKeyFromPem(maps[0]['asymmetric_public_key']),
|
|
acceptedAt: maps[0]['accepted_at'] != null ? DateTime.parse(maps[0]['accepted_at']) : null,
|
|
username: maps[0]['username'],
|
|
);
|
|
}
|
|
|
|
|
|
Future<List<Friend>> getFriends({bool? accepted}) async {
|
|
final db = await getDatabaseConnection();
|
|
|
|
String? where;
|
|
|
|
if (accepted == true) {
|
|
where = 'accepted_at IS NOT NULL';
|
|
}
|
|
|
|
if (accepted == false) {
|
|
where = 'accepted_at IS NULL';
|
|
}
|
|
|
|
final List<Map<String, dynamic>> maps = await db.query(
|
|
'friends',
|
|
where: where,
|
|
);
|
|
|
|
return List.generate(maps.length, (i) {
|
|
return Friend(
|
|
id: maps[i]['id'],
|
|
userId: maps[i]['user_id'],
|
|
friendId: maps[i]['friend_id'],
|
|
friendSymmetricKey: maps[i]['symmetric_key'],
|
|
publicKey: CryptoUtils.rsaPublicKeyFromPem(maps[i]['asymmetric_public_key']),
|
|
acceptedAt: maps[i]['accepted_at'] != null ? DateTime.parse(maps[i]['accepted_at']) : null,
|
|
username: maps[i]['username'],
|
|
);
|
|
});
|
|
}
|
|
|
|
class Friend{
|
|
String id;
|
|
String userId;
|
|
String username;
|
|
String friendId;
|
|
String friendSymmetricKey;
|
|
RSAPublicKey publicKey;
|
|
DateTime? acceptedAt;
|
|
bool? selected;
|
|
Friend({
|
|
required this.id,
|
|
required this.userId,
|
|
required this.username,
|
|
required this.friendId,
|
|
required this.friendSymmetricKey,
|
|
required this.publicKey,
|
|
required this.acceptedAt,
|
|
this.selected,
|
|
});
|
|
|
|
factory Friend.fromJson(Map<String, dynamic> json, RSAPrivateKey privKey) {
|
|
Uint8List idDecrypted = CryptoUtils.rsaDecrypt(
|
|
base64.decode(json['friend_id']),
|
|
privKey,
|
|
);
|
|
|
|
Uint8List username = CryptoUtils.rsaDecrypt(
|
|
base64.decode(json['friend_username']),
|
|
privKey,
|
|
);
|
|
|
|
Uint8List symmetricKeyDecrypted = CryptoUtils.rsaDecrypt(
|
|
base64.decode(json['symmetric_key']),
|
|
privKey,
|
|
);
|
|
|
|
String publicKeyString = AesHelper.aesDecrypt(
|
|
symmetricKeyDecrypted,
|
|
base64.decode(json['asymmetric_public_key'])
|
|
);
|
|
|
|
RSAPublicKey publicKey = CryptoUtils.rsaPublicKeyFromPem(publicKeyString);
|
|
|
|
return Friend(
|
|
id: json['id'],
|
|
userId: json['user_id'],
|
|
username: String.fromCharCodes(username),
|
|
friendId: String.fromCharCodes(idDecrypted),
|
|
friendSymmetricKey: base64.encode(symmetricKeyDecrypted),
|
|
publicKey: publicKey,
|
|
acceptedAt: json['accepted_at']['Valid'] ?
|
|
DateTime.parse(json['accepted_at']['Time']) :
|
|
null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> payloadJson() {
|
|
|
|
Uint8List friendIdEncrypted = CryptoUtils.rsaEncrypt(
|
|
Uint8List.fromList(friendId.codeUnits),
|
|
publicKey,
|
|
);
|
|
|
|
Uint8List usernameEncrypted = CryptoUtils.rsaEncrypt(
|
|
Uint8List.fromList(username.codeUnits),
|
|
publicKey,
|
|
);
|
|
|
|
Uint8List symmetricKeyEncrypted = CryptoUtils.rsaEncrypt(
|
|
Uint8List.fromList(
|
|
base64.decode(friendSymmetricKey),
|
|
),
|
|
publicKey,
|
|
);
|
|
|
|
var publicKeyEncrypted = AesHelper.aesEncrypt(
|
|
base64.decode(friendSymmetricKey),
|
|
Uint8List.fromList(CryptoUtils.encodeRSAPublicKeyToPem(publicKey).codeUnits),
|
|
);
|
|
|
|
return {
|
|
'id': id,
|
|
'user_id': userId,
|
|
'friend_id': base64.encode(friendIdEncrypted),
|
|
'friend_username': base64.encode(usernameEncrypted),
|
|
'symmetric_key': base64.encode(symmetricKeyEncrypted),
|
|
'asymmetric_public_key': publicKeyEncrypted,
|
|
'accepted_at': null,
|
|
};
|
|
}
|
|
|
|
String publicKeyPem() {
|
|
return CryptoUtils.encodeRSAPublicKeyToPem(publicKey);
|
|
}
|
|
|
|
Map<String, dynamic> toMap() {
|
|
return {
|
|
'id': id,
|
|
'user_id': userId,
|
|
'username': username,
|
|
'friend_id': friendId,
|
|
'symmetric_key': base64.encode(friendSymmetricKey.codeUnits),
|
|
'asymmetric_public_key': publicKeyPem(),
|
|
'accepted_at': acceptedAt?.toIso8601String(),
|
|
};
|
|
}
|
|
|
|
@override
|
|
String toString() {
|
|
return '''
|
|
|
|
|
|
id: $id
|
|
userId: $userId
|
|
username: $username
|
|
friendId: $friendId
|
|
accepted_at: $acceptedAt''';
|
|
}
|
|
}
|