LCOV - code coverage report
Current view: top level - lib/encryption - key_verification_manager.dart (source / functions) Coverage Total Hit
Test: merged.info Lines: 97.0 % 67 65
Test Date: 2025-01-14 13:39:53 Functions: - 0 0

            Line data    Source code
       1              : /*
       2              :  *   Famedly Matrix SDK
       3              :  *   Copyright (C) 2020, 2021 Famedly GmbH
       4              :  *
       5              :  *   This program is free software: you can redistribute it and/or modify
       6              :  *   it under the terms of the GNU Affero General Public License as
       7              :  *   published by the Free Software Foundation, either version 3 of the
       8              :  *   License, or (at your option) any later version.
       9              :  *
      10              :  *   This program is distributed in the hope that it will be useful,
      11              :  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      13              :  *   GNU Affero General Public License for more details.
      14              :  *
      15              :  *   You should have received a copy of the GNU Affero General Public License
      16              :  *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
      17              :  */
      18              : 
      19              : import 'package:matrix/encryption/encryption.dart';
      20              : import 'package:matrix/encryption/utils/key_verification.dart';
      21              : import 'package:matrix/matrix.dart';
      22              : 
      23              : class KeyVerificationManager {
      24              :   final Encryption encryption;
      25            9 :   Client get client => encryption.client;
      26              : 
      27           24 :   KeyVerificationManager(this.encryption);
      28              : 
      29              :   final Map<String, KeyVerification> _requests = {};
      30              : 
      31           24 :   Future<void> cleanup() async {
      32              :     final Set entriesToDispose = <String>{};
      33           50 :     for (final entry in _requests.entries) {
      34            4 :       var dispose = entry.value.canceled ||
      35            6 :           entry.value.state == KeyVerificationState.done ||
      36            6 :           entry.value.state == KeyVerificationState.error;
      37              :       if (!dispose) {
      38            4 :         dispose = !(await entry.value.verifyActivity());
      39              :       }
      40              :       if (dispose) {
      41            4 :         entry.value.dispose();
      42            4 :         entriesToDispose.add(entry.key);
      43              :       }
      44              :     }
      45           72 :     entriesToDispose.forEach(_requests.remove);
      46              :   }
      47              : 
      48            3 :   void addRequest(KeyVerification request) {
      49            3 :     if (request.transactionId == null) {
      50              :       return;
      51              :     }
      52            9 :     _requests[request.transactionId!] = request;
      53              :   }
      54              : 
      55            6 :   KeyVerification? getRequest(String requestId) => _requests[requestId];
      56              : 
      57            1 :   Future<void> handleToDeviceEvent(ToDeviceEvent event) async {
      58            2 :     if (!event.type.startsWith('m.key.verification.') ||
      59            3 :         client.verificationMethods.isEmpty) {
      60              :       return;
      61              :     }
      62              :     // we have key verification going on!
      63            2 :     final transactionId = KeyVerification.getTransactionId(event.content);
      64              :     if (transactionId == null) {
      65              :       return; // TODO: send cancel with unknown transaction id
      66              :     }
      67            2 :     final request = _requests[transactionId];
      68              :     if (request != null) {
      69              :       // make sure that new requests can't come from ourself
      70            3 :       if (!{EventTypes.KeyVerificationRequest}.contains(event.type)) {
      71            3 :         await request.handlePayload(event.type, event.content);
      72              :       }
      73              :     } else {
      74            2 :       if (!{EventTypes.KeyVerificationRequest, EventTypes.KeyVerificationStart}
      75            2 :           .contains(event.type)) {
      76              :         return; // we can only start on these
      77              :       }
      78              :       final newKeyRequest =
      79            3 :           KeyVerification(encryption: encryption, userId: event.sender);
      80            3 :       await newKeyRequest.handlePayload(event.type, event.content);
      81            2 :       if (newKeyRequest.state != KeyVerificationState.askAccept) {
      82              :         // okay, something went wrong (unknown transaction id?), just dispose it
      83            0 :         newKeyRequest.dispose();
      84              :       } else {
      85            2 :         _requests[transactionId] = newKeyRequest;
      86            3 :         client.onKeyVerificationRequest.add(newKeyRequest);
      87              :       }
      88              :     }
      89              :   }
      90              : 
      91            2 :   Future<void> handleEventUpdate(Event update) async {
      92            4 :     final type = update.type.startsWith('m.key.verification.')
      93            1 :         ? update.type
      94            4 :         : update.content.tryGet<String>('msgtype');
      95              :     if (type == null ||
      96            2 :         !type.startsWith('m.key.verification.') ||
      97            6 :         client.verificationMethods.isEmpty) {
      98              :       return;
      99              :     }
     100            1 :     if (type == EventTypes.KeyVerificationRequest) {
     101            2 :       update.content['timestamp'] =
     102            2 :           update.originServerTs.millisecondsSinceEpoch;
     103              :     }
     104              : 
     105              :     final transactionId =
     106            3 :         KeyVerification.getTransactionId(update.content) ?? update.eventId;
     107              : 
     108            2 :     final req = _requests[transactionId];
     109              :     if (req != null) {
     110            2 :       final otherDeviceId = update.content.tryGet<String>('from_device');
     111            4 :       if (update.senderId != client.userID) {
     112            3 :         await req.handlePayload(type, update.content, update.eventId);
     113            4 :       } else if (update.senderId == client.userID &&
     114              :           otherDeviceId != null &&
     115            3 :           otherDeviceId != client.deviceID) {
     116              :         // okay, another of our devices answered
     117            1 :         req.otherDeviceAccepted();
     118            1 :         req.dispose();
     119            2 :         _requests.remove(transactionId);
     120              :       }
     121            4 :     } else if (update.senderId != client.userID) {
     122            2 :       if (!{EventTypes.KeyVerificationRequest, EventTypes.KeyVerificationStart}
     123            1 :           .contains(type)) {
     124              :         return; // we can only start on these
     125              :       }
     126            3 :       final room = client.getRoomById(update.roomId!) ??
     127            3 :           Room(id: update.roomId!, client: client);
     128            1 :       final newKeyRequest = KeyVerification(
     129            1 :         encryption: encryption,
     130            1 :         userId: update.senderId,
     131              :         room: room,
     132              :       );
     133            1 :       await newKeyRequest.handlePayload(
     134              :         type,
     135            1 :         update.content,
     136            1 :         update.eventId,
     137              :       );
     138            2 :       if (newKeyRequest.state != KeyVerificationState.askAccept) {
     139              :         // something went wrong, let's just dispose the request
     140            0 :         newKeyRequest.dispose();
     141              :       } else {
     142              :         // new request! Let's notify it and stuff
     143            2 :         _requests[transactionId] = newKeyRequest;
     144            3 :         client.onKeyVerificationRequest.add(newKeyRequest);
     145              :       }
     146              :     }
     147              :   }
     148              : 
     149           21 :   void dispose() {
     150           45 :     for (final req in _requests.values) {
     151            3 :       req.dispose();
     152              :     }
     153              :   }
     154              : }
        

Generated by: LCOV version 2.0-1