|
|
- import 'dart:convert';
- import 'dart:io';
-
- import 'package:flutter/material.dart';
- import 'package:pointycastle/impl.dart';
- import 'package:qr_code_scanner/qr_code_scanner.dart';
- import 'package:sqflite/sqflite.dart';
- import 'package:uuid/uuid.dart';
- import 'package:http/http.dart' as http;
-
- import '/components/custom_title_bar.dart';
- import '/database/models/friends.dart';
- import '/database/models/my_profile.dart';
- import '/utils/encryption/aes_helper.dart';
- import '/utils/encryption/crypto_utils.dart';
- import '/utils/storage/database.dart';
- import '/utils/strings.dart';
- import '/utils/storage/session_cookie.dart';
- import 'flash_message.dart';
-
- class QrReader extends StatefulWidget {
- const QrReader({
- Key? key,
- }) : super(key: key);
-
- @override
- State<QrReader> createState() => _QrReaderState();
- }
-
- class _QrReaderState extends State<QrReader> {
- final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
- Barcode? result;
- QRViewController? controller;
-
- // In order to get hot reload to work we need to pause the camera if the platform
- // is android, or resume the camera if the platform is iOS.
- @override
- void reassemble() {
- super.reassemble();
- if (Platform.isAndroid) {
- controller!.pauseCamera();
- } else if (Platform.isIOS) {
- controller!.resumeCamera();
- }
- }
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: CustomTitleBar(
- title: Text(
- 'Add Friend',
- style: TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w600,
- color: Theme.of(context).appBarTheme.toolbarTextStyle?.color
- )
- ),
- showBack: true,
- backgroundColor: Colors.transparent,
- ),
- body: Column(
- children: <Widget>[
- Expanded(
- flex: 5,
- child: QRView(
- key: qrKey,
- onQRViewCreated: _onQRViewCreated,
- formatsAllowed: const [BarcodeFormat.qrcode],
- overlay: QrScannerOverlayShape(),
- ),
- ),
- ],
- ),
- );
- }
-
- void _onQRViewCreated(QRViewController controller) {
- this.controller = controller;
- controller.scannedDataStream.listen((scanData) {
- addFriend(scanData)
- .then((dynamic ret) {
- if (ret) {
- // Delay exit to prevent exit mid way through rendering
- Future.delayed(Duration.zero, () {
- Navigator.of(context).pop();
- });
- }
- });
- });
- }
-
- @override
- void dispose() {
- controller?.dispose();
- super.dispose();
- }
-
- Future<bool> addFriend(Barcode scanData) async {
- Map<String, dynamic> friendJson = jsonDecode(scanData.code!);
-
- RSAPublicKey publicKey = CryptoUtils.rsaPublicKeyFromPem(
- String.fromCharCodes(
- base64.decode(
- friendJson['k']
- )
- )
- );
-
- MyProfile profile = await MyProfile.getProfile();
-
- var uuid = const Uuid();
-
- final symmetricKey1 = AesHelper.deriveKey(generateRandomString(32));
- final symmetricKey2 = AesHelper.deriveKey(generateRandomString(32));
-
- Friend request1 = Friend(
- id: uuid.v4(),
- userId: friendJson['i'],
- username: profile.username,
- friendId: profile.id,
- friendSymmetricKey: base64.encode(symmetricKey1),
- publicKey: profile.publicKey!,
- acceptedAt: DateTime.now(),
- );
-
- Friend request2 = Friend(
- id: uuid.v4(),
- userId: profile.id,
- friendId: friendJson['i'],
- username: friendJson['u'],
- friendSymmetricKey: base64.encode(symmetricKey2),
- publicKey: publicKey,
- acceptedAt: DateTime.now(),
- );
-
- String payload = jsonEncode([
- request1.payloadJson(),
- request2.payloadJson(),
- ]);
-
- var resp = await http.post(
- await MyProfile.getServerUrl('api/v1/auth/friend_request/qr_code'),
- headers: <String, String>{
- 'Content-Type': 'application/json; charset=UTF-8',
- 'cookie': await getSessionCookie(),
- },
- body: payload,
- );
-
- if (resp.statusCode != 200) {
- showMessage(
- 'Failed to add friend, please try again later',
- context
- );
- return false;
- }
-
- final db = await getDatabaseConnection();
-
- await db.insert(
- 'friends',
- request1.toMap(),
- conflictAlgorithm: ConflictAlgorithm.replace,
- );
-
- await db.insert(
- 'friends',
- request2.toMap(),
- conflictAlgorithm: ConflictAlgorithm.replace,
- );
-
- return true;
- }
- }
|