Merge pull request #1597 from famedly/nico/stricter-lints
stricter lints
This commit is contained in:
commit
ee14fb7116
|
|
@ -2,19 +2,44 @@ include: package:lints/recommended.yaml
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
rules:
|
rules:
|
||||||
camel_case_types: true
|
# We enable a few additional rules not in the default and recommended sets.
|
||||||
avoid_print: true
|
# Those in general have low impact on correct code apart from possibly requiring an additional keyword (like async,
|
||||||
constant_identifier_names: true
|
# await, final) or asking you to move a statement to a different line. However many of these linter rules make the
|
||||||
prefer_final_locals: true
|
# code either more uniform or avoid bug prone behaviour. For example not awaiting a future usually is a mistake.
|
||||||
|
# You can always disable a linter warning with a comment like `// ignore: unawaited_futures`. Please add reasoning,
|
||||||
|
# why you disable the rule in such cases. This helps others understand, that you explicitly want a behaviour, that
|
||||||
|
# usually would be considered a mistake.
|
||||||
|
|
||||||
|
# Performance (or potential bugs)
|
||||||
|
# Fixing these warnings makes code easier to optimize for the compiler or prevents leaks.
|
||||||
|
cancel_subscriptions: true
|
||||||
prefer_final_in_for_each: true
|
prefer_final_in_for_each: true
|
||||||
sort_pub_dependencies: true
|
prefer_final_locals: true
|
||||||
always_use_package_imports: true
|
|
||||||
|
# Warn about possible bugs
|
||||||
|
# Usually code with these warnings indicates a bug.
|
||||||
|
# Please document if your code explicitly wants such a behaviour.
|
||||||
always_declare_return_types: true
|
always_declare_return_types: true
|
||||||
|
discarded_futures: true
|
||||||
|
no_adjacent_strings_in_list: true
|
||||||
|
test_types_in_equals: true
|
||||||
|
throw_in_finally: true
|
||||||
|
unawaited_futures: true
|
||||||
|
unnecessary_statements: true
|
||||||
|
unsafe_html: true
|
||||||
|
|
||||||
|
# Readability & Style
|
||||||
|
# These are opinionated choices, where Dart gives us 2 ways to express the same thing.
|
||||||
|
# This avoids mental overhead by not having to make a choice and making code more uniform to read.
|
||||||
|
always_use_package_imports: true
|
||||||
|
avoid_bool_literals_in_conditional_expressions: true
|
||||||
prefer_single_quotes: true
|
prefer_single_quotes: true
|
||||||
sort_child_properties_last: true
|
sort_child_properties_last: true
|
||||||
unawaited_futures: true
|
sort_pub_dependencies: true
|
||||||
unsafe_html: true
|
|
||||||
avoid_function_literals_in_foreach_calls: false
|
# Be nice to our users and allow them to configure what gets logged.
|
||||||
|
avoid_print: true
|
||||||
|
|
||||||
non_constant_identifier_names: false # seems to wrongly diagnose static const variables
|
non_constant_identifier_names: false # seems to wrongly diagnose static const variables
|
||||||
|
|
||||||
analyzer:
|
analyzer:
|
||||||
|
|
@ -22,6 +47,4 @@ analyzer:
|
||||||
todo: ignore
|
todo: ignore
|
||||||
exclude:
|
exclude:
|
||||||
- example/main.dart
|
- example/main.dart
|
||||||
# needed until crypto packages upgrade
|
|
||||||
- lib/src/database/database.g.dart
|
|
||||||
plugins:
|
plugins:
|
||||||
|
|
|
||||||
|
|
@ -100,11 +100,12 @@ class Encryption {
|
||||||
|
|
||||||
void handleDeviceOneTimeKeysCount(
|
void handleDeviceOneTimeKeysCount(
|
||||||
Map<String, int>? countJson, List<String>? unusedFallbackKeyTypes) {
|
Map<String, int>? countJson, List<String>? unusedFallbackKeyTypes) {
|
||||||
runInRoot(() => olmManager.handleDeviceOneTimeKeysCount(
|
runInRoot(() async => olmManager.handleDeviceOneTimeKeysCount(
|
||||||
countJson, unusedFallbackKeyTypes));
|
countJson, unusedFallbackKeyTypes));
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSync() {
|
void onSync() {
|
||||||
|
// ignore: discarded_futures
|
||||||
keyVerificationManager.cleanup();
|
keyVerificationManager.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,30 +119,25 @@ class Encryption {
|
||||||
.contains(event.type)) {
|
.contains(event.type)) {
|
||||||
// "just" room key request things. We don't need these asap, so we handle
|
// "just" room key request things. We don't need these asap, so we handle
|
||||||
// them in the background
|
// them in the background
|
||||||
// ignore: unawaited_futures
|
|
||||||
runInRoot(() => keyManager.handleToDeviceEvent(event));
|
runInRoot(() => keyManager.handleToDeviceEvent(event));
|
||||||
}
|
}
|
||||||
if (event.type == EventTypes.Dummy) {
|
if (event.type == EventTypes.Dummy) {
|
||||||
// the previous device just had to create a new olm session, due to olm session
|
// the previous device just had to create a new olm session, due to olm session
|
||||||
// corruption. We want to try to send it the last message we just sent it, if possible
|
// corruption. We want to try to send it the last message we just sent it, if possible
|
||||||
// ignore: unawaited_futures
|
|
||||||
runInRoot(() => olmManager.handleToDeviceEvent(event));
|
runInRoot(() => olmManager.handleToDeviceEvent(event));
|
||||||
}
|
}
|
||||||
if (event.type.startsWith('m.key.verification.')) {
|
if (event.type.startsWith('m.key.verification.')) {
|
||||||
// some key verification event. No need to handle it now, we can easily
|
// some key verification event. No need to handle it now, we can easily
|
||||||
// do this in the background
|
// do this in the background
|
||||||
|
|
||||||
// ignore: unawaited_futures
|
|
||||||
runInRoot(() => keyVerificationManager.handleToDeviceEvent(event));
|
runInRoot(() => keyVerificationManager.handleToDeviceEvent(event));
|
||||||
}
|
}
|
||||||
if (event.type.startsWith('m.secret.')) {
|
if (event.type.startsWith('m.secret.')) {
|
||||||
// some ssss thing. We can do this in the background
|
// some ssss thing. We can do this in the background
|
||||||
// ignore: unawaited_futures
|
|
||||||
runInRoot(() => ssss.handleToDeviceEvent(event));
|
runInRoot(() => ssss.handleToDeviceEvent(event));
|
||||||
}
|
}
|
||||||
if (event.sender == client.userID) {
|
if (event.sender == client.userID) {
|
||||||
// maybe we need to re-try SSSS secrets
|
// maybe we need to re-try SSSS secrets
|
||||||
// ignore: unawaited_futures
|
|
||||||
runInRoot(() => ssss.periodicallyRequestMissingCache());
|
runInRoot(() => ssss.periodicallyRequestMissingCache());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -157,14 +153,11 @@ class Encryption {
|
||||||
update.content['content']['msgtype']
|
update.content['content']['msgtype']
|
||||||
.startsWith('m.key.verification.'))) {
|
.startsWith('m.key.verification.'))) {
|
||||||
// "just" key verification, no need to do this in sync
|
// "just" key verification, no need to do this in sync
|
||||||
|
|
||||||
// ignore: unawaited_futures
|
|
||||||
runInRoot(() => keyVerificationManager.handleEventUpdate(update));
|
runInRoot(() => keyVerificationManager.handleEventUpdate(update));
|
||||||
}
|
}
|
||||||
if (update.content['sender'] == client.userID &&
|
if (update.content['sender'] == client.userID &&
|
||||||
update.content['unsigned']?['transaction_id'] == null) {
|
update.content['unsigned']?['transaction_id'] == null) {
|
||||||
// maybe we need to re-try SSSS secrets
|
// maybe we need to re-try SSSS secrets
|
||||||
// ignore: unawaited_futures
|
|
||||||
runInRoot(() => ssss.periodicallyRequestMissingCache());
|
runInRoot(() => ssss.periodicallyRequestMissingCache());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -239,6 +232,7 @@ class Encryption {
|
||||||
// the entry should always exist. In the case it doesn't, the following
|
// the entry should always exist. In the case it doesn't, the following
|
||||||
// line *could* throw an error. As that is a future, though, and we call
|
// line *could* throw an error. As that is a future, though, and we call
|
||||||
// it un-awaited here, nothing happens, which is exactly the result we want
|
// it un-awaited here, nothing happens, which is exactly the result we want
|
||||||
|
// ignore: discarded_futures
|
||||||
client.database?.updateInboundGroupSessionIndexes(
|
client.database?.updateInboundGroupSessionIndexes(
|
||||||
json.encode(inboundGroupSession.indexes), roomId, sessionId);
|
json.encode(inboundGroupSession.indexes), roomId, sessionId);
|
||||||
}
|
}
|
||||||
|
|
@ -252,7 +246,7 @@ class Encryption {
|
||||||
?.session_id() ??
|
?.session_id() ??
|
||||||
'') ==
|
'') ==
|
||||||
content.sessionId) {
|
content.sessionId) {
|
||||||
runInRoot(() =>
|
runInRoot(() async =>
|
||||||
keyManager.clearOrUseOutboundGroupSession(roomId, wipe: true));
|
keyManager.clearOrUseOutboundGroupSession(roomId, wipe: true));
|
||||||
}
|
}
|
||||||
if (canRequestSession) {
|
if (canRequestSession) {
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,8 @@ class KeyManager {
|
||||||
!client.isUnknownSession) {
|
!client.isUnknownSession) {
|
||||||
// do e2ee recovery
|
// do e2ee recovery
|
||||||
_requestedSessionIds.add(requestIdent);
|
_requestedSessionIds.add(requestIdent);
|
||||||
runInRoot(() => request(
|
|
||||||
|
runInRoot(() async => request(
|
||||||
room,
|
room,
|
||||||
sessionId,
|
sessionId,
|
||||||
senderKey,
|
senderKey,
|
||||||
|
|
@ -775,8 +776,8 @@ class KeyManager {
|
||||||
Future<void>? _uploadingFuture;
|
Future<void>? _uploadingFuture;
|
||||||
|
|
||||||
void startAutoUploadKeys() {
|
void startAutoUploadKeys() {
|
||||||
_uploadKeysOnSync = encryption.client.onSync.stream
|
_uploadKeysOnSync = encryption.client.onSync.stream.listen(
|
||||||
.listen((_) => uploadInboundGroupSessions(skipIfInProgress: true));
|
(_) async => uploadInboundGroupSessions(skipIfInProgress: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This task should be performed after sync processing but should not block
|
/// This task should be performed after sync processing but should not block
|
||||||
|
|
@ -1064,6 +1065,7 @@ class KeyManager {
|
||||||
StreamSubscription<SyncUpdate>? _uploadKeysOnSync;
|
StreamSubscription<SyncUpdate>? _uploadKeysOnSync;
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
// ignore: discarded_futures
|
||||||
_uploadKeysOnSync?.cancel();
|
_uploadKeysOnSync?.cancel();
|
||||||
for (final sess in _outboundGroupSessions.values) {
|
for (final sess in _outboundGroupSessions.values) {
|
||||||
sess.dispose();
|
sess.dispose();
|
||||||
|
|
|
||||||
|
|
@ -396,8 +396,8 @@ class OlmManager {
|
||||||
final device = client.userDeviceKeys[event.sender]?.deviceKeys.values
|
final device = client.userDeviceKeys[event.sender]?.deviceKeys.values
|
||||||
.firstWhereOrNull((d) => d.curve25519Key == senderKey);
|
.firstWhereOrNull((d) => d.curve25519Key == senderKey);
|
||||||
final existingSessions = olmSessions[senderKey];
|
final existingSessions = olmSessions[senderKey];
|
||||||
Future<void> updateSessionUsage([OlmSession? session]) =>
|
Future<void> updateSessionUsage([OlmSession? session]) async {
|
||||||
runInRoot(() async {
|
try {
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
session.lastReceived = DateTime.now();
|
session.lastReceived = DateTime.now();
|
||||||
await storeOlmSession(session);
|
await storeOlmSession(session);
|
||||||
|
|
@ -409,7 +409,11 @@ class OlmManager {
|
||||||
device.userId,
|
device.userId,
|
||||||
device.deviceId!);
|
device.deviceId!);
|
||||||
}
|
}
|
||||||
});
|
} catch (e, s) {
|
||||||
|
Logs().e('Error while updating olm session timestamp', e, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (existingSessions != null) {
|
if (existingSessions != null) {
|
||||||
for (final session in existingSessions) {
|
for (final session in existingSessions) {
|
||||||
if (session.session == null) {
|
if (session.session == null) {
|
||||||
|
|
@ -446,14 +450,16 @@ class OlmManager {
|
||||||
newSession.create_inbound_from(_olmAccount!, senderKey, body);
|
newSession.create_inbound_from(_olmAccount!, senderKey, body);
|
||||||
_olmAccount!.remove_one_time_keys(newSession);
|
_olmAccount!.remove_one_time_keys(newSession);
|
||||||
await encryption.olmDatabase?.updateClientKeys(pickledOlmAccount!);
|
await encryption.olmDatabase?.updateClientKeys(pickledOlmAccount!);
|
||||||
|
|
||||||
plaintext = newSession.decrypt(type, body);
|
plaintext = newSession.decrypt(type, body);
|
||||||
await runInRoot(() => storeOlmSession(OlmSession(
|
|
||||||
|
await storeOlmSession(OlmSession(
|
||||||
key: client.userID!,
|
key: client.userID!,
|
||||||
identityKey: senderKey,
|
identityKey: senderKey,
|
||||||
sessionId: newSession.session_id(),
|
sessionId: newSession.session_id(),
|
||||||
session: newSession,
|
session: newSession,
|
||||||
lastReceived: DateTime.now(),
|
lastReceived: DateTime.now(),
|
||||||
)));
|
));
|
||||||
await updateSessionUsage();
|
await updateSessionUsage();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
newSession.free();
|
newSession.free();
|
||||||
|
|
@ -570,8 +576,6 @@ class OlmManager {
|
||||||
return _decryptToDeviceEvent(event);
|
return _decryptToDeviceEvent(event);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// okay, the thing errored while decrypting. It is safe to assume that the olm session is corrupt and we should generate a new one
|
// okay, the thing errored while decrypting. It is safe to assume that the olm session is corrupt and we should generate a new one
|
||||||
|
|
||||||
// ignore: unawaited_futures
|
|
||||||
runInRoot(() => restoreOlmSession(event.senderId, senderKey));
|
runInRoot(() => restoreOlmSession(event.senderId, senderKey));
|
||||||
|
|
||||||
rethrow;
|
rethrow;
|
||||||
|
|
@ -658,14 +662,18 @@ class OlmManager {
|
||||||
final encryptResult = sess.first.session!.encrypt(json.encode(fullPayload));
|
final encryptResult = sess.first.session!.encrypt(json.encode(fullPayload));
|
||||||
await storeOlmSession(sess.first);
|
await storeOlmSession(sess.first);
|
||||||
if (encryption.olmDatabase != null) {
|
if (encryption.olmDatabase != null) {
|
||||||
await runInRoot(
|
try {
|
||||||
() async => encryption.olmDatabase?.setLastSentMessageUserDeviceKey(
|
await encryption.olmDatabase?.setLastSentMessageUserDeviceKey(
|
||||||
json.encode({
|
json.encode({
|
||||||
'type': type,
|
'type': type,
|
||||||
'content': payload,
|
'content': payload,
|
||||||
}),
|
}),
|
||||||
device.userId,
|
device.userId,
|
||||||
device.deviceId!));
|
device.deviceId!);
|
||||||
|
} catch (e, s) {
|
||||||
|
// we can ignore this error, since it would just make us use a different olm session possibly
|
||||||
|
Logs().w('Error while updating olm usage timestamp', e, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
final encryptedBody = <String, dynamic>{
|
final encryptedBody = <String, dynamic>{
|
||||||
'algorithm': AlgorithmTypes.olmV1Curve25519AesSha2,
|
'algorithm': AlgorithmTypes.olmV1Curve25519AesSha2,
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ import 'package:matrix/encryption/utils/ssss_cache.dart';
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
import 'package:matrix/src/utils/cached_stream_controller.dart';
|
import 'package:matrix/src/utils/cached_stream_controller.dart';
|
||||||
import 'package:matrix/src/utils/crypto/crypto.dart' as uc;
|
import 'package:matrix/src/utils/crypto/crypto.dart' as uc;
|
||||||
import 'package:matrix/src/utils/run_in_root.dart';
|
|
||||||
|
|
||||||
const cacheTypes = <String>{
|
const cacheTypes = <String>{
|
||||||
EventTypes.CrossSigningSelfSigning,
|
EventTypes.CrossSigningSelfSigning,
|
||||||
|
|
@ -722,7 +721,11 @@ class OpenSSSS {
|
||||||
throw InvalidPassphraseException('Inalid key');
|
throw InvalidPassphraseException('Inalid key');
|
||||||
}
|
}
|
||||||
if (postUnlock) {
|
if (postUnlock) {
|
||||||
await runInRoot(() => _postUnlock());
|
try {
|
||||||
|
await _postUnlock();
|
||||||
|
} catch (e, s) {
|
||||||
|
Logs().e('Error during post unlock', e, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import 'dart:typed_data';
|
||||||
|
|
||||||
/// decodes base64
|
/// decodes base64
|
||||||
///
|
///
|
||||||
/// Dart's native [base64.decode] requires a padded base64 input String.
|
/// Dart's native [base64.decode()] requires a padded base64 input String.
|
||||||
/// This function allows unpadded base64 too.
|
/// This function allows unpadded base64 too.
|
||||||
///
|
///
|
||||||
/// See: https://github.com/dart-lang/sdk/issues/39510
|
/// See: https://github.com/dart-lang/sdk/issues/39510
|
||||||
|
|
|
||||||
|
|
@ -267,11 +267,8 @@ class KeyVerification {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `qrCanWork` - qr cannot work if we are verifying another master key but our own is unverified
|
/// `qrCanWork` - qr cannot work if we are verifying another master key but our own is unverified
|
||||||
final qrCanWork = (userId != client.userID)
|
final qrCanWork = (userId == client.userID) ||
|
||||||
? ((client.userDeviceKeys[client.userID]?.masterKey?.verified ?? false)
|
((client.userDeviceKeys[client.userID]?.masterKey?.verified ?? false));
|
||||||
? true
|
|
||||||
: false)
|
|
||||||
: true;
|
|
||||||
|
|
||||||
if (client.verificationMethods.contains(KeyVerificationMethod.qrShow) &&
|
if (client.verificationMethods.contains(KeyVerificationMethod.qrShow) &&
|
||||||
qrCanWork) {
|
qrCanWork) {
|
||||||
|
|
|
||||||
|
|
@ -1636,7 +1636,7 @@ class Client extends MatrixApi {
|
||||||
set backgroundSync(bool enabled) {
|
set backgroundSync(bool enabled) {
|
||||||
_backgroundSync = enabled;
|
_backgroundSync = enabled;
|
||||||
if (_backgroundSync) {
|
if (_backgroundSync) {
|
||||||
_sync();
|
runInRoot(() async => _sync());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2232,7 +2232,7 @@ class Client extends MatrixApi {
|
||||||
requestHistoryOnLimitedTimeline) {
|
requestHistoryOnLimitedTimeline) {
|
||||||
Logs().v(
|
Logs().v(
|
||||||
'Limited timeline for ${rooms[roomIndex].id} request history now');
|
'Limited timeline for ${rooms[roomIndex].id} request history now');
|
||||||
unawaited(runInRoot(rooms[roomIndex].requestHistory));
|
runInRoot(rooms[roomIndex].requestHistory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return room;
|
return room;
|
||||||
|
|
|
||||||
|
|
@ -612,7 +612,7 @@ class HiveCollectionsDatabase extends DatabaseApi {
|
||||||
// post-load the heroes
|
// post-load the heroes
|
||||||
final heroes = room.summary.mHeroes;
|
final heroes = room.summary.mHeroes;
|
||||||
if (heroes != null) {
|
if (heroes != null) {
|
||||||
heroes.forEach((hero) => membersToPostload.add(hero));
|
membersToPostload.addAll(heroes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Load members
|
// Load members
|
||||||
|
|
@ -771,9 +771,9 @@ class HiveCollectionsDatabase extends DatabaseApi {
|
||||||
.toList();
|
.toList();
|
||||||
final states = await _roomMembersBox.getAll(keys);
|
final states = await _roomMembersBox.getAll(keys);
|
||||||
states.removeWhere((state) => state == null);
|
states.removeWhere((state) => state == null);
|
||||||
states.forEach(
|
for (final state in states) {
|
||||||
(state) => users.add(Event.fromJson(copyMap(state!), room).asUser),
|
users.add(Event.fromJson(copyMap(state!), room).asUser);
|
||||||
);
|
}
|
||||||
|
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ class Event extends MatrixEvent {
|
||||||
final json = toJson();
|
final json = toJson();
|
||||||
json['unsigned'] ??= <String, dynamic>{};
|
json['unsigned'] ??= <String, dynamic>{};
|
||||||
json['unsigned'][messageSendingStatusKey] = EventStatus.error.intValue;
|
json['unsigned'][messageSendingStatusKey] = EventStatus.error.intValue;
|
||||||
|
// ignore: discarded_futures
|
||||||
room.client.handleSync(
|
room.client.handleSync(
|
||||||
SyncUpdate(
|
SyncUpdate(
|
||||||
nextBatch: '',
|
nextBatch: '',
|
||||||
|
|
@ -154,6 +155,7 @@ class Event extends MatrixEvent {
|
||||||
MessageTypes.File,
|
MessageTypes.File,
|
||||||
}.contains(messageType) &&
|
}.contains(messageType) &&
|
||||||
!room.sendingFilePlaceholders.containsKey(eventId)) {
|
!room.sendingFilePlaceholders.containsKey(eventId)) {
|
||||||
|
// ignore: discarded_futures
|
||||||
remove();
|
remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1620,6 +1620,7 @@ class Room {
|
||||||
return user.asUser;
|
return user.asUser;
|
||||||
} else {
|
} else {
|
||||||
if (mxID.isValidMatrixId) {
|
if (mxID.isValidMatrixId) {
|
||||||
|
// ignore: discarded_futures
|
||||||
requestUser(
|
requestUser(
|
||||||
mxID,
|
mxID,
|
||||||
ignoreErrors: true,
|
ignoreErrors: true,
|
||||||
|
|
@ -2280,7 +2281,7 @@ class Room {
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<String, int> servers = {};
|
final Map<String, int> servers = {};
|
||||||
users.forEach((user) {
|
for (final user in users) {
|
||||||
if (user.id.domain != null) {
|
if (user.id.domain != null) {
|
||||||
if (servers.containsKey(user.id.domain!)) {
|
if (servers.containsKey(user.id.domain!)) {
|
||||||
servers[user.id.domain!] = servers[user.id.domain!]! + 1;
|
servers[user.id.domain!] = servers[user.id.domain!]! + 1;
|
||||||
|
|
@ -2288,7 +2289,7 @@ class Room {
|
||||||
servers[user.id.domain!] = 1;
|
servers[user.id.domain!] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
final sortedServers = Map.fromEntries(servers.entries.toList()
|
final sortedServers = Map.fromEntries(servers.entries.toList()
|
||||||
..sort((e1, e2) => e1.value.compareTo(e2.value)));
|
..sort((e1, e2) => e1.value.compareTo(e2.value)));
|
||||||
for (var i = 0; i <= 2; i++) {
|
for (var i = 0; i <= 2; i++) {
|
||||||
|
|
|
||||||
|
|
@ -300,8 +300,11 @@ class Timeline {
|
||||||
|
|
||||||
/// Don't forget to call this before you dismiss this object!
|
/// Don't forget to call this before you dismiss this object!
|
||||||
void cancelSubscriptions() {
|
void cancelSubscriptions() {
|
||||||
|
// ignore: discarded_futures
|
||||||
sub?.cancel();
|
sub?.cancel();
|
||||||
|
// ignore: discarded_futures
|
||||||
roomSub?.cancel();
|
roomSub?.cancel();
|
||||||
|
// ignore: discarded_futures
|
||||||
sessionIdReceivedSub?.cancel();
|
sessionIdReceivedSub?.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -433,17 +433,16 @@ class DeviceKeys extends SignableKey {
|
||||||
bool? _validSelfSignature;
|
bool? _validSelfSignature;
|
||||||
bool get selfSigned =>
|
bool get selfSigned =>
|
||||||
_validSelfSignature ??
|
_validSelfSignature ??
|
||||||
(_validSelfSignature = (deviceId != null &&
|
(_validSelfSignature = deviceId != null &&
|
||||||
signatures
|
signatures
|
||||||
?.tryGetMap<String, Object?>(userId)
|
?.tryGetMap<String, Object?>(userId)
|
||||||
?.tryGet<String>('ed25519:$deviceId') ==
|
?.tryGet<String>('ed25519:$deviceId') !=
|
||||||
null
|
null &&
|
||||||
? false
|
|
||||||
// without libolm we still want to be able to add devices. In that case we ofc just can't
|
// without libolm we still want to be able to add devices. In that case we ofc just can't
|
||||||
// verify the signature
|
// verify the signature
|
||||||
: _verifySignature(
|
_verifySignature(
|
||||||
ed25519Key!, signatures![userId]!['ed25519:$deviceId']!,
|
ed25519Key!, signatures![userId]!['ed25519:$deviceId']!,
|
||||||
isSignatureWithoutLibolmValid: true)));
|
isSignatureWithoutLibolmValid: true));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get blocked => super.blocked || !selfSigned;
|
bool get blocked => super.blocked || !selfSigned;
|
||||||
|
|
@ -505,7 +504,7 @@ class DeviceKeys extends SignableKey {
|
||||||
lastActive = DateTime.fromMillisecondsSinceEpoch(0);
|
lastActive = DateTime.fromMillisecondsSinceEpoch(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyVerification startVerification() {
|
Future<KeyVerification> startVerification() async {
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
throw Exception('setVerification called on invalid key');
|
throw Exception('setVerification called on invalid key');
|
||||||
}
|
}
|
||||||
|
|
@ -517,7 +516,7 @@ class DeviceKeys extends SignableKey {
|
||||||
final request = KeyVerification(
|
final request = KeyVerification(
|
||||||
encryption: encryption, userId: userId, deviceId: deviceId!);
|
encryption: encryption, userId: userId, deviceId: deviceId!);
|
||||||
|
|
||||||
request.start();
|
await request.start();
|
||||||
encryption.keyVerificationManager.addRequest(request);
|
encryption.keyVerificationManager.addRequest(request);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,9 @@ abstract class NativeImplementations {
|
||||||
bool retryInDummy = false,
|
bool retryInDummy = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
|
||||||
|
|
||||||
/// this implementation will catch any non-implemented method
|
/// this implementation will catch any non-implemented method
|
||||||
dynamic noSuchMethod(Invocation invocation) {
|
@override
|
||||||
|
dynamic noSuchMethod(Invocation invocation) async {
|
||||||
final dynamic argument = invocation.positionalArguments.single;
|
final dynamic argument = invocation.positionalArguments.single;
|
||||||
final memberName = invocation.memberName.toString().split('"')[1];
|
final memberName = invocation.memberName.toString().split('"')[1];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,13 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
Future<T?> runInRoot<T>(FutureOr<T> Function() fn) async {
|
void runInRoot<T>(FutureOr<T> Function() fn) {
|
||||||
return await Zone.root.run(() async {
|
// ignore: discarded_futures
|
||||||
|
Zone.root.run(() async {
|
||||||
try {
|
try {
|
||||||
return await fn();
|
await fn();
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logs().e('Error thrown in root zone', e, s);
|
Logs().e('Error thrown in root zone', e, s);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ class UiaRequest<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
UiaRequest({this.onUpdate, required this.request}) {
|
UiaRequest({this.onUpdate, required this.request}) {
|
||||||
|
// ignore: discarded_futures
|
||||||
_run();
|
_run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ class NativeImplementationsWebWorker extends NativeImplementations {
|
||||||
return completer.future.timeout(timeout);
|
return completer.future.timeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleIncomingMessage(MessageEvent event) {
|
Future<void> _handleIncomingMessage(MessageEvent event) async {
|
||||||
final data = event.data;
|
final data = event.data;
|
||||||
// don't forget handling errors of our second thread...
|
// don't forget handling errors of our second thread...
|
||||||
if (data['label'] == 'stacktrace') {
|
if (data['label'] == 'stacktrace') {
|
||||||
|
|
@ -46,12 +46,10 @@ class NativeImplementationsWebWorker extends NativeImplementations {
|
||||||
|
|
||||||
final error = event.data['error']!;
|
final error = event.data['error']!;
|
||||||
|
|
||||||
Future.value(
|
final stackTrace =
|
||||||
onStackTrace.call(event.data['stacktrace'] as String),
|
await onStackTrace.call(event.data['stacktrace'] as String);
|
||||||
).then(
|
completer?.completeError(
|
||||||
(stackTrace) => completer?.completeError(
|
|
||||||
WebWorkerError(error: error, stackTrace: stackTrace),
|
WebWorkerError(error: error, stackTrace: stackTrace),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final response = WebWorkerData.fromJson(event.data);
|
final response = WebWorkerData.fromJson(event.data);
|
||||||
|
|
|
||||||
|
|
@ -522,17 +522,18 @@ class CallSession {
|
||||||
await gotCallFeedsForAnswer(callFeeds);
|
await gotCallFeedsForAnswer(callFeeds);
|
||||||
}
|
}
|
||||||
|
|
||||||
void replacedBy(CallSession newCall) {
|
Future<void> replacedBy(CallSession newCall) async {
|
||||||
if (state == CallState.kWaitLocalMedia) {
|
if (state == CallState.kWaitLocalMedia) {
|
||||||
Logs().v('Telling new call to wait for local media');
|
Logs().v('Telling new call to wait for local media');
|
||||||
newCall.waitForLocalAVStream = true;
|
newCall.waitForLocalAVStream = true;
|
||||||
} else if (state == CallState.kCreateOffer ||
|
} else if (state == CallState.kCreateOffer ||
|
||||||
state == CallState.kInviteSent) {
|
state == CallState.kInviteSent) {
|
||||||
Logs().v('Handing local stream to new call');
|
Logs().v('Handing local stream to new call');
|
||||||
newCall.gotCallFeedsForAnswer(getLocalStreams);
|
await newCall.gotCallFeedsForAnswer(getLocalStreams);
|
||||||
}
|
}
|
||||||
successor = newCall;
|
successor = newCall;
|
||||||
onCallReplaced.add(newCall);
|
onCallReplaced.add(newCall);
|
||||||
|
// ignore: unawaited_futures
|
||||||
hangup(CallErrorCode.Replaced, true);
|
hangup(CallErrorCode.Replaced, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -698,7 +699,7 @@ class CallSession {
|
||||||
Logs().i(
|
Logs().i(
|
||||||
'Stream purpose update: \nid = "$streamId", \npurpose = "${sdpStreamMetadata.purpose}", \naudio_muted = ${sdpStreamMetadata.audio_muted}, \nvideo_muted = ${sdpStreamMetadata.video_muted}');
|
'Stream purpose update: \nid = "$streamId", \npurpose = "${sdpStreamMetadata.purpose}", \naudio_muted = ${sdpStreamMetadata.audio_muted}, \nvideo_muted = ${sdpStreamMetadata.video_muted}');
|
||||||
});
|
});
|
||||||
getRemoteStreams.forEach((wpstream) {
|
for (final wpstream in getRemoteStreams) {
|
||||||
final streamId = wpstream.stream!.id;
|
final streamId = wpstream.stream!.id;
|
||||||
final purpose = metadata.sdpStreamMetadatas[streamId];
|
final purpose = metadata.sdpStreamMetadatas[streamId];
|
||||||
if (purpose != null) {
|
if (purpose != null) {
|
||||||
|
|
@ -712,7 +713,7 @@ class CallSession {
|
||||||
wpstream.stopped = true;
|
wpstream.stopped = true;
|
||||||
fireCallEvent(CallEvent.kFeedsChanged);
|
fireCallEvent(CallEvent.kFeedsChanged);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onSDPStreamMetadataReceived(SDPStreamMetadata metadata) async {
|
Future<void> onSDPStreamMetadataReceived(SDPStreamMetadata metadata) async {
|
||||||
|
|
@ -1510,17 +1511,18 @@ class CallSession {
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void createDataChannel(String label, RTCDataChannelInit dataChannelDict) {
|
Future<void> createDataChannel(
|
||||||
pc?.createDataChannel(label, dataChannelDict);
|
String label, RTCDataChannelInit dataChannelDict) async {
|
||||||
|
await pc?.createDataChannel(label, dataChannelDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tryRemoveStopedStreams() async {
|
Future<void> tryRemoveStopedStreams() async {
|
||||||
final removedStreams = <String, WrappedMediaStream>{};
|
final removedStreams = <String, WrappedMediaStream>{};
|
||||||
streams.forEach((stream) {
|
for (final stream in streams) {
|
||||||
if (stream.stopped) {
|
if (stream.stopped) {
|
||||||
removedStreams[stream.stream!.id] = stream;
|
removedStreams[stream.stream!.id] = stream;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
streams
|
streams
|
||||||
.removeWhere((stream) => removedStreams.containsKey(stream.stream!.id));
|
.removeWhere((stream) => removedStreams.containsKey(stream.stream!.id));
|
||||||
for (final element in removedStreams.entries) {
|
for (final element in removedStreams.entries) {
|
||||||
|
|
@ -1561,9 +1563,9 @@ class CallSession {
|
||||||
try {
|
try {
|
||||||
if (candidatesQueue.isNotEmpty) {
|
if (candidatesQueue.isNotEmpty) {
|
||||||
final candidates = <Map<String, dynamic>>[];
|
final candidates = <Map<String, dynamic>>[];
|
||||||
candidatesQueue.forEach((element) {
|
for (final element in candidatesQueue) {
|
||||||
candidates.add(element.toMap());
|
candidates.add(element.toMap());
|
||||||
});
|
}
|
||||||
localCandidates = [];
|
localCandidates = [];
|
||||||
final res = await sendCallCandidates(
|
final res = await sendCallCandidates(
|
||||||
opts.room, callId, localPartyId, candidates);
|
opts.room, callId, localPartyId, candidates);
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,15 @@ class ConnectionTester {
|
||||||
|
|
||||||
await pc1!.setRemoteDescription(answer);
|
await pc1!.setRemoteDescription(answer);
|
||||||
|
|
||||||
void dispose() {
|
Future<void> dispose() async {
|
||||||
pc1!.close();
|
await Future.wait([
|
||||||
pc1!.dispose();
|
pc1!.close(),
|
||||||
pc2!.close();
|
pc2!.close(),
|
||||||
pc2!.dispose();
|
]);
|
||||||
|
await Future.wait([
|
||||||
|
pc1!.dispose(),
|
||||||
|
pc2!.dispose(),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
|
|
@ -69,6 +73,7 @@ class ConnectionTester {
|
||||||
.e('[VOIP] ConnectionTester Error while testing TURN server: ', e, s);
|
.e('[VOIP] ConnectionTester Error while testing TURN server: ', e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore: unawaited_futures
|
||||||
dispose();
|
dispose();
|
||||||
return connected;
|
return connected;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,8 +150,9 @@ class IGroupCallRoomMemberState {
|
||||||
List<IGroupCallRoomMemberCallState> calls = [];
|
List<IGroupCallRoomMemberCallState> calls = [];
|
||||||
IGroupCallRoomMemberState.fromJson(MatrixEvent event) {
|
IGroupCallRoomMemberState.fromJson(MatrixEvent event) {
|
||||||
if (event.content['m.calls'] != null) {
|
if (event.content['m.calls'] != null) {
|
||||||
(event.content['m.calls'] as List<dynamic>).forEach(
|
for (final call in (event.content['m.calls'] as List<dynamic>)) {
|
||||||
(call) => calls.add(IGroupCallRoomMemberCallState.fromJson(call)));
|
calls.add(IGroupCallRoomMemberCallState.fromJson(call));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -231,11 +232,11 @@ class GroupCall {
|
||||||
this.groupCallId = groupCallId ?? genCallID();
|
this.groupCallId = groupCallId ?? genCallID();
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupCall create() {
|
Future<GroupCall> create() async {
|
||||||
voip.groupCalls[groupCallId] = this;
|
voip.groupCalls[groupCallId] = this;
|
||||||
voip.groupCalls[room.id] = this;
|
voip.groupCalls[room.id] = this;
|
||||||
|
|
||||||
client.setRoomStateWithKey(
|
await client.setRoomStateWithKey(
|
||||||
room.id,
|
room.id,
|
||||||
EventTypes.GroupCallPrefix,
|
EventTypes.GroupCallPrefix,
|
||||||
groupCallId,
|
groupCallId,
|
||||||
|
|
@ -276,12 +277,12 @@ class GroupCall {
|
||||||
final List<MatrixEvent> events = [];
|
final List<MatrixEvent> events = [];
|
||||||
final roomStates = await client.getRoomState(room.id);
|
final roomStates = await client.getRoomState(room.id);
|
||||||
roomStates.sort((a, b) => a.originServerTs.compareTo(b.originServerTs));
|
roomStates.sort((a, b) => a.originServerTs.compareTo(b.originServerTs));
|
||||||
roomStates.forEach((value) {
|
for (final value in roomStates) {
|
||||||
if (value.type == EventTypes.GroupCallMemberPrefix &&
|
if (value.type == EventTypes.GroupCallMemberPrefix &&
|
||||||
!room.callMemberStateIsExpired(value, groupCallId)) {
|
!room.callMemberStateIsExpired(value, groupCallId)) {
|
||||||
events.add(value);
|
events.add(value);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -412,6 +413,7 @@ class GroupCall {
|
||||||
if (localUserMediaStream != null) {
|
if (localUserMediaStream != null) {
|
||||||
final oldStream = localUserMediaStream!.stream;
|
final oldStream = localUserMediaStream!.stream;
|
||||||
localUserMediaStream!.setNewStream(stream.stream!);
|
localUserMediaStream!.setNewStream(stream.stream!);
|
||||||
|
// ignore: discarded_futures
|
||||||
stopMediaStream(oldStream);
|
stopMediaStream(oldStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ Future<void> stopMediaStream(MediaStream? stream) async {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTracksEnabled(List<MediaStreamTrack> tracks, bool enabled) {
|
void setTracksEnabled(List<MediaStreamTrack> tracks, bool enabled) {
|
||||||
tracks.forEach((element) {
|
for (final element in tracks) {
|
||||||
element.enabled = enabled;
|
element.enabled = enabled;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> hasAudioDevice() async {
|
Future<bool> hasAudioDevice() async {
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ class VoIP {
|
||||||
for (final room in client.rooms) {
|
for (final room in client.rooms) {
|
||||||
if (room.activeGroupCallEvents.isNotEmpty) {
|
if (room.activeGroupCallEvents.isNotEmpty) {
|
||||||
for (final groupCall in room.activeGroupCallEvents) {
|
for (final groupCall in room.activeGroupCallEvents) {
|
||||||
|
// ignore: discarded_futures
|
||||||
createGroupCallFromRoomStateEvent(groupCall,
|
createGroupCallFromRoomStateEvent(groupCall,
|
||||||
emitHandleNewGroupCall: false);
|
emitHandleNewGroupCall: false);
|
||||||
}
|
}
|
||||||
|
|
@ -589,7 +590,7 @@ class VoIP {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final groupId = genCallID();
|
final groupId = genCallID();
|
||||||
final groupCall = GroupCall(
|
final groupCall = await GroupCall(
|
||||||
groupCallId: groupId,
|
groupCallId: groupId,
|
||||||
client: client,
|
client: client,
|
||||||
voip: this,
|
voip: this,
|
||||||
|
|
|
||||||
|
|
@ -1137,8 +1137,8 @@ void main() {
|
||||||
reason: '!5345234235:example.com not found as archived room');
|
reason: '!5345234235:example.com not found as archived room');
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() {
|
tearDown(() async {
|
||||||
matrix.dispose(closeDatabase: true);
|
await matrix.dispose(closeDatabase: true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,30 +28,10 @@ import 'fake_database.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('HiveCollections Database Test', () {
|
group('HiveCollections Database Test', () {
|
||||||
testDatabase(
|
|
||||||
getHiveCollectionsDatabase(null),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> olmEnabled() async {
|
|
||||||
var olmEnabled = true;
|
|
||||||
try {
|
|
||||||
await olm.init();
|
|
||||||
olm.get_library_version();
|
|
||||||
} catch (e) {
|
|
||||||
olmEnabled = false;
|
|
||||||
}
|
|
||||||
return olmEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testDatabase(
|
|
||||||
Future<DatabaseApi> futureDatabase,
|
|
||||||
) {
|
|
||||||
late DatabaseApi database;
|
late DatabaseApi database;
|
||||||
late int toDeviceQueueIndex;
|
late int toDeviceQueueIndex;
|
||||||
test('Open', () async {
|
test('Open', () async {
|
||||||
database = await futureDatabase;
|
database = await getHiveCollectionsDatabase(null);
|
||||||
});
|
});
|
||||||
test('transaction', () async {
|
test('transaction', () async {
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
|
|
@ -231,7 +211,8 @@ void testDatabase(
|
||||||
expect(users.isEmpty, true);
|
expect(users.isEmpty, true);
|
||||||
});
|
});
|
||||||
test('removeEvent', () async {
|
test('removeEvent', () async {
|
||||||
await database.removeEvent('\$event:example.com', '!testroom:example.com');
|
await database.removeEvent(
|
||||||
|
'\$event:example.com', '!testroom:example.com');
|
||||||
final event = await database.getEventById('\$event:example.com',
|
final event = await database.getEventById('\$event:example.com',
|
||||||
Room(id: '!testroom:example.com', client: Client('testclient')));
|
Room(id: '!testroom:example.com', client: Client('testclient')));
|
||||||
expect(event, null);
|
expect(event, null);
|
||||||
|
|
@ -241,7 +222,8 @@ void testDatabase(
|
||||||
expect(result.isEmpty, true);
|
expect(result.isEmpty, true);
|
||||||
});
|
});
|
||||||
test('getInboundGroupSession', () async {
|
test('getInboundGroupSession', () async {
|
||||||
await database.getInboundGroupSession('!testroom:example.com', 'sessionId');
|
await database.getInboundGroupSession(
|
||||||
|
'!testroom:example.com', 'sessionId');
|
||||||
});
|
});
|
||||||
test('getInboundGroupSessionsToUpload', () async {
|
test('getInboundGroupSessionsToUpload', () async {
|
||||||
await database.getInboundGroupSessionsToUpload();
|
await database.getInboundGroupSessionsToUpload();
|
||||||
|
|
@ -490,5 +472,16 @@ void testDatabase(
|
||||||
test('Close', () async {
|
test('Close', () async {
|
||||||
await database.close();
|
await database.close();
|
||||||
});
|
});
|
||||||
return;
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> olmEnabled() async {
|
||||||
|
var olmEnabled = true;
|
||||||
|
try {
|
||||||
|
await olm.init();
|
||||||
|
olm.get_library_version();
|
||||||
|
} catch (e) {
|
||||||
|
olmEnabled = false;
|
||||||
|
}
|
||||||
|
return olmEnabled;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ void main() {
|
||||||
|
|
||||||
test('start verification', () async {
|
test('start verification', () async {
|
||||||
if (!olmEnabled) return;
|
if (!olmEnabled) return;
|
||||||
var req = client
|
var req = await client
|
||||||
.userDeviceKeys['@alice:example.com']?.deviceKeys['JLAFKJWSCS']
|
.userDeviceKeys['@alice:example.com']?.deviceKeys['JLAFKJWSCS']
|
||||||
?.startVerification();
|
?.startVerification();
|
||||||
expect(req != null, true);
|
expect(req != null, true);
|
||||||
|
|
|
||||||
|
|
@ -123,9 +123,9 @@ void main() {
|
||||||
0);
|
0);
|
||||||
|
|
||||||
// rotate after too many messages
|
// rotate after too many messages
|
||||||
Iterable.generate(300).forEach((_) {
|
for (final _ in Iterable.generate(300)) {
|
||||||
sess.outboundGroupSession!.encrypt('some string');
|
sess.outboundGroupSession!.encrypt('some string');
|
||||||
});
|
}
|
||||||
await client.encryption!.keyManager
|
await client.encryption!.keyManager
|
||||||
.clearOrUseOutboundGroupSession(roomId);
|
.clearOrUseOutboundGroupSession(roomId);
|
||||||
expect(
|
expect(
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,7 @@ class FakeMatrixApi extends BaseClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// and generate a fake sync
|
// and generate a fake sync
|
||||||
|
// ignore: discarded_futures
|
||||||
_client!.handleSync(sdk.SyncUpdate(nextBatch: ''));
|
_client!.handleSync(sdk.SyncUpdate(nextBatch: ''));
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ void main() {
|
||||||
insertList.clear();
|
insertList.clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() => client.dispose().onError((e, s) {}));
|
tearDown(() async => client.dispose().onError((e, s) {}));
|
||||||
|
|
||||||
test('archive room not loaded', () async {
|
test('archive room not loaded', () async {
|
||||||
final archiveRoom =
|
final archiveRoom =
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ void main() {
|
||||||
var olmEnabled = true;
|
var olmEnabled = true;
|
||||||
|
|
||||||
final countStream = StreamController<int>.broadcast();
|
final countStream = StreamController<int>.broadcast();
|
||||||
Future<int> waitForCount(int count) {
|
Future<int> waitForCount(int count) async {
|
||||||
if (updateCount == count) {
|
if (updateCount == count) {
|
||||||
return Future.value(updateCount);
|
return Future.value(updateCount);
|
||||||
}
|
}
|
||||||
|
|
@ -46,9 +46,9 @@ void main() {
|
||||||
final completer = Completer<int>();
|
final completer = Completer<int>();
|
||||||
|
|
||||||
StreamSubscription<int>? sub;
|
StreamSubscription<int>? sub;
|
||||||
sub = countStream.stream.listen((newCount) {
|
sub = countStream.stream.listen((newCount) async {
|
||||||
if (newCount == count) {
|
if (newCount == count) {
|
||||||
sub?.cancel();
|
await sub?.cancel();
|
||||||
completer.complete(count);
|
completer.complete(count);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -100,7 +100,8 @@ void main() {
|
||||||
testTimeStamp = DateTime.now().millisecondsSinceEpoch;
|
testTimeStamp = DateTime.now().millisecondsSinceEpoch;
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() => client.dispose(closeDatabase: true).onError((e, s) {}));
|
tearDown(
|
||||||
|
() async => client.dispose(closeDatabase: true).onError((e, s) {}));
|
||||||
|
|
||||||
test('Request future', () async {
|
test('Request future', () async {
|
||||||
timeline.events.clear();
|
timeline.events.clear();
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ void main() {
|
||||||
var currentPoison = 0;
|
var currentPoison = 0;
|
||||||
|
|
||||||
final countStream = StreamController<int>.broadcast();
|
final countStream = StreamController<int>.broadcast();
|
||||||
Future<int> waitForCount(int count) {
|
Future<int> waitForCount(int count) async {
|
||||||
if (updateCount == count) {
|
if (updateCount == count) {
|
||||||
return Future.value(updateCount);
|
return Future.value(updateCount);
|
||||||
}
|
}
|
||||||
|
|
@ -47,9 +47,9 @@ void main() {
|
||||||
final completer = Completer<int>();
|
final completer = Completer<int>();
|
||||||
|
|
||||||
StreamSubscription<int>? sub;
|
StreamSubscription<int>? sub;
|
||||||
sub = countStream.stream.listen((newCount) {
|
sub = countStream.stream.listen((newCount) async {
|
||||||
if (newCount == count) {
|
if (newCount == count) {
|
||||||
sub?.cancel();
|
await sub?.cancel();
|
||||||
completer.complete(count);
|
completer.complete(count);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -109,7 +109,8 @@ void main() {
|
||||||
testTimeStamp = DateTime.now().millisecondsSinceEpoch;
|
testTimeStamp = DateTime.now().millisecondsSinceEpoch;
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() => client.dispose(closeDatabase: true).onError((e, s) {}));
|
tearDown(
|
||||||
|
() async => client.dispose(closeDatabase: true).onError((e, s) {}));
|
||||||
|
|
||||||
test('Create', () async {
|
test('Create', () async {
|
||||||
client.onEvent.add(EventUpdate(
|
client.onEvent.add(EventUpdate(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue