Merge pull request #1918 from famedly/nico/fix-archive-rooms-becoming-joined

fix archive rooms becoming joined
This commit is contained in:
Nicolas Werner 2024-09-18 11:28:43 +02:00 committed by GitHub
commit ca41a963e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 107 additions and 5 deletions

View File

@ -164,6 +164,7 @@ class KeyManager {
if (!client.isLogged() || client.encryption == null) {
return;
}
final storeFuture = client.database
?.storeInboundGroupSession(
roomId,
@ -201,7 +202,18 @@ class KeyManager {
await client.handleSync(
SyncUpdate(
nextBatch: '',
rooms: RoomsUpdate(join: {room.id: JoinedRoomUpdate()})),
rooms: switch (room.membership) {
Membership.join =>
RoomsUpdate(join: {room.id: JoinedRoomUpdate()}),
Membership.ban ||
Membership.leave =>
RoomsUpdate(leave: {room.id: LeftRoomUpdate()}),
Membership.invite =>
RoomsUpdate(invite: {room.id: InvitedRoomUpdate()}),
Membership.knock =>
RoomsUpdate(knock: {room.id: KnockRoomUpdate()}),
},
),
);
});
}

View File

@ -114,11 +114,13 @@ class RoomsUpdate {
Map<String, JoinedRoomUpdate>? join;
Map<String, InvitedRoomUpdate>? invite;
Map<String, LeftRoomUpdate>? leave;
Map<String, KnockRoomUpdate>? knock;
RoomsUpdate({
this.join,
this.invite,
this.leave,
this.knock,
});
RoomsUpdate.fromJson(Map<String, Object?> json) {
@ -128,6 +130,8 @@ class RoomsUpdate {
MapEntry(k, InvitedRoomUpdate.fromJson(v as Map<String, Object?>)));
leave = json.tryGetMap<String, Object?>('leave')?.catchMap((k, v) =>
MapEntry(k, LeftRoomUpdate.fromJson(v as Map<String, Object?>)));
knock = json.tryGetMap<String, Object?>('knock')?.catchMap((k, v) =>
MapEntry(k, KnockRoomUpdate.fromJson(v as Map<String, Object?>)));
}
Map<String, Object?> toJson() {
@ -141,6 +145,9 @@ class RoomsUpdate {
if (leave != null) {
data['leave'] = leave!.map((k, v) => MapEntry(k, v.toJson()));
}
if (knock != null) {
data['knock'] = knock!.map((k, v) => MapEntry(k, v.toJson()));
}
return data;
}
}
@ -234,6 +241,28 @@ class InvitedRoomUpdate extends SyncRoomUpdate {
}
}
class KnockRoomUpdate extends SyncRoomUpdate {
List<StrippedStateEvent>? knockState;
KnockRoomUpdate({this.knockState});
KnockRoomUpdate.fromJson(Map<String, Object?> json)
: knockState = json
.tryGetMap<String, List<Object?>>('knock_state')?['events']
?.map((i) => StrippedStateEvent.fromJson(i as Map<String, Object?>))
.toList();
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (knockState != null) {
data['knock_state'] = {
'events': knockState!.map((i) => i.toJson()).toList(),
};
}
return data;
}
}
class LeftRoomUpdate extends SyncRoomUpdate {
List<MatrixEvent>? state;
TimelineUpdate? timeline;

View File

@ -80,7 +80,8 @@ class BoxCollection with ZoneTransactionMixin {
Future<void> close() async {
assert(_txnCache == null, 'Database closed while in transaction!');
return _db.close();
// Note, zoneTransaction and txnCache are different kinds of transactions.
return zoneTransaction(() async => _db.close());
}
@Deprecated('use collection.deleteDatabase now')

View File

@ -66,7 +66,7 @@ class BoxCollection with ZoneTransactionMixin {
},
);
Future<void> close() => _db.close();
Future<void> close() => zoneTransaction(() => _db.close());
@Deprecated('use collection.deleteDatabase now')
static Future<void> delete(String path, [dynamic factory]) =>

View File

@ -23,7 +23,7 @@ import 'package:test/test.dart';
import 'package:matrix/matrix.dart';
import 'fake_client.dart';
void main() {
void main() async {
group('Timeline', () {
Logs().level = Level.error;
@ -115,6 +115,66 @@ void main() {
expect(client.getArchiveRoomFromCache('!5345234235:example.com'), null);
});
test("assert that key updates don't change membership", () async {
const roomid = '!5345234235:example.com';
// prep work to be able to set a last event that would trigger the (fixed) bug
await client.loadArchiveWithTimeline();
expect(client.getArchiveRoomFromCache(roomid) != null, true);
expect(client.getRoomById(roomid)?.membership, Membership.leave);
final outboundSession = await client.encryption?.keyManager
.createOutboundGroupSession(roomid);
final inboundSession = client.encryption!.keyManager
.getInboundGroupSession(
roomid, outboundSession!.outboundGroupSession!.session_id())!;
// ensure encryption is "enabled"
client.getRoomById(roomid)?.setState(StrippedStateEvent(
type: EventTypes.Encryption,
content: {'algorithm': AlgorithmTypes.megolmV1AesSha2},
senderId: client.userID!,
stateKey: '',
));
final encryptedEvent = await client.encryption!
.encryptGroupMessagePayload(
roomid, {'msgtype': 'm.room.text', 'body': 'empty'});
// reset client
await client.dispose().onError((e, s) {});
client = await getClient(
sendTimelineEventTimeout: const Duration(seconds: 5),
);
await client.abortSync();
insertList.clear();
// now do our tests
await client.loadArchiveWithTimeline();
expect(client.getArchiveRoomFromCache(roomid) != null, true);
expect(client.getRoomById(roomid)?.membership, Membership.leave);
// set the last event
final room = client.getRoomById(roomid)!;
room.lastEvent = Event(
type: EventTypes.Encrypted,
content: encryptedEvent,
senderId: client.userID!,
eventId: '\$archivedencr',
room: room,
originServerTs: DateTime.now());
// import the inbound session
await client.encryption!.keyManager.setInboundGroupSession(
roomid,
inboundSession.sessionId,
inboundSession.senderKey,
inboundSession.content);
expect(client.getArchiveRoomFromCache(roomid) != null, true);
expect(client.getRoomById(roomid)?.membership, Membership.leave);
}, tags: 'olm');
test('clear archive', () async {
await client.loadArchiveWithTimeline();
client.clearArchivesFromCache();