refactor: Added type casts to match refactored matrix_api_lite

This commit is contained in:
Malin Errenst 2023-06-09 14:41:34 +02:00
parent 17df38b874
commit 5943576b1b
No known key found for this signature in database
13 changed files with 122 additions and 67 deletions

View File

@ -70,8 +70,8 @@ class KeyManager {
lastEvent.type == EventTypes.Encrypted && lastEvent.type == EventTypes.Encrypted &&
lastEvent.content['can_request_session'] == true) { lastEvent.content['can_request_session'] == true) {
try { try {
maybeAutoRequest(room.id, lastEvent.content['session_id'], maybeAutoRequest(room.id, lastEvent.content['session_id'] as String,
lastEvent.content['sender_key']); lastEvent.content['sender_key'] as String?);
} catch (_) { } catch (_) {
// dispose // dispose
} }
@ -638,7 +638,7 @@ class KeyManager {
final sessionId = sessionEntry.key; final sessionId = sessionEntry.key;
final session = sessionEntry.value; final session = sessionEntry.value;
final sessionData = session.sessionData; final sessionData = session.sessionData;
Map<String, dynamic>? decrypted; Map<String, Object?>? decrypted;
try { try {
decrypted = json.decode(decryption.decrypt( decrypted = json.decode(decryption.decrypt(
sessionData['ephemeral'] as String, sessionData['ephemeral'] as String,
@ -651,11 +651,11 @@ class KeyManager {
decrypted['session_id'] = sessionId; decrypted['session_id'] = sessionId;
decrypted['room_id'] = roomId; decrypted['room_id'] = roomId;
await setInboundGroupSession( await setInboundGroupSession(
roomId, sessionId, decrypted['sender_key'], decrypted, roomId, sessionId, decrypted['sender_key'] as String, decrypted,
forwarded: true, forwarded: true,
senderClaimedKeys: decrypted['sender_claimed_keys'] != null senderClaimedKeys: decrypted['sender_claimed_keys']
? Map<String, String>.from( is Map<String, String>
decrypted['sender_claimed_keys']!) ? (decrypted['sender_claimed_keys'] as Map<String, String>)
: <String, String>{}, : <String, String>{},
uploaded: true); uploaded: true);
} }
@ -836,6 +836,7 @@ class KeyManager {
Logs().i('[KeyManager] No body, doing nothing'); Logs().i('[KeyManager] No body, doing nothing');
return; // no body return; // no body
} }
final body = event.content['body'] as Map<String, Object?>;
final device = client.userDeviceKeys[event.sender] final device = client.userDeviceKeys[event.sender]
?.deviceKeys[event.content['requesting_device_id']]; ?.deviceKeys[event.content['requesting_device_id']];
if (device == null) { if (device == null) {
@ -847,20 +848,29 @@ class KeyManager {
Logs().i('[KeyManager] Request is by ourself, ignoring'); Logs().i('[KeyManager] Request is by ourself, ignoring');
return; // ignore requests by ourself return; // ignore requests by ourself
} }
final room = client.getRoomById(event.content['body']['room_id']); if (body['room_id'] is! String) {
return; // wrong type for room_id
}
final room = client.getRoomById(body['room_id'] as String);
if (room == null) { if (room == null) {
Logs().i('[KeyManager] Unknown room, ignoring'); Logs().i('[KeyManager] Unknown room, ignoring');
return; // unknown room return; // unknown room
} }
final sessionId = event.content['body']['session_id']; final sessionId = body['session_id'];
if (sessionId is! String) {
return; // wrong type for session_id
}
// okay, let's see if we have this session at all // okay, let's see if we have this session at all
final session = await loadInboundGroupSession(room.id, sessionId); final session = await loadInboundGroupSession(room.id, sessionId);
if (session == null) { if (session == null) {
Logs().i('[KeyManager] Unknown session, ignoring'); Logs().i('[KeyManager] Unknown session, ignoring');
return; // we don't have this session anyways return; // we don't have this session anyways
} }
if (event.content['request_id'] is! String) {
return; // wrong type for request_id
}
final request = KeyManagerKeyShareRequest( final request = KeyManagerKeyShareRequest(
requestId: event.content['request_id'], requestId: event.content['request_id'] as String,
devices: [device], devices: [device],
room: room, room: room,
sessionId: sessionId, sessionId: sessionId,
@ -933,15 +943,18 @@ class KeyManager {
if (event.content['forwarding_curve25519_key_chain'] is! List) { if (event.content['forwarding_curve25519_key_chain'] is! List) {
event.content['forwarding_curve25519_key_chain'] = <String>[]; event.content['forwarding_curve25519_key_chain'] = <String>[];
} }
event.content['forwarding_curve25519_key_chain'] (event.content['forwarding_curve25519_key_chain'] as List)
.add(encryptedContent['sender_key']); .add(encryptedContent['sender_key']);
if (event.content['sender_claimed_ed25519_key'] is! String) {
return; // wrong type
}
// TODO: verify that the keys work to decrypt a message // TODO: verify that the keys work to decrypt a message
// alright, all checks out, let's go ahead and store this session // alright, all checks out, let's go ahead and store this session
await setInboundGroupSession(request.room.id, request.sessionId, await setInboundGroupSession(request.room.id, request.sessionId,
device.curve25519Key!, event.content, device.curve25519Key!, event.content,
forwarded: true, forwarded: true,
senderClaimedKeys: { senderClaimedKeys: {
'ed25519': event.content['sender_claimed_ed25519_key'], 'ed25519': event.content['sender_claimed_ed25519_key'] as String,
}); });
request.devices.removeWhere( request.devices.removeWhere(
(k) => k.userId == device.userId && k.deviceId == device.deviceId); (k) => k.userId == device.userId && k.deviceId == device.deviceId);
@ -974,8 +987,8 @@ class KeyManager {
Logs().v('[KeyManager] not encrypted, ignoring...'); Logs().v('[KeyManager] not encrypted, ignoring...');
return; // the event wasn't encrypted, this is a security risk; return; // the event wasn't encrypted, this is a security risk;
} }
final String roomId = event.content['room_id']; final String roomId = event.content['room_id'] as String;
final String sessionId = event.content['session_id']; final String sessionId = event.content['session_id'] as String;
final sender_ed25519 = client.userDeviceKeys[event.sender] final sender_ed25519 = client.userDeviceKeys[event.sender]
?.deviceKeys[event.content['requesting_device_id']]?.ed25519Key; ?.deviceKeys[event.content['requesting_device_id']]?.ed25519Key;
if (sender_ed25519 != null) { if (sender_ed25519 != null) {

View File

@ -295,8 +295,9 @@ class SSSS {
bool isValid(SSSSCache dbEntry) => bool isValid(SSSSCache dbEntry) =>
keys.contains(dbEntry.keyId) && keys.contains(dbEntry.keyId) &&
dbEntry.ciphertext != null && dbEntry.ciphertext != null &&
client.accountData[type]?.content['encrypted'][dbEntry.keyId] ((client.accountData[type]?.content['encrypted']
['ciphertext'] == as Map<String, Object?>)[dbEntry.keyId]
as Map<String, Object?>)['ciphertext'] ==
dbEntry.ciphertext; dbEntry.ciphertext;
final fromCache = _cache[type]; final fromCache = _cache[type];
@ -322,17 +323,22 @@ class SSSS {
if (secretInfo.content['encrypted'] is! Map) { if (secretInfo.content['encrypted'] is! Map) {
throw Exception('Content is not encrypted'); throw Exception('Content is not encrypted');
} }
if (secretInfo.content['encrypted'][keyId] is! Map) { if ((secretInfo.content['encrypted'] as Map<String, Object?>)[keyId]
is! Map) {
throw Exception('Wrong / unknown key'); throw Exception('Wrong / unknown key');
} }
final enc = secretInfo.content['encrypted'][keyId]; final enc = (secretInfo.content['encrypted'] as Map<String, Object?>)[keyId]
as Map<String, Object?>;
final encryptInfo = EncryptedContent( final encryptInfo = EncryptedContent(
iv: enc['iv'], ciphertext: enc['ciphertext'], mac: enc['mac']); iv: enc['iv'] as String,
ciphertext: enc['ciphertext'] as String,
mac: enc['mac'] as String);
final decrypted = await decryptAes(encryptInfo, key, type); final decrypted = await decryptAes(encryptInfo, key, type);
final db = client.database; final db = client.database;
if (cacheTypes.contains(type) && db != null) { if (cacheTypes.contains(type) && db != null) {
// cache the thing // cache the thing
await db.storeSSSSCache(type, keyId, enc['ciphertext'], decrypted); await db.storeSSSSCache(
type, keyId, enc['ciphertext'] as String, decrypted);
onSecretStored.add(keyId); onSecretStored.add(keyId);
if (_cacheCallbacks.containsKey(type) && await getCached(type) == null) { if (_cacheCallbacks.containsKey(type) && await getCached(type) == null) {
_cacheCallbacks[type]!(decrypted); _cacheCallbacks[type]!(decrypted);
@ -382,10 +388,11 @@ class SSSS {
if (content == null) { if (content == null) {
throw InvalidPassphraseException('Key has no content!'); throw InvalidPassphraseException('Key has no content!');
} }
final contentEncrypted = content['encrypted'] as Map<String, Object?>;
final otherKeys = final otherKeys =
Set<String>.from(content['encrypted'].keys.where((k) => k != keyId)); Set<String>.from(contentEncrypted.keys.where((k) => k != keyId));
content['encrypted'].removeWhere((k, v) => otherKeys.contains(k)); contentEncrypted.removeWhere((k, v) => otherKeys.contains(k));
// yes, we are paranoid... // yes, we are paranoid...
if (await getStored(type, keyId, key) != secret) { if (await getStored(type, keyId, key) != secret) {
throw Exception('Secrets do not match up!'); throw Exception('Secrets do not match up!');
@ -394,8 +401,9 @@ class SSSS {
await client.setAccountData(client.userID!, type, content); await client.setAccountData(client.userID!, type, content);
if (cacheTypes.contains(type)) { if (cacheTypes.contains(type)) {
// cache the thing // cache the thing
await client.database?.storeSSSSCache( final ciphertext = (contentEncrypted[keyId]
type, keyId, content['encrypted'][keyId]['ciphertext'], secret); as Map<String, Object?>)['ciphertext'] as String;
await client.database?.storeSSSSCache(type, keyId, ciphertext, secret);
onSecretStored.add(keyId); onSecretStored.add(keyId);
} }
} }
@ -502,7 +510,7 @@ class SSSS {
} }
// alright, all seems fine...let's check if we actually have the secret they are asking for // alright, all seems fine...let's check if we actually have the secret they are asking for
final type = event.content['name']; final type = event.content['name'];
final secret = await getCached(type); final secret = await getCached(type as String);
if (secret == null) { if (secret == null) {
Logs() Logs()
.i('[SSSS] We don\'t have the secret for $type ourself, ignoring'); .i('[SSSS] We don\'t have the secret for $type ourself, ignoring');
@ -536,11 +544,11 @@ class SSSS {
Logs().i('[SSSS] Someone else replied?'); Logs().i('[SSSS] Someone else replied?');
return; // someone replied whom we didn't send the share request to return; // someone replied whom we didn't send the share request to
} }
final secret = event.content['secret'];
if (event.content['secret'] is! String) { if (event.content['secret'] is! String) {
Logs().i('[SSSS] Secret wasn\'t a string'); Logs().i('[SSSS] Secret wasn\'t a string');
return; // the secret wasn't a string....wut? return; // the secret wasn't a string....wut?
} }
final secret = event.content['secret'] as String;
// let's validate if the secret is, well, valid // let's validate if the secret is, well, valid
if (_validators.containsKey(request.type) && if (_validators.containsKey(request.type) &&
!(await _validators[request.type]!(secret))) { !(await _validators[request.type]!(secret))) {
@ -557,8 +565,9 @@ class SSSS {
if (db != null) { if (db != null) {
final keyId = keyIdFromType(request.type); final keyId = keyIdFromType(request.type);
if (keyId != null) { if (keyId != null) {
final ciphertext = client.accountData[request.type]! final ciphertext = ((client.accountData[request.type]!
.content['encrypted'][keyId]['ciphertext']; .content['encrypted'] as Map<String, Object?>)[keyId]
as Map<String, Object?>)['ciphertext'] as String;
await db.storeSSSSCache(request.type, keyId, ciphertext, secret); await db.storeSSSSCache(request.type, keyId, ciphertext, secret);
if (_cacheCallbacks.containsKey(request.type)) { if (_cacheCallbacks.containsKey(request.type)) {
_cacheCallbacks[request.type]!(secret); _cacheCallbacks[request.type]!(secret);
@ -575,7 +584,7 @@ class SSSS {
return null; return null;
} }
if (data.content['encrypted'] is Map) { if (data.content['encrypted'] is Map) {
return data.content['encrypted'].keys.toSet(); return (data.content['encrypted'] as Map<String, Object?>).keys.toSet();
} }
return null; return null;
} }

View File

@ -109,7 +109,8 @@ class Bootstrap {
} }
final validKeys = <String>{}; final validKeys = <String>{};
final invalidKeys = <String>{}; final invalidKeys = <String>{};
for (final keyEntry in event.content['encrypted'].entries) { for (final keyEntry
in (event.content['encrypted'] as Map<String, Object?>).entries) {
final key = keyEntry.key; final key = keyEntry.key;
final value = keyEntry.value; final value = keyEntry.value;
if (value is! Map) { if (value is! Map) {

View File

@ -47,7 +47,8 @@ extension DehydratedDeviceMatrixApi on MatrixApi {
}, },
}, },
); );
return Map<String, int>.from(response['one_time_key_counts']); return Map<String, int>.from(
response['one_time_key_counts'] as Map<String, Object?>);
} }
/// uploads a dehydrated device. /// uploads a dehydrated device.

View File

@ -2731,12 +2731,16 @@ class Client extends MatrixApi {
/// Whether all push notifications are muted using the [.m.rule.master] /// Whether all push notifications are muted using the [.m.rule.master]
/// rule of the push rules: https://matrix.org/docs/spec/client_server/r0.6.0#m-rule-master /// rule of the push rules: https://matrix.org/docs/spec/client_server/r0.6.0#m-rule-master
bool get allPushNotificationsMuted { bool get allPushNotificationsMuted {
final Map<String, dynamic>? globalPushRules = final Map<String, Object?>? globalPushRules =
_accountData[EventTypes.PushRules]?.content['global']; _accountData[EventTypes.PushRules]?.content['global']
is Map<String, Object?>?
? _accountData[EventTypes.PushRules]?.content['global']
as Map<String, Object?>?
: null;
if (globalPushRules == null) return false; if (globalPushRules == null) return false;
if (globalPushRules['override'] is List) { if (globalPushRules['override'] is List) {
for (final pushRule in globalPushRules['override']) { for (final pushRule in globalPushRules['override'] as List) {
if (pushRule['rule_id'] == '.m.rule.master') { if (pushRule['rule_id'] == '.m.rule.master') {
return pushRule['enabled']; return pushRule['enabled'];
} }
@ -2816,8 +2820,9 @@ class Client extends MatrixApi {
List<String> get ignoredUsers => (_accountData List<String> get ignoredUsers => (_accountData
.containsKey('m.ignored_user_list') && .containsKey('m.ignored_user_list') &&
_accountData['m.ignored_user_list']?.content['ignored_users'] is Map) _accountData['m.ignored_user_list']?.content['ignored_users'] is Map)
? List<String>.from( ? List<String>.from((_accountData['m.ignored_user_list']
_accountData['m.ignored_user_list']?.content['ignored_users'].keys) ?.content['ignored_users'] as Map<String, Object?>)
.keys)
: []; : [];
/// Ignore another user. This will clear the local cached messages to /// Ignore another user. This will clear the local cached messages to

View File

@ -259,7 +259,9 @@ class Event extends MatrixEvent {
String get messageType => type == EventTypes.Sticker String get messageType => type == EventTypes.Sticker
? MessageTypes.Sticker ? MessageTypes.Sticker
: (content['msgtype'] is String ? content['msgtype'] : MessageTypes.Text); : (content['msgtype'] is String
? content['msgtype'] as String
: MessageTypes.Text);
void setRedactionEvent(Event redactedBecause) { void setRedactionEvent(Event redactedBecause) {
unsigned = { unsigned = {
@ -301,11 +303,12 @@ class Event extends MatrixEvent {
} }
/// Returns the body of this event if it has a body. /// Returns the body of this event if it has a body.
String get text => content['body'] is String ? content['body'] : ''; String get text => content['body'] is String ? content['body'] as String : '';
/// Returns the formatted boy of this event if it has a formatted body. /// Returns the formatted boy of this event if it has a formatted body.
String get formattedText => String get formattedText => content['formatted_body'] is String
content['formatted_body'] is String ? content['formatted_body'] : ''; ? content['formatted_body'] as String
: '';
/// Use this to get the body. /// Use this to get the body.
String get body { String get body {
@ -398,11 +401,16 @@ class Event extends MatrixEvent {
); );
} }
String transactionId = eventId;
if (unsigned?['transaction_id'] is String) {
transactionId = unsigned?['transaction_id'] as String;
}
// we do not remove the event here. It will automatically be updated // we do not remove the event here. It will automatically be updated
// in the `sendEvent` method to transition -1 -> 0 -> 1 -> 2 // in the `sendEvent` method to transition -1 -> 0 -> 1 -> 2
return await room.sendEvent( return await room.sendEvent(
content, content,
txid: txid ?? unsigned?['transaction_id'] ?? eventId, txid: txid ?? transactionId,
); );
} }
@ -432,13 +440,15 @@ class Event extends MatrixEvent {
content['can_request_session'] != true) { content['can_request_session'] != true) {
throw ('Session key not requestable'); throw ('Session key not requestable');
} }
await room.requestSessionKey(content['session_id'], content['sender_key']); await room.requestSessionKey(
content['session_id'] as String, content['sender_key'] as String);
return; return;
} }
/// Gets the info map of file events, or a blank map if none present /// Gets the info map of file events, or a blank map if none present
Map get infoMap => Map get infoMap => content['info'] is Map
content['info'] is Map ? content['info'] : <String, dynamic>{}; ? content['info'] as Map<String, Object?>
: <String, Object?>{};
/// Gets the thumbnail info map of file events, or a blank map if nonepresent /// Gets the thumbnail info map of file events, or a blank map if nonepresent
Map get thumbnailInfoMap => infoMap['thumbnail_info'] is Map Map get thumbnailInfoMap => infoMap['thumbnail_info'] is Map
@ -461,8 +471,9 @@ class Event extends MatrixEvent {
/// Gets the mimetype of the attachment of a file event, or a blank string if not present /// Gets the mimetype of the attachment of a file event, or a blank string if not present
String get attachmentMimetype => infoMap['mimetype'] is String String get attachmentMimetype => infoMap['mimetype'] is String
? infoMap['mimetype'].toLowerCase() ? infoMap['mimetype'].toLowerCase()
: (content['file'] is Map && content['file']['mimetype'] is String : (content['file'] is Map &&
? content['file']['mimetype'] (content['file'] as Map<String, Object?>)['mimetype'] is String
? (content['file'] as Map<String, Object?>)['mimetype']
: ''); : '');
/// Gets the mimetype of the thumbnail of a file event, or a blank string if not present /// Gets the mimetype of the thumbnail of a file event, or a blank string if not present
@ -475,7 +486,9 @@ class Event extends MatrixEvent {
/// Gets the underlying mxc url of an attachment of a file event, or null if not present /// Gets the underlying mxc url of an attachment of a file event, or null if not present
Uri? get attachmentMxcUrl { Uri? get attachmentMxcUrl {
final url = isAttachmentEncrypted ? content['file']['url'] : content['url']; final url = isAttachmentEncrypted
? (content['file'] as Map<String, Object?>)['url']
: content['url'];
return url is String ? Uri.tryParse(url) : null; return url is String ? Uri.tryParse(url) : null;
} }
@ -763,7 +776,8 @@ class Event extends MatrixEvent {
relationshipType == RelationshipTypes.edit && relationshipType == RelationshipTypes.edit &&
content.tryGet<Map<String, dynamic>>('m.new_content') != null) { content.tryGet<Map<String, dynamic>>('m.new_content') != null) {
if (plaintextBody && if (plaintextBody &&
content['m.new_content']['format'] == 'org.matrix.custom.html') { (content['m.new_content'] as Map<String, Object?>)['format'] ==
'org.matrix.custom.html') {
htmlMessage = true; htmlMessage = true;
body = HtmlToText.convert( body = HtmlToText.convert(
(content['m.new_content'] as Map<String, dynamic>) (content['m.new_content'] as Map<String, dynamic>)
@ -818,7 +832,8 @@ class Event extends MatrixEvent {
if (content.tryGet<Map<String, dynamic>>('m.relates_to') == null) { if (content.tryGet<Map<String, dynamic>>('m.relates_to') == null) {
return null; return null;
} }
if (content['m.relates_to'].containsKey('rel_type')) { if ((content['m.relates_to'] as Map<String, Object?>)
.containsKey('rel_type')) {
if (content if (content
.tryGet<Map<String, dynamic>>('m.relates_to') .tryGet<Map<String, dynamic>>('m.relates_to')
?.tryGet<String>('rel_type') == ?.tryGet<String>('rel_type') ==
@ -826,7 +841,8 @@ class Event extends MatrixEvent {
return RelationshipTypes.thread; return RelationshipTypes.thread;
} }
} }
if (content['m.relates_to'].containsKey('m.in_reply_to')) { if ((content['m.relates_to'] as Map<String, Object?>)
.containsKey('m.in_reply_to')) {
return RelationshipTypes.reply; return RelationshipTypes.reply;
} }
return content return content

View File

@ -269,7 +269,7 @@ class Room {
final invitation = getState(EventTypes.RoomMember, client.userID!); final invitation = getState(EventTypes.RoomMember, client.userID!);
if (invitation != null && invitation.unsigned?['prev_sender'] != null) { if (invitation != null && invitation.unsigned?['prev_sender'] != null) {
final name = unsafeGetUserFromMemoryOrFallback( final name = unsafeGetUserFromMemoryOrFallback(
invitation.unsigned?['prev_sender']) invitation.unsigned?['prev_sender'] as String)
.calcDisplayname(i18n: i18n); .calcDisplayname(i18n: i18n);
return i18n.wasDirectChatDisplayName(name); return i18n.wasDirectChatDisplayName(name);
} }
@ -1315,8 +1315,9 @@ class Room {
Future<void> removeFromDirectChat() async { Future<void> removeFromDirectChat() async {
final directChats = client.directChats.copy(); final directChats = client.directChats.copy();
for (final k in directChats.keys) { for (final k in directChats.keys) {
if (directChats[k] is List && directChats[k].contains(id)) { final directChat = directChats[k];
directChats[k].remove(id); if (directChat is List && directChat.contains(id)) {
directChat.remove(id);
} }
} }
@ -1833,7 +1834,9 @@ class Room {
final currentPowerLevelsMap = getState(EventTypes.RoomPowerLevels)?.content; final currentPowerLevelsMap = getState(EventTypes.RoomPowerLevels)?.content;
if (currentPowerLevelsMap != null) { if (currentPowerLevelsMap != null) {
final newPowerLevelMap = currentPowerLevelsMap; final newPowerLevelMap = currentPowerLevelsMap;
final eventsMap = newPowerLevelMap['events'] ?? {}; final eventsMap = newPowerLevelMap['events'] is Map<String, Object?>
? newPowerLevelMap['events'] as Map<String, Object?>
: <String, Object?>{};
eventsMap.addAll({ eventsMap.addAll({
EventTypes.GroupCallPrefix: getDefaultPowerLevel(currentPowerLevelsMap), EventTypes.GroupCallPrefix: getDefaultPowerLevel(currentPowerLevelsMap),
EventTypes.GroupCallMemberPrefix: EventTypes.GroupCallMemberPrefix:

View File

@ -350,8 +350,8 @@ class Timeline {
try { try {
room.client.encryption?.keyManager.maybeAutoRequest( room.client.encryption?.keyManager.maybeAutoRequest(
room.id, room.id,
event.content['session_id'], event.content['session_id'] as String,
event.content['sender_key'], event.content['sender_key'] as String,
tryOnlineBackup: tryOnlineBackup, tryOnlineBackup: tryOnlineBackup,
onlineKeyBackupOnly: onlineKeyBackupOnly, onlineKeyBackupOnly: onlineKeyBackupOnly,
); );
@ -389,7 +389,7 @@ class Timeline {
final txnid = events[i].unsigned?['transaction_id']; final txnid = events[i].unsigned?['transaction_id'];
if (txnid != null) { if (txnid != null) {
searchHaystack.add(txnid); searchHaystack.add(txnid as String);
} }
if (searchNeedle.intersection(searchHaystack).isNotEmpty) { if (searchNeedle.intersection(searchHaystack).isNotEmpty) {
break; break;
@ -402,7 +402,10 @@ class Timeline {
eventSet.removeWhere((e) => eventSet.removeWhere((e) =>
e.matchesEventOrTransactionId(event.eventId) || e.matchesEventOrTransactionId(event.eventId) ||
(event.unsigned != null && (event.unsigned != null &&
e.matchesEventOrTransactionId(event.unsigned?['transaction_id']))); e.matchesEventOrTransactionId(
(event.unsigned?['transaction_id'] is String)
? (event.unsigned?['transaction_id'] as String)
: null)));
} }
void addAggregatedEvent(Event event) { void addAggregatedEvent(Event event) {

View File

@ -426,7 +426,7 @@ class DeviceKeys extends SignableKey {
late DateTime lastActive; late DateTime lastActive;
String? get curve25519Key => keys['curve25519:$deviceId']; String? get curve25519Key => keys['curve25519:$deviceId'];
String? get deviceDisplayName => unsigned?['device_display_name']; String? get deviceDisplayName => unsigned?['device_display_name'] as String;
bool? _validSelfSignature; bool? _validSelfSignature;
bool get selfSigned => bool get selfSigned =>

View File

@ -204,11 +204,11 @@ abstract class EventLocalizations {
event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n)), event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n)),
EventTypes.RoomName: (event, i18n, body) => i18n.changedTheChatNameTo( EventTypes.RoomName: (event, i18n, body) => i18n.changedTheChatNameTo(
event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n), event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n),
event.content['name']), event.content['name'] as String),
EventTypes.RoomTopic: (event, i18n, body) => EventTypes.RoomTopic: (event, i18n, body) =>
i18n.changedTheChatDescriptionTo( i18n.changedTheChatDescriptionTo(
event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n), event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n),
event.content['topic']), event.content['topic'] as String),
EventTypes.RoomAvatar: (event, i18n, body) => i18n.changedTheChatAvatar( EventTypes.RoomAvatar: (event, i18n, body) => i18n.changedTheChatAvatar(
event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n)), event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n)),
EventTypes.GuestAccess: (event, i18n, body) { EventTypes.GuestAccess: (event, i18n, body) {

View File

@ -61,11 +61,13 @@ extension ImagePackRoomExtension on Room {
// next we add all the external image packs // next we add all the external image packs
final packRooms = client.accountData['im.ponies.emote_rooms']; final packRooms = client.accountData['im.ponies.emote_rooms'];
if (packRooms != null && packRooms.content['rooms'] is Map) { if (packRooms != null && packRooms.content['rooms'] is Map) {
for (final roomEntry in packRooms.content['rooms'].entries) { for (final roomEntry
in (packRooms.content['rooms'] as Map<String, Object?>).entries) {
final roomId = roomEntry.key; final roomId = roomEntry.key;
final room = client.getRoomById(roomId); final room = client.getRoomById(roomId);
if (room != null && roomEntry.value is Map) { if (room != null && roomEntry.value is Map) {
for (final stateKeyEntry in roomEntry.value.entries) { for (final stateKeyEntry
in (roomEntry.value as Map<String, Object?>).entries) {
final stateKey = stateKeyEntry.key; final stateKey = stateKeyEntry.key;
final fallbackSlug = final fallbackSlug =
'${room.getLocalizedDisplayname()}-${stateKey.isNotEmpty ? '$stateKey-' : ''}${room.id}'; '${room.getLocalizedDisplayname()}-${stateKey.isNotEmpty ? '$stateKey-' : ''}${room.id}';

View File

@ -726,8 +726,8 @@ class VoIP {
voip: this, voip: this,
room: room, room: room,
groupCallId: groupCallId, groupCallId: groupCallId,
type: callType, type: callType as String,
intent: callIntent, intent: callIntent as String,
); );
groupCalls[groupCallId!] = groupCall; groupCalls[groupCallId!] = groupCall;

View File

@ -1042,8 +1042,10 @@ void main() {
test('pushRuleState', () async { test('pushRuleState', () async {
expect(room.pushRuleState, PushRuleState.mentionsOnly); expect(room.pushRuleState, PushRuleState.mentionsOnly);
matrix.accountData['m.push_rules']?.content['global']['override'].add( ((matrix.accountData['m.push_rules']?.content['global']
matrix.accountData['m.push_rules']?.content['global']['room'][0]); as Map<String, Object?>)['override'] as List)
.add(((matrix.accountData['m.push_rules']?.content['global']
as Map<String, Object?>)['room'] as List)[0]);
expect(room.pushRuleState, PushRuleState.dontNotify); expect(room.pushRuleState, PushRuleState.dontNotify);
}); });