refactor: Added type casts to match refactored matrix_api_lite
This commit is contained in:
parent
17df38b874
commit
5943576b1b
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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 =>
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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}';
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue