Compare commits
3 Commits
44ab31aebb
...
5a097e4d2a
Author | SHA1 | Date | |
---|---|---|---|
5a097e4d2a | |||
710b3c9497 | |||
f540a80ec2 |
@ -12,6 +12,14 @@ class RatchetModifiedEvent extends OmemoEvent {
|
|||||||
final OmemoDoubleRatchet ratchet;
|
final OmemoDoubleRatchet ratchet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Triggered when a ratchet has been removed and should be removed from storage.
|
||||||
|
class RatchetRemovedEvent extends OmemoEvent {
|
||||||
|
|
||||||
|
RatchetRemovedEvent(this.jid, this.deviceId);
|
||||||
|
final String jid;
|
||||||
|
final int deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
/// Triggered when the device map has been modified
|
/// Triggered when the device map has been modified
|
||||||
class DeviceMapModifiedEvent extends OmemoEvent {
|
class DeviceMapModifiedEvent extends OmemoEvent {
|
||||||
|
|
||||||
|
@ -50,6 +50,17 @@ class OmemoSessionManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserialise the OmemoSessionManager from JSON data [data] that does not contain
|
||||||
|
/// the ratchet sessions.
|
||||||
|
factory OmemoSessionManager.fromJsonWithoutSessions(Map<String, dynamic> data, Map<RatchetMapKey, OmemoDoubleRatchet> ratchetMap, TrustManager trustManager) {
|
||||||
|
return OmemoSessionManager(
|
||||||
|
Device.fromJson(data['device']! as Map<String, dynamic>),
|
||||||
|
data['devices']! as Map<String, List<int>>,
|
||||||
|
ratchetMap,
|
||||||
|
trustManager,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate a new cryptographic identity.
|
/// Generate a new cryptographic identity.
|
||||||
static Future<OmemoSessionManager> generateNewIdentity(String jid, TrustManager trustManager, { int opkAmount = 100 }) async {
|
static Future<OmemoSessionManager> generateNewIdentity(String jid, TrustManager trustManager, { int opkAmount = 100 }) async {
|
||||||
assert(opkAmount > 0, 'opkAmount must be bigger than 0.');
|
assert(opkAmount > 0, 'opkAmount must be bigger than 0.');
|
||||||
@ -83,6 +94,7 @@ class OmemoSessionManager {
|
|||||||
/// A stream that receives events regarding the session
|
/// A stream that receives events regarding the session
|
||||||
Stream<OmemoEvent> get eventStream => _eventStreamController.stream;
|
Stream<OmemoEvent> get eventStream => _eventStreamController.stream;
|
||||||
|
|
||||||
|
/// Returns our own device.
|
||||||
Future<Device> getDevice() async {
|
Future<Device> getDevice() async {
|
||||||
Device? dev;
|
Device? dev;
|
||||||
await _deviceLock.synchronized(() async {
|
await _deviceLock.synchronized(() async {
|
||||||
@ -393,12 +405,32 @@ class OmemoSessionManager {
|
|||||||
Map<String, List<int>>? map;
|
Map<String, List<int>>? map;
|
||||||
|
|
||||||
await _lock.synchronized(() async {
|
await _lock.synchronized(() async {
|
||||||
map = _deviceMap;
|
map = _deviceMap;
|
||||||
});
|
});
|
||||||
|
|
||||||
return map!;
|
return map!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes the ratchet identified by [jid] and [deviceId] from the session manager.
|
||||||
|
/// Also triggers events for commiting the new device map to storage and removing
|
||||||
|
/// the old ratchet.
|
||||||
|
Future<void> removeRatchet(String jid, int deviceId) async {
|
||||||
|
await _lock.synchronized(() async {
|
||||||
|
// Remove the ratchet
|
||||||
|
_ratchetMap.remove(RatchetMapKey(jid, deviceId));
|
||||||
|
// Commit it
|
||||||
|
_eventStreamController.add(RatchetRemovedEvent(jid, deviceId));
|
||||||
|
|
||||||
|
// Remove the device from jid
|
||||||
|
_deviceMap[jid]!.remove(deviceId);
|
||||||
|
if (_deviceMap[jid]!.isEmpty) {
|
||||||
|
_deviceMap.remove(jid);
|
||||||
|
}
|
||||||
|
// Commit it
|
||||||
|
_eventStreamController.add(DeviceMapModifiedEvent(_deviceMap));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
OmemoDoubleRatchet getRatchet(String jid, int deviceId) => _ratchetMap[RatchetMapKey(jid, deviceId)]!;
|
OmemoDoubleRatchet getRatchet(String jid, int deviceId) => _ratchetMap[RatchetMapKey(jid, deviceId)]!;
|
||||||
|
|
||||||
@ -423,7 +455,6 @@ class OmemoSessionManager {
|
|||||||
},
|
},
|
||||||
...
|
...
|
||||||
],
|
],
|
||||||
'trust': { ... }
|
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -439,8 +470,25 @@ class OmemoSessionManager {
|
|||||||
'devices': _deviceMap,
|
'devices': _deviceMap,
|
||||||
'device': await (await getDevice()).toJson(),
|
'device': await (await getDevice()).toJson(),
|
||||||
'sessions': sessions,
|
'sessions': sessions,
|
||||||
// TODO(PapaTutuWawa): Implement
|
};
|
||||||
'trust': <String, dynamic>{},
|
}
|
||||||
|
|
||||||
|
/// Serialise the entire session manager into a JSON object.
|
||||||
|
Future<Map<String, dynamic>> toJsonWithoutSessions() async {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
'devices': {
|
||||||
|
'alice@...': [1, 2, ...],
|
||||||
|
'bob@...': [1],
|
||||||
|
...
|
||||||
|
},
|
||||||
|
'device': { ... },
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return {
|
||||||
|
'devices': _deviceMap,
|
||||||
|
'device': await (await getDevice()).toJson(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -422,4 +422,81 @@ void main() {
|
|||||||
expect(messageText, aliceReceivedMessage);
|
expect(messageText, aliceReceivedMessage);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('Test removing a ratchet', () {
|
||||||
|
test('Test removing a ratchet when the user has multiple', () async {
|
||||||
|
const aliceJid = 'alice@server.local';
|
||||||
|
const bobJid = 'bob@some.server.local';
|
||||||
|
final aliceSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
aliceJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
final bobSession1 = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
bobJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
final bobSession2 = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
bobJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Alice sends a message to those two Bobs
|
||||||
|
final aliceMessage = await aliceSession.encryptToJid(
|
||||||
|
bobJid,
|
||||||
|
'Hallo Welt',
|
||||||
|
newSessions: [
|
||||||
|
await (await bobSession1.getDevice()).toBundle(),
|
||||||
|
await (await bobSession2.getDevice()).toBundle(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// One of those two sessions is broken, so Alice removes the session2 ratchet
|
||||||
|
final id1 = (await bobSession1.getDevice()).id;
|
||||||
|
final id2 = (await bobSession2.getDevice()).id;
|
||||||
|
await aliceSession.removeRatchet(bobJid, id1);
|
||||||
|
|
||||||
|
final map = await aliceSession.getRatchetMap();
|
||||||
|
expect(map.containsKey(RatchetMapKey(bobJid, id1)), false);
|
||||||
|
expect(map.containsKey(RatchetMapKey(bobJid, id2)), true);
|
||||||
|
final deviceMap = await aliceSession.getDeviceMap();
|
||||||
|
expect(deviceMap.containsKey(bobJid), true);
|
||||||
|
expect(deviceMap[bobJid], [id2]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Test removing a ratchet when the user has only one', () async {
|
||||||
|
const aliceJid = 'alice@server.local';
|
||||||
|
const bobJid = 'bob@some.server.local';
|
||||||
|
final aliceSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
aliceJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
final bobSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
bobJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Alice sends a message to those two Bobs
|
||||||
|
final aliceMessage = await aliceSession.encryptToJid(
|
||||||
|
bobJid,
|
||||||
|
'Hallo Welt',
|
||||||
|
newSessions: [
|
||||||
|
await (await bobSession.getDevice()).toBundle(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// One of those two sessions is broken, so Alice removes the session2 ratchet
|
||||||
|
final id = (await bobSession.getDevice()).id;
|
||||||
|
await aliceSession.removeRatchet(bobJid, id);
|
||||||
|
|
||||||
|
final map = await aliceSession.getRatchetMap();
|
||||||
|
expect(map.containsKey(RatchetMapKey(bobJid, id)), false);
|
||||||
|
final deviceMap = await aliceSession.getDeviceMap();
|
||||||
|
expect(deviceMap.containsKey(bobJid), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user