feat: Implement getting fingerprints
This commit is contained in:
		
							parent
							
								
									d37a4bd719
								
							
						
					
					
						commit
						5bc1136ec0
					
				@ -22,9 +22,9 @@ class RatchetRemovedEvent extends OmemoEvent {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Triggered when the device map has been modified
 | 
					/// Triggered when the device map has been modified
 | 
				
			||||||
class DeviceMapModifiedEvent extends OmemoEvent {
 | 
					class DeviceListModifiedEvent extends OmemoEvent {
 | 
				
			||||||
  DeviceMapModifiedEvent(this.map);
 | 
					  DeviceListModifiedEvent(this.list);
 | 
				
			||||||
  final Map<String, List<int>> map;
 | 
					  final Map<String, List<int>> list;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Triggered by the OmemoSessionManager when our own device bundle was modified
 | 
					/// Triggered by the OmemoSessionManager when our own device bundle was modified
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,6 @@ import 'package:meta/meta.dart';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@immutable
 | 
					@immutable
 | 
				
			||||||
class DeviceFingerprint {
 | 
					class DeviceFingerprint {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  const DeviceFingerprint(this.deviceId, this.fingerprint);
 | 
					  const DeviceFingerprint(this.deviceId, this.fingerprint);
 | 
				
			||||||
  final String fingerprint;
 | 
					  final String fingerprint;
 | 
				
			||||||
  final int deviceId;
 | 
					  final int deviceId;
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ import 'dart:collection';
 | 
				
			|||||||
import 'dart:convert';
 | 
					import 'dart:convert';
 | 
				
			||||||
import 'package:collection/collection.dart';
 | 
					import 'package:collection/collection.dart';
 | 
				
			||||||
import 'package:cryptography/cryptography.dart';
 | 
					import 'package:cryptography/cryptography.dart';
 | 
				
			||||||
 | 
					import 'package:hex/hex.dart';
 | 
				
			||||||
import 'package:logging/logging.dart';
 | 
					import 'package:logging/logging.dart';
 | 
				
			||||||
import 'package:meta/meta.dart';
 | 
					import 'package:meta/meta.dart';
 | 
				
			||||||
import 'package:omemo_dart/src/crypto.dart';
 | 
					import 'package:omemo_dart/src/crypto.dart';
 | 
				
			||||||
@ -16,6 +17,7 @@ import 'package:omemo_dart/src/omemo/device.dart';
 | 
				
			|||||||
import 'package:omemo_dart/src/omemo/encrypted_key.dart';
 | 
					import 'package:omemo_dart/src/omemo/encrypted_key.dart';
 | 
				
			||||||
import 'package:omemo_dart/src/omemo/encryption_result.dart';
 | 
					import 'package:omemo_dart/src/omemo/encryption_result.dart';
 | 
				
			||||||
import 'package:omemo_dart/src/omemo/events.dart';
 | 
					import 'package:omemo_dart/src/omemo/events.dart';
 | 
				
			||||||
 | 
					import 'package:omemo_dart/src/omemo/fingerprint.dart';
 | 
				
			||||||
import 'package:omemo_dart/src/omemo/ratchet_map_key.dart';
 | 
					import 'package:omemo_dart/src/omemo/ratchet_map_key.dart';
 | 
				
			||||||
import 'package:omemo_dart/src/omemo/stanza.dart';
 | 
					import 'package:omemo_dart/src/omemo/stanza.dart';
 | 
				
			||||||
import 'package:omemo_dart/src/protobuf/omemo_authenticated_message.dart';
 | 
					import 'package:omemo_dart/src/protobuf/omemo_authenticated_message.dart';
 | 
				
			||||||
@ -48,7 +50,6 @@ class OmemoManager {
 | 
				
			|||||||
  Map<String, List<int>> _deviceList = {};
 | 
					  Map<String, List<int>> _deviceList = {};
 | 
				
			||||||
  /// Map bare JIDs to whether we already requested the device list once
 | 
					  /// Map bare JIDs to whether we already requested the device list once
 | 
				
			||||||
  final Map<String, bool> _deviceListRequested = {};
 | 
					  final Map<String, bool> _deviceListRequested = {};
 | 
				
			||||||
 | 
					 | 
				
			||||||
  /// Map bare a ratchet key to its ratchet. Note that this is also locked by
 | 
					  /// Map bare a ratchet key to its ratchet. Note that this is also locked by
 | 
				
			||||||
  /// _ratchetCriticalSectionLock.
 | 
					  /// _ratchetCriticalSectionLock.
 | 
				
			||||||
  Map<RatchetMapKey, OmemoDoubleRatchet> _ratchetMap = {};
 | 
					  Map<RatchetMapKey, OmemoDoubleRatchet> _ratchetMap = {};
 | 
				
			||||||
@ -126,14 +127,14 @@ class OmemoManager {
 | 
				
			|||||||
      _deviceList[jid] = [deviceId];
 | 
					      _deviceList[jid] = [deviceId];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Commit the device map
 | 
					      // Commit the device map
 | 
				
			||||||
      _eventStreamController.add(DeviceMapModifiedEvent(_deviceList));
 | 
					      _eventStreamController.add(DeviceListModifiedEvent(_deviceList));
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // Prevent having the same device multiple times in the list
 | 
					      // Prevent having the same device multiple times in the list
 | 
				
			||||||
      if (!_deviceList[jid]!.contains(deviceId)) {
 | 
					      if (!_deviceList[jid]!.contains(deviceId)) {
 | 
				
			||||||
        _deviceList[jid]!.add(deviceId);
 | 
					        _deviceList[jid]!.add(deviceId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Commit the device map
 | 
					        // Commit the device map
 | 
				
			||||||
        _eventStreamController.add(DeviceMapModifiedEvent(_deviceList));
 | 
					        _eventStreamController.add(DeviceListModifiedEvent(_deviceList));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -239,7 +240,7 @@ class OmemoManager {
 | 
				
			|||||||
  /// element, then [ciphertext] must be set to null. In this case, this function
 | 
					  /// element, then [ciphertext] must be set to null. In this case, this function
 | 
				
			||||||
  /// will return null as there is no message to be decrypted. This, however, is used
 | 
					  /// will return null as there is no message to be decrypted. This, however, is used
 | 
				
			||||||
  /// to set up sessions or advance the ratchets.
 | 
					  /// to set up sessions or advance the ratchets.
 | 
				
			||||||
  Future<String?> decryptMessage(List<int>? ciphertext, String senderJid, int senderDeviceId, List<EncryptedKey> keys, int timestamp) async {
 | 
					  Future<String?> _decryptMessage(List<int>? ciphertext, String senderJid, int senderDeviceId, List<EncryptedKey> keys, int timestamp) async {
 | 
				
			||||||
    // Try to find a session we can decrypt with.
 | 
					    // Try to find a session we can decrypt with.
 | 
				
			||||||
    var device = await getDevice();
 | 
					    var device = await getDevice();
 | 
				
			||||||
    final rawKey = keys.firstWhereOrNull((key) => key.rid == device.id);
 | 
					    final rawKey = keys.firstWhereOrNull((key) => key.rid == device.id);
 | 
				
			||||||
@ -263,7 +264,7 @@ class OmemoManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      // Guard against old key exchanges
 | 
					      // Guard against old key exchanges
 | 
				
			||||||
      if (oldRatchet != null) {
 | 
					      if (oldRatchet != null) {
 | 
				
			||||||
        _log.finest('KEX for existent ratchet. ${oldRatchet.pn}');
 | 
					        _log.finest('KEX for existent ratchet ${ratchetKey.toJsonKey()}. ${oldRatchet.kexTimestamp} > $timestamp: ${oldRatchet.kexTimestamp > timestamp}');
 | 
				
			||||||
        if (oldRatchet.kexTimestamp > timestamp) {
 | 
					        if (oldRatchet.kexTimestamp > timestamp) {
 | 
				
			||||||
          throw InvalidKeyExchangeException();
 | 
					          throw InvalidKeyExchangeException();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -368,6 +369,9 @@ class OmemoManager {
 | 
				
			|||||||
          return !_ratchetMap.containsKey(RatchetMapKey(jid, id)) ||
 | 
					          return !_ratchetMap.containsKey(RatchetMapKey(jid, id)) ||
 | 
				
			||||||
                 _deviceList[jid]?.contains(id) == false;
 | 
					                 _deviceList[jid]?.contains(id) == false;
 | 
				
			||||||
        }).toList();
 | 
					        }).toList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Trigger an event with the new device list
 | 
				
			||||||
 | 
					      _eventStreamController.add(DeviceListModifiedEvent(_deviceList));
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // We already have an up-to-date version of the device list
 | 
					      // We already have an up-to-date version of the device list
 | 
				
			||||||
      bundlesToFetch = _deviceList[jid]!
 | 
					      bundlesToFetch = _deviceList[jid]!
 | 
				
			||||||
@ -503,6 +507,8 @@ class OmemoManager {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Call when receiving an OMEMO:2 encrypted stanza. Will handle everything and
 | 
				
			||||||
 | 
					  /// decrypt it.
 | 
				
			||||||
  Future<DecryptionResult> onIncomingStanza(OmemoIncomingStanza stanza) async {
 | 
					  Future<DecryptionResult> onIncomingStanza(OmemoIncomingStanza stanza) async {
 | 
				
			||||||
    await _enterRatchetCriticalSection(stanza.bareSenderJid);
 | 
					    await _enterRatchetCriticalSection(stanza.bareSenderJid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -510,7 +516,7 @@ class OmemoManager {
 | 
				
			|||||||
    final ratchetCreated = !_ratchetMap.containsKey(ratchetKey);
 | 
					    final ratchetCreated = !_ratchetMap.containsKey(ratchetKey);
 | 
				
			||||||
    String? payload;
 | 
					    String? payload;
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      payload = await decryptMessage(
 | 
					      payload = await _decryptMessage(
 | 
				
			||||||
        base64.decode(stanza.payload),
 | 
					        base64.decode(stanza.payload),
 | 
				
			||||||
        stanza.bareSenderJid,
 | 
					        stanza.bareSenderJid,
 | 
				
			||||||
        stanza.senderDeviceId,
 | 
					        stanza.senderDeviceId,
 | 
				
			||||||
@ -569,6 +575,8 @@ class OmemoManager {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Call when sending out an encrypted stanza. Will handle everything and
 | 
				
			||||||
 | 
					  /// encrypt it.
 | 
				
			||||||
  Future<EncryptionResult?> onOutgoingStanza(OmemoOutgoingStanza stanza) async {
 | 
					  Future<EncryptionResult?> onOutgoingStanza(OmemoOutgoingStanza stanza) async {
 | 
				
			||||||
    return _encryptToJids(
 | 
					    return _encryptToJids(
 | 
				
			||||||
      stanza.recipientJids,
 | 
					      stanza.recipientJids,
 | 
				
			||||||
@ -589,20 +597,58 @@ class OmemoManager {
 | 
				
			|||||||
    if (enterCriticalSection) await _leaveRatchetCriticalSection(jid);
 | 
					    if (enterCriticalSection) await _leaveRatchetCriticalSection(jid);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Generates an entirely new device. May be useful when the user wants to reset their cryptographic
 | 
				
			||||||
 | 
					  /// identity. Triggers an event to commit it to storage.
 | 
				
			||||||
 | 
					  Future<void> regenerateDevice({ int opkAmount = 100 }) async {
 | 
				
			||||||
 | 
					    await _deviceLock.synchronized(() async {
 | 
				
			||||||
 | 
					      _device = await Device.generateNewDevice(_device.jid, opkAmount: opkAmount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Commit it
 | 
				
			||||||
 | 
					      _eventStreamController.add(DeviceModifiedEvent(_device));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  /// Returns the device used for encryption and decryption.
 | 
				
			||||||
  Future<Device> getDevice() => _deviceLock.synchronized(() => _device);
 | 
					  Future<Device> getDevice() => _deviceLock.synchronized(() => _device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Returns the fingerprints for all devices of [jid] that we have a session with.
 | 
				
			||||||
 | 
					  /// If there are not sessions with [jid], then returns null.
 | 
				
			||||||
 | 
					  Future<List<DeviceFingerprint>?> getFingerprintsForJid(String jid) async {
 | 
				
			||||||
 | 
					    if (!_deviceList.containsKey(jid)) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await _enterRatchetCriticalSection(jid);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    final fingerprintKeys = _deviceList[jid]!
 | 
				
			||||||
 | 
					      .map((id) => RatchetMapKey(jid, id))
 | 
				
			||||||
 | 
					      .where((key) => _ratchetMap.containsKey(key));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final fingerprints = List<DeviceFingerprint>.empty(growable: true);
 | 
				
			||||||
 | 
					    for (final key in fingerprintKeys) {
 | 
				
			||||||
 | 
					      fingerprints.add(
 | 
				
			||||||
 | 
					        DeviceFingerprint(
 | 
				
			||||||
 | 
					          key.deviceId,
 | 
				
			||||||
 | 
					          HEX.encode(await _ratchetMap[key]!.ik.getBytes()),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await _leaveRatchetCriticalSection(jid);
 | 
				
			||||||
 | 
					    return fingerprints;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  /// Ensures that the device list is fetched again on the next message sending.
 | 
					  /// Ensures that the device list is fetched again on the next message sending.
 | 
				
			||||||
  void onNewConnection() {
 | 
					  void onNewConnection() {
 | 
				
			||||||
    _deviceListRequested.clear();
 | 
					    _deviceListRequested.clear();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Sets the device list for [jid] to [devices].
 | 
					  /// Sets the device list for [jid] to [devices]. Triggers a DeviceListModifiedEvent.
 | 
				
			||||||
  void onDeviceListUpdate(String jid, List<int> devices) {
 | 
					  void onDeviceListUpdate(String jid, List<int> devices) {
 | 
				
			||||||
    _deviceList[jid] = devices;
 | 
					    _deviceList[jid] = devices;
 | 
				
			||||||
    _deviceListRequested[jid] = true;
 | 
					    _deviceListRequested[jid] = true;
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  List<int>? getDeviceListForJid(String jid) => _deviceList[jid];
 | 
					    // Trigger an event
 | 
				
			||||||
 | 
					    _eventStreamController.add(DeviceListModifiedEvent(_deviceList));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void initialize(Map<RatchetMapKey, OmemoDoubleRatchet> ratchetMap, Map<String, List<int>> deviceList) {
 | 
					  void initialize(Map<RatchetMapKey, OmemoDoubleRatchet> ratchetMap, Map<String, List<int>> deviceList) {
 | 
				
			||||||
    _deviceList = deviceList;
 | 
					    _deviceList = deviceList;
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,6 @@ import 'package:meta/meta.dart';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@immutable
 | 
					@immutable
 | 
				
			||||||
class RatchetMapKey {
 | 
					class RatchetMapKey {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  const RatchetMapKey(this.jid, this.deviceId);
 | 
					  const RatchetMapKey(this.jid, this.deviceId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  factory RatchetMapKey.fromJsonKey(String key) {
 | 
					  factory RatchetMapKey.fromJsonKey(String key) {
 | 
				
			||||||
 | 
				
			|||||||
@ -119,14 +119,14 @@ class OmemoSessionManager {
 | 
				
			|||||||
        _deviceMap[jid] = [deviceId];
 | 
					        _deviceMap[jid] = [deviceId];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Commit the device map
 | 
					        // Commit the device map
 | 
				
			||||||
        _eventStreamController.add(DeviceMapModifiedEvent(_deviceMap));
 | 
					        _eventStreamController.add(DeviceListModifiedEvent(_deviceMap));
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        // Prevent having the same device multiple times in the list
 | 
					        // Prevent having the same device multiple times in the list
 | 
				
			||||||
        if (!_deviceMap[jid]!.contains(deviceId)) {
 | 
					        if (!_deviceMap[jid]!.contains(deviceId)) {
 | 
				
			||||||
          _deviceMap[jid]!.add(deviceId);
 | 
					          _deviceMap[jid]!.add(deviceId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          // Commit the device map
 | 
					          // Commit the device map
 | 
				
			||||||
          _eventStreamController.add(DeviceMapModifiedEvent(_deviceMap));
 | 
					          _eventStreamController.add(DeviceListModifiedEvent(_deviceMap));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -562,7 +562,7 @@ class OmemoSessionManager {
 | 
				
			|||||||
        _deviceMap.remove(jid);
 | 
					        _deviceMap.remove(jid);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      // Commit it
 | 
					      // Commit it
 | 
				
			||||||
      _eventStreamController.add(DeviceMapModifiedEvent(_deviceMap));
 | 
					      _eventStreamController.add(DeviceListModifiedEvent(_deviceMap));
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -580,7 +580,7 @@ class OmemoSessionManager {
 | 
				
			|||||||
      // Remove the device from jid
 | 
					      // Remove the device from jid
 | 
				
			||||||
      _deviceMap.remove(jid);
 | 
					      _deviceMap.remove(jid);
 | 
				
			||||||
      // Commit it
 | 
					      // Commit it
 | 
				
			||||||
      _eventStreamController.add(DeviceMapModifiedEvent(_deviceMap));
 | 
					      _eventStreamController.add(DeviceListModifiedEvent(_deviceMap));
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
				
			|||||||
@ -65,7 +65,7 @@ void main() {
 | 
				
			|||||||
        deviceModified = true;
 | 
					        deviceModified = true;
 | 
				
			||||||
      } else if (event is RatchetModifiedEvent) {
 | 
					      } else if (event is RatchetModifiedEvent) {
 | 
				
			||||||
        ratchetModified++;
 | 
					        ratchetModified++;
 | 
				
			||||||
      } else if (event is DeviceMapModifiedEvent) {
 | 
					      } else if (event is DeviceListModifiedEvent) {
 | 
				
			||||||
        deviceMapModified++;
 | 
					        deviceMapModified++;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user