refactor: remove redundant null checks

This commit is contained in:
Nicolas Werner 2021-10-28 14:32:09 +02:00
parent e6f77924d6
commit 6e20c53b01
No known key found for this signature in database
GPG Key ID: C8D75E610773F2D9
18 changed files with 108 additions and 143 deletions

View File

@ -12,9 +12,6 @@ analyzer:
errors: errors:
todo: ignore todo: ignore
import_of_legacy_library_into_null_safe: ignore import_of_legacy_library_into_null_safe: ignore
# ignore those until we are completely nullsafe
invalid_null_aware_operator: ignore
unnecessary_null_comparison: ignore
exclude: exclude:
- example/main.dart - example/main.dart
# needed until crypto packages upgrade # needed until crypto packages upgrade

View File

@ -90,9 +90,11 @@ class CrossSigning {
final masterPrivateKey = final masterPrivateKey =
base64.decode(await handle.getStored(EventTypes.CrossSigningMasterKey)); base64.decode(await handle.getStored(EventTypes.CrossSigningMasterKey));
final keyObj = olm.PkSigning(); final keyObj = olm.PkSigning();
String masterPubkey; String? masterPubkey;
try { try {
masterPubkey = keyObj.init_with_seed(masterPrivateKey); masterPubkey = keyObj.init_with_seed(masterPrivateKey);
} catch (e) {
masterPubkey = null;
} finally { } finally {
keyObj.free(); keyObj.free();
} }
@ -131,9 +133,6 @@ class CrossSigning {
final addSignature = final addSignature =
(SignableKey key, SignableKey signedWith, String signature) { (SignableKey key, SignableKey signedWith, String signature) {
if (key == null || signedWith == null || signature == null) {
return;
}
final signedKey = key.cloneForSigning(); final signedKey = key.cloneForSigning();
((signedKey.signatures ??= ((signedKey.signatures ??=
<String, Map<String, String>>{})[signedWith.userId] ??= <String, Map<String, String>>{})[signedWith.userId] ??=

View File

@ -24,8 +24,10 @@ import '../../matrix.dart';
extension JsonSignatureCheckExtension on Map<String, dynamic> { extension JsonSignatureCheckExtension on Map<String, dynamic> {
/// Checks the signature of a signed json object. /// Checks the signature of a signed json object.
bool checkJsonSignature(String key, String userId, String deviceId) { bool checkJsonSignature(String key, String userId, String deviceId) {
final Map<String, dynamic> signatures = this['signatures']; final signatures = this['signatures'];
if (signatures == null || !signatures.containsKey(userId)) return false; if (signatures == null ||
!(signatures is Map<String, dynamic>) ||
!signatures.containsKey(userId)) return false;
remove('unsigned'); remove('unsigned');
remove('signatures'); remove('signatures');
if (!signatures[userId].containsKey('ed25519:$deviceId')) return false; if (!signatures[userId].containsKey('ed25519:$deviceId')) return false;

View File

@ -152,9 +152,9 @@ class KeyVerification {
List<String> get knownVerificationMethods { List<String> get knownVerificationMethods {
final methods = <String>[]; final methods = <String>[];
if (client.verificationMethods?.contains(KeyVerificationMethod.numbers) == if (client.verificationMethods.contains(KeyVerificationMethod.numbers) ==
true || true ||
client.verificationMethods?.contains(KeyVerificationMethod.emoji) == client.verificationMethods.contains(KeyVerificationMethod.emoji) ==
true) { true) {
methods.add('m.sas.v1'); methods.add('m.sas.v1');
} }
@ -358,10 +358,8 @@ class KeyVerification {
if (_nextAction == 'request') { if (_nextAction == 'request') {
sendStart(); sendStart();
} else if (_nextAction == 'done') { } else if (_nextAction == 'done') {
if (_verifiedDevices != null) { // and now let's sign them all in the background
// and now let's sign them all in the background encryption.crossSigning.sign(_verifiedDevices);
encryption.crossSigning.sign(_verifiedDevices);
}
setState(KeyVerificationState.done); setState(KeyVerificationState.done);
} }
}; };
@ -532,8 +530,7 @@ class KeyVerification {
} }
Future<bool> verifyActivity() async { Future<bool> verifyActivity() async {
if (lastActivity != null && if (lastActivity.add(Duration(minutes: 10)).isAfter(DateTime.now())) {
lastActivity.add(Duration(minutes: 10)).isAfter(DateTime.now())) {
lastActivity = DateTime.now(); lastActivity = DateTime.now();
return true; return true;
} }
@ -675,12 +672,12 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
List<String> get knownAuthentificationTypes { List<String> get knownAuthentificationTypes {
final types = <String>[]; final types = <String>[];
if (request.client.verificationMethods if (request.client.verificationMethods
?.contains(KeyVerificationMethod.emoji) == .contains(KeyVerificationMethod.emoji) ==
true) { true) {
types.add('emoji'); types.add('emoji');
} }
if (request.client.verificationMethods if (request.client.verificationMethods
?.contains(KeyVerificationMethod.numbers) == .contains(KeyVerificationMethod.numbers) ==
true) { true) {
types.add('decimal'); types.add('decimal');
} }

View File

@ -431,10 +431,7 @@ class Client extends MatrixApi {
final deviceId_ = response.deviceId; final deviceId_ = response.deviceId;
final userId = response.userId; final userId = response.userId;
final homeserver = this.homeserver; final homeserver = this.homeserver;
if (accessToken == null || if (accessToken == null || deviceId_ == null || homeserver == null) {
deviceId_ == null ||
userId == null ||
homeserver == null) {
throw Exception( throw Exception(
'Registered but token, device ID, user ID or homeserver is null.'); 'Registered but token, device ID, user ID or homeserver is null.');
} }
@ -570,8 +567,6 @@ class Client extends MatrixApi {
preset: CreateRoomPreset.trustedPrivateChat, preset: CreateRoomPreset.trustedPrivateChat,
); );
if (roomId == null) return roomId;
await Room(id: roomId, client: this).addToDirectChat(mxid); await Room(id: roomId, client: this).addToDirectChat(mxid);
return roomId; return roomId;
@ -1501,11 +1496,8 @@ class Client extends MatrixApi {
void _updateRoomsByRoomUpdate(String roomId, SyncRoomUpdate chatUpdate) { void _updateRoomsByRoomUpdate(String roomId, SyncRoomUpdate chatUpdate) {
// Update the chat list item. // Update the chat list item.
// Search the room in the rooms // Search the room in the rooms
var j = 0; final roomIndex = rooms.indexWhere((r) => r.id == roomId);
for (j = 0; j < rooms.length; j++) { final found = roomIndex != -1;
if (rooms[j].id == roomId) break;
}
final found = (j < rooms.length && rooms[j].id == roomId);
final membership = chatUpdate is LeftRoomUpdate final membership = chatUpdate is LeftRoomUpdate
? Membership.leave ? Membership.leave
: chatUpdate is InvitedRoomUpdate : chatUpdate is InvitedRoomUpdate
@ -1514,7 +1506,7 @@ class Client extends MatrixApi {
// Does the chat already exist in the list rooms? // Does the chat already exist in the list rooms?
if (!found && membership != Membership.leave) { if (!found && membership != Membership.leave) {
final position = membership == Membership.invite ? 0 : j; final position = membership == Membership.invite ? 0 : rooms.length;
// Add the new chat to the list // Add the new chat to the list
final newRoom = chatUpdate is JoinedRoomUpdate final newRoom = chatUpdate is JoinedRoomUpdate
? Room( ? Room(
@ -1533,38 +1525,39 @@ class Client extends MatrixApi {
} }
// If the membership is "leave" then remove the item and stop here // If the membership is "leave" then remove the item and stop here
else if (found && membership == Membership.leave) { else if (found && membership == Membership.leave) {
rooms.removeAt(j); rooms.removeAt(roomIndex);
} }
// Update notification, highlight count and/or additional informations // Update notification, highlight count and/or additional informations
else if (found && else if (found &&
chatUpdate is JoinedRoomUpdate && chatUpdate is JoinedRoomUpdate &&
(rooms[j].membership != membership || (rooms[roomIndex].membership != membership ||
rooms[j].notificationCount != rooms[roomIndex].notificationCount !=
(chatUpdate.unreadNotifications?.notificationCount ?? 0) || (chatUpdate.unreadNotifications?.notificationCount ?? 0) ||
rooms[j].highlightCount != rooms[roomIndex].highlightCount !=
(chatUpdate.unreadNotifications?.highlightCount ?? 0) || (chatUpdate.unreadNotifications?.highlightCount ?? 0) ||
chatUpdate.summary != null || chatUpdate.summary != null ||
chatUpdate.timeline?.prevBatch != null)) { chatUpdate.timeline?.prevBatch != null)) {
rooms[j].membership = membership; rooms[roomIndex].membership = membership;
rooms[j].notificationCount = rooms[roomIndex].notificationCount =
chatUpdate.unreadNotifications?.notificationCount ?? 0; chatUpdate.unreadNotifications?.notificationCount ?? 0;
rooms[j].highlightCount = rooms[roomIndex].highlightCount =
chatUpdate.unreadNotifications?.highlightCount ?? 0; chatUpdate.unreadNotifications?.highlightCount ?? 0;
if (chatUpdate.timeline?.prevBatch != null) { if (chatUpdate.timeline?.prevBatch != null) {
rooms[j].prev_batch = chatUpdate.timeline?.prevBatch; rooms[roomIndex].prev_batch = chatUpdate.timeline?.prevBatch;
} }
final summary = chatUpdate.summary; final summary = chatUpdate.summary;
if (summary != null) { if (summary != null) {
final roomSummaryJson = rooms[j].summary.toJson() final roomSummaryJson = rooms[roomIndex].summary.toJson()
..addAll(summary.toJson()); ..addAll(summary.toJson());
rooms[j].summary = RoomSummary.fromJson(roomSummaryJson); rooms[roomIndex].summary = RoomSummary.fromJson(roomSummaryJson);
} }
if (rooms[j].onUpdate != null) rooms[j].onUpdate.add(rooms[j].id); rooms[roomIndex].onUpdate.add(rooms[roomIndex].id);
if ((chatUpdate.timeline?.limited ?? false) && if ((chatUpdate.timeline?.limited ?? false) &&
requestHistoryOnLimitedTimeline) { requestHistoryOnLimitedTimeline) {
Logs().v('Limited timeline for ${rooms[j].id} request history now'); Logs().v(
runInRoot(rooms[j].requestHistory); 'Limited timeline for ${rooms[roomIndex].id} request history now');
runInRoot(rooms[roomIndex].requestHistory);
} }
} }
} }
@ -1637,7 +1630,7 @@ class Client extends MatrixApi {
void _sortRooms() { void _sortRooms() {
if (prevBatch == null || _sortLock || rooms.length < 2) return; if (prevBatch == null || _sortLock || rooms.length < 2) return;
_sortLock = true; _sortLock = true;
rooms?.sort(sortRoomsBy); rooms.sort(sortRoomsBy);
_sortLock = false; _sortLock = false;
} }
@ -1808,10 +1801,8 @@ class Client extends MatrixApi {
} }
} }
userKeys.outdated = false; userKeys.outdated = false;
if (database != null) { dbActions
dbActions .add(() => database.storeUserDeviceKeysInfo(userId, false));
.add(() => database.storeUserDeviceKeysInfo(userId, false));
}
} }
} }
// next we parse and persist the cross signing keys // next we parse and persist the cross signing keys
@ -1837,7 +1828,7 @@ class Client extends MatrixApi {
for (final oldEntry in oldKeys.entries) { for (final oldEntry in oldKeys.entries) {
if (!oldEntry.value.usage.contains(keyType)) { if (!oldEntry.value.usage.contains(keyType)) {
userKeys.crossSigningKeys[oldEntry.key] = oldEntry.value; userKeys.crossSigningKeys[oldEntry.key] = oldEntry.value;
} else if (database != null) { } else {
// There is a previous cross-signing key with this usage, that we no // There is a previous cross-signing key with this usage, that we no
// longer need/use. Clear it from the database. // longer need/use. Clear it from the database.
dbActions.add(() => dbActions.add(() =>
@ -1863,21 +1854,17 @@ class Client extends MatrixApi {
// if we should instead use the new key with unknown verified / blocked status // if we should instead use the new key with unknown verified / blocked status
userKeys.crossSigningKeys[publicKey] = oldKey; userKeys.crossSigningKeys[publicKey] = oldKey;
} }
if (database != null) { dbActions.add(() => database.storeUserCrossSigningKey(
dbActions.add(() => database.storeUserCrossSigningKey( userId,
userId, publicKey,
publicKey, json.encode(entry.toJson()),
json.encode(entry.toJson()), entry.directVerified,
entry.directVerified, entry.blocked,
entry.blocked, ));
));
}
} }
_userDeviceKeys[userId]?.outdated = false; _userDeviceKeys[userId]?.outdated = false;
if (database != null) { dbActions
dbActions .add(() => database.storeUserDeviceKeysInfo(userId, false));
.add(() => database.storeUserDeviceKeysInfo(userId, false));
}
} }
} }
@ -1992,7 +1979,6 @@ class Client extends MatrixApi {
// then only send it to verified devices // then only send it to verified devices
if (deviceKeys.isNotEmpty) { if (deviceKeys.isNotEmpty) {
deviceKeys.removeWhere((DeviceKeys deviceKeys) => deviceKeys.removeWhere((DeviceKeys deviceKeys) =>
deviceKeys == null ||
deviceKeys.blocked || deviceKeys.blocked ||
(deviceKeys.userId == userID && deviceKeys.deviceId == deviceID) || (deviceKeys.userId == userID && deviceKeys.deviceId == deviceID) ||
(onlyVerified && !deviceKeys.verified)); (onlyVerified && !deviceKeys.verified));

View File

@ -518,8 +518,9 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
// We always need the member event for ourself // We always need the member event for ourself
final membersToPostload = <String>{if (userID != null) userID}; final membersToPostload = <String>{if (userID != null) userID};
// If the room is a direct chat, those IDs should be there too // If the room is a direct chat, those IDs should be there too
if (room.isDirectChat) if (room.isDirectChat) {
membersToPostload.add(room.directChatMatrixID!); membersToPostload.add(room.directChatMatrixID!);
}
// the lastEvent message preview might have an author we need to fetch, if it is a group chat // the lastEvent message preview might have an author we need to fetch, if it is a group chat
final lastEvent = room.getState(EventTypes.Message); final lastEvent = room.getState(EventTypes.Message);
if (lastEvent != null && !room.isDirectChat) { if (lastEvent != null && !room.isDirectChat) {
@ -910,13 +911,12 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
return; return;
} }
final status = final status = newStatus.isError || prevEvent == null
newStatus.isError || prevEvent == null || prevEvent.status != null ? newStatus
? newStatus : latestEventStatus(
: latestEventStatus( prevEvent.status,
prevEvent.status, newStatus,
newStatus, );
);
// Add the status and the sort order to the content so it get stored // Add the status and the sort order to the content so it get stored
eventUpdate.content['unsigned'] ??= <String, dynamic>{}; eventUpdate.content['unsigned'] ??= <String, dynamic>{};

View File

@ -118,7 +118,7 @@ class Event extends MatrixEvent {
// Mark event as failed to send if status is `sending` and event is older // Mark event as failed to send if status is `sending` and event is older
// than the timeout. This should not happen with the deprecated Moor // than the timeout. This should not happen with the deprecated Moor
// database! // database!
if (status.isSending && room?.client?.database != null) { if (status.isSending && room?.client.database != null) {
// Age of this event in milliseconds // Age of this event in milliseconds
final age = DateTime.now().millisecondsSinceEpoch - final age = DateTime.now().millisecondsSinceEpoch -
originServerTs.millisecondsSinceEpoch; originServerTs.millisecondsSinceEpoch;
@ -411,16 +411,21 @@ 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.parse( Uri? get attachmentMxcUrl {
isAttachmentEncrypted ? content['file']['url'] : content['url']); final url = isAttachmentEncrypted ? content['file']['url'] : content['url'];
return url is String ? Uri.tryParse(url) : null;
}
/// Gets the underlying mxc url of a thumbnail of a file event, or null if not present /// Gets the underlying mxc url of a thumbnail of a file event, or null if not present
Uri get thumbnailMxcUrl => Uri.parse(isThumbnailEncrypted Uri? get thumbnailMxcUrl {
? infoMap['thumbnail_file']['url'] final url = isThumbnailEncrypted
: infoMap['thumbnail_url']); ? infoMap['thumbnail_file']['url']
: infoMap['thumbnail_url'];
return url is String ? Uri.tryParse(url) : null;
}
/// Gets the mxc url of an attachment/thumbnail of a file event, taking sizes into account, or null if not present /// Gets the mxc url of an attachment/thumbnail of a file event, taking sizes into account, or null if not present
Uri attachmentOrThumbnailMxcUrl({bool getThumbnail = false}) { Uri? attachmentOrThumbnailMxcUrl({bool getThumbnail = false}) {
if (getThumbnail && if (getThumbnail &&
infoMap['size'] is int && infoMap['size'] is int &&
thumbnailInfoMap['size'] is int && thumbnailInfoMap['size'] is int &&
@ -599,7 +604,7 @@ class Event extends MatrixEvent {
bool plaintextBody = false, bool plaintextBody = false,
}) { }) {
if (redacted) { if (redacted) {
return i18n.removedBy(redactedBecause?.sender?.calcDisplayname() ?? ''); return i18n.removedBy(redactedBecause?.sender.calcDisplayname() ?? '');
} }
var body = plaintextBody ? this.plaintextBody : this.body; var body = plaintextBody ? this.plaintextBody : this.body;
@ -643,7 +648,7 @@ class Event extends MatrixEvent {
textOnlyMessageTypes.contains(messageType)) { textOnlyMessageTypes.contains(messageType)) {
final senderNameOrYou = senderId == room?.client.userID final senderNameOrYou = senderId == room?.client.userID
? i18n.you ? i18n.you
: (sender?.calcDisplayname() ?? ''); : (sender.calcDisplayname());
localizedBody = '$senderNameOrYou: $localizedBody'; localizedBody = '$senderNameOrYou: $localizedBody';
} }
@ -670,7 +675,7 @@ 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) { if (content.tryGet<Map<String, dynamic>>('m.relates_to') == null) {
return null; return null;
} }
if (content['m.relates_to'].containsKey('m.in_reply_to')) { if (content['m.relates_to'].containsKey('m.in_reply_to')) {
@ -683,7 +688,7 @@ class Event extends MatrixEvent {
/// 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 {
if (content == null || !(content['m.relates_to'] is Map)) { if (!(content['m.relates_to'] is Map)) {
return null; return null;
} }
if (content['m.relates_to'].containsKey('event_id')) { if (content['m.relates_to'].containsKey('event_id')) {

View File

@ -239,13 +239,13 @@ class Room {
/// Empty chats will become the localized version of 'Empty Chat'. /// Empty chats will become the localized version of 'Empty Chat'.
/// This method requires a localization class which implements [MatrixLocalizations] /// This method requires a localization class which implements [MatrixLocalizations]
String getLocalizedDisplayname(MatrixLocalizations i18n) { String getLocalizedDisplayname(MatrixLocalizations i18n) {
if ((name?.isEmpty ?? true) && if (name.isEmpty &&
(canonicalAlias?.isEmpty ?? true) && canonicalAlias.isEmpty &&
!isDirectChat && !isDirectChat &&
(summary.mHeroes != null && summary.mHeroes?.isNotEmpty == true)) { (summary.mHeroes != null && summary.mHeroes?.isNotEmpty == true)) {
return i18n.groupWith(displayname); return i18n.groupWith(displayname);
} }
if (displayname?.isNotEmpty ?? false) { if (displayname.isNotEmpty) {
return displayname; return displayname;
} }
return i18n.emptyChat; return i18n.emptyChat;
@ -356,9 +356,8 @@ class Room {
states.forEach((final String key, final entry) { states.forEach((final String key, final entry) {
final state = entry['']; final state = entry[''];
if (state == null) return; if (state == null) return;
if (state.originServerTs != null && if (state.originServerTs.millisecondsSinceEpoch >
state.originServerTs.millisecondsSinceEpoch > lastTime.millisecondsSinceEpoch) {
lastTime.millisecondsSinceEpoch) {
lastTime = state.originServerTs; lastTime = state.originServerTs;
lastEvent = state; lastEvent = state;
} }
@ -405,9 +404,9 @@ class Room {
/// Calculates the displayname. First checks if there is a name, then checks for a canonical alias and /// Calculates the displayname. First checks if there is a name, then checks for a canonical alias and
/// then generates a name from the heroes. /// then generates a name from the heroes.
String get displayname { String get displayname {
if (name != null && name.isNotEmpty) return name; if (name.isNotEmpty) return name;
final canonicalAlias = this.canonicalAlias?.localpart; final canonicalAlias = this.canonicalAlias.localpart;
if (canonicalAlias != null && canonicalAlias.isNotEmpty) { if (canonicalAlias != null && canonicalAlias.isNotEmpty) {
return canonicalAlias; return canonicalAlias;
} }
@ -529,7 +528,7 @@ class Room {
content, content,
); );
final lastEvent = this.lastEvent; final lastEvent = this.lastEvent;
if (unread == false && lastEvent != null) { if (!unread && lastEvent != null) {
await setReadMarker( await setReadMarker(
lastEvent.eventId, lastEvent.eventId,
mRead: lastEvent.eventId, mRead: lastEvent.eventId,
@ -1188,16 +1187,6 @@ class Room {
bool ignoreErrors = false, bool ignoreErrors = false,
bool requestProfile = true, bool requestProfile = true,
}) async { }) async {
// TODO: Why is this bug happening at all?
if (mxID == null) {
// Show a warning but first generate a stacktrace.
try {
throw Exception();
} catch (e, s) {
Logs().w('requestUser has been called with a null mxID', e, s);
}
return null;
}
final stateUser = getState(EventTypes.RoomMember, mxID); final stateUser = getState(EventTypes.RoomMember, mxID);
if (stateUser != null) { if (stateUser != null) {
return stateUser.asUser; return stateUser.asUser;
@ -1500,7 +1489,7 @@ class Room {
/// intended for any member of the room other than the sender of the event. /// intended for any member of the room other than the sender of the event.
/// [party_id] The party ID for call, Can be set to client.deviceId. /// [party_id] The party ID for call, Can be set to client.deviceId.
Future<String?> inviteToCall( Future<String?> inviteToCall(
String callId, int lifetime, String party_id, String invitee, String sdp, String callId, int lifetime, String party_id, String? invitee, String sdp,
{String type = 'offer', {String type = 'offer',
String version = voipProtoVersion, String version = voipProtoVersion,
String? txid, String? txid,
@ -1678,7 +1667,8 @@ class Room {
/// [callId] The ID of the call this event relates to. /// [callId] The ID of the call this event relates to.
/// [version] is the version of the VoIP specification this message adheres to. This specification is version 1. /// [version] is the version of the VoIP specification this message adheres to. This specification is version 1.
/// [party_id] The party ID for call, Can be set to client.deviceId. /// [party_id] The party ID for call, Can be set to client.deviceId.
Future<String?> hangupCall(String callId, String party_id, String hangupCause, Future<String?> hangupCall(
String callId, String party_id, String? hangupCause,
{String version = voipProtoVersion, String? txid}) async { {String version = voipProtoVersion, String? txid}) async {
txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}';
@ -1855,7 +1845,7 @@ class Room {
/// Returns the encryption algorithm. Currently only `m.megolm.v1.aes-sha2` is supported. /// Returns the encryption algorithm. Currently only `m.megolm.v1.aes-sha2` is supported.
/// Returns null if there is no encryption algorithm. /// Returns null if there is no encryption algorithm.
String? get encryptionAlgorithm => String? get encryptionAlgorithm =>
getState(EventTypes.Encryption)?.parsedRoomEncryptionContent?.algorithm; getState(EventTypes.Encryption)?.parsedRoomEncryptionContent.algorithm;
/// Checks if this room is encrypted. /// Checks if this room is encrypted.
bool get encrypted => encryptionAlgorithm != null; bool get encrypted => encryptionAlgorithm != null;
@ -1920,7 +1910,7 @@ class Room {
/// Checks if the `m.room.create` state has a `type` key with the value /// Checks if the `m.room.create` state has a `type` key with the value
/// `m.space`. /// `m.space`.
bool get isSpace => bool get isSpace =>
getState(EventTypes.RoomCreate)?.content?.tryGet<String>('type') == getState(EventTypes.RoomCreate)?.content.tryGet<String>('type') ==
RoomCreationTypes.mSpace; // TODO: Magic string! RoomCreationTypes.mSpace; // TODO: Magic string!
/// The parents of this room. Currently this SDK doesn't yet set the canonical /// The parents of this room. Currently this SDK doesn't yet set the canonical
@ -1930,9 +1920,9 @@ class Room {
List<SpaceParent> get spaceParents => List<SpaceParent> get spaceParents =>
states[EventTypes.spaceParent] states[EventTypes.spaceParent]
?.values ?.values
?.map((state) => SpaceParent.fromState(state)) .map((state) => SpaceParent.fromState(state))
?.where((child) => child.via?.isNotEmpty ?? false) .where((child) => child.via?.isNotEmpty ?? false)
?.toList() ?? .toList() ??
[]; [];
/// List all children of this space. Children without a `via` domain will be /// List all children of this space. Children without a `via` domain will be
@ -1943,9 +1933,9 @@ class Room {
? throw Exception('Room is not a space!') ? throw Exception('Room is not a space!')
: (states[EventTypes.spaceChild] : (states[EventTypes.spaceChild]
?.values ?.values
?.map((state) => SpaceChild.fromState(state)) .map((state) => SpaceChild.fromState(state))
?.where((child) => child.via?.isNotEmpty ?? false) .where((child) => child.via?.isNotEmpty ?? false)
?.toList() ?? .toList() ??
[]) [])
..sort((a, b) => a.order.isEmpty || b.order.isEmpty ..sort((a, b) => a.order.isEmpty || b.order.isEmpty
? b.order.compareTo(a.order) ? b.order.compareTo(a.order)

View File

@ -187,10 +187,7 @@ class Timeline {
} }
int i; int i;
for (i = 0; i < events.length; i++) { for (i = 0; i < events.length; i++) {
final searchHaystack = <String>{}; final searchHaystack = <String>{events[i].eventId};
if (events[i].eventId != null) {
searchHaystack.add(events[i].eventId);
}
final txnid = events[i].unsigned?['transaction_id']; final txnid = events[i].unsigned?['transaction_id'];
if (txnid != null) { if (txnid != null) {

View File

@ -72,7 +72,7 @@ class User extends Event {
/// The displayname of the user if the user has set one. /// The displayname of the user if the user has set one.
String? get displayName => String? get displayName =>
content?.tryGet<String>('displayname') ?? content.tryGet<String>('displayname') ??
prevContent?.tryGet<String>('displayname'); prevContent?.tryGet<String>('displayname');
/// Returns the power level of this user. /// Returns the power level of this user.
@ -112,8 +112,8 @@ class User extends Event {
bool? formatLocalpart, bool? formatLocalpart,
bool? mxidLocalPartFallback, bool? mxidLocalPartFallback,
}) { }) {
formatLocalpart ??= room?.client?.formatLocalpart ?? true; formatLocalpart ??= room?.client.formatLocalpart ?? true;
mxidLocalPartFallback ??= room?.client?.mxidLocalPartFallback ?? true; mxidLocalPartFallback ??= room?.client.mxidLocalPartFallback ?? true;
final displayName = this.displayName; final displayName = this.displayName;
if (displayName != null && displayName.isNotEmpty) { if (displayName != null && displayName.isNotEmpty) {
return displayName; return displayName;

View File

@ -199,7 +199,7 @@ extension CommandsClientExtension on Client {
}); });
addCommand('discardsession', (CommandArgs args) async { addCommand('discardsession', (CommandArgs args) async {
await encryption?.keyManager await encryption?.keyManager
?.clearOrUseOutboundGroupSession(args.room.id, wipe: true); .clearOrUseOutboundGroupSession(args.room.id, wipe: true);
return ''; return '';
}); });
} }

View File

@ -75,9 +75,6 @@ class DeviceKeysList {
if (userId != client.userID) { if (userId != client.userID) {
// in-room verification with someone else // in-room verification with someone else
final roomId = await client.startDirectChat(userId); final roomId = await client.startDirectChat(userId);
if (roomId == null) {
throw Exception('Unable to start new room');
}
final room = final room =
client.getRoomById(roomId) ?? Room(id: roomId, client: client); client.getRoomById(roomId) ?? Room(id: roomId, client: client);

View File

@ -84,8 +84,8 @@ class CallCapabilities {
transferee: json['m.call.transferee'] as bool? ?? false, transferee: json['m.call.transferee'] as bool? ?? false,
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
if (transferee != null) 'm.call.transferee': transferee, 'm.call.transferee': transferee,
if (dtmf != null) 'm.call.dtmf': dtmf, 'm.call.dtmf': dtmf,
}; };
} }
@ -118,8 +118,8 @@ class SDPStreamPurpose {
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'purpose': purpose, 'purpose': purpose,
if (audio_muted != null) 'audio_muted': audio_muted, 'audio_muted': audio_muted,
if (video_muted != null) 'video_muted': video_muted, 'video_muted': video_muted,
}; };
} }

View File

@ -86,7 +86,7 @@ void main() {
try { try {
await matrix.checkHomeserver('https://fakeserver.wrongaddress'); await matrix.checkHomeserver('https://fakeserver.wrongaddress');
} catch (exception) { } catch (exception) {
expect(exception != null, true); expect(exception.toString().isNotEmpty, true);
} }
await matrix.checkHomeserver('https://fakeserver.notexisting', await matrix.checkHomeserver('https://fakeserver.notexisting',
checkWellKnown: false); checkWellKnown: false);
@ -311,7 +311,7 @@ void main() {
identifier: AuthenticationUserIdentifier(user: 'test'), identifier: AuthenticationUserIdentifier(user: 'test'),
password: '1234'); password: '1234');
expect(loginResp != null, true); expect(loginResp.userId != null, true);
}); });
test('setAvatar', () async { test('setAvatar', () async {

View File

@ -409,7 +409,7 @@ void main() {
client.encryption!.keyManager client.encryption!.keyManager
.getInboundGroupSession(roomId, sessionId, senderKey) .getInboundGroupSession(roomId, sessionId, senderKey)
?.forwardingCurve25519KeyChain ?.forwardingCurve25519KeyChain
?.length, .length,
1); 1);
// not set one with a higher first known index // not set one with a higher first known index
@ -435,7 +435,7 @@ void main() {
client.encryption!.keyManager client.encryption!.keyManager
.getInboundGroupSession(roomId, sessionId, senderKey) .getInboundGroupSession(roomId, sessionId, senderKey)
?.forwardingCurve25519KeyChain ?.forwardingCurve25519KeyChain
?.length, .length,
1); 1);
// set one with a lower first known index // set one with a lower first known index
@ -461,7 +461,7 @@ void main() {
client.encryption!.keyManager client.encryption!.keyManager
.getInboundGroupSession(roomId, sessionId, senderKey) .getInboundGroupSession(roomId, sessionId, senderKey)
?.forwardingCurve25519KeyChain ?.forwardingCurve25519KeyChain
?.length, .length,
1); 1);
// not set one with a longer forwarding chain // not set one with a longer forwarding chain
@ -487,7 +487,7 @@ void main() {
client.encryption!.keyManager client.encryption!.keyManager
.getInboundGroupSession(roomId, sessionId, senderKey) .getInboundGroupSession(roomId, sessionId, senderKey)
?.forwardingCurve25519KeyChain ?.forwardingCurve25519KeyChain
?.length, .length,
1); 1);
// set one with a shorter forwarding chain // set one with a shorter forwarding chain
@ -513,7 +513,7 @@ void main() {
client.encryption!.keyManager client.encryption!.keyManager
.getInboundGroupSession(roomId, sessionId, senderKey) .getInboundGroupSession(roomId, sessionId, senderKey)
?.forwardingCurve25519KeyChain ?.forwardingCurve25519KeyChain
?.length, .length,
0); 0);
// test that it decrypted the last event // test that it decrypted the last event

View File

@ -130,7 +130,6 @@ void main() {
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt); await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
await Future.delayed(Duration(milliseconds: 10)); await Future.delayed(Duration(milliseconds: 10));
await sub.cancel(); await sub.cancel();
expect(req2 != null, true);
expect( expect(
client2.encryption!.keyVerificationManager client2.encryption!.keyVerificationManager
@ -254,7 +253,6 @@ void main() {
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt); await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
await Future.delayed(Duration(milliseconds: 10)); await Future.delayed(Duration(milliseconds: 10));
await sub.cancel(); await sub.cancel();
expect(req2 != null, true);
// send ready // send ready
FakeMatrixApi.calledEndpoints.clear(); FakeMatrixApi.calledEndpoints.clear();
@ -389,7 +387,6 @@ void main() {
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt); await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
await Future.delayed(Duration(milliseconds: 10)); await Future.delayed(Duration(milliseconds: 10));
await sub.cancel(); await sub.cancel();
expect(req2 != null, true);
// send ready // send ready
FakeMatrixApi.calledEndpoints.clear(); FakeMatrixApi.calledEndpoints.clear();
@ -451,7 +448,6 @@ void main() {
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt); await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
await Future.delayed(Duration(milliseconds: 10)); await Future.delayed(Duration(milliseconds: 10));
await sub.cancel(); await sub.cancel();
expect(req2 != null, true);
await client2.encryption!.keyVerificationManager await client2.encryption!.keyVerificationManager
.handleEventUpdate(EventUpdate( .handleEventUpdate(EventUpdate(

View File

@ -42,7 +42,7 @@ void main() {
} }
if (olmEnabled) { if (olmEnabled) {
final encryptedFile = await file.encrypt(); final encryptedFile = await file.encrypt();
expect(encryptedFile != null, true); expect(encryptedFile.data.isNotEmpty, true);
} }
}); });
}); });

View File

@ -55,7 +55,7 @@ void test() async {
Logs().i('++++ (Alice) Leave all rooms ++++'); Logs().i('++++ (Alice) Leave all rooms ++++');
while (testClientA.rooms.isNotEmpty) { while (testClientA.rooms.isNotEmpty) {
final room = testClientA.rooms.first; final room = testClientA.rooms.first;
if (room.canonicalAlias?.isNotEmpty ?? false) { if (room.canonicalAlias.isNotEmpty) {
break; break;
} }
try { try {
@ -95,7 +95,6 @@ void test() async {
await testClientA.createRoom(invite: [TestUser.username2]); await testClientA.createRoom(invite: [TestUser.username2]);
await Future.delayed(Duration(seconds: 1)); await Future.delayed(Duration(seconds: 1));
final room = testClientA.rooms.first; final room = testClientA.rooms.first;
assert(room != null);
final roomId = room.id; final roomId = room.id;
Logs().i('++++ (Bob) Join room ++++'); Logs().i('++++ (Bob) Join room ++++');
@ -220,7 +219,7 @@ void test() async {
.client.encryption!.keyManager .client.encryption!.keyManager
.getOutboundGroupSession(inviteRoom.id)!; .getOutboundGroupSession(inviteRoom.id)!;
assert(inviteRoomOutboundGroupSession != null); assert(inviteRoomOutboundGroupSession.isValid);
/*assert(inviteRoom.client.encryption.keyManager.getInboundGroupSession( /*assert(inviteRoom.client.encryption.keyManager.getInboundGroupSession(
inviteRoom.id, inviteRoom.id,
inviteRoomOutboundGroupSession.outboundGroupSession.session_id(), inviteRoomOutboundGroupSession.outboundGroupSession.session_id(),
@ -237,7 +236,7 @@ void test() async {
"++++ (Alice) Received decrypted message: '${room.lastEvent!.body}' ++++"); "++++ (Alice) Received decrypted message: '${room.lastEvent!.body}' ++++");
Logs().i('++++ Login Bob in another client ++++'); Logs().i('++++ Login Bob in another client ++++');
var testClientC = Client('TestClientC', databaseBuilder: getDatabase); final testClientC = Client('TestClientC', databaseBuilder: getDatabase);
await testClientC.checkHomeserver(TestUser.homeserver); await testClientC.checkHomeserver(TestUser.homeserver);
await testClientC.login(LoginType.mLoginPassword, await testClientC.login(LoginType.mLoginPassword,
identifier: AuthenticationUserIdentifier(user: TestUser.username2), identifier: AuthenticationUserIdentifier(user: TestUser.username2),