refactor: Use tryGet for type casts whenever possible
This commit is contained in:
parent
3b90ede959
commit
395ef0eb8e
|
|
@ -69,11 +69,14 @@ class KeyManager {
|
||||||
if (lastEvent != null &&
|
if (lastEvent != null &&
|
||||||
lastEvent.type == EventTypes.Encrypted &&
|
lastEvent.type == EventTypes.Encrypted &&
|
||||||
lastEvent.content['can_request_session'] == true) {
|
lastEvent.content['can_request_session'] == true) {
|
||||||
try {
|
final sessionId = lastEvent.content.tryGet<String>('session_id');
|
||||||
maybeAutoRequest(room.id, lastEvent.content['session_id'] as String,
|
final senderKey = lastEvent.content.tryGet<String>('sender_key');
|
||||||
lastEvent.content['sender_key'] as String?);
|
if (sessionId != null && senderKey != null) {
|
||||||
} catch (_) {
|
maybeAutoRequest(
|
||||||
// dispose
|
room.id,
|
||||||
|
sessionId,
|
||||||
|
senderKey,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -647,16 +650,16 @@ class KeyManager {
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logs().e('[LibOlm] Error decrypting room key', e, s);
|
Logs().e('[LibOlm] Error decrypting room key', e, s);
|
||||||
}
|
}
|
||||||
if (decrypted != null) {
|
final senderKey = decrypted?.tryGet<String>('sender_key');
|
||||||
|
if (decrypted != null && senderKey != null) {
|
||||||
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'] as String, decrypted,
|
roomId, sessionId, senderKey, decrypted,
|
||||||
forwarded: true,
|
forwarded: true,
|
||||||
senderClaimedKeys: decrypted['sender_claimed_keys']
|
senderClaimedKeys: decrypted
|
||||||
is Map<String, String>
|
.tryGetMap<String, String>('sender_claimed_keys') ??
|
||||||
? (decrypted['sender_claimed_keys'] as Map<String, String>)
|
<String, String>{},
|
||||||
: <String, String>{},
|
|
||||||
uploaded: true);
|
uploaded: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -833,14 +836,24 @@ class KeyManager {
|
||||||
Logs().i(
|
Logs().i(
|
||||||
'[KeyManager] Received key sharing request from ${event.sender}:${event.content['requesting_device_id']}...');
|
'[KeyManager] Received key sharing request from ${event.sender}:${event.content['requesting_device_id']}...');
|
||||||
if (!event.content.containsKey('body')) {
|
if (!event.content.containsKey('body')) {
|
||||||
Logs().i('[KeyManager] No body, doing nothing');
|
Logs().w('[KeyManager] No body, doing nothing');
|
||||||
return; // no body
|
return; // no body
|
||||||
}
|
}
|
||||||
final body = event.content['body'] as Map<String, Object?>;
|
final body = event.content.tryGetMap<String, Object?>('body');
|
||||||
|
if (body == null) {
|
||||||
|
Logs().w('[KeyManager] Wrong type for body, doing nothing');
|
||||||
|
return; // wrong type for body
|
||||||
|
}
|
||||||
|
final roomId = body.tryGet<String>('room_id');
|
||||||
|
if (roomId == null) {
|
||||||
|
Logs().w(
|
||||||
|
'[KeyManager] Wrong type for room_id or no room_id, doing nothing');
|
||||||
|
return; // wrong type for roomId or no roomId found
|
||||||
|
}
|
||||||
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) {
|
||||||
Logs().i('[KeyManager] Device not found, doing nothing');
|
Logs().w('[KeyManager] Device not found, doing nothing');
|
||||||
return; // device not found
|
return; // device not found
|
||||||
}
|
}
|
||||||
if (device.userId == client.userID &&
|
if (device.userId == client.userID &&
|
||||||
|
|
@ -848,16 +861,15 @@ 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
|
||||||
}
|
}
|
||||||
if (body['room_id'] is! String) {
|
final room = client.getRoomById(roomId);
|
||||||
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 = body['session_id'];
|
final sessionId = body.tryGet<String>('session_id');
|
||||||
if (sessionId is! String) {
|
if (sessionId == null) {
|
||||||
|
Logs().w(
|
||||||
|
'[KeyManager] Wrong type for session_id or no session_id, doing nothing');
|
||||||
return; // wrong type for session_id
|
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
|
||||||
|
|
@ -867,10 +879,12 @@ class KeyManager {
|
||||||
return; // we don't have this session anyways
|
return; // we don't have this session anyways
|
||||||
}
|
}
|
||||||
if (event.content['request_id'] is! String) {
|
if (event.content['request_id'] is! String) {
|
||||||
|
Logs().w(
|
||||||
|
'[KeyManager] Wrong type for request_id or no request_id, doing nothing');
|
||||||
return; // wrong type for request_id
|
return; // wrong type for request_id
|
||||||
}
|
}
|
||||||
final request = KeyManagerKeyShareRequest(
|
final request = KeyManagerKeyShareRequest(
|
||||||
requestId: event.content['request_id'] as String,
|
requestId: event.content.tryGet<String>('request_id')!,
|
||||||
devices: [device],
|
devices: [device],
|
||||||
room: room,
|
room: room,
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
|
|
@ -890,7 +904,7 @@ class KeyManager {
|
||||||
await roomKeyRequest.forwardKey();
|
await roomKeyRequest.forwardKey();
|
||||||
} else if (device.encryptToDevice &&
|
} else if (device.encryptToDevice &&
|
||||||
session.allowedAtIndex
|
session.allowedAtIndex
|
||||||
.tryGet<Map<String, dynamic>>(device.userId)
|
.tryGet<Map<String, Object?>>(device.userId)
|
||||||
?.tryGet(device.curve25519Key!) !=
|
?.tryGet(device.curve25519Key!) !=
|
||||||
null) {
|
null) {
|
||||||
// if we know the user may see the message, then we can just forward the key.
|
// if we know the user may see the message, then we can just forward the key.
|
||||||
|
|
@ -946,6 +960,7 @@ class KeyManager {
|
||||||
(event.content['forwarding_curve25519_key_chain'] as List)
|
(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) {
|
if (event.content['sender_claimed_ed25519_key'] is! String) {
|
||||||
|
Logs().w('sender_claimed_ed255519_key has wrong type');
|
||||||
return; // wrong type
|
return; // wrong type
|
||||||
}
|
}
|
||||||
// TODO: verify that the keys work to decrypt a message
|
// TODO: verify that the keys work to decrypt a message
|
||||||
|
|
@ -987,8 +1002,13 @@ 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'] as String;
|
final roomId = event.content.tryGet<String>('room_id');
|
||||||
final String sessionId = event.content['session_id'] as String;
|
final sessionId = event.content.tryGet<String>('session_id');
|
||||||
|
if (roomId == null || sessionId == null) {
|
||||||
|
Logs().w(
|
||||||
|
'Either room_id or session_id are not the expected type or missing');
|
||||||
|
return;
|
||||||
|
}
|
||||||
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) {
|
||||||
|
|
|
||||||
|
|
@ -598,35 +598,34 @@ class OlmManager {
|
||||||
final identityKey =
|
final identityKey =
|
||||||
client.userDeviceKeys[userId]!.deviceKeys[deviceId]!.curve25519Key;
|
client.userDeviceKeys[userId]!.deviceKeys[deviceId]!.curve25519Key;
|
||||||
for (final deviceKey in deviceKeysEntry.value.values) {
|
for (final deviceKey in deviceKeysEntry.value.values) {
|
||||||
if (deviceKey is Map<String, Object?>) {
|
if (fingerprintKey == null ||
|
||||||
if (fingerprintKey == null ||
|
identityKey == null ||
|
||||||
identityKey == null ||
|
deviceKey is! Map<String, Object?> ||
|
||||||
!deviceKey.checkJsonSignature(
|
!deviceKey.checkJsonSignature(fingerprintKey, userId, deviceId) ||
|
||||||
fingerprintKey, userId, deviceId)) {
|
deviceKey['key'] is! String) {
|
||||||
Logs().w(
|
Logs().w(
|
||||||
'Skipping invalid device key from $userId:$deviceId',
|
'Skipping invalid device key from $userId:$deviceId',
|
||||||
deviceKey,
|
deviceKey,
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Logs().v('[OlmManager] Starting session with $userId:$deviceId');
|
Logs().v('[OlmManager] Starting session with $userId:$deviceId');
|
||||||
final session = olm.Session();
|
final session = olm.Session();
|
||||||
try {
|
try {
|
||||||
session.create_outbound(
|
session.create_outbound(
|
||||||
_olmAccount!, identityKey, deviceKey['key'] as String);
|
_olmAccount!, identityKey, deviceKey.tryGet<String>('key')!);
|
||||||
await storeOlmSession(OlmSession(
|
await storeOlmSession(OlmSession(
|
||||||
key: client.userID!,
|
key: client.userID!,
|
||||||
identityKey: identityKey,
|
identityKey: identityKey,
|
||||||
sessionId: session.session_id(),
|
sessionId: session.session_id(),
|
||||||
session: session,
|
session: session,
|
||||||
lastReceived:
|
lastReceived:
|
||||||
DateTime.now(), // we want to use a newly created session
|
DateTime.now(), // we want to use a newly created session
|
||||||
));
|
));
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
session.free();
|
session.free();
|
||||||
Logs().e(
|
Logs()
|
||||||
'[LibOlm] Could not create new outbound olm session', e, s);
|
.e('[LibOlm] Could not create new outbound olm session', e, s);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -280,8 +280,7 @@ class SSSS {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSecret(String type) =>
|
bool isSecret(String type) =>
|
||||||
client.accountData[type] != null &&
|
client.accountData[type]?.content['encrypted'] is Map;
|
||||||
client.accountData[type]!.content['encrypted'] is Map;
|
|
||||||
|
|
||||||
Future<String?> getCached(String type) async {
|
Future<String?> getCached(String type) async {
|
||||||
if (client.database == null) {
|
if (client.database == null) {
|
||||||
|
|
@ -295,9 +294,11 @@ 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 != null &&
|
||||||
as Map<String, Object?>)[dbEntry.keyId]
|
client.accountData[type]?.content
|
||||||
as Map<String, Object?>)['ciphertext'] ==
|
.tryGetMap<String, Object?>('encrypted')
|
||||||
|
?.tryGetMap<String, Object?>(dbEntry.keyId!)
|
||||||
|
?.tryGet<String>('ciphertext') ==
|
||||||
dbEntry.ciphertext;
|
dbEntry.ciphertext;
|
||||||
|
|
||||||
final fromCache = _cache[type];
|
final fromCache = _cache[type];
|
||||||
|
|
@ -320,25 +321,31 @@ class SSSS {
|
||||||
if (secretInfo == null) {
|
if (secretInfo == null) {
|
||||||
throw Exception('Not found');
|
throw Exception('Not found');
|
||||||
}
|
}
|
||||||
if (secretInfo.content['encrypted'] is! Map) {
|
final encryptedContent =
|
||||||
|
secretInfo.content.tryGetMap<String, Object?>('encrypted');
|
||||||
|
if (encryptedContent == null) {
|
||||||
throw Exception('Content is not encrypted');
|
throw Exception('Content is not encrypted');
|
||||||
}
|
}
|
||||||
if ((secretInfo.content['encrypted'] as Map<String, Object?>)[keyId]
|
final enc = encryptedContent.tryGetMap<String, Object?>(keyId);
|
||||||
is! Map) {
|
if (enc == null) {
|
||||||
throw Exception('Wrong / unknown key');
|
throw Exception('Wrong / unknown key');
|
||||||
}
|
}
|
||||||
final enc = (secretInfo.content['encrypted'] as Map<String, Object?>)[keyId]
|
final ciphertext = enc.tryGet<String>('ciphertext');
|
||||||
as Map<String, Object?>;
|
final iv = enc.tryGet<String>('iv');
|
||||||
|
final mac = enc.tryGet<String>('mac');
|
||||||
|
if (ciphertext == null || iv == null || mac == null) {
|
||||||
|
throw Exception('Wrong types for encrypted content or missing keys.');
|
||||||
|
}
|
||||||
final encryptInfo = EncryptedContent(
|
final encryptInfo = EncryptedContent(
|
||||||
iv: enc['iv'] as String,
|
iv: iv,
|
||||||
ciphertext: enc['ciphertext'] as String,
|
ciphertext: ciphertext,
|
||||||
mac: enc['mac'] as String);
|
mac: mac,
|
||||||
|
);
|
||||||
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(
|
await db.storeSSSSCache(type, keyId, ciphertext, decrypted);
|
||||||
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);
|
||||||
|
|
@ -388,11 +395,14 @@ 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 encryptedContent = content.tryGetMap<String, Object?>('encrypted');
|
||||||
|
if (encryptedContent == null) {
|
||||||
|
throw Exception('Wrong type for encrypted content!');
|
||||||
|
}
|
||||||
|
|
||||||
final otherKeys =
|
final otherKeys =
|
||||||
Set<String>.from(contentEncrypted.keys.where((k) => k != keyId));
|
Set<String>.from(encryptedContent.keys.where((k) => k != keyId));
|
||||||
contentEncrypted.removeWhere((k, v) => otherKeys.contains(k));
|
encryptedContent.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!');
|
||||||
|
|
@ -401,8 +411,12 @@ 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
|
||||||
final ciphertext = (contentEncrypted[keyId]
|
final ciphertext = encryptedContent
|
||||||
as Map<String, Object?>)['ciphertext'] as String;
|
.tryGetMap<String, Object?>(keyId)
|
||||||
|
?.tryGet<String>('ciphertext');
|
||||||
|
if (ciphertext == null) {
|
||||||
|
throw Exception('Wrong type for ciphertext!');
|
||||||
|
}
|
||||||
await client.database?.storeSSSSCache(type, keyId, ciphertext, secret);
|
await client.database?.storeSSSSCache(type, keyId, ciphertext, secret);
|
||||||
onSecretStored.add(keyId);
|
onSecretStored.add(keyId);
|
||||||
}
|
}
|
||||||
|
|
@ -509,8 +523,12 @@ class SSSS {
|
||||||
return; // nope....unknown or untrusted device
|
return; // nope....unknown or untrusted device
|
||||||
}
|
}
|
||||||
// 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.tryGet<String>('name');
|
||||||
final secret = await getCached(type as String);
|
if (type == null) {
|
||||||
|
Logs().i('[SSSS] Wrong data type for type param, ignoring');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final secret = await getCached(type);
|
||||||
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');
|
||||||
|
|
@ -544,11 +562,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
|
||||||
}
|
}
|
||||||
if (event.content['secret'] is! String) {
|
final secret = event.content.tryGet<String>('secret');
|
||||||
|
if (secret == null) {
|
||||||
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))) {
|
||||||
|
|
@ -565,9 +583,14 @@ 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
|
||||||
.content['encrypted'] as Map<String, Object?>)[keyId]
|
.tryGetMap<String, Object?>('encrypted'))
|
||||||
as Map<String, Object?>)['ciphertext'] as String;
|
?.tryGetMap<String, Object?>(keyId)
|
||||||
|
?.tryGet<String>('ciphertext');
|
||||||
|
if (ciphertext == null) {
|
||||||
|
Logs().i('[SSSS] Ciphertext is empty or not a String');
|
||||||
|
return;
|
||||||
|
}
|
||||||
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);
|
||||||
|
|
@ -583,8 +606,10 @@ class SSSS {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (data.content['encrypted'] is Map) {
|
final contentEncrypted =
|
||||||
return (data.content['encrypted'] as Map<String, Object?>).keys.toSet();
|
data.content.tryGetMap<String, Object?>('encrypted');
|
||||||
|
if (contentEncrypted != null) {
|
||||||
|
return contentEncrypted.keys.toSet();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,13 +104,14 @@ class Bootstrap {
|
||||||
for (final entry in client.accountData.entries) {
|
for (final entry in client.accountData.entries) {
|
||||||
final type = entry.key;
|
final type = entry.key;
|
||||||
final event = entry.value;
|
final event = entry.value;
|
||||||
if (event.content['encrypted'] is! Map) {
|
final encryptedContent =
|
||||||
|
event.content.tryGetMap<String, Object?>('encrypted');
|
||||||
|
if (encryptedContent == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final validKeys = <String>{};
|
final validKeys = <String>{};
|
||||||
final invalidKeys = <String>{};
|
final invalidKeys = <String>{};
|
||||||
for (final keyEntry
|
for (final keyEntry in encryptedContent.entries) {
|
||||||
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) {
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ extension DehydratedDeviceMatrixApi on MatrixApi {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return Map<String, int>.from(
|
return Map<String, int>.from(
|
||||||
response['one_time_key_counts'] as Map<String, Object?>);
|
response.tryGetMap<String, Object?>('one_time_key_counts') ??
|
||||||
|
<String, int>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// uploads a dehydrated device.
|
/// uploads a dehydrated device.
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,7 @@ class Client extends MatrixApi {
|
||||||
final ruleset = TryGetPushRule.tryFromJson(
|
final ruleset = TryGetPushRule.tryFromJson(
|
||||||
_accountData[EventTypes.PushRules]
|
_accountData[EventTypes.PushRules]
|
||||||
?.content
|
?.content
|
||||||
.tryGetMap<String, dynamic>('global') ??
|
.tryGetMap<String, Object?>('global') ??
|
||||||
{});
|
{});
|
||||||
_pushruleEvaluator = PushruleEvaluator.fromRuleset(ruleset);
|
_pushruleEvaluator = PushruleEvaluator.fromRuleset(ruleset);
|
||||||
}
|
}
|
||||||
|
|
@ -1068,7 +1068,7 @@ class Client extends MatrixApi {
|
||||||
PushRuleSet? get globalPushRules {
|
PushRuleSet? get globalPushRules {
|
||||||
final pushrules = _accountData['m.push_rules']
|
final pushrules = _accountData['m.push_rules']
|
||||||
?.content
|
?.content
|
||||||
.tryGetMap<String, dynamic>('global');
|
.tryGetMap<String, Object?>('global');
|
||||||
return pushrules != null ? TryGetPushRule.tryFromJson(pushrules) : null;
|
return pushrules != null ? TryGetPushRule.tryFromJson(pushrules) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1076,7 +1076,7 @@ class Client extends MatrixApi {
|
||||||
PushRuleSet? get devicePushRules {
|
PushRuleSet? get devicePushRules {
|
||||||
final pushrules = _accountData['m.push_rules']
|
final pushrules = _accountData['m.push_rules']
|
||||||
?.content
|
?.content
|
||||||
.tryGetMap<String, dynamic>('device');
|
.tryGetMap<String, Object?>('device');
|
||||||
return pushrules != null ? TryGetPushRule.tryFromJson(pushrules) : null;
|
return pushrules != null ? TryGetPushRule.tryFromJson(pushrules) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2732,15 +2732,14 @@ class Client extends MatrixApi {
|
||||||
/// 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, Object?>? globalPushRules =
|
final Map<String, Object?>? globalPushRules =
|
||||||
_accountData[EventTypes.PushRules]?.content['global']
|
_accountData[EventTypes.PushRules]
|
||||||
is Map<String, Object?>?
|
?.content
|
||||||
? _accountData[EventTypes.PushRules]?.content['global']
|
.tryGetMap<String, Object?>('global');
|
||||||
as Map<String, Object?>?
|
|
||||||
: null;
|
|
||||||
if (globalPushRules == null) return false;
|
if (globalPushRules == null) return false;
|
||||||
|
|
||||||
if (globalPushRules['override'] is List) {
|
final globalPushRulesOverride = globalPushRules.tryGetList('override');
|
||||||
for (final pushRule in globalPushRules['override'] as List) {
|
if (globalPushRulesOverride != null) {
|
||||||
|
for (final pushRule in globalPushRulesOverride) {
|
||||||
if (pushRule['rule_id'] == '.m.rule.master') {
|
if (pushRule['rule_id'] == '.m.rule.master') {
|
||||||
return pushRule['enabled'];
|
return pushRule['enabled'];
|
||||||
}
|
}
|
||||||
|
|
@ -2817,13 +2816,12 @@ class Client extends MatrixApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A list of mxids of users who are ignored.
|
/// A list of mxids of users who are ignored.
|
||||||
List<String> get ignoredUsers => (_accountData
|
List<String> get ignoredUsers =>
|
||||||
.containsKey('m.ignored_user_list') &&
|
List<String>.from(_accountData['m.ignored_user_list']
|
||||||
_accountData['m.ignored_user_list']?.content['ignored_users'] is Map)
|
?.content
|
||||||
? List<String>.from((_accountData['m.ignored_user_list']
|
.tryGetMap<String, Object?>('ignored_users')
|
||||||
?.content['ignored_users'] as Map<String, Object?>)
|
?.keys ??
|
||||||
.keys)
|
<String>[]);
|
||||||
: [];
|
|
||||||
|
|
||||||
/// Ignore another user. This will clear the local cached messages to
|
/// Ignore another user. This will clear the local cached messages to
|
||||||
/// hide all previous messages from this user.
|
/// hide all previous messages from this user.
|
||||||
|
|
|
||||||
|
|
@ -259,9 +259,7 @@ 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.tryGet<String>('msgtype') ?? MessageTypes.Text);
|
||||||
? content['msgtype'] as String
|
|
||||||
: MessageTypes.Text);
|
|
||||||
|
|
||||||
void setRedactionEvent(Event redactedBecause) {
|
void setRedactionEvent(Event redactedBecause) {
|
||||||
unsigned = {
|
unsigned = {
|
||||||
|
|
@ -303,12 +301,10 @@ 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'] as String : '';
|
String get text => content.tryGet<String>('body') ?? '';
|
||||||
|
|
||||||
/// 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 => content['formatted_body'] is String
|
String get formattedText => content.tryGet<String>('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 {
|
||||||
|
|
@ -401,16 +397,11 @@ 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 ?? transactionId,
|
txid: txid ?? unsigned?.tryGet<String>('transaction_id') ?? eventId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -440,15 +431,19 @@ 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'] as String, content['sender_key'] as String);
|
final sessionId = content.tryGet<String>('session_id');
|
||||||
|
final senderKey = content.tryGet<String>('sender_key');
|
||||||
|
if (sessionId == null || senderKey == null) {
|
||||||
|
throw ('Unknown session_id or sender_key');
|
||||||
|
}
|
||||||
|
await room.requestSessionKey(sessionId, senderKey);
|
||||||
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 => content['info'] is Map
|
Map get infoMap =>
|
||||||
? content['info'] as Map<String, Object?>
|
content.tryGetMap<String, Object?>('info') ?? <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
|
||||||
|
|
@ -471,10 +466,10 @@ 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
|
||||||
(content['file'] as Map<String, Object?>)['mimetype'] is String
|
.tryGetMap<String, Object?>('file')
|
||||||
? (content['file'] as Map<String, Object?>)['mimetype']
|
?.tryGet<String>('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
|
||||||
String get thumbnailMimetype => thumbnailInfoMap['mimetype'] is String
|
String get thumbnailMimetype => thumbnailInfoMap['mimetype'] is String
|
||||||
|
|
@ -487,7 +482,7 @@ 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
|
final url = isAttachmentEncrypted
|
||||||
? (content['file'] as Map<String, Object?>)['url']
|
? (content.tryGetMap<String, Object?>('file')?['url'])
|
||||||
: content['url'];
|
: content['url'];
|
||||||
return url is String ? Uri.tryParse(url) : null;
|
return url is String ? Uri.tryParse(url) : null;
|
||||||
}
|
}
|
||||||
|
|
@ -772,22 +767,17 @@ class Event extends MatrixEvent {
|
||||||
// if we need to strip the reply fallback.
|
// if we need to strip the reply fallback.
|
||||||
var htmlMessage = content['format'] != 'org.matrix.custom.html';
|
var htmlMessage = content['format'] != 'org.matrix.custom.html';
|
||||||
// If we have an edit, we want to operate on the new content
|
// If we have an edit, we want to operate on the new content
|
||||||
|
final newContent = content.tryGetMap<String, Object?>('m.new_content');
|
||||||
if (hideEdit &&
|
if (hideEdit &&
|
||||||
relationshipType == RelationshipTypes.edit &&
|
relationshipType == RelationshipTypes.edit &&
|
||||||
content.tryGet<Map<String, dynamic>>('m.new_content') != null) {
|
newContent != null) {
|
||||||
if (plaintextBody &&
|
if (plaintextBody && newContent['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>)
|
newContent.tryGet<String>('formatted_body') ?? formattedText);
|
||||||
.tryGet<String>('formatted_body') ??
|
|
||||||
formattedText);
|
|
||||||
} else {
|
} else {
|
||||||
htmlMessage = false;
|
htmlMessage = false;
|
||||||
body = (content['m.new_content'] as Map<String, dynamic>)
|
body = newContent.tryGet<String>('body') ?? body;
|
||||||
.tryGet<String>('body') ??
|
|
||||||
body;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Hide reply fallback
|
// Hide reply fallback
|
||||||
|
|
@ -829,33 +819,27 @@ class Event extends MatrixEvent {
|
||||||
|
|
||||||
/// Get the relationship type of an event. `null` if there is none
|
/// Get the relationship type of an event. `null` if there is none
|
||||||
String? get relationshipType {
|
String? get relationshipType {
|
||||||
if (content.tryGet<Map<String, dynamic>>('m.relates_to') == null) {
|
final mRelatesTo = content.tryGetMap<String, Object?>('m.relates_to');
|
||||||
|
if (mRelatesTo == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ((content['m.relates_to'] as Map<String, Object?>)
|
final relType = mRelatesTo.tryGet<String>('rel_type');
|
||||||
.containsKey('rel_type')) {
|
if (relType == RelationshipTypes.thread) {
|
||||||
if (content
|
return RelationshipTypes.thread;
|
||||||
.tryGet<Map<String, dynamic>>('m.relates_to')
|
|
||||||
?.tryGet<String>('rel_type') ==
|
|
||||||
RelationshipTypes.thread) {
|
|
||||||
return RelationshipTypes.thread;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ((content['m.relates_to'] as Map<String, Object?>)
|
|
||||||
.containsKey('m.in_reply_to')) {
|
if (mRelatesTo.containsKey('m.in_reply_to')) {
|
||||||
return RelationshipTypes.reply;
|
return RelationshipTypes.reply;
|
||||||
}
|
}
|
||||||
return content
|
return relType;
|
||||||
.tryGet<Map<String, dynamic>>('m.relates_to')
|
|
||||||
?.tryGet<String>('rel_type');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the event ID that this relationship will reference. `null` if there is none
|
/// Get the event ID that this relationship will reference. `null` if there is none
|
||||||
String? get relationshipEventId {
|
String? get relationshipEventId {
|
||||||
final relatesToMap = content.tryGetMap<String, dynamic>('m.relates_to');
|
final relatesToMap = content.tryGetMap<String, Object?>('m.relates_to');
|
||||||
return relatesToMap?.tryGet<String>('event_id') ??
|
return relatesToMap?.tryGet<String>('event_id') ??
|
||||||
relatesToMap
|
relatesToMap
|
||||||
?.tryGetMap<String, dynamic>('m.in_reply_to')
|
?.tryGetMap<String, Object?>('m.in_reply_to')
|
||||||
?.tryGet<String>('event_id');
|
?.tryGet<String>('event_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -267,9 +267,10 @@ class Room {
|
||||||
}
|
}
|
||||||
if (membership == Membership.leave) {
|
if (membership == Membership.leave) {
|
||||||
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?.tryGet<String>('prev_sender') != null) {
|
||||||
final name = unsafeGetUserFromMemoryOrFallback(
|
final name = unsafeGetUserFromMemoryOrFallback(
|
||||||
invitation.unsigned?['prev_sender'] as String)
|
invitation.unsigned!.tryGet<String>('prev_sender')!)
|
||||||
.calcDisplayname(i18n: i18n);
|
.calcDisplayname(i18n: i18n);
|
||||||
return i18n.wasDirectChatDisplayName(name);
|
return i18n.wasDirectChatDisplayName(name);
|
||||||
}
|
}
|
||||||
|
|
@ -1748,7 +1749,7 @@ class Room {
|
||||||
return getState(EventTypes.RoomCreate)?.senderId == userId ? 100 : 0;
|
return getState(EventTypes.RoomCreate)?.senderId == userId ? 100 : 0;
|
||||||
}
|
}
|
||||||
return powerLevelMap
|
return powerLevelMap
|
||||||
.tryGetMap<String, dynamic>('users')
|
.tryGetMap<String, Object?>('users')
|
||||||
?.tryGet<int>(userId) ??
|
?.tryGet<int>(userId) ??
|
||||||
powerLevelMap.tryGet<int>('users_default') ??
|
powerLevelMap.tryGet<int>('users_default') ??
|
||||||
0;
|
0;
|
||||||
|
|
@ -1803,7 +1804,7 @@ class Room {
|
||||||
final powerLevelMap = getState(EventTypes.RoomPowerLevels)?.content;
|
final powerLevelMap = getState(EventTypes.RoomPowerLevels)?.content;
|
||||||
if (powerLevelMap == null) return 0;
|
if (powerLevelMap == null) return 0;
|
||||||
return powerLevelMap
|
return powerLevelMap
|
||||||
.tryGetMap<String, dynamic>('events')
|
.tryGetMap<String, Object?>('events')
|
||||||
?.tryGet<int>(action) ??
|
?.tryGet<int>(action) ??
|
||||||
powerLevelMap.tryGet<int>('state_default') ??
|
powerLevelMap.tryGet<int>('state_default') ??
|
||||||
50;
|
50;
|
||||||
|
|
@ -1834,9 +1835,8 @@ 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'] is Map<String, Object?>
|
final eventsMap = newPowerLevelMap.tryGetMap<String, Object?>('events') ??
|
||||||
? newPowerLevelMap['events'] as Map<String, Object?>
|
<String, Object?>{};
|
||||||
: <String, Object?>{};
|
|
||||||
eventsMap.addAll({
|
eventsMap.addAll({
|
||||||
EventTypes.GroupCallPrefix: getDefaultPowerLevel(currentPowerLevelsMap),
|
EventTypes.GroupCallPrefix: getDefaultPowerLevel(currentPowerLevelsMap),
|
||||||
EventTypes.GroupCallMemberPrefix:
|
EventTypes.GroupCallMemberPrefix:
|
||||||
|
|
@ -1904,7 +1904,7 @@ class Room {
|
||||||
final powerLevelsMap = getState(EventTypes.RoomPowerLevels)?.content;
|
final powerLevelsMap = getState(EventTypes.RoomPowerLevels)?.content;
|
||||||
if (powerLevelsMap == null) return 0 <= ownPowerLevel;
|
if (powerLevelsMap == null) return 0 <= ownPowerLevel;
|
||||||
final pl = powerLevelsMap
|
final pl = powerLevelsMap
|
||||||
.tryGetMap<String, dynamic>('events')
|
.tryGetMap<String, Object?>('events')
|
||||||
?.tryGet<int>(eventType) ??
|
?.tryGet<int>(eventType) ??
|
||||||
powerLevelsMap.tryGet<int>('events_default') ??
|
powerLevelsMap.tryGet<int>('events_default') ??
|
||||||
0;
|
0;
|
||||||
|
|
@ -1916,7 +1916,7 @@ class Room {
|
||||||
final userLevel = getPowerLevelByUserId(userid);
|
final userLevel = getPowerLevelByUserId(userid);
|
||||||
final notificationLevel = getState(EventTypes.RoomPowerLevels)
|
final notificationLevel = getState(EventTypes.RoomPowerLevels)
|
||||||
?.content
|
?.content
|
||||||
.tryGetMap<String, dynamic>('notifications')
|
.tryGetMap<String, Object?>('notifications')
|
||||||
?.tryGet<int>(notificationType) ??
|
?.tryGet<int>(notificationType) ??
|
||||||
50;
|
50;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -347,16 +347,16 @@ class Timeline {
|
||||||
if (event.type == EventTypes.Encrypted &&
|
if (event.type == EventTypes.Encrypted &&
|
||||||
event.messageType == MessageTypes.BadEncrypted &&
|
event.messageType == MessageTypes.BadEncrypted &&
|
||||||
event.content['can_request_session'] == true) {
|
event.content['can_request_session'] == true) {
|
||||||
try {
|
final sessionId = event.content.tryGet<String>('session_id');
|
||||||
|
final senderKey = event.content.tryGet<String>('sender_key');
|
||||||
|
if (sessionId != null && senderKey != null) {
|
||||||
room.client.encryption?.keyManager.maybeAutoRequest(
|
room.client.encryption?.keyManager.maybeAutoRequest(
|
||||||
room.id,
|
room.id,
|
||||||
event.content['session_id'] as String,
|
sessionId,
|
||||||
event.content['sender_key'] as String,
|
senderKey,
|
||||||
tryOnlineBackup: tryOnlineBackup,
|
tryOnlineBackup: tryOnlineBackup,
|
||||||
onlineKeyBackupOnly: onlineKeyBackupOnly,
|
onlineKeyBackupOnly: onlineKeyBackupOnly,
|
||||||
);
|
);
|
||||||
} catch (_) {
|
|
||||||
// dispose
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -387,9 +387,9 @@ class Timeline {
|
||||||
for (i = 0; i < events.length; i++) {
|
for (i = 0; i < events.length; i++) {
|
||||||
final searchHaystack = <String>{events[i].eventId};
|
final searchHaystack = <String>{events[i].eventId};
|
||||||
|
|
||||||
final txnid = events[i].unsigned?['transaction_id'];
|
final txnid = events[i].unsigned?.tryGet<String>('transaction_id');
|
||||||
if (txnid != null) {
|
if (txnid != null) {
|
||||||
searchHaystack.add(txnid as String);
|
searchHaystack.add(txnid);
|
||||||
}
|
}
|
||||||
if (searchNeedle.intersection(searchHaystack).isNotEmpty) {
|
if (searchNeedle.intersection(searchHaystack).isNotEmpty) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -401,11 +401,9 @@ class Timeline {
|
||||||
void _removeEventFromSet(Set<Event> eventSet, Event event) {
|
void _removeEventFromSet(Set<Event> eventSet, Event event) {
|
||||||
eventSet.removeWhere((e) =>
|
eventSet.removeWhere((e) =>
|
||||||
e.matchesEventOrTransactionId(event.eventId) ||
|
e.matchesEventOrTransactionId(event.eventId) ||
|
||||||
(event.unsigned != null &&
|
event.unsigned != null &&
|
||||||
e.matchesEventOrTransactionId(
|
e.matchesEventOrTransactionId(
|
||||||
(event.unsigned?['transaction_id'] is String)
|
event.unsigned?.tryGet<String>('transaction_id')));
|
||||||
? (event.unsigned?['transaction_id'] as String)
|
|
||||||
: null)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addAggregatedEvent(Event event) {
|
void addAggregatedEvent(Event event) {
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ abstract class SignableKey extends MatrixSignableKey {
|
||||||
var haveValidSignature = false;
|
var haveValidSignature = false;
|
||||||
var gotSignatureFromCache = false;
|
var gotSignatureFromCache = false;
|
||||||
final fullKeyIdBool = validSignatures
|
final fullKeyIdBool = validSignatures
|
||||||
?.tryGetMap<String, dynamic>(otherUserId)
|
?.tryGetMap<String, Object?>(otherUserId)
|
||||||
?.tryGet<bool>(fullKeyId);
|
?.tryGet<bool>(fullKeyId);
|
||||||
if (fullKeyIdBool == true) {
|
if (fullKeyIdBool == true) {
|
||||||
haveValidSignature = true;
|
haveValidSignature = true;
|
||||||
|
|
@ -426,14 +426,15 @@ 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'] as String;
|
String? get deviceDisplayName =>
|
||||||
|
unsigned?.tryGet<String>('device_display_name');
|
||||||
|
|
||||||
bool? _validSelfSignature;
|
bool? _validSelfSignature;
|
||||||
bool get selfSigned =>
|
bool get selfSigned =>
|
||||||
_validSelfSignature ??
|
_validSelfSignature ??
|
||||||
(_validSelfSignature = (deviceId != null &&
|
(_validSelfSignature = (deviceId != null &&
|
||||||
signatures
|
signatures
|
||||||
?.tryGetMap<String, dynamic>(userId)
|
?.tryGetMap<String, Object?>(userId)
|
||||||
?.tryGet<String>('ed25519:$deviceId') ==
|
?.tryGet<String>('ed25519:$deviceId') ==
|
||||||
null
|
null
|
||||||
? false
|
? false
|
||||||
|
|
|
||||||
|
|
@ -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'] as String),
|
event.content.tryGet<String>('name') ?? ''),
|
||||||
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'] as String),
|
event.content.tryGet<String>('topic') ?? ''),
|
||||||
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) {
|
||||||
|
|
@ -260,7 +260,7 @@ abstract class EventLocalizations {
|
||||||
EventTypes.Reaction: (event, i18n, body) => i18n.sentReaction(
|
EventTypes.Reaction: (event, i18n, body) => i18n.sentReaction(
|
||||||
event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n),
|
event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n),
|
||||||
event.content
|
event.content
|
||||||
.tryGetMap<String, dynamic>('m.relates_to')
|
.tryGetMap<String, Object?>('m.relates_to')
|
||||||
?.tryGet<String>('key') ??
|
?.tryGet<String>('key') ??
|
||||||
body,
|
body,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -60,14 +60,14 @@ extension ImagePackRoomExtension on Room {
|
||||||
addImagePack(client.accountData['im.ponies.user_emotes'], slug: 'user');
|
addImagePack(client.accountData['im.ponies.user_emotes'], slug: 'user');
|
||||||
// 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) {
|
final rooms = packRooms?.content.tryGetMap<String, Object?>('rooms');
|
||||||
for (final roomEntry
|
if (packRooms != null && rooms != null) {
|
||||||
in (packRooms.content['rooms'] as Map<String, Object?>).entries) {
|
for (final roomEntry in rooms.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) {
|
final roomEntryValue = roomEntry.value;
|
||||||
for (final stateKeyEntry
|
if (room != null && roomEntryValue is Map<String, Object?>) {
|
||||||
in (roomEntry.value as Map<String, Object?>).entries) {
|
for (final stateKeyEntry in roomEntryValue.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}';
|
||||||
|
|
|
||||||
|
|
@ -704,18 +704,20 @@ class VoIP {
|
||||||
|
|
||||||
final groupCallId = event.stateKey;
|
final groupCallId = event.stateKey;
|
||||||
|
|
||||||
final callType = content['m.type'];
|
final callType = content.tryGet<String>('m.type');
|
||||||
|
|
||||||
if (callType != GroupCallType.Video && callType != GroupCallType.Voice) {
|
if (callType == null ||
|
||||||
|
callType != GroupCallType.Video && callType != GroupCallType.Voice) {
|
||||||
Logs().w('Received invalid group call type $callType for room $roomId.');
|
Logs().w('Received invalid group call type $callType for room $roomId.');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final callIntent = content['m.intent'];
|
final callIntent = content.tryGet<String>('m.intent');
|
||||||
|
|
||||||
if (callIntent != GroupCallIntent.Prompt &&
|
if (callIntent == null ||
|
||||||
callIntent != GroupCallIntent.Room &&
|
callIntent != GroupCallIntent.Prompt &&
|
||||||
callIntent != GroupCallIntent.Ring) {
|
callIntent != GroupCallIntent.Room &&
|
||||||
|
callIntent != GroupCallIntent.Ring) {
|
||||||
Logs()
|
Logs()
|
||||||
.w('Received invalid group call intent $callType for room $roomId.');
|
.w('Received invalid group call intent $callType for room $roomId.');
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -726,8 +728,8 @@ class VoIP {
|
||||||
voip: this,
|
voip: this,
|
||||||
room: room,
|
room: room,
|
||||||
groupCallId: groupCallId,
|
groupCallId: groupCallId,
|
||||||
type: callType as String,
|
type: callType,
|
||||||
intent: callIntent as String,
|
intent: callIntent,
|
||||||
);
|
);
|
||||||
|
|
||||||
groupCalls[groupCallId!] = groupCall;
|
groupCalls[groupCallId!] = groupCall;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue