[Room] Fix clean up

This commit is contained in:
Christian Pauly 2020-02-18 09:23:55 +00:00
parent 2f3afb28ee
commit cf31237457
3 changed files with 115 additions and 61 deletions

View file

@ -706,7 +706,7 @@ class Client {
final String olmSessionPickleString = final String olmSessionPickleString =
await storeAPI.getItem("/clients/$userID/olm-sessions"); await storeAPI.getItem("/clients/$userID/olm-sessions");
if (olmSessionPickleString != null) { if (olmSessionPickleString != null) {
final Map<String, List<String>> pickleMap = final Map<String, dynamic> pickleMap =
json.decode(olmSessionPickleString); json.decode(olmSessionPickleString);
for (var entry in pickleMap.entries) { for (var entry in pickleMap.entries) {
for (String pickle in entry.value) { for (String pickle in entry.value) {
@ -1362,56 +1362,61 @@ class Client {
} }
Future<void> _updateUserDeviceKeys() async { Future<void> _updateUserDeviceKeys() async {
Set<String> trackedUserIds = await _getUserIdsInEncryptedRooms(); try {
trackedUserIds.add(this.userID); if (!this.isLogged()) return;
Set<String> trackedUserIds = await _getUserIdsInEncryptedRooms();
trackedUserIds.add(this.userID);
// Remove all userIds we no longer need to track the devices of. // Remove all userIds we no longer need to track the devices of.
_userDeviceKeys _userDeviceKeys
.removeWhere((String userId, v) => !trackedUserIds.contains(userId)); .removeWhere((String userId, v) => !trackedUserIds.contains(userId));
// Check if there are outdated device key lists. Add it to the set. // Check if there are outdated device key lists. Add it to the set.
Map<String, dynamic> outdatedLists = {}; Map<String, dynamic> outdatedLists = {};
for (String userId in trackedUserIds) { for (String userId in trackedUserIds) {
if (!userDeviceKeys.containsKey(userId)) { if (!userDeviceKeys.containsKey(userId)) {
_userDeviceKeys[userId] = DeviceKeysList(userId); _userDeviceKeys[userId] = DeviceKeysList(userId);
} }
DeviceKeysList deviceKeysList = userDeviceKeys[userId]; DeviceKeysList deviceKeysList = userDeviceKeys[userId];
if (deviceKeysList.outdated) { if (deviceKeysList.outdated) {
outdatedLists[userId] = []; outdatedLists[userId] = [];
}
}
// Request the missing device key lists.
if (outdatedLists.isNotEmpty) {
final Map<String, dynamic> response = await this.jsonRequest(
type: HTTPType.POST,
action: "/client/r0/keys/query",
data: {"timeout": 10000, "device_keys": outdatedLists});
final Map<String, DeviceKeysList> oldUserDeviceKeys =
Map<String, DeviceKeysList>.from(_userDeviceKeys);
for (final rawDeviceKeyListEntry in response["device_keys"].entries) {
final String userId = rawDeviceKeyListEntry.key;
_userDeviceKeys[userId].deviceKeys = {};
for (final rawDeviceKeyEntry in rawDeviceKeyListEntry.value.entries) {
final String deviceId = rawDeviceKeyEntry.key;
_userDeviceKeys[userId].deviceKeys[deviceId] =
DeviceKeys.fromJson(rawDeviceKeyEntry.value);
if (oldUserDeviceKeys.containsKey(userId) &&
_userDeviceKeys[userId].deviceKeys.containsKey(deviceId)) {
_userDeviceKeys[userId].deviceKeys[deviceId].verified =
_userDeviceKeys[userId].deviceKeys[deviceId].verified;
_userDeviceKeys[userId].deviceKeys[deviceId].blocked =
_userDeviceKeys[userId].deviceKeys[deviceId].blocked;
} else if (deviceId == this.deviceID &&
_userDeviceKeys[userId].deviceKeys[deviceId].ed25519Key ==
this.fingerprintKey) {
_userDeviceKeys[userId].deviceKeys[deviceId].verified = true;
}
} }
_userDeviceKeys[userId].outdated = false;
} }
// Request the missing device key lists.
if (outdatedLists.isNotEmpty) {
final Map<String, dynamic> response = await this.jsonRequest(
type: HTTPType.POST,
action: "/client/r0/keys/query",
data: {"timeout": 10000, "device_keys": outdatedLists});
final Map<String, DeviceKeysList> oldUserDeviceKeys =
Map<String, DeviceKeysList>.from(_userDeviceKeys);
for (final rawDeviceKeyListEntry in response["device_keys"].entries) {
final String userId = rawDeviceKeyListEntry.key;
_userDeviceKeys[userId].deviceKeys = {};
for (final rawDeviceKeyEntry in rawDeviceKeyListEntry.value.entries) {
final String deviceId = rawDeviceKeyEntry.key;
_userDeviceKeys[userId].deviceKeys[deviceId] =
DeviceKeys.fromJson(rawDeviceKeyEntry.value);
if (oldUserDeviceKeys.containsKey(userId) &&
_userDeviceKeys[userId].deviceKeys.containsKey(deviceId)) {
_userDeviceKeys[userId].deviceKeys[deviceId].verified =
_userDeviceKeys[userId].deviceKeys[deviceId].verified;
_userDeviceKeys[userId].deviceKeys[deviceId].blocked =
_userDeviceKeys[userId].deviceKeys[deviceId].blocked;
} else if (deviceId == this.deviceID &&
_userDeviceKeys[userId].deviceKeys[deviceId].ed25519Key ==
this.fingerprintKey) {
_userDeviceKeys[userId].deviceKeys[deviceId].verified = true;
}
}
_userDeviceKeys[userId].outdated = false;
}
}
await this.storeAPI?.storeUserDeviceKeys(userDeviceKeys);
} catch (e) {
print("[LibOlm] Unable to update user device keys: " + e.toString());
} }
await this.storeAPI?.storeUserDeviceKeys(userDeviceKeys);
} }
String get fingerprintKey => encryptionEnabled String get fingerprintKey => encryptionEnabled

View file

@ -123,6 +123,7 @@ class Room {
} }
Future<void> _storeOutboundGroupSession() async { Future<void> _storeOutboundGroupSession() async {
if (_outboundGroupSession == null) return;
await client.storeAPI?.setItem( await client.storeAPI?.setItem(
"/clients/${client.deviceID}/rooms/${this.id}/outbound_group_session", "/clients/${client.deviceID}/rooms/${this.id}/outbound_group_session",
_outboundGroupSession.pickle(client.userID)); _outboundGroupSession.pickle(client.userID));
@ -170,10 +171,11 @@ class Room {
indexes: {}, indexes: {},
key: client.userID, key: client.userID,
); );
if (_fullyRestored) {
client.storeAPI?.setItem( client.storeAPI?.setItem(
"/clients/${client.deviceID}/rooms/${this.id}/session_keys", "/clients/${client.deviceID}/rooms/${this.id}/session_keys",
json.encode(sessionKeys)); json.encode(sessionKeys));
}
} }
/// Returns the [Event] for the given [typeKey] and optional [stateKey]. /// Returns the [Event] for the given [typeKey] and optional [stateKey].
@ -842,8 +844,11 @@ class Room {
} }
} }
} }
_fullyRestored = true;
} }
bool _fullyRestored = false;
/// Returns a Room from a json String which comes normally from the store. If the /// Returns a Room from a json String which comes normally from the store. If the
/// state are also given, the method will await them. /// state are also given, the method will await them.
static Future<Room> getRoomFromTableRow( static Future<Room> getRoomFromTableRow(

View file

@ -31,20 +31,25 @@ void test() async {
if (room.canonicalAlias?.isNotEmpty ?? false) { if (room.canonicalAlias?.isNotEmpty ?? false) {
break; break;
} }
await room.leave(); try {
await room.forget(); await room.leave();
await room.forget();
} catch (e) {
print(e);
}
} }
print("++++ ($testUserB) Leave all rooms ++++"); print("++++ ($testUserB) Leave all rooms ++++");
if (testClientB.rooms.isNotEmpty) { for (int i = 0; i < 3; i++) {
Room room = testClientB.rooms.first; if (testClientB.rooms.isNotEmpty) {
await room.leave(); Room room = testClientB.rooms.first;
await room.forget(); try {
} await room.leave();
if (testClientB.rooms.isNotEmpty) { await room.forget();
Room room = testClientB.rooms.first; } catch (e) {
await room.leave(); print(e);
await room.forget(); }
}
} }
print("++++ ($testUserA) Create room and invite $testUserB ++++"); print("++++ ($testUserA) Create room and invite $testUserB ++++");
@ -80,6 +85,8 @@ void test() async {
assert(room.sessionKeys.containsKey(room.outboundGroupSession.session_id())); assert(room.sessionKeys.containsKey(room.outboundGroupSession.session_id()));
assert(testClientA.olmSessions[testClientB.identityKey].length == 1); assert(testClientA.olmSessions[testClientB.identityKey].length == 1);
assert(testClientB.olmSessions[testClientA.identityKey].length == 1); assert(testClientB.olmSessions[testClientA.identityKey].length == 1);
assert(testClientA.olmSessions[testClientB.identityKey].first.session_id() ==
testClientB.olmSessions[testClientA.identityKey].first.session_id());
assert(inviteRoom.sessionKeys assert(inviteRoom.sessionKeys
.containsKey(room.outboundGroupSession.session_id())); .containsKey(room.outboundGroupSession.session_id()));
assert(room.lastMessage == testMessage); assert(room.lastMessage == testMessage);
@ -92,6 +99,9 @@ void test() async {
await Future.delayed(Duration(seconds: 5)); await Future.delayed(Duration(seconds: 5));
assert(testClientA.olmSessions[testClientB.identityKey].length == 1); assert(testClientA.olmSessions[testClientB.identityKey].length == 1);
assert(testClientB.olmSessions[testClientA.identityKey].length == 1); assert(testClientB.olmSessions[testClientA.identityKey].length == 1);
assert(testClientA.olmSessions[testClientB.identityKey].first.session_id() ==
testClientB.olmSessions[testClientA.identityKey].first.session_id());
assert(room.outboundGroupSession.session_id() == currentSessionIdA); assert(room.outboundGroupSession.session_id() == currentSessionIdA);
assert(inviteRoom.sessionKeys assert(inviteRoom.sessionKeys
.containsKey(room.outboundGroupSession.session_id())); .containsKey(room.outboundGroupSession.session_id()));
@ -116,6 +126,40 @@ void test() async {
print( print(
"++++ ($testUserA) Received decrypted message: '${room.lastMessage}' ++++"); "++++ ($testUserA) Received decrypted message: '${room.lastMessage}' ++++");
print("++++ ($testUserA) Restore user ++++");
FakeStore clientAStore = testClientA.storeAPI;
testClientA = null;
testClientA = Client("TestClient", debug: false);
testClientA.storeAPI = FakeStore(testClientA, clientAStore.storeMap);
await Future.delayed(Duration(seconds: 3));
Room restoredRoom = testClientA.rooms.first;
assert(room != null);
assert(restoredRoom.id == room.id);
assert(restoredRoom.outboundGroupSession.session_id() ==
room.outboundGroupSession.session_id());
assert(restoredRoom.sessionKeys.length == 2);
assert(restoredRoom.sessionKeys.keys.first == room.sessionKeys.keys.first);
assert(restoredRoom.sessionKeys.keys.last == room.sessionKeys.keys.last);
assert(testClientA.olmSessions[testClientB.identityKey].length == 1);
assert(testClientB.olmSessions[testClientA.identityKey].length == 1);
assert(testClientA.olmSessions[testClientB.identityKey].first.session_id() ==
testClientB.olmSessions[testClientA.identityKey].first.session_id());
print("++++ ($testUserA) Send again encrypted message: '$testMessage2' ++++");
await restoredRoom.sendTextEvent(testMessage2);
await Future.delayed(Duration(seconds: 5));
assert(testClientA.olmSessions[testClientB.identityKey].length == 1);
assert(testClientB.olmSessions[testClientA.identityKey].length == 1);
assert(testClientA.olmSessions[testClientB.identityKey].first.session_id() ==
testClientB.olmSessions[testClientA.identityKey].first.session_id());
assert(restoredRoom.outboundGroupSession.session_id() == currentSessionIdA);
assert(inviteRoom.sessionKeys
.containsKey(restoredRoom.outboundGroupSession.session_id()));
assert(restoredRoom.lastMessage == testMessage2);
assert(inviteRoom.lastMessage == testMessage2);
print(
"++++ ($testUserB) Received decrypted message: '${inviteRoom.lastMessage}' ++++");
print("++++ Logout $testUserA and $testUserB ++++"); print("++++ Logout $testUserA and $testUserB ++++");
await room.leave(); await room.leave();
await room.forget(); await room.forget();