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.

151 lines
4.4 KiB

import 'dart:io' show Platform;
import 'dart:convert';
import 'dart:typed_data';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:pointycastle/impl.dart';
import '/components/custom_circle_avatar.dart';
import '/data_models/user_search.dart';
import '/database/models/my_profile.dart';
import '/utils/encryption/aes_helper.dart';
import '/utils/storage/session_cookie.dart';
import '/utils/strings.dart';
import '/utils/encryption/crypto_utils.dart';
@immutable
class UserSearchResult extends StatefulWidget {
final UserSearch user;
const UserSearchResult({
Key? key,
required this.user,
}) : super(key: key);
@override
_UserSearchResultState createState() => _UserSearchResultState();
}
class _UserSearchResultState extends State<UserSearchResult>{
bool showFailed = false;
@override
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.only(top: 30),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CustomCircleAvatar(
initials: widget.user.username[0].toUpperCase(),
icon: const Icon(Icons.person, size: 80),
radius: 50,
),
const SizedBox(height: 10),
Text(
widget.user.username,
style: const TextStyle(
fontSize: 35,
),
),
const SizedBox(height: 30),
TextButton(
onPressed: sendFriendRequest,
child: Text(
'Send Friend Request',
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimary,
fontSize: 20,
),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Theme.of(context).colorScheme.primary),
padding: MaterialStateProperty.all<EdgeInsets>(
const EdgeInsets.only(left: 20, right: 20, top: 8, bottom: 8)),
),
),
showFailed ? const SizedBox(height: 20) : const SizedBox.shrink(),
failedMessage(context),
],
),
),
);
}
Widget failedMessage(BuildContext context) {
if (!showFailed) {
return const SizedBox.shrink();
}
return Text(
'Failed to send friend request',
style: TextStyle(
color: Theme.of(context).colorScheme.error,
fontSize: 16,
),
);
}
Future<void> sendFriendRequest() async {
MyProfile profile = await MyProfile.getProfile();
String publicKeyString = CryptoUtils.encodeRSAPublicKeyToPem(profile.publicKey!);
RSAPublicKey friendPublicKey = CryptoUtils.rsaPublicKeyFromPem(widget.user.publicKey);
final symmetricKey = AesHelper.deriveKey(generateRandomString(32));
String? token = await FirebaseMessaging.instance.getToken();
String payloadJson = jsonEncode({
'user_id': widget.user.id,
'friend_id': base64.encode(CryptoUtils.rsaEncrypt(
Uint8List.fromList(profile.id.codeUnits),
friendPublicKey,
)),
'friend_username': base64.encode(CryptoUtils.rsaEncrypt(
Uint8List.fromList(profile.username.codeUnits),
friendPublicKey,
)),
'symmetric_key': base64.encode(CryptoUtils.rsaEncrypt(
Uint8List.fromList(symmetricKey),
friendPublicKey,
)),
'asymmetric_public_key': AesHelper.aesEncrypt(
symmetricKey,
Uint8List.fromList(publicKeyString.codeUnits),
),
'tokens': token == null ? {} : [{
'device_token': {
'device_type': base64.encode(CryptoUtils.rsaEncrypt(
Uint8List.fromList((Platform.isAndroid ? 'android' : 'ios').codeUnits),
friendPublicKey,
)),
'token': base64.encode(CryptoUtils.rsaEncrypt(
Uint8List.fromList(token.codeUnits),
friendPublicKey,
)),
}
}],
});
var resp = await http.post(
await MyProfile.getServerUrl('api/v1/auth/friend_request'),
headers: {
'cookie': await getSessionCookie(),
},
body: payloadJson,
);
if (resp.statusCode != 200) {
showFailed = true;
setState(() {});
return;
}
Navigator.pop(context);
}
}