Compare commits
	
		
			2 Commits
		
	
	
		
			5a097e4d2a
			...
			fda06cef55
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fda06cef55 | |||
| 800b53b11f | 
							
								
								
									
										2
									
								
								.gitlint
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								.gitlint
									
									
									
									
									
								
							@ -5,6 +5,6 @@ line-length=72
 | 
				
			|||||||
[title-trailing-punctuation]
 | 
					[title-trailing-punctuation]
 | 
				
			||||||
[title-hard-tab]
 | 
					[title-hard-tab]
 | 
				
			||||||
[title-match-regex]
 | 
					[title-match-regex]
 | 
				
			||||||
regex=^(feat|fix|test|release|chore|security|docs|refactor):.*$
 | 
					regex=^(feat|fix|test|release|chore|security|docs|refactor|style):.*$
 | 
				
			||||||
[body-trailing-whitespace]
 | 
					[body-trailing-whitespace]
 | 
				
			||||||
[body-first-line-empty]
 | 
					[body-first-line-empty]
 | 
				
			||||||
 | 
				
			|||||||
@ -67,6 +67,7 @@ class OmemoDoubleRatchet {
 | 
				
			|||||||
    this.ik,
 | 
					    this.ik,
 | 
				
			||||||
    this.sessionAd,
 | 
					    this.sessionAd,
 | 
				
			||||||
    this.mkSkipped, // MKSKIPPED
 | 
					    this.mkSkipped, // MKSKIPPED
 | 
				
			||||||
 | 
					    this.acknowledged,
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  factory OmemoDoubleRatchet.fromJson(Map<String, dynamic> data) {
 | 
					  factory OmemoDoubleRatchet.fromJson(Map<String, dynamic> data) {
 | 
				
			||||||
@ -83,6 +84,7 @@ class OmemoDoubleRatchet {
 | 
				
			|||||||
      'pn': 0,
 | 
					      'pn': 0,
 | 
				
			||||||
      'ik_pub': 'base/64/encoded',
 | 
					      'ik_pub': 'base/64/encoded',
 | 
				
			||||||
      'session_ad': 'base/64/encoded',
 | 
					      'session_ad': 'base/64/encoded',
 | 
				
			||||||
 | 
					      'acknowledged': true | false,
 | 
				
			||||||
      'mkskipped': [
 | 
					      'mkskipped': [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          'key': 'base/64/encoded',
 | 
					          'key': 'base/64/encoded',
 | 
				
			||||||
@ -117,6 +119,7 @@ class OmemoDoubleRatchet {
 | 
				
			|||||||
      ),
 | 
					      ),
 | 
				
			||||||
      base64.decode(data['session_ad']! as String),
 | 
					      base64.decode(data['session_ad']! as String),
 | 
				
			||||||
      mkSkipped,
 | 
					      mkSkipped,
 | 
				
			||||||
 | 
					      data['acknowledged']! as bool,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
@ -148,6 +151,10 @@ class OmemoDoubleRatchet {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  final Map<SkippedKey, List<int>> mkSkipped;
 | 
					  final Map<SkippedKey, List<int>> mkSkipped;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Indicates whether we received an empty OMEMO message after building a session with
 | 
				
			||||||
 | 
					  /// the device.
 | 
				
			||||||
 | 
					  bool acknowledged;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Create an OMEMO session using the Signed Pre Key [spk], the shared secret [sk] that
 | 
					  /// Create an OMEMO session using the Signed Pre Key [spk], the shared secret [sk] that
 | 
				
			||||||
  /// was obtained using a X3DH and the associated data [ad] that was also obtained through
 | 
					  /// was obtained using a X3DH and the associated data [ad] that was also obtained through
 | 
				
			||||||
  /// a X3DH. [ik] refers to Bob's (the receiver's) IK public key.
 | 
					  /// a X3DH. [ik] refers to Bob's (the receiver's) IK public key.
 | 
				
			||||||
@ -169,6 +176,7 @@ class OmemoDoubleRatchet {
 | 
				
			|||||||
      ik,
 | 
					      ik,
 | 
				
			||||||
      ad,
 | 
					      ad,
 | 
				
			||||||
      {},
 | 
					      {},
 | 
				
			||||||
 | 
					      false,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -189,6 +197,7 @@ class OmemoDoubleRatchet {
 | 
				
			|||||||
      ik,
 | 
					      ik,
 | 
				
			||||||
      ad,
 | 
					      ad,
 | 
				
			||||||
      {},
 | 
					      {},
 | 
				
			||||||
 | 
					      true,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -214,6 +223,7 @@ class OmemoDoubleRatchet {
 | 
				
			|||||||
      'ik_pub': base64.encode(await ik.getBytes()),
 | 
					      'ik_pub': base64.encode(await ik.getBytes()),
 | 
				
			||||||
      'session_ad': base64.encode(sessionAd),
 | 
					      'session_ad': base64.encode(sessionAd),
 | 
				
			||||||
      'mkskipped': mkSkippedSerialised,
 | 
					      'mkskipped': mkSkippedSerialised,
 | 
				
			||||||
 | 
					      'acknowledged': acknowledged,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
				
			|||||||
@ -430,6 +430,33 @@ class OmemoSessionManager {
 | 
				
			|||||||
      _eventStreamController.add(DeviceMapModifiedEvent(_deviceMap));
 | 
					      _eventStreamController.add(DeviceMapModifiedEvent(_deviceMap));
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Returns the list of device identifiers belonging to [jid] that are yet unacked, i.e.
 | 
				
			||||||
 | 
					  /// we have not yet received an empty OMEMO message from.
 | 
				
			||||||
 | 
					  Future<List<int>> getUnacknowledgedRatchets(String jid) async {
 | 
				
			||||||
 | 
					    final ret = List<int>.empty(growable: true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await _lock.synchronized(() async {
 | 
				
			||||||
 | 
					      final devices = _deviceMap[jid]!;
 | 
				
			||||||
 | 
					      for (final device in devices) {
 | 
				
			||||||
 | 
					        final ratchet = _ratchetMap[RatchetMapKey(jid, device)]!;
 | 
				
			||||||
 | 
					        if (!ratchet.acknowledged) ret.add(device);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Mark the ratchet for device [deviceId] from [jid] as acked.
 | 
				
			||||||
 | 
					  Future<void> ratchetAcknowledged(String jid, int deviceId) async {
 | 
				
			||||||
 | 
					    await _lock.synchronized(() async {
 | 
				
			||||||
 | 
					      final ratchet = _ratchetMap[RatchetMapKey(jid, deviceId)]!
 | 
				
			||||||
 | 
					        ..acknowledged = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Commit it
 | 
				
			||||||
 | 
					      _eventStreamController.add(RatchetModifiedEvent(jid, deviceId, ratchet));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  @visibleForTesting
 | 
					  @visibleForTesting
 | 
				
			||||||
  OmemoDoubleRatchet getRatchet(String jid, int deviceId) => _ratchetMap[RatchetMapKey(jid, deviceId)]!;
 | 
					  OmemoDoubleRatchet getRatchet(String jid, int deviceId) => _ratchetMap[RatchetMapKey(jid, deviceId)]!;
 | 
				
			||||||
 | 
				
			|||||||
@ -444,7 +444,7 @@ void main() {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Alice sends a message to those two Bobs
 | 
					      // Alice sends a message to those two Bobs
 | 
				
			||||||
      final aliceMessage = await aliceSession.encryptToJid(
 | 
					      await aliceSession.encryptToJid(
 | 
				
			||||||
        bobJid,
 | 
					        bobJid,
 | 
				
			||||||
        'Hallo Welt',
 | 
					        'Hallo Welt',
 | 
				
			||||||
        newSessions: [
 | 
					        newSessions: [
 | 
				
			||||||
@ -458,7 +458,7 @@ void main() {
 | 
				
			|||||||
      final id2 = (await bobSession2.getDevice()).id;
 | 
					      final id2 = (await bobSession2.getDevice()).id;
 | 
				
			||||||
      await aliceSession.removeRatchet(bobJid, id1);
 | 
					      await aliceSession.removeRatchet(bobJid, id1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      final map = await aliceSession.getRatchetMap();
 | 
					      final map = aliceSession.getRatchetMap();
 | 
				
			||||||
      expect(map.containsKey(RatchetMapKey(bobJid, id1)), false);
 | 
					      expect(map.containsKey(RatchetMapKey(bobJid, id1)), false);
 | 
				
			||||||
      expect(map.containsKey(RatchetMapKey(bobJid, id2)), true);
 | 
					      expect(map.containsKey(RatchetMapKey(bobJid, id2)), true);
 | 
				
			||||||
      final deviceMap = await aliceSession.getDeviceMap();
 | 
					      final deviceMap = await aliceSession.getDeviceMap();
 | 
				
			||||||
@ -481,7 +481,7 @@ void main() {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Alice sends a message to those two Bobs
 | 
					      // Alice sends a message to those two Bobs
 | 
				
			||||||
      final aliceMessage = await aliceSession.encryptToJid(
 | 
					      await aliceSession.encryptToJid(
 | 
				
			||||||
        bobJid,
 | 
					        bobJid,
 | 
				
			||||||
        'Hallo Welt',
 | 
					        'Hallo Welt',
 | 
				
			||||||
        newSessions: [
 | 
					        newSessions: [
 | 
				
			||||||
@ -493,10 +493,54 @@ void main() {
 | 
				
			|||||||
      final id = (await bobSession.getDevice()).id;
 | 
					      final id = (await bobSession.getDevice()).id;
 | 
				
			||||||
      await aliceSession.removeRatchet(bobJid, id);
 | 
					      await aliceSession.removeRatchet(bobJid, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      final map = await aliceSession.getRatchetMap();
 | 
					      final map = aliceSession.getRatchetMap();
 | 
				
			||||||
      expect(map.containsKey(RatchetMapKey(bobJid, id)), false);
 | 
					      expect(map.containsKey(RatchetMapKey(bobJid, id)), false);
 | 
				
			||||||
      final deviceMap = await aliceSession.getDeviceMap();
 | 
					      final deviceMap = await aliceSession.getDeviceMap();
 | 
				
			||||||
      expect(deviceMap.containsKey(bobJid), false);
 | 
					      expect(deviceMap.containsKey(bobJid), false);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('Test acknowledging a ratchet', () async {
 | 
				
			||||||
 | 
					    const aliceJid = 'alice@server.example';
 | 
				
			||||||
 | 
					    const bobJid = 'bob@other.server.example';
 | 
				
			||||||
 | 
					    // Alice and Bob generate their sessions
 | 
				
			||||||
 | 
					    final aliceSession = await OmemoSessionManager.generateNewIdentity(
 | 
				
			||||||
 | 
					      aliceJid,
 | 
				
			||||||
 | 
					      AlwaysTrustingTrustManager(),
 | 
				
			||||||
 | 
					      opkAmount: 1,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    final bobSession = await OmemoSessionManager.generateNewIdentity(
 | 
				
			||||||
 | 
					      bobJid,
 | 
				
			||||||
 | 
					      AlwaysTrustingTrustManager(),
 | 
				
			||||||
 | 
					      opkAmount: 1,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Alice sends Bob a message
 | 
				
			||||||
 | 
					    await aliceSession.encryptToJid(
 | 
				
			||||||
 | 
					      bobJid,
 | 
				
			||||||
 | 
					      'Hallo Welt',
 | 
				
			||||||
 | 
					      newSessions: [
 | 
				
			||||||
 | 
					        await (await bobSession.getDevice()).toBundle(),
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(
 | 
				
			||||||
 | 
					      await aliceSession.getUnacknowledgedRatchets(bobJid),
 | 
				
			||||||
 | 
					      [
 | 
				
			||||||
 | 
					        (await bobSession.getDevice()).id,
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Bob sends alice an empty message
 | 
				
			||||||
 | 
					    // ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Alice decrypts it
 | 
				
			||||||
 | 
					    // ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Alice marks the ratchet as acknowledged
 | 
				
			||||||
 | 
					    await aliceSession.ratchetAcknowledged(bobJid, (await bobSession.getDevice()).id);
 | 
				
			||||||
 | 
					    expect(
 | 
				
			||||||
 | 
					      (await aliceSession.getUnacknowledgedRatchets(bobJid)).isEmpty,
 | 
				
			||||||
 | 
					      true,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user