Merge branch 'nico/nullsafe' into 'main'
Make SDK nullsafe Closes #201 See merge request famedly/company/frontend/famedlysdk!867
This commit is contained in:
commit
6ee5771334
|
|
@ -11,10 +11,6 @@ linter:
|
|||
analyzer:
|
||||
errors:
|
||||
todo: 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:
|
||||
- example/main.dart
|
||||
# needed until crypto packages upgrade
|
||||
|
|
|
|||
|
|
@ -90,9 +90,11 @@ class CrossSigning {
|
|||
final masterPrivateKey =
|
||||
base64.decode(await handle.getStored(EventTypes.CrossSigningMasterKey));
|
||||
final keyObj = olm.PkSigning();
|
||||
String masterPubkey;
|
||||
String? masterPubkey;
|
||||
try {
|
||||
masterPubkey = keyObj.init_with_seed(masterPrivateKey);
|
||||
} catch (e) {
|
||||
masterPubkey = null;
|
||||
} finally {
|
||||
keyObj.free();
|
||||
}
|
||||
|
|
@ -131,9 +133,6 @@ class CrossSigning {
|
|||
|
||||
final addSignature =
|
||||
(SignableKey key, SignableKey signedWith, String signature) {
|
||||
if (key == null || signedWith == null || signature == null) {
|
||||
return;
|
||||
}
|
||||
final signedKey = key.cloneForSigning();
|
||||
((signedKey.signatures ??=
|
||||
<String, Map<String, String>>{})[signedWith.userId] ??=
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ class Encryption {
|
|||
crossSigning = CrossSigning(this);
|
||||
}
|
||||
|
||||
Future<void> init(String olmAccount) async {
|
||||
// initial login passes null to init a new olm account
|
||||
Future<void> init(String? olmAccount) async {
|
||||
await olmManager.init(olmAccount);
|
||||
_backgroundTasksRunning = true;
|
||||
_backgroundTasks(); // start the background tasks
|
||||
|
|
@ -86,7 +87,7 @@ class Encryption {
|
|||
);
|
||||
|
||||
void handleDeviceOneTimeKeysCount(
|
||||
Map<String, int> countJson, List<String> unusedFallbackKeyTypes) {
|
||||
Map<String, int>? countJson, List<String>? unusedFallbackKeyTypes) {
|
||||
runInRoot(() => olmManager.handleDeviceOneTimeKeysCount(
|
||||
countJson, unusedFallbackKeyTypes));
|
||||
}
|
||||
|
|
@ -308,9 +309,10 @@ class Encryption {
|
|||
await client.database?.storeEventUpdate(
|
||||
EventUpdate(
|
||||
content: event.toJson(),
|
||||
roomID: event.roomId,
|
||||
roomID: roomId,
|
||||
type: updateType,
|
||||
),
|
||||
client,
|
||||
);
|
||||
}
|
||||
return event;
|
||||
|
|
@ -374,12 +376,13 @@ class Encryption {
|
|||
|
||||
Future<void> autovalidateMasterOwnKey() async {
|
||||
// check if we can set our own master key as verified, if it isn't yet
|
||||
final masterKey = client.userDeviceKeys[client.userID]?.masterKey;
|
||||
final userId = client.userID;
|
||||
final masterKey = client.userDeviceKeys[userId]?.masterKey;
|
||||
if (client.database != null &&
|
||||
masterKey != null &&
|
||||
userId != null &&
|
||||
!masterKey.directVerified &&
|
||||
masterKey
|
||||
.hasValidSignatureChain(onlyValidateUserIds: {client.userID})) {
|
||||
masterKey.hasValidSignatureChain(onlyValidateUserIds: {userId})) {
|
||||
await masterKey.setVerified(true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ class KeyManager {
|
|||
_requestedSessionIds.clear();
|
||||
for (final room in client.rooms) {
|
||||
final lastEvent = room.lastEvent;
|
||||
if (lastEvent.type == EventTypes.Encrypted &&
|
||||
if (lastEvent != null &&
|
||||
lastEvent.type == EventTypes.Encrypted &&
|
||||
lastEvent.content['can_request_session'] == true) {
|
||||
try {
|
||||
maybeAutoRequest(room.id, lastEvent.content['session_id'],
|
||||
|
|
@ -95,6 +96,8 @@ class KeyManager {
|
|||
}) {
|
||||
final senderClaimedKeys_ = senderClaimedKeys ?? <String, String>{};
|
||||
final allowedAtIndex_ = allowedAtIndex ?? <String, Map<String, int>>{};
|
||||
final userId = client.userID;
|
||||
if (userId == null) return;
|
||||
|
||||
if (!senderClaimedKeys_.containsKey('ed25519')) {
|
||||
final device = client.getUserDeviceKeysByCurve25519Key(senderKey);
|
||||
|
|
@ -126,7 +129,7 @@ class KeyManager {
|
|||
indexes: {},
|
||||
roomId: roomId,
|
||||
sessionId: sessionId,
|
||||
key: client.userID,
|
||||
key: userId,
|
||||
senderKey: senderKey,
|
||||
senderClaimedKeys: senderClaimedKeys_,
|
||||
allowedAtIndex: allowedAtIndex_,
|
||||
|
|
@ -157,7 +160,7 @@ class KeyManager {
|
|||
?.storeInboundGroupSession(
|
||||
roomId,
|
||||
sessionId,
|
||||
inboundGroupSession.pickle(client.userID),
|
||||
inboundGroupSession.pickle(userId),
|
||||
json.encode(content),
|
||||
json.encode({}),
|
||||
json.encode(allowedAtIndex_),
|
||||
|
|
@ -169,7 +172,7 @@ class KeyManager {
|
|||
return;
|
||||
}
|
||||
if (uploaded) {
|
||||
client.database.markInboundGroupSessionAsUploaded(roomId, sessionId);
|
||||
client.database?.markInboundGroupSessionAsUploaded(roomId, sessionId);
|
||||
} else {
|
||||
_haveKeysToUpload = true;
|
||||
}
|
||||
|
|
@ -239,10 +242,10 @@ class KeyManager {
|
|||
}
|
||||
final session =
|
||||
await client.database?.getInboundGroupSession(roomId, sessionId);
|
||||
if (session == null) {
|
||||
return null;
|
||||
}
|
||||
final dbSess = SessionKey.fromDb(session, client.userID);
|
||||
if (session == null) return null;
|
||||
final userID = client.userID;
|
||||
if (userID == null) return null;
|
||||
final dbSess = SessionKey.fromDb(session, userID);
|
||||
final roomInboundGroupSessions =
|
||||
_inboundGroupSessions[roomId] ??= <String, SessionKey>{};
|
||||
if (!dbSess.isValid ||
|
||||
|
|
@ -394,12 +397,10 @@ class KeyManager {
|
|||
sess.outboundGroupSession!.message_index();
|
||||
}
|
||||
}
|
||||
if (client.database != null) {
|
||||
await client.database.updateInboundGroupSessionAllowedAtIndex(
|
||||
json.encode(inboundSess!.allowedAtIndex),
|
||||
room.id,
|
||||
sess.outboundGroupSession!.session_id());
|
||||
}
|
||||
await client.database?.updateInboundGroupSessionAllowedAtIndex(
|
||||
json.encode(inboundSess!.allowedAtIndex),
|
||||
room.id,
|
||||
sess.outboundGroupSession!.session_id());
|
||||
// send out the key
|
||||
await client.sendToDeviceEncryptedChunked(
|
||||
devicesToReceive, EventTypes.RoomKey, rawSession);
|
||||
|
|
@ -422,9 +423,11 @@ class KeyManager {
|
|||
/// Store an outbound group session in the database
|
||||
Future<void> storeOutboundGroupSession(
|
||||
String roomId, OutboundGroupSession sess) async {
|
||||
final userID = client.userID;
|
||||
if (userID == null) return;
|
||||
await client.database?.storeOutboundGroupSession(
|
||||
roomId,
|
||||
sess.outboundGroupSession!.pickle(client.userID),
|
||||
sess.outboundGroupSession!.pickle(userID),
|
||||
json.encode(sess.devices),
|
||||
sess.creationTime.millisecondsSinceEpoch);
|
||||
}
|
||||
|
|
@ -464,6 +467,12 @@ class KeyManager {
|
|||
throw Exception(
|
||||
'Tried to create a megolm session in a non-existing room ($roomId)!');
|
||||
}
|
||||
final userID = client.userID;
|
||||
if (userID == null) {
|
||||
throw Exception(
|
||||
'Tried to create a megolm session without being logged in!');
|
||||
}
|
||||
|
||||
final deviceKeys = await room.getUserDeviceKeys();
|
||||
final deviceKeyIds = _getDeviceKeyIdMap(deviceKeys);
|
||||
deviceKeys.removeWhere((k) => !k.encryptToDevice);
|
||||
|
|
@ -498,7 +507,7 @@ class KeyManager {
|
|||
devices: deviceKeyIds,
|
||||
creationTime: DateTime.now(),
|
||||
outboundGroupSession: outboundGroupSession,
|
||||
key: client.userID,
|
||||
key: userID,
|
||||
);
|
||||
try {
|
||||
await client.sendToDeviceEncryptedChunked(
|
||||
|
|
@ -523,15 +532,18 @@ class KeyManager {
|
|||
|
||||
/// Load an outbound group session from database
|
||||
Future<void> loadOutboundGroupSession(String roomId) async {
|
||||
final database = client.database;
|
||||
final userID = client.userID;
|
||||
if (_loadedOutboundGroupSessions.contains(roomId) ||
|
||||
_outboundGroupSessions.containsKey(roomId) ||
|
||||
client.database == null) {
|
||||
database == null ||
|
||||
userID == null) {
|
||||
return; // nothing to do
|
||||
}
|
||||
_loadedOutboundGroupSessions.add(roomId);
|
||||
final sess = await client.database.getOutboundGroupSession(
|
||||
final sess = await database.getOutboundGroupSession(
|
||||
roomId,
|
||||
client.userID,
|
||||
userID,
|
||||
);
|
||||
if (sess == null || !sess.isValid) {
|
||||
return;
|
||||
|
|
@ -699,7 +711,9 @@ class KeyManager {
|
|||
bool _isUploadingKeys = false;
|
||||
bool _haveKeysToUpload = true;
|
||||
Future<void> backgroundTasks() async {
|
||||
if (_isUploadingKeys || client.database == null) {
|
||||
final database = client.database;
|
||||
final userID = client.userID;
|
||||
if (_isUploadingKeys || database == null || userID == null) {
|
||||
return;
|
||||
}
|
||||
_isUploadingKeys = true;
|
||||
|
|
@ -707,8 +721,7 @@ class KeyManager {
|
|||
if (!_haveKeysToUpload || !(await isCached())) {
|
||||
return; // we can't backup anyways
|
||||
}
|
||||
final dbSessions =
|
||||
await client.database.getInboundGroupSessionsToUpload();
|
||||
final dbSessions = await database.getInboundGroupSessionsToUpload();
|
||||
if (dbSessions.isEmpty) {
|
||||
_haveKeysToUpload = false;
|
||||
return; // nothing to do
|
||||
|
|
@ -730,7 +743,7 @@ class KeyManager {
|
|||
final args = _GenerateUploadKeysArgs(
|
||||
pubkey: backupPubKey,
|
||||
dbSessions: <_DbInboundGroupSessionBundle>[],
|
||||
userId: client.userID,
|
||||
userId: userID,
|
||||
);
|
||||
// we need to calculate verified beforehand, as else we pass a closure to an isolate
|
||||
// with 500 keys they do, however, noticably block the UI, which is why we give brief async suspentions in here
|
||||
|
|
@ -741,7 +754,7 @@ class KeyManager {
|
|||
client.getUserDeviceKeysByCurve25519Key(dbSession.senderKey);
|
||||
args.dbSessions.add(_DbInboundGroupSessionBundle(
|
||||
dbSession: dbSession,
|
||||
verified: device.verified,
|
||||
verified: device?.verified ?? false,
|
||||
));
|
||||
i++;
|
||||
if (i > 10) {
|
||||
|
|
@ -758,7 +771,7 @@ class KeyManager {
|
|||
// and now finally mark all the keys as uploaded
|
||||
// no need to optimze this, as we only run it so seldomly and almost never with many keys at once
|
||||
for (final dbSession in dbSessions) {
|
||||
await client.database.markInboundGroupSessionAsUploaded(
|
||||
await database.markInboundGroupSessionAsUploaded(
|
||||
dbSession.roomId, dbSession.sessionId);
|
||||
}
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class OlmManager {
|
|||
/// Returns the base64 encoded keys to store them in a store.
|
||||
/// This String should **never** leave the device!
|
||||
String? get pickledOlmAccount =>
|
||||
enabled ? _olmAccount!.pickle(client.userID) : null;
|
||||
enabled ? _olmAccount!.pickle(client.userID!) : null;
|
||||
String? get fingerprintKey =>
|
||||
enabled ? json.decode(_olmAccount!.identity_keys())['ed25519'] : null;
|
||||
String? get identityKey =>
|
||||
|
|
@ -57,8 +57,7 @@ class OlmManager {
|
|||
await olm.init();
|
||||
_olmAccount = olm.Account();
|
||||
_olmAccount!.create();
|
||||
if (await uploadKeys(uploadDeviceKeys: true, updateDatabase: false) ==
|
||||
false) {
|
||||
if (!await uploadKeys(uploadDeviceKeys: true, updateDatabase: false)) {
|
||||
throw ('Upload key failed');
|
||||
}
|
||||
} catch (_) {
|
||||
|
|
@ -70,7 +69,7 @@ class OlmManager {
|
|||
try {
|
||||
await olm.init();
|
||||
_olmAccount = olm.Account();
|
||||
_olmAccount!.unpickle(client.userID, olmAccount);
|
||||
_olmAccount!.unpickle(client.userID!, olmAccount);
|
||||
} catch (_) {
|
||||
_olmAccount?.free();
|
||||
_olmAccount = null;
|
||||
|
|
@ -279,7 +278,7 @@ class OlmManager {
|
|||
// fixup accidental too many uploads. We delete only one of them so that the server has time to update the counts and because we will get rate limited anyway.
|
||||
if (keyCount > _olmAccount!.max_number_of_one_time_keys()) {
|
||||
final requestingKeysFrom = {
|
||||
client.userID: {client.deviceID: 'signed_curve25519'}
|
||||
client.userID!: {client.deviceID!: 'signed_curve25519'}
|
||||
};
|
||||
client.claimKeys(requestingKeysFrom, timeout: 10000);
|
||||
}
|
||||
|
|
@ -311,10 +310,7 @@ class OlmManager {
|
|||
// update an existing session
|
||||
_olmSessions[session.identityKey]![ix] = session;
|
||||
}
|
||||
if (client.database == null) {
|
||||
return;
|
||||
}
|
||||
await client.database.storeOlmSession(
|
||||
await client.database?.storeOlmSession(
|
||||
session.identityKey,
|
||||
session.sessionId!,
|
||||
session.pickledSession!,
|
||||
|
|
@ -362,7 +358,7 @@ class OlmManager {
|
|||
if (session.session == null) {
|
||||
continue;
|
||||
}
|
||||
if (type == 0 && session.session!.matches_inbound(body) == true) {
|
||||
if (type == 0 && session.session!.matches_inbound(body)) {
|
||||
try {
|
||||
plaintext = session.session!.decrypt(type, body);
|
||||
} catch (e) {
|
||||
|
|
@ -395,7 +391,7 @@ class OlmManager {
|
|||
client.database?.updateClientKeys(pickledOlmAccount!);
|
||||
plaintext = newSession.decrypt(type, body);
|
||||
runInRoot(() => storeOlmSession(OlmSession(
|
||||
key: client.userID,
|
||||
key: client.userID!,
|
||||
identityKey: senderKey,
|
||||
sessionId: newSession.session_id(),
|
||||
session: newSession,
|
||||
|
|
@ -428,25 +424,19 @@ class OlmManager {
|
|||
}
|
||||
|
||||
Future<List<OlmSession>> getOlmSessionsFromDatabase(String senderKey) async {
|
||||
if (client.database == null) {
|
||||
return [];
|
||||
}
|
||||
final olmSessions =
|
||||
await client.database.getOlmSessions(senderKey, client.userID);
|
||||
return olmSessions.where((sess) => sess.isValid).toList();
|
||||
await client.database?.getOlmSessions(senderKey, client.userID!);
|
||||
return olmSessions?.where((sess) => sess.isValid).toList() ?? [];
|
||||
}
|
||||
|
||||
Future<void> getOlmSessionsForDevicesFromDatabase(
|
||||
List<String> senderKeys) async {
|
||||
if (client.database == null) {
|
||||
return;
|
||||
}
|
||||
final rows = await client.database.getOlmSessionsForDevices(
|
||||
final rows = await client.database?.getOlmSessionsForDevices(
|
||||
senderKeys,
|
||||
client.userID,
|
||||
client.userID!,
|
||||
);
|
||||
final res = <String, List<OlmSession>>{};
|
||||
for (final sess in rows) {
|
||||
for (final sess in rows ?? []) {
|
||||
res[sess.identityKey] ??= <OlmSession>[];
|
||||
if (sess.isValid) {
|
||||
res[sess.identityKey]!.add(sess);
|
||||
|
|
@ -565,7 +555,7 @@ class OlmManager {
|
|||
session.create_outbound(
|
||||
_olmAccount!, identityKey, deviceKey['key']);
|
||||
await storeOlmSession(OlmSession(
|
||||
key: client.userID,
|
||||
key: client.userID!,
|
||||
identityKey: identityKey,
|
||||
sessionId: session.session_id(),
|
||||
session: session,
|
||||
|
|
@ -602,7 +592,7 @@ class OlmManager {
|
|||
await storeOlmSession(sess.first);
|
||||
if (client.database != null) {
|
||||
// ignore: unawaited_futures
|
||||
runInRoot(() => client.database.setLastSentMessageUserDeviceKey(
|
||||
runInRoot(() => client.database?.setLastSentMessageUserDeviceKey(
|
||||
json.encode({
|
||||
'type': type,
|
||||
'content': payload,
|
||||
|
|
@ -668,8 +658,10 @@ class OlmManager {
|
|||
Logs().v(
|
||||
'[OlmManager] Device ${device.userId}:${device.deviceId} generated a new olm session, replaying last sent message...');
|
||||
final lastSentMessageRes = await client.database
|
||||
.getLastSentMessageUserDeviceKey(device.userId, device.deviceId!);
|
||||
if (lastSentMessageRes.isEmpty || (lastSentMessageRes.first.isEmpty)) {
|
||||
?.getLastSentMessageUserDeviceKey(device.userId, device.deviceId!);
|
||||
if (lastSentMessageRes == null ||
|
||||
lastSentMessageRes.isEmpty ||
|
||||
lastSentMessageRes.first.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final lastSentMessage = json.decode(lastSentMessageRes.first);
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ class SSSS {
|
|||
|
||||
Future<void> setDefaultKeyId(String keyId) async {
|
||||
await client.setAccountData(
|
||||
client.userID,
|
||||
client.userID!,
|
||||
EventTypes.SecretStorageDefaultKey,
|
||||
SecretStorageDefaultKeyContent(key: keyId).toJson(),
|
||||
);
|
||||
|
|
@ -250,7 +250,7 @@ class SSSS {
|
|||
syncUpdate.accountData!
|
||||
.any((accountData) => accountData.type == accountDataType));
|
||||
await client.setAccountData(
|
||||
client.userID, accountDataType, content.toJson());
|
||||
client.userID!, accountDataType, content.toJson());
|
||||
await waitForAccountData;
|
||||
|
||||
final key = open(keyId);
|
||||
|
|
@ -295,7 +295,7 @@ class SSSS {
|
|||
if (_cache.containsKey(type) && isValid(_cache[type])) {
|
||||
return _cache[type]?.content;
|
||||
}
|
||||
final ret = await client.database.getSSSSCache(type);
|
||||
final ret = await client.database?.getSSSSCache(type);
|
||||
if (ret == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -321,10 +321,10 @@ class SSSS {
|
|||
final encryptInfo = _Encrypted(
|
||||
iv: enc['iv'], ciphertext: enc['ciphertext'], mac: enc['mac']);
|
||||
final decrypted = await decryptAes(encryptInfo, key, type);
|
||||
if (cacheTypes.contains(type) && client.database != null) {
|
||||
final db = client.database;
|
||||
if (cacheTypes.contains(type) && db != null) {
|
||||
// cache the thing
|
||||
await client.database
|
||||
.storeSSSSCache(type, keyId, enc['ciphertext'], decrypted);
|
||||
await db.storeSSSSCache(type, keyId, enc['ciphertext'], decrypted);
|
||||
if (_cacheCallbacks.containsKey(type) && await getCached(type) == null) {
|
||||
_cacheCallbacks[type]!(decrypted);
|
||||
}
|
||||
|
|
@ -351,11 +351,11 @@ class SSSS {
|
|||
'mac': encrypted.mac,
|
||||
};
|
||||
// store the thing in your account data
|
||||
await client.setAccountData(client.userID, type, content);
|
||||
if (cacheTypes.contains(type) && client.database != null) {
|
||||
await client.setAccountData(client.userID!, type, content);
|
||||
final db = client.database;
|
||||
if (cacheTypes.contains(type) && db != null) {
|
||||
// cache the thing
|
||||
await client.database
|
||||
.storeSSSSCache(type, keyId, encrypted.ciphertext, secret);
|
||||
await db.storeSSSSCache(type, keyId, encrypted.ciphertext, secret);
|
||||
if (_cacheCallbacks.containsKey(type) && await getCached(type) == null) {
|
||||
_cacheCallbacks[type]!(secret);
|
||||
}
|
||||
|
|
@ -381,10 +381,10 @@ class SSSS {
|
|||
throw Exception('Secrets do not match up!');
|
||||
}
|
||||
// store the thing in your account data
|
||||
await client.setAccountData(client.userID, type, content);
|
||||
if (cacheTypes.contains(type) && client.database != null) {
|
||||
await client.setAccountData(client.userID!, type, content);
|
||||
if (cacheTypes.contains(type)) {
|
||||
// cache the thing
|
||||
await client.database.storeSSSSCache(
|
||||
await client.database?.storeSSSSCache(
|
||||
type, keyId, content['encrypted'][keyId]['ciphertext'], secret);
|
||||
}
|
||||
}
|
||||
|
|
@ -542,13 +542,13 @@ class SSSS {
|
|||
return; // our request is more than 15min in the past...better not trust it anymore
|
||||
}
|
||||
Logs().i('[SSSS] Secret for type ${request.type} is ok, storing it');
|
||||
if (client.database != null) {
|
||||
final db = client.database;
|
||||
if (db != null) {
|
||||
final keyId = keyIdFromType(request.type);
|
||||
if (keyId != null) {
|
||||
final ciphertext = client.accountData[request.type]!
|
||||
.content['encrypted'][keyId]['ciphertext'];
|
||||
await client.database
|
||||
.storeSSSSCache(request.type, keyId, ciphertext, secret);
|
||||
await db.storeSSSSCache(request.type, keyId, ciphertext, secret);
|
||||
if (_cacheCallbacks.containsKey(request.type)) {
|
||||
_cacheCallbacks[request.type]!(secret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -357,6 +357,7 @@ class Bootstrap {
|
|||
checkOnlineKeyBackup();
|
||||
return;
|
||||
}
|
||||
final userID = client.userID!;
|
||||
try {
|
||||
Uint8List masterSigningKey;
|
||||
final secretsToStore = <String, String>{};
|
||||
|
|
@ -370,7 +371,7 @@ class Bootstrap {
|
|||
masterSigningKey = master.generate_seed();
|
||||
masterPub = master.init_with_seed(masterSigningKey);
|
||||
final json = <String, dynamic>{
|
||||
'user_id': client.userID,
|
||||
'user_id': userID,
|
||||
'usage': ['master'],
|
||||
'keys': <String, dynamic>{
|
||||
'ed25519:$masterPub': masterPub,
|
||||
|
|
@ -414,7 +415,7 @@ class Bootstrap {
|
|||
final selfSigningPriv = selfSigning.generate_seed();
|
||||
final selfSigningPub = selfSigning.init_with_seed(selfSigningPriv);
|
||||
final json = <String, dynamic>{
|
||||
'user_id': client.userID,
|
||||
'user_id': userID,
|
||||
'usage': ['self_signing'],
|
||||
'keys': <String, dynamic>{
|
||||
'ed25519:$selfSigningPub': selfSigningPub,
|
||||
|
|
@ -422,7 +423,7 @@ class Bootstrap {
|
|||
};
|
||||
final signature = _sign(json);
|
||||
json['signatures'] = <String, dynamic>{
|
||||
client.userID: <String, dynamic>{
|
||||
userID: <String, dynamic>{
|
||||
'ed25519:$masterPub': signature,
|
||||
},
|
||||
};
|
||||
|
|
@ -439,7 +440,7 @@ class Bootstrap {
|
|||
final userSigningPriv = userSigning.generate_seed();
|
||||
final userSigningPub = userSigning.init_with_seed(userSigningPriv);
|
||||
final json = <String, dynamic>{
|
||||
'user_id': client.userID,
|
||||
'user_id': userID,
|
||||
'usage': ['user_signing'],
|
||||
'keys': <String, dynamic>{
|
||||
'ed25519:$userSigningPub': userSigningPub,
|
||||
|
|
@ -447,7 +448,7 @@ class Bootstrap {
|
|||
};
|
||||
final signature = _sign(json);
|
||||
json['signatures'] = <String, dynamic>{
|
||||
client.userID: <String, dynamic>{
|
||||
userID: <String, dynamic>{
|
||||
'ed25519:$masterPub': signature,
|
||||
},
|
||||
};
|
||||
|
|
@ -462,7 +463,7 @@ class Bootstrap {
|
|||
state = BootstrapState.loading;
|
||||
Logs().v('Upload device signing keys.');
|
||||
await client.uiaRequestBackground(
|
||||
(AuthenticationData auth) => client.uploadCrossSigningKeys(
|
||||
(AuthenticationData? auth) => client.uploadCrossSigningKeys(
|
||||
masterKey: masterKey,
|
||||
selfSigningKey: selfSigningKey,
|
||||
userSigningKey: userSigningKey,
|
||||
|
|
|
|||
|
|
@ -24,8 +24,10 @@ import '../../matrix.dart';
|
|||
extension JsonSignatureCheckExtension on Map<String, dynamic> {
|
||||
/// Checks the signature of a signed json object.
|
||||
bool checkJsonSignature(String key, String userId, String deviceId) {
|
||||
final Map<String, dynamic> signatures = this['signatures'];
|
||||
if (signatures == null || !signatures.containsKey(userId)) return false;
|
||||
final signatures = this['signatures'];
|
||||
if (signatures == null ||
|
||||
!(signatures is Map<String, dynamic>) ||
|
||||
!signatures.containsKey(userId)) return false;
|
||||
remove('unsigned');
|
||||
remove('signatures');
|
||||
if (!signatures[userId].containsKey('ed25519:$deviceId')) return false;
|
||||
|
|
|
|||
|
|
@ -356,10 +356,8 @@ class KeyVerification {
|
|||
if (_nextAction == 'request') {
|
||||
sendStart();
|
||||
} else if (_nextAction == 'done') {
|
||||
if (_verifiedDevices != null) {
|
||||
// and now let's sign them all in the background
|
||||
encryption.crossSigning.sign(_verifiedDevices);
|
||||
}
|
||||
// and now let's sign them all in the background
|
||||
encryption.crossSigning.sign(_verifiedDevices);
|
||||
setState(KeyVerificationState.done);
|
||||
}
|
||||
};
|
||||
|
|
@ -530,8 +528,7 @@ class KeyVerification {
|
|||
}
|
||||
|
||||
Future<bool> verifyActivity() async {
|
||||
if (lastActivity != null &&
|
||||
lastActivity.add(Duration(minutes: 10)).isAfter(DateTime.now())) {
|
||||
if (lastActivity.add(Duration(minutes: 10)).isAfter(DateTime.now())) {
|
||||
lastActivity = DateTime.now();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -876,7 +873,7 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
|
|||
: theirInfo + ourInfo) +
|
||||
request.transactionId!;
|
||||
} else if (keyAgreementProtocol == 'curve25519') {
|
||||
final ourInfo = client.userID + client.deviceID;
|
||||
final ourInfo = client.userID! + client.deviceID!;
|
||||
final theirInfo = request.userId + request.deviceId!;
|
||||
sasInfo = 'MATRIX_KEY_VERIFICATION_SAS' +
|
||||
(request.startedVerification
|
||||
|
|
@ -891,8 +888,8 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
|
|||
|
||||
Future<void> _sendMac() async {
|
||||
final baseInfo = 'MATRIX_KEY_VERIFICATION_MAC' +
|
||||
client.userID +
|
||||
client.deviceID +
|
||||
client.userID! +
|
||||
client.deviceID! +
|
||||
request.userId +
|
||||
request.deviceId! +
|
||||
request.transactionId!;
|
||||
|
|
@ -929,8 +926,8 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
|
|||
final baseInfo = 'MATRIX_KEY_VERIFICATION_MAC' +
|
||||
request.userId +
|
||||
request.deviceId! +
|
||||
client.userID +
|
||||
client.deviceID +
|
||||
client.userID! +
|
||||
client.deviceID! +
|
||||
request.transactionId!;
|
||||
|
||||
final keyList = payload['mac'].keys.toList();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -35,10 +35,10 @@ abstract class DatabaseApi {
|
|||
String homeserverUrl,
|
||||
String token,
|
||||
String userId,
|
||||
String deviceId,
|
||||
String deviceName,
|
||||
String prevBatch,
|
||||
String olmAccount,
|
||||
String? deviceId,
|
||||
String? deviceName,
|
||||
String? prevBatch,
|
||||
String? olmAccount,
|
||||
);
|
||||
|
||||
Future insertClient(
|
||||
|
|
@ -46,10 +46,10 @@ abstract class DatabaseApi {
|
|||
String homeserverUrl,
|
||||
String token,
|
||||
String userId,
|
||||
String deviceId,
|
||||
String deviceName,
|
||||
String prevBatch,
|
||||
String olmAccount,
|
||||
String? deviceId,
|
||||
String? deviceName,
|
||||
String? prevBatch,
|
||||
String? olmAccount,
|
||||
);
|
||||
|
||||
Future<List<Room>> getRoomList(Client client);
|
||||
|
|
@ -58,12 +58,12 @@ abstract class DatabaseApi {
|
|||
|
||||
/// Stores a RoomUpdate object in the database. Must be called inside of
|
||||
/// [transaction].
|
||||
Future<void> storeRoomUpdate(String roomId, SyncRoomUpdate roomUpdate,
|
||||
[Room oldRoom]);
|
||||
Future<void> storeRoomUpdate(
|
||||
String roomId, SyncRoomUpdate roomUpdate, Client client);
|
||||
|
||||
/// Stores an EventUpdate object in the database. Must be called inside of
|
||||
/// [transaction].
|
||||
Future<void> storeEventUpdate(EventUpdate eventUpdate);
|
||||
Future<void> storeEventUpdate(EventUpdate eventUpdate, Client client);
|
||||
|
||||
Future<Event?> getEventById(String eventId, Room room);
|
||||
|
||||
|
|
@ -233,6 +233,7 @@ abstract class DatabaseApi {
|
|||
Future setRoomPrevBatch(
|
||||
String prevBatch,
|
||||
String roomId,
|
||||
Client client,
|
||||
);
|
||||
|
||||
Future resetNotificationCount(String roomId);
|
||||
|
|
|
|||
|
|
@ -507,6 +507,7 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
|||
Future<List<Room>> getRoomList(Client client) =>
|
||||
runBenchmarked<List<Room>>('Get room list from hive', () async {
|
||||
final rooms = <String, Room>{};
|
||||
final userID = client.userID;
|
||||
final importantRoomStates = client.importantStateEvents;
|
||||
for (final key in _roomsBox.keys) {
|
||||
// Get the room
|
||||
|
|
@ -515,12 +516,15 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
|||
|
||||
// let's see if we need any m.room.member events
|
||||
// We always need the member event for ourself
|
||||
final membersToPostload = <String>{client.userID};
|
||||
final membersToPostload = <String>{if (userID != null) userID};
|
||||
// If the room is a direct chat, those IDs should be there too
|
||||
if (room.isDirectChat) membersToPostload.add(room.directChatMatrixID);
|
||||
if (room.isDirectChat) {
|
||||
membersToPostload.add(room.directChatMatrixID!);
|
||||
}
|
||||
// the lastEvent message preview might have an author we need to fetch, if it is a group chat
|
||||
if (room.getState(EventTypes.Message) != null && !room.isDirectChat) {
|
||||
membersToPostload.add(room.getState(EventTypes.Message).senderId);
|
||||
final lastEvent = room.getState(EventTypes.Message);
|
||||
if (lastEvent != null && !room.isDirectChat) {
|
||||
membersToPostload.add(lastEvent.senderId);
|
||||
}
|
||||
// if the room has no name and no canonical alias, its name is calculated
|
||||
// based on the heroes of the room
|
||||
|
|
@ -528,7 +532,7 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
|||
room.getState(EventTypes.RoomCanonicalAlias) == null) {
|
||||
// we don't have a name and no canonical alias, so we'll need to
|
||||
// post-load the heroes
|
||||
membersToPostload.addAll(room.summary?.mHeroes ?? []);
|
||||
membersToPostload.addAll(room.summary.mHeroes ?? []);
|
||||
}
|
||||
// Load members
|
||||
for (final userId in membersToPostload) {
|
||||
|
|
@ -671,10 +675,10 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
|||
String homeserverUrl,
|
||||
String token,
|
||||
String userId,
|
||||
String deviceId,
|
||||
String deviceName,
|
||||
String prevBatch,
|
||||
String olmAccount) async {
|
||||
String? deviceId,
|
||||
String? deviceName,
|
||||
String? prevBatch,
|
||||
String? olmAccount) async {
|
||||
await _clientBox.put('homeserver_url', homeserverUrl);
|
||||
await _clientBox.put('token', token);
|
||||
await _clientBox.put('user_id', userId);
|
||||
|
|
@ -816,10 +820,11 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> setRoomPrevBatch(String prevBatch, String roomId) async {
|
||||
Future<void> setRoomPrevBatch(
|
||||
String prevBatch, String roomId, Client client) async {
|
||||
final raw = await _roomsBox.get(roomId.toHiveKey);
|
||||
if (raw == null) return;
|
||||
final room = Room.fromJson(convertToJson(raw));
|
||||
final room = Room.fromJson(convertToJson(raw), client);
|
||||
room.prev_batch = prevBatch;
|
||||
await _roomsBox.put(roomId.toHiveKey, room.toJson());
|
||||
return;
|
||||
|
|
@ -860,13 +865,13 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> storeEventUpdate(EventUpdate eventUpdate) async {
|
||||
Future<void> storeEventUpdate(EventUpdate eventUpdate, Client client) async {
|
||||
// Ephemerals should not be stored
|
||||
if (eventUpdate.type == EventUpdateType.ephemeral) return;
|
||||
|
||||
// In case of this is a redaction event
|
||||
if (eventUpdate.content['type'] == EventTypes.Redaction) {
|
||||
final tmpRoom = Room(id: eventUpdate.roomID);
|
||||
final tmpRoom = Room(id: eventUpdate.roomID, client: client);
|
||||
final event = await getEventById(eventUpdate.content['redacts'], tmpRoom);
|
||||
if (event != null) {
|
||||
event.setRedactionEvent(Event.fromJson(eventUpdate.content, tmpRoom));
|
||||
|
|
@ -906,13 +911,12 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
|||
return;
|
||||
}
|
||||
|
||||
final status =
|
||||
newStatus.isError || prevEvent == null || prevEvent.status != null
|
||||
? newStatus
|
||||
: latestEventStatus(
|
||||
prevEvent.status,
|
||||
newStatus,
|
||||
);
|
||||
final status = newStatus.isError || prevEvent == null
|
||||
? newStatus
|
||||
: latestEventStatus(
|
||||
prevEvent.status,
|
||||
newStatus,
|
||||
);
|
||||
|
||||
// Add the status and the sort order to the content so it get stored
|
||||
eventUpdate.content['unsigned'] ??= <String, dynamic>{};
|
||||
|
|
@ -1076,8 +1080,8 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> storeRoomUpdate(String roomId, SyncRoomUpdate roomUpdate,
|
||||
[dynamic _]) async {
|
||||
Future<void> storeRoomUpdate(
|
||||
String roomId, SyncRoomUpdate roomUpdate, Client client) async {
|
||||
// Leave room if membership is leave
|
||||
if (roomUpdate is LeftRoomUpdate) {
|
||||
await forgetRoom(roomId);
|
||||
|
|
@ -1094,26 +1098,31 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
|||
roomId.toHiveKey,
|
||||
roomUpdate is JoinedRoomUpdate
|
||||
? Room(
|
||||
client: client,
|
||||
id: roomId,
|
||||
membership: membership,
|
||||
highlightCount:
|
||||
roomUpdate.unreadNotifications?.highlightCount?.toInt(),
|
||||
roomUpdate.unreadNotifications?.highlightCount?.toInt() ??
|
||||
0,
|
||||
notificationCount: roomUpdate
|
||||
.unreadNotifications?.notificationCount
|
||||
?.toInt(),
|
||||
.unreadNotifications?.notificationCount
|
||||
?.toInt() ??
|
||||
0,
|
||||
prev_batch: roomUpdate.timeline?.prevBatch,
|
||||
summary: roomUpdate.summary,
|
||||
).toJson()
|
||||
: Room(
|
||||
client: client,
|
||||
id: roomId,
|
||||
membership: membership,
|
||||
).toJson());
|
||||
} else if (roomUpdate is JoinedRoomUpdate) {
|
||||
final currentRawRoom = await _roomsBox.get(roomId.toHiveKey);
|
||||
final currentRoom = Room.fromJson(convertToJson(currentRawRoom));
|
||||
final currentRoom = Room.fromJson(convertToJson(currentRawRoom), client);
|
||||
await _roomsBox.put(
|
||||
roomId.toHiveKey,
|
||||
Room(
|
||||
client: client,
|
||||
id: roomId,
|
||||
membership: membership,
|
||||
highlightCount:
|
||||
|
|
@ -1250,10 +1259,10 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
|||
String homeserverUrl,
|
||||
String token,
|
||||
String userId,
|
||||
String deviceId,
|
||||
String deviceName,
|
||||
String prevBatch,
|
||||
String olmAccount,
|
||||
String? deviceId,
|
||||
String? deviceName,
|
||||
String? prevBatch,
|
||||
String? olmAccount,
|
||||
) async {
|
||||
await _clientBox.put('homeserver_url', homeserverUrl);
|
||||
await _clientBox.put('token', token);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
|
||||
|
|
@ -39,7 +38,13 @@ abstract class RelationshipTypes {
|
|||
|
||||
/// All data exchanged over Matrix is expressed as an "event". Typically each client action (e.g. sending a message) correlates with exactly one event.
|
||||
class Event extends MatrixEvent {
|
||||
User get sender => room.getUserByMXIDSync(senderId ?? '@unknown:unknown');
|
||||
User get sender =>
|
||||
room?.getUserByMXIDSync(senderId) ??
|
||||
User.fromState(
|
||||
stateKey: senderId,
|
||||
typeKey: EventTypes.RoomMember,
|
||||
originServerTs: DateTime.now(),
|
||||
);
|
||||
|
||||
@Deprecated('Use [originServerTs] instead')
|
||||
DateTime get time => originServerTs;
|
||||
|
|
@ -48,10 +53,10 @@ class Event extends MatrixEvent {
|
|||
String get typeKey => type;
|
||||
|
||||
@Deprecated('Use [sender.calcDisplayname()] instead')
|
||||
String get senderName => sender.calcDisplayname();
|
||||
String? get senderName => sender.calcDisplayname();
|
||||
|
||||
/// The room this event belongs to. May be null.
|
||||
final Room room;
|
||||
final Room? room;
|
||||
|
||||
/// The status of this event.
|
||||
EventStatus status;
|
||||
|
|
@ -59,33 +64,39 @@ class Event extends MatrixEvent {
|
|||
static const EventStatus defaultStatus = EventStatus.synced;
|
||||
|
||||
/// Optional. The event that redacted this event, if any. Otherwise null.
|
||||
Event get redactedBecause =>
|
||||
unsigned != null && unsigned['redacted_because'] is Map
|
||||
? Event.fromJson(unsigned['redacted_because'], room)
|
||||
: null;
|
||||
Event? get redactedBecause {
|
||||
final redacted_because = unsigned?['redacted_because'];
|
||||
final room = this.room;
|
||||
return (redacted_because is Map<String, dynamic>)
|
||||
? Event.fromJson(redacted_because, room)
|
||||
: null;
|
||||
}
|
||||
|
||||
bool get redacted => redactedBecause != null;
|
||||
|
||||
User get stateKeyUser => room.getUserByMXIDSync(stateKey);
|
||||
User? get stateKeyUser => room?.getUserByMXIDSync(stateKey!);
|
||||
|
||||
Event({
|
||||
this.status = defaultStatus,
|
||||
Map<String, dynamic> content,
|
||||
String type,
|
||||
String eventId,
|
||||
String roomId,
|
||||
String senderId,
|
||||
DateTime originServerTs,
|
||||
Map<String, dynamic> unsigned,
|
||||
Map<String, dynamic> prevContent,
|
||||
String stateKey,
|
||||
required Map<String, dynamic> content,
|
||||
required String type,
|
||||
required String eventId,
|
||||
String? roomId,
|
||||
required String senderId,
|
||||
required DateTime originServerTs,
|
||||
Map<String, dynamic>? unsigned,
|
||||
Map<String, dynamic>? prevContent,
|
||||
String? stateKey,
|
||||
this.room,
|
||||
}) {
|
||||
this.content = content;
|
||||
this.type = type;
|
||||
}) : super(
|
||||
content: content,
|
||||
type: type,
|
||||
eventId: eventId,
|
||||
senderId: senderId,
|
||||
originServerTs: originServerTs,
|
||||
roomId: roomId ?? room?.id,
|
||||
) {
|
||||
this.eventId = eventId;
|
||||
this.roomId = roomId ?? room?.id;
|
||||
this.senderId = senderId;
|
||||
this.unsigned = unsigned;
|
||||
// synapse unfortunately isn't following the spec and tosses the prev_content
|
||||
// into the unsigned block.
|
||||
|
|
@ -103,17 +114,17 @@ class Event extends MatrixEvent {
|
|||
// A strange bug in dart web makes this crash
|
||||
}
|
||||
this.stateKey = stateKey;
|
||||
this.originServerTs = originServerTs;
|
||||
|
||||
// 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
|
||||
// database!
|
||||
if (status.isSending && room?.client?.database != null) {
|
||||
if (status.isSending && room?.client.database != null) {
|
||||
// Age of this event in milliseconds
|
||||
final age = DateTime.now().millisecondsSinceEpoch -
|
||||
originServerTs.millisecondsSinceEpoch;
|
||||
|
||||
if (age > room.client.sendMessageTimeoutSeconds * 1000) {
|
||||
final room = this.room;
|
||||
if (room != null && age > room.client.sendMessageTimeoutSeconds * 1000) {
|
||||
// Update this event in database and open timelines
|
||||
final json = toJson();
|
||||
json['unsigned'] ??= <String, dynamic>{};
|
||||
|
|
@ -143,7 +154,7 @@ class Event extends MatrixEvent {
|
|||
factory Event.fromMatrixEvent(
|
||||
MatrixEvent matrixEvent,
|
||||
Room room, {
|
||||
EventStatus status,
|
||||
EventStatus status = defaultStatus,
|
||||
}) =>
|
||||
Event(
|
||||
status: status,
|
||||
|
|
@ -162,7 +173,7 @@ class Event extends MatrixEvent {
|
|||
/// Get a State event from a table row or from the event stream.
|
||||
factory Event.fromJson(
|
||||
Map<String, dynamic> jsonPayload,
|
||||
Room room,
|
||||
Room? room,
|
||||
) {
|
||||
final content = Event.getMapFromPayload(jsonPayload['content']);
|
||||
final unsigned = Event.getMapFromPayload(jsonPayload['unsigned']);
|
||||
|
|
@ -175,7 +186,7 @@ class Event extends MatrixEvent {
|
|||
prevContent: prevContent,
|
||||
content: content,
|
||||
type: jsonPayload['type'],
|
||||
eventId: jsonPayload['event_id'],
|
||||
eventId: jsonPayload['event_id'] ?? '',
|
||||
roomId: jsonPayload['room_id'],
|
||||
senderId: jsonPayload['sender'],
|
||||
originServerTs: jsonPayload.containsKey('origin_server_ts')
|
||||
|
|
@ -190,7 +201,7 @@ class Event extends MatrixEvent {
|
|||
Map<String, dynamic> toJson() {
|
||||
final data = <String, dynamic>{};
|
||||
if (stateKey != null) data['state_key'] = stateKey;
|
||||
if (prevContent != null && prevContent.isNotEmpty) {
|
||||
if (prevContent?.isNotEmpty == true) {
|
||||
data['prev_content'] = prevContent;
|
||||
}
|
||||
data['content'] = content;
|
||||
|
|
@ -199,14 +210,15 @@ class Event extends MatrixEvent {
|
|||
data['room_id'] = roomId;
|
||||
data['sender'] = senderId;
|
||||
data['origin_server_ts'] = originServerTs.millisecondsSinceEpoch;
|
||||
if (unsigned != null && unsigned.isNotEmpty) {
|
||||
if (unsigned?.isNotEmpty == true) {
|
||||
data['unsigned'] = unsigned;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
User get asUser => User.fromState(
|
||||
stateKey: stateKey,
|
||||
// state key should always be set for member events
|
||||
stateKey: stateKey!,
|
||||
prevContent: prevContent,
|
||||
content: content,
|
||||
typeKey: type,
|
||||
|
|
@ -282,8 +294,10 @@ class Event extends MatrixEvent {
|
|||
|
||||
/// Returns a list of [Receipt] instances for this event.
|
||||
List<Receipt> get receipts {
|
||||
if (!(room.roomAccountData.containsKey('m.receipt'))) return [];
|
||||
return room.roomAccountData['m.receipt'].content.entries
|
||||
final room = this.room;
|
||||
final receipt = room?.roomAccountData['m.receipt'];
|
||||
if (receipt == null || room == null) return [];
|
||||
return receipt.content.entries
|
||||
.where((entry) => entry.value['event_id'] == eventId)
|
||||
.map((entry) => Receipt(room.getUserByMXIDSync(entry.key),
|
||||
DateTime.fromMillisecondsSinceEpoch(entry.value['ts'])))
|
||||
|
|
@ -294,6 +308,11 @@ class Event extends MatrixEvent {
|
|||
/// This event will just be removed from the database and the timelines.
|
||||
/// Returns [false] if not removed.
|
||||
Future<bool> remove() async {
|
||||
final room = this.room;
|
||||
if (room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!status.isSent) {
|
||||
await room.client.database?.removeEvent(eventId, room.id);
|
||||
|
||||
|
|
@ -311,29 +330,33 @@ class Event extends MatrixEvent {
|
|||
return false;
|
||||
}
|
||||
|
||||
/// Try to send this event again. Only works with events of `EventStatus.isError`.
|
||||
Future<String> sendAgain({String txid}) async {
|
||||
/// Try to send this event again. Only works with events of status -1.
|
||||
Future<String?> sendAgain({String? txid}) async {
|
||||
if (!status.isError) return null;
|
||||
// we do not remove the event here. It will automatically be updated
|
||||
// in the `sendEvent` method to transition -1 -> 0 -> 1 -> 2
|
||||
final newEventId = await room.sendEvent(
|
||||
final newEventId = await room?.sendEvent(
|
||||
content,
|
||||
txid: txid ?? unsigned['transaction_id'] ?? eventId,
|
||||
txid: txid ?? unsigned?['transaction_id'] ?? eventId,
|
||||
);
|
||||
return newEventId;
|
||||
}
|
||||
|
||||
/// Whether the client is allowed to redact this event.
|
||||
bool get canRedact => senderId == room.client.userID || room.canRedact;
|
||||
bool get canRedact =>
|
||||
senderId == room?.client.userID || (room?.canRedact ?? false);
|
||||
|
||||
/// Redacts this event. Throws `ErrorResponse` on error.
|
||||
Future<dynamic> redactEvent({String reason, String txid}) =>
|
||||
room.redactEvent(eventId, reason: reason, txid: txid);
|
||||
Future<String?> redactEvent({String? reason, String? txid}) async =>
|
||||
await room?.redactEvent(eventId, reason: reason, txid: txid);
|
||||
|
||||
/// Searches for the reply event in the given timeline.
|
||||
Future<Event> getReplyEvent(Timeline timeline) async {
|
||||
Future<Event?> getReplyEvent(Timeline timeline) async {
|
||||
if (relationshipType != RelationshipTypes.reply) return null;
|
||||
return await timeline.getEventById(relationshipEventId);
|
||||
final relationshipEventId = this.relationshipEventId;
|
||||
return relationshipEventId == null
|
||||
? null
|
||||
: await timeline.getEventById(relationshipEventId);
|
||||
}
|
||||
|
||||
/// If this event is encrypted and the decryption was not successful because
|
||||
|
|
@ -346,7 +369,7 @@ class Event extends MatrixEvent {
|
|||
content['can_request_session'] != true) {
|
||||
throw ('Session key not requestable');
|
||||
}
|
||||
await room.requestSessionKey(content['session_id'], content['sender_key']);
|
||||
await room?.requestSessionKey(content['session_id'], content['sender_key']);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -388,16 +411,21 @@ class Event extends MatrixEvent {
|
|||
: '');
|
||||
|
||||
/// Gets the underlying mxc url of an attachment of a file event, or null if not present
|
||||
Uri get attachmentMxcUrl => Uri.parse(
|
||||
isAttachmentEncrypted ? content['file']['url'] : content['url']);
|
||||
Uri? get attachmentMxcUrl {
|
||||
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
|
||||
Uri get thumbnailMxcUrl => Uri.parse(isThumbnailEncrypted
|
||||
? infoMap['thumbnail_file']['url']
|
||||
: infoMap['thumbnail_url']);
|
||||
Uri? get thumbnailMxcUrl {
|
||||
final url = isThumbnailEncrypted
|
||||
? 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
|
||||
Uri attachmentOrThumbnailMxcUrl({bool getThumbnail = false}) {
|
||||
Uri? attachmentOrThumbnailMxcUrl({bool getThumbnail = false}) {
|
||||
if (getThumbnail &&
|
||||
infoMap['size'] is int &&
|
||||
thumbnailInfoMap['size'] is int &&
|
||||
|
|
@ -420,7 +448,7 @@ class Event extends MatrixEvent {
|
|||
/// [minNoThumbSize] is the minimum size that an original image may be to not fetch its thumbnail, defaults to 80k
|
||||
/// [useThumbnailMxcUrl] says weather to use the mxc url of the thumbnail, rather than the original attachment.
|
||||
/// [animated] says weather the thumbnail is animated
|
||||
Uri getAttachmentUrl(
|
||||
Uri? getAttachmentUrl(
|
||||
{bool getThumbnail = false,
|
||||
bool useThumbnailMxcUrl = false,
|
||||
double width = 800.0,
|
||||
|
|
@ -428,6 +456,10 @@ class Event extends MatrixEvent {
|
|||
ThumbnailMethod method = ThumbnailMethod.scale,
|
||||
int minNoThumbSize = _minNoThumbSize,
|
||||
bool animated = false}) {
|
||||
final client = room?.client;
|
||||
if (client == null) {
|
||||
return null;
|
||||
}
|
||||
if (![EventTypes.Message, EventTypes.Sticker].contains(type) ||
|
||||
!hasAttachment ||
|
||||
isAttachmentEncrypted) {
|
||||
|
|
@ -449,14 +481,14 @@ class Event extends MatrixEvent {
|
|||
// now generate the actual URLs
|
||||
if (getThumbnail) {
|
||||
return Uri.parse(thisMxcUrl).getThumbnail(
|
||||
room.client,
|
||||
client,
|
||||
width: width,
|
||||
height: height,
|
||||
method: method,
|
||||
animated: animated,
|
||||
);
|
||||
} else {
|
||||
return Uri.parse(thisMxcUrl).getDownloadLink(room.client);
|
||||
return Uri.parse(thisMxcUrl).getDownloadLink(client);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -472,13 +504,17 @@ class Event extends MatrixEvent {
|
|||
getThumbnail = mxcUrl != attachmentMxcUrl;
|
||||
// Is this file storeable?
|
||||
final thisInfoMap = getThumbnail ? thumbnailInfoMap : infoMap;
|
||||
final storeable = room.client.database != null &&
|
||||
thisInfoMap['size'] is int &&
|
||||
thisInfoMap['size'] <= room.client.database.maxFileSize;
|
||||
final database = room?.client.database;
|
||||
if (database == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Uint8List uint8list;
|
||||
final storeable = thisInfoMap['size'] is int &&
|
||||
thisInfoMap['size'] <= database.maxFileSize;
|
||||
|
||||
Uint8List? uint8list;
|
||||
if (storeable) {
|
||||
uint8list = await room.client.database.getFile(mxcUrl);
|
||||
uint8list = await database.getFile(mxcUrl);
|
||||
}
|
||||
return uint8list != null;
|
||||
}
|
||||
|
|
@ -487,12 +523,17 @@ class Event extends MatrixEvent {
|
|||
/// event and returns it as a [MatrixFile]. If this event doesn't
|
||||
/// contain an attachment, this throws an error. Set [getThumbnail] to
|
||||
/// true to download the thumbnail instead.
|
||||
Future<MatrixFile> downloadAndDecryptAttachment(
|
||||
Future<MatrixFile?> downloadAndDecryptAttachment(
|
||||
{bool getThumbnail = false,
|
||||
Future<Uint8List> Function(Uri) downloadCallback}) async {
|
||||
Future<Uint8List> Function(Uri)? downloadCallback}) async {
|
||||
if (![EventTypes.Message, EventTypes.Sticker].contains(type)) {
|
||||
throw ("This event has the type '$type' and so it can't contain an attachment.");
|
||||
}
|
||||
final client = room?.client;
|
||||
final database = room?.client.database;
|
||||
if (client == null) {
|
||||
throw 'This event has no valid client.';
|
||||
}
|
||||
final mxcUrl = attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail);
|
||||
if (mxcUrl == null) {
|
||||
throw "This event hasn't any attachment or thumbnail.";
|
||||
|
|
@ -500,33 +541,30 @@ class Event extends MatrixEvent {
|
|||
getThumbnail = mxcUrl != attachmentMxcUrl;
|
||||
final isEncrypted =
|
||||
getThumbnail ? isThumbnailEncrypted : isAttachmentEncrypted;
|
||||
|
||||
if (isEncrypted && !room.client.encryptionEnabled) {
|
||||
if (isEncrypted && !client.encryptionEnabled) {
|
||||
throw ('Encryption is not enabled in your Client.');
|
||||
}
|
||||
|
||||
Uint8List uint8list;
|
||||
|
||||
// Is this file storeable?
|
||||
final thisInfoMap = getThumbnail ? thumbnailInfoMap : infoMap;
|
||||
var storeable = room.client.database != null &&
|
||||
var storeable = database != null &&
|
||||
thisInfoMap['size'] is int &&
|
||||
thisInfoMap['size'] <= room.client.database.maxFileSize;
|
||||
thisInfoMap['size'] <= database.maxFileSize;
|
||||
|
||||
Uint8List? uint8list;
|
||||
if (storeable) {
|
||||
uint8list = await room.client.database.getFile(mxcUrl);
|
||||
uint8list = await client.database?.getFile(mxcUrl);
|
||||
}
|
||||
|
||||
// Download the file
|
||||
if (uint8list == null) {
|
||||
downloadCallback ??= (Uri url) async {
|
||||
return (await http.get(url)).bodyBytes;
|
||||
};
|
||||
uint8list = await downloadCallback(mxcUrl.getDownloadLink(room.client));
|
||||
storeable = storeable &&
|
||||
uint8list.lengthInBytes < room.client.database.maxFileSize;
|
||||
downloadCallback ??= (Uri url) async => (await http.get(url)).bodyBytes;
|
||||
uint8list = await downloadCallback(mxcUrl.getDownloadLink(client));
|
||||
storeable = database != null &&
|
||||
storeable &&
|
||||
uint8list.lengthInBytes < database.maxFileSize;
|
||||
if (storeable) {
|
||||
await room.client.database.storeFile(
|
||||
await database.storeFile(
|
||||
mxcUrl, uint8list, DateTime.now().millisecondsSinceEpoch);
|
||||
}
|
||||
}
|
||||
|
|
@ -544,9 +582,10 @@ class Event extends MatrixEvent {
|
|||
k: fileMap['key']['k'],
|
||||
sha256: fileMap['hashes']['sha256'],
|
||||
);
|
||||
uint8list = await room.client.runInBackground(decryptFile, encryptedFile);
|
||||
uint8list = await client.runInBackground<Uint8List?, EncryptedFile>(
|
||||
decryptFile, encryptedFile);
|
||||
}
|
||||
return MatrixFile(bytes: uint8list, name: body);
|
||||
return uint8list != null ? MatrixFile(bytes: uint8list, name: body) : null;
|
||||
}
|
||||
|
||||
/// Returns if this is a known event type.
|
||||
|
|
@ -565,7 +604,7 @@ class Event extends MatrixEvent {
|
|||
bool plaintextBody = false,
|
||||
}) {
|
||||
if (redacted) {
|
||||
return i18n.removedBy(redactedBecause.sender.calcDisplayname());
|
||||
return i18n.removedBy(redactedBecause?.sender.calcDisplayname() ?? '');
|
||||
}
|
||||
var body = plaintextBody ? this.plaintextBody : this.body;
|
||||
|
||||
|
|
@ -607,8 +646,9 @@ class Event extends MatrixEvent {
|
|||
if (withSenderNamePrefix &&
|
||||
type == EventTypes.Message &&
|
||||
textOnlyMessageTypes.contains(messageType)) {
|
||||
final senderNameOrYou =
|
||||
senderId == room.client.userID ? i18n.you : sender.calcDisplayname();
|
||||
final senderNameOrYou = senderId == room?.client.userID
|
||||
? i18n.you
|
||||
: (sender.calcDisplayname());
|
||||
localizedBody = '$senderNameOrYou: $localizedBody';
|
||||
}
|
||||
|
||||
|
|
@ -623,19 +663,19 @@ class Event extends MatrixEvent {
|
|||
};
|
||||
|
||||
/// returns if this event matches the passed event or transaction id
|
||||
bool matchesEventOrTransactionId(String search) {
|
||||
bool matchesEventOrTransactionId(String? search) {
|
||||
if (search == null) {
|
||||
return false;
|
||||
}
|
||||
if (eventId == search) {
|
||||
return true;
|
||||
}
|
||||
return unsigned != null && unsigned['transaction_id'] == search;
|
||||
return unsigned?['transaction_id'] == search;
|
||||
}
|
||||
|
||||
/// Get the relationship type of an event. `null` if there is none
|
||||
String get relationshipType {
|
||||
if (content?.tryGet<Map<String, dynamic>>('m.relates_to') == null) {
|
||||
String? get relationshipType {
|
||||
if (content.tryGet<Map<String, dynamic>>('m.relates_to') == null) {
|
||||
return null;
|
||||
}
|
||||
if (content['m.relates_to'].containsKey('m.in_reply_to')) {
|
||||
|
|
@ -643,12 +683,12 @@ class Event extends MatrixEvent {
|
|||
}
|
||||
return content
|
||||
.tryGet<Map<String, dynamic>>('m.relates_to')
|
||||
.tryGet<String>('rel_type');
|
||||
?.tryGet<String>('rel_type');
|
||||
}
|
||||
|
||||
/// Get the event ID that this relationship will reference. `null` if there is none
|
||||
String get relationshipEventId {
|
||||
if (content == null || !(content['m.relates_to'] is Map)) {
|
||||
String? get relationshipEventId {
|
||||
if (!(content['m.relates_to'] is Map)) {
|
||||
return null;
|
||||
}
|
||||
if (content['m.relates_to'].containsKey('event_id')) {
|
||||
|
|
@ -664,15 +704,12 @@ class Event extends MatrixEvent {
|
|||
/// Get whether this event has aggregated events from a certain [type]
|
||||
/// To be able to do that you need to pass a [timeline]
|
||||
bool hasAggregatedEvents(Timeline timeline, String type) =>
|
||||
timeline.aggregatedEvents.containsKey(eventId) &&
|
||||
timeline.aggregatedEvents[eventId].containsKey(type);
|
||||
timeline.aggregatedEvents[eventId]?.containsKey(type) == true;
|
||||
|
||||
/// Get all the aggregated event objects for a given [type]. To be able to do this
|
||||
/// you have to pass a [timeline]
|
||||
Set<Event> aggregatedEvents(Timeline timeline, String type) =>
|
||||
hasAggregatedEvents(timeline, type)
|
||||
? timeline.aggregatedEvents[eventId][type]
|
||||
: <Event>{};
|
||||
timeline.aggregatedEvents[eventId]?[type] ?? <Event>{};
|
||||
|
||||
/// Fetches the event to be rendered, taking into account all the edits and the like.
|
||||
/// It needs a [timeline] for that.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -132,15 +132,16 @@ class Timeline {
|
|||
void _sessionKeyReceived(String sessionId) async {
|
||||
var decryptAtLeastOneEvent = false;
|
||||
final decryptFn = () async {
|
||||
if (!room.client.encryptionEnabled) {
|
||||
final encryption = room.client.encryption;
|
||||
if (!room.client.encryptionEnabled || encryption == null) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
if (events[i].type == EventTypes.Encrypted &&
|
||||
events[i].messageType == MessageTypes.BadEncrypted &&
|
||||
events[i].content['session_id'] == sessionId) {
|
||||
events[i] = await room.client.encryption
|
||||
.decryptRoomEvent(room.id, events[i], store: true);
|
||||
events[i] = await encryption.decryptRoomEvent(room.id, events[i],
|
||||
store: true);
|
||||
if (events[i].type != EventTypes.Encrypted) {
|
||||
decryptAtLeastOneEvent = true;
|
||||
}
|
||||
|
|
@ -148,7 +149,7 @@ class Timeline {
|
|||
}
|
||||
};
|
||||
if (room.client.database != null) {
|
||||
await room.client.database.transaction(decryptFn);
|
||||
await room.client.database?.transaction(decryptFn);
|
||||
} else {
|
||||
await decryptFn();
|
||||
}
|
||||
|
|
@ -162,7 +163,7 @@ class Timeline {
|
|||
event.messageType == MessageTypes.BadEncrypted &&
|
||||
event.content['can_request_session'] == true) {
|
||||
try {
|
||||
room.client.encryption.keyManager.maybeAutoRequest(room.id,
|
||||
room.client.encryption?.keyManager.maybeAutoRequest(room.id,
|
||||
event.content['session_id'], event.content['sender_key']);
|
||||
} catch (_) {
|
||||
// dispose
|
||||
|
|
@ -186,13 +187,11 @@ class Timeline {
|
|||
}
|
||||
int i;
|
||||
for (i = 0; i < events.length; i++) {
|
||||
final searchHaystack = <String>{};
|
||||
if (events[i].eventId != null) {
|
||||
searchHaystack.add(events[i].eventId);
|
||||
}
|
||||
if (events[i].unsigned != null &&
|
||||
events[i].unsigned['transaction_id'] != null) {
|
||||
searchHaystack.add(events[i].unsigned['transaction_id']);
|
||||
final searchHaystack = <String>{events[i].eventId};
|
||||
|
||||
final txnid = events[i].unsigned?['transaction_id'];
|
||||
if (txnid != null) {
|
||||
searchHaystack.add(txnid);
|
||||
}
|
||||
if (searchNeedle.intersection(searchHaystack).isNotEmpty) {
|
||||
break;
|
||||
|
|
@ -205,19 +204,18 @@ class Timeline {
|
|||
eventSet.removeWhere((e) =>
|
||||
e.matchesEventOrTransactionId(event.eventId) ||
|
||||
(event.unsigned != null &&
|
||||
e.matchesEventOrTransactionId(event.unsigned['transaction_id'])));
|
||||
e.matchesEventOrTransactionId(event.unsigned?['transaction_id'])));
|
||||
}
|
||||
|
||||
void addAggregatedEvent(Event event) {
|
||||
// we want to add an event to the aggregation tree
|
||||
if (event.relationshipType == null || event.relationshipEventId == null) {
|
||||
final relationshipType = event.relationshipType;
|
||||
final relationshipEventId = event.relationshipEventId;
|
||||
if (relationshipType == null || relationshipEventId == null) {
|
||||
return; // nothing to do
|
||||
}
|
||||
if (!aggregatedEvents.containsKey(event.relationshipEventId)) {
|
||||
aggregatedEvents[event.relationshipEventId] = <String, Set<Event>>{};
|
||||
}
|
||||
final events = (aggregatedEvents[event.relationshipEventId] ??=
|
||||
<String, Set<Event>>{})[event.relationshipType] ??= <Event>{};
|
||||
final events = (aggregatedEvents[relationshipEventId] ??=
|
||||
<String, Set<Event>>{})[relationshipType] ??= <Event>{};
|
||||
// remove a potential old event
|
||||
_removeEventFromSet(events, event);
|
||||
// add the new one
|
||||
|
|
@ -227,7 +225,7 @@ class Timeline {
|
|||
void removeAggregatedEvent(Event event) {
|
||||
aggregatedEvents.remove(event.eventId);
|
||||
if (event.unsigned != null) {
|
||||
aggregatedEvents.remove(event.unsigned['transaction_id']);
|
||||
aggregatedEvents.remove(event.unsigned?['transaction_id']);
|
||||
}
|
||||
for (final types in aggregatedEvents.values) {
|
||||
for (final events in types.values) {
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ class User extends Event {
|
|||
required String stateKey,
|
||||
dynamic content,
|
||||
required String typeKey,
|
||||
String? eventId,
|
||||
String eventId = 'fakevent',
|
||||
String? roomId,
|
||||
String? senderId,
|
||||
String senderId = 'fakesender',
|
||||
required DateTime originServerTs,
|
||||
dynamic unsigned,
|
||||
Room? room})
|
||||
|
|
@ -68,11 +68,11 @@ class User extends Event {
|
|||
room: room);
|
||||
|
||||
/// The full qualified Matrix ID in the format @username:server.abc.
|
||||
String get id => stateKey;
|
||||
String get id => stateKey ?? '@unknown:unknown';
|
||||
|
||||
/// The displayname of the user if the user has set one.
|
||||
String? get displayName =>
|
||||
content?.tryGet<String>('displayname') ??
|
||||
content.tryGet<String>('displayname') ??
|
||||
prevContent?.tryGet<String>('displayname');
|
||||
|
||||
/// Returns the power level of this user.
|
||||
|
|
@ -91,13 +91,16 @@ class User extends Event {
|
|||
}, orElse: () => Membership.join);
|
||||
|
||||
/// The avatar if the user has one.
|
||||
Uri? get avatarUrl => content != null && content.containsKey('avatar_url')
|
||||
? (content['avatar_url'] is String
|
||||
? Uri.tryParse(content['avatar_url'])
|
||||
: null)
|
||||
: (prevContent != null && prevContent['avatar_url'] is String
|
||||
? Uri.tryParse(prevContent['avatar_url'])
|
||||
: null);
|
||||
Uri? get avatarUrl {
|
||||
final prevContent = this.prevContent;
|
||||
return content.containsKey('avatar_url')
|
||||
? (content['avatar_url'] is String
|
||||
? Uri.tryParse(content['avatar_url'])
|
||||
: null)
|
||||
: (prevContent != null && prevContent['avatar_url'] is String
|
||||
? Uri.tryParse(prevContent['avatar_url'])
|
||||
: null);
|
||||
}
|
||||
|
||||
/// Returns the displayname or the local part of the Matrix ID if the user
|
||||
/// has no displayname. If [formatLocalpart] is true, then the localpart will
|
||||
|
|
@ -109,8 +112,8 @@ class User extends Event {
|
|||
bool? formatLocalpart,
|
||||
bool? mxidLocalPartFallback,
|
||||
}) {
|
||||
formatLocalpart ??= room?.client?.formatLocalpart ?? true;
|
||||
mxidLocalPartFallback ??= room?.client?.mxidLocalPartFallback ?? true;
|
||||
formatLocalpart ??= room?.client.formatLocalpart ?? true;
|
||||
mxidLocalPartFallback ??= room?.client.mxidLocalPartFallback ?? true;
|
||||
final displayName = this.displayName;
|
||||
if (displayName != null && displayName.isNotEmpty) {
|
||||
return displayName;
|
||||
|
|
@ -132,37 +135,40 @@ class User extends Event {
|
|||
}
|
||||
|
||||
/// Call the Matrix API to kick this user from this room.
|
||||
Future<void> kick() => room.kick(id);
|
||||
Future<void> kick() async => await room?.kick(id);
|
||||
|
||||
/// Call the Matrix API to ban this user from this room.
|
||||
Future<void> ban() => room.ban(id);
|
||||
Future<void> ban() async => await room?.ban(id);
|
||||
|
||||
/// Call the Matrix API to unban this banned user from this room.
|
||||
Future<void> unban() => room.unban(id);
|
||||
Future<void> unban() async => await room?.unban(id);
|
||||
|
||||
/// Call the Matrix API to change the power level of this user.
|
||||
Future<void> setPower(int power) => room.setPower(id, power);
|
||||
Future<void> setPower(int power) async => await room?.setPower(id, power);
|
||||
|
||||
/// Returns an existing direct chat ID with this user or creates a new one.
|
||||
/// Returns null on error.
|
||||
Future<String?> startDirectChat() => room.client.startDirectChat(id);
|
||||
Future<String?> startDirectChat() async => room?.client.startDirectChat(id);
|
||||
|
||||
/// The newest presence of this user if there is any and null if not.
|
||||
Presence? get presence => room.client.presences[id];
|
||||
Presence? get presence => room?.client.presences[id];
|
||||
|
||||
/// Whether the client is able to ban/unban this user.
|
||||
bool get canBan => room.canBan && powerLevel < room.ownPowerLevel;
|
||||
bool get canBan =>
|
||||
(room?.canBan ?? false) &&
|
||||
powerLevel < (room?.ownPowerLevel ?? powerLevel);
|
||||
|
||||
/// Whether the client is able to kick this user.
|
||||
bool get canKick =>
|
||||
[Membership.join, Membership.invite].contains(membership) &&
|
||||
room.canKick &&
|
||||
powerLevel < room.ownPowerLevel;
|
||||
(room?.canKick ?? false) &&
|
||||
powerLevel < (room?.ownPowerLevel ?? powerLevel);
|
||||
|
||||
/// Whether the client is allowed to change the power level of this user.
|
||||
/// Please be aware that you can only set the power level to at least your own!
|
||||
bool get canChangePowerLevel =>
|
||||
room.canChangePowerLevel && powerLevel < room.ownPowerLevel;
|
||||
(room?.canChangePowerLevel ?? false) &&
|
||||
powerLevel < (room?.ownPowerLevel ?? powerLevel);
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) => (other is User &&
|
||||
|
|
@ -190,7 +196,7 @@ class User extends Event {
|
|||
: '[$displayName]');
|
||||
|
||||
// get all the users with the same display name
|
||||
final allUsersWithSameDisplayname = room.getParticipants();
|
||||
final allUsersWithSameDisplayname = room?.getParticipants() ?? [];
|
||||
allUsersWithSameDisplayname.removeWhere((user) =>
|
||||
user.id == id ||
|
||||
(user.displayName?.isEmpty ?? true) ||
|
||||
|
|
|
|||
|
|
@ -171,33 +171,35 @@ extension CommandsClientExtension on Client {
|
|||
});
|
||||
addCommand('myroomnick', (CommandArgs args) async {
|
||||
final currentEventJson = args.room
|
||||
.getState(EventTypes.RoomMember, args.room.client.userID)
|
||||
.content
|
||||
.copy();
|
||||
.getState(EventTypes.RoomMember, args.room.client.userID!)
|
||||
?.content
|
||||
.copy() ??
|
||||
{};
|
||||
currentEventJson['displayname'] = args.msg;
|
||||
return await args.room.client.setRoomStateWithKey(
|
||||
args.room.id,
|
||||
EventTypes.RoomMember,
|
||||
args.room.client.userID,
|
||||
args.room.client.userID!,
|
||||
currentEventJson,
|
||||
);
|
||||
});
|
||||
addCommand('myroomavatar', (CommandArgs args) async {
|
||||
final currentEventJson = args.room
|
||||
.getState(EventTypes.RoomMember, args.room.client.userID)
|
||||
.content
|
||||
.copy();
|
||||
.getState(EventTypes.RoomMember, args.room.client.userID!)
|
||||
?.content
|
||||
.copy() ??
|
||||
{};
|
||||
currentEventJson['avatar_url'] = args.msg;
|
||||
return await args.room.client.setRoomStateWithKey(
|
||||
args.room.id,
|
||||
EventTypes.RoomMember,
|
||||
args.room.client.userID,
|
||||
args.room.client.userID!,
|
||||
currentEventJson,
|
||||
);
|
||||
});
|
||||
addCommand('discardsession', (CommandArgs args) async {
|
||||
await encryption?.keyManager
|
||||
?.clearOrUseOutboundGroupSession(args.room.id, wipe: true);
|
||||
.clearOrUseOutboundGroupSession(args.room.id, wipe: true);
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,17 +68,18 @@ class DeviceKeysList {
|
|||
}
|
||||
|
||||
Future<KeyVerification> startVerification() async {
|
||||
final encryption = client.encryption;
|
||||
if (encryption == null) {
|
||||
throw Exception('Encryption not enabled');
|
||||
}
|
||||
if (userId != client.userID) {
|
||||
// in-room verification with someone else
|
||||
final roomId = await client.startDirectChat(userId);
|
||||
if (roomId ==
|
||||
null /* can be null as long as startDirectChat is not migrated */) {
|
||||
throw Exception('Unable to start new room');
|
||||
}
|
||||
|
||||
final room =
|
||||
client.getRoomById(roomId) ?? Room(id: roomId, client: client);
|
||||
final request = KeyVerification(
|
||||
encryption: client.encryption, room: room, userId: userId);
|
||||
final request =
|
||||
KeyVerification(encryption: encryption, room: room, userId: userId);
|
||||
await request.start();
|
||||
// no need to add to the request client object. As we are doing a room
|
||||
// verification request that'll happen automatically once we know the transaction id
|
||||
|
|
@ -86,9 +87,9 @@ class DeviceKeysList {
|
|||
} else {
|
||||
// broadcast self-verification
|
||||
final request = KeyVerification(
|
||||
encryption: client.encryption, userId: userId, deviceId: '*');
|
||||
encryption: encryption, userId: userId, deviceId: '*');
|
||||
await request.start();
|
||||
client.encryption.keyVerificationManager.addRequest(request);
|
||||
encryption.keyVerificationManager.addRequest(request);
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
|
@ -314,13 +315,15 @@ abstract class SignableKey extends MatrixSignableKey {
|
|||
|
||||
Future<void> setVerified(bool newVerified, [bool sign = true]) async {
|
||||
_verified = newVerified;
|
||||
final encryption = client.encryption;
|
||||
if (newVerified &&
|
||||
sign &&
|
||||
encryption != null &&
|
||||
client.encryptionEnabled &&
|
||||
client.encryption.crossSigning.signable([this])) {
|
||||
encryption.crossSigning.signable([this])) {
|
||||
// sign the key!
|
||||
// ignore: unawaited_futures
|
||||
client.encryption.crossSigning.sign([this]);
|
||||
encryption.crossSigning.sign([this]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -493,11 +496,16 @@ class DeviceKeys extends SignableKey {
|
|||
if (!isValid) {
|
||||
throw Exception('setVerification called on invalid key');
|
||||
}
|
||||
final encryption = client.encryption;
|
||||
if (encryption == null) {
|
||||
throw Exception('setVerification called with disabled encryption');
|
||||
}
|
||||
|
||||
final request = KeyVerification(
|
||||
encryption: client.encryption, userId: userId, deviceId: deviceId!);
|
||||
encryption: encryption, userId: userId, deviceId: deviceId!);
|
||||
|
||||
request.start();
|
||||
client.encryption.keyVerificationManager.addRequest(request);
|
||||
encryption.keyVerificationManager.addRequest(request);
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,12 +104,11 @@ abstract class EventLocalizations {
|
|||
},
|
||||
EventTypes.RoomMember: (event, i18n, body) {
|
||||
var text = 'Failed to parse member event';
|
||||
final targetName = event.stateKeyUser.calcDisplayname();
|
||||
final targetName = event.stateKeyUser?.calcDisplayname() ?? '';
|
||||
// Has the membership changed?
|
||||
final newMembership = event.content['membership'] ?? '';
|
||||
final oldMembership = event.prevContent != null
|
||||
? event.prevContent['membership'] ?? ''
|
||||
: '';
|
||||
final oldMembership = event.prevContent?['membership'] ?? '';
|
||||
|
||||
if (newMembership != oldMembership) {
|
||||
if (oldMembership == 'invite' && newMembership == 'join') {
|
||||
text = i18n.acceptedTheInvitation(targetName);
|
||||
|
|
@ -146,22 +145,19 @@ abstract class EventLocalizations {
|
|||
}
|
||||
} else if (newMembership == 'join') {
|
||||
final newAvatar = event.content['avatar_url'] ?? '';
|
||||
final oldAvatar = event.prevContent != null
|
||||
? event.prevContent['avatar_url'] ?? ''
|
||||
: '';
|
||||
final oldAvatar = event.prevContent?['avatar_url'] ?? '';
|
||||
|
||||
final newDisplayname = event.content['displayname'] ?? '';
|
||||
final oldDisplayname = event.prevContent != null
|
||||
? event.prevContent['displayname'] ?? ''
|
||||
: '';
|
||||
final oldDisplayname = event.prevContent?['displayname'] ?? '';
|
||||
final stateKey = event.stateKey;
|
||||
|
||||
// Has the user avatar changed?
|
||||
if (newAvatar != oldAvatar) {
|
||||
text = i18n.changedTheProfileAvatar(targetName);
|
||||
}
|
||||
// Has the user avatar changed?
|
||||
else if (newDisplayname != oldDisplayname) {
|
||||
text = i18n.changedTheDisplaynameTo(event.stateKey, newDisplayname);
|
||||
// Has the user displayname changed?
|
||||
else if (newDisplayname != oldDisplayname && stateKey != null) {
|
||||
text = i18n.changedTheDisplaynameTo(stateKey, newDisplayname);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
|
|
@ -201,7 +197,7 @@ abstract class EventLocalizations {
|
|||
EventTypes.Encryption: (event, i18n, body) {
|
||||
var localizedBody =
|
||||
i18n.activatedEndToEndEncryption(event.sender.calcDisplayname());
|
||||
if (!event.room.client.encryptionEnabled) {
|
||||
if (event.room?.client.encryptionEnabled == false) {
|
||||
localizedBody += '. ' + i18n.needPantalaimonWarning;
|
||||
}
|
||||
return localizedBody;
|
||||
|
|
|
|||
|
|
@ -49,12 +49,14 @@ class EventUpdate {
|
|||
});
|
||||
|
||||
Future<EventUpdate> decrypt(Room room, {bool store = false}) async {
|
||||
final encryption = room.client.encryption;
|
||||
if (content['type'] != EventTypes.Encrypted ||
|
||||
!room.client.encryptionEnabled) {
|
||||
!room.client.encryptionEnabled ||
|
||||
encryption == null) {
|
||||
return this;
|
||||
}
|
||||
try {
|
||||
final decrpytedEvent = await room.client.encryption.decryptRoomEvent(
|
||||
final decrpytedEvent = await encryption.decryptRoomEvent(
|
||||
room.id, Event.fromJson(content, room),
|
||||
store: store, updateType: type);
|
||||
return EventUpdate(
|
||||
|
|
|
|||
|
|
@ -79,7 +79,9 @@ extension ImagePackRoomExtension on Room {
|
|||
for (final entry in allRoomEmotes.entries) {
|
||||
addImagePack(entry.value,
|
||||
room: this,
|
||||
slug: entry.value.stateKey.isEmpty ? 'room' : entry.value.stateKey);
|
||||
slug: (entry.value.stateKey?.isNotEmpty == true)
|
||||
? entry.value.stateKey
|
||||
: 'room');
|
||||
}
|
||||
}
|
||||
return packs;
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ class PillSyntax extends InlineSyntax {
|
|||
}
|
||||
|
||||
class MentionSyntax extends InlineSyntax {
|
||||
final String Function(String)? getMention;
|
||||
final String? Function(String)? getMention;
|
||||
MentionSyntax(this.getMention) : super(r'(@(?:\[[^\]:]+\]|\w+)(?:#\w+)?)');
|
||||
|
||||
@override
|
||||
|
|
@ -206,7 +206,7 @@ class MentionSyntax extends InlineSyntax {
|
|||
String markdown(
|
||||
String text, {
|
||||
Map<String, Map<String, String>> Function()? getEmotePacks,
|
||||
String Function(String)? getMention,
|
||||
String? Function(String)? getMention,
|
||||
}) {
|
||||
var ret = markdownToHtml(
|
||||
text,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import 'package:matrix_api_lite/matrix_api_lite.dart';
|
|||
import '../event.dart';
|
||||
|
||||
class SpaceChild {
|
||||
final String roomId;
|
||||
final String? roomId;
|
||||
final List<String>? via;
|
||||
final String order;
|
||||
final bool? suggested;
|
||||
|
|
@ -35,7 +35,7 @@ class SpaceChild {
|
|||
}
|
||||
|
||||
class SpaceParent {
|
||||
final String roomId;
|
||||
final String? roomId;
|
||||
final List<String>? via;
|
||||
final bool? canonical;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ extension MxcUriExtension on Uri {
|
|||
/// Returns a download Link to this content.
|
||||
Uri getDownloadLink(Client matrix) => isScheme('mxc')
|
||||
? matrix.homeserver != null
|
||||
? matrix.homeserver.resolve('_matrix/media/r0/download/$host$path')
|
||||
? matrix.homeserver
|
||||
?.resolve('_matrix/media/r0/download/$host$path') ??
|
||||
Uri()
|
||||
: Uri()
|
||||
: this;
|
||||
|
||||
|
|
@ -39,14 +41,15 @@ extension MxcUriExtension on Uri {
|
|||
ThumbnailMethod? method = ThumbnailMethod.crop,
|
||||
bool? animated = false}) {
|
||||
if (!isScheme('mxc')) return this;
|
||||
if (matrix.homeserver == null) {
|
||||
final homeserver = matrix.homeserver;
|
||||
if (homeserver == null) {
|
||||
return Uri();
|
||||
}
|
||||
return Uri(
|
||||
scheme: matrix.homeserver.scheme,
|
||||
host: matrix.homeserver.host,
|
||||
scheme: homeserver.scheme,
|
||||
host: homeserver.host,
|
||||
path: '/_matrix/media/r0/thumbnail/$host$path',
|
||||
port: matrix.homeserver.port,
|
||||
port: homeserver.port,
|
||||
queryParameters: {
|
||||
if (width != null) 'width': width.round().toString(),
|
||||
if (height != null) 'height': height.round().toString(),
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ class CallCapabilities {
|
|||
transferee: json['m.call.transferee'] as bool? ?? false,
|
||||
);
|
||||
Map<String, dynamic> toJson() => {
|
||||
if (transferee != null) 'm.call.transferee': transferee,
|
||||
if (dtmf != null) 'm.call.dtmf': dtmf,
|
||||
'm.call.transferee': transferee,
|
||||
'm.call.dtmf': dtmf,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -118,8 +118,8 @@ class SDPStreamPurpose {
|
|||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'purpose': purpose,
|
||||
if (audio_muted != null) 'audio_muted': audio_muted,
|
||||
if (video_muted != null) 'video_muted': video_muted,
|
||||
'audio_muted': audio_muted,
|
||||
'video_muted': video_muted,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -35,7 +34,7 @@ import 'fake_database.dart';
|
|||
import 'fake_matrix_api.dart';
|
||||
|
||||
void main() {
|
||||
Client matrix;
|
||||
late Client matrix;
|
||||
|
||||
Future<List<EventUpdate>> eventUpdateListFuture;
|
||||
Future<List<ToDeviceEvent>> toDeviceUpdateListFuture;
|
||||
|
|
@ -87,7 +86,7 @@ void main() {
|
|||
try {
|
||||
await matrix.checkHomeserver('https://fakeserver.wrongaddress');
|
||||
} catch (exception) {
|
||||
expect(exception != null, true);
|
||||
expect(exception.toString().isNotEmpty, true);
|
||||
}
|
||||
await matrix.checkHomeserver('https://fakeserver.notexisting',
|
||||
checkWellKnown: false);
|
||||
|
|
@ -128,7 +127,7 @@ void main() {
|
|||
expect(matrix.getDirectChatFromUserId('@bob:example.com'),
|
||||
'!726s6s6q:example.com');
|
||||
expect(matrix.rooms[1].directChatMatrixID, '@bob:example.com');
|
||||
expect(matrix.directChats, matrix.accountData['m.direct'].content);
|
||||
expect(matrix.directChats, matrix.accountData['m.direct']?.content);
|
||||
expect(matrix.presences.length, 1);
|
||||
expect(matrix.rooms[1].ephemerals.length, 2);
|
||||
expect(matrix.rooms[1].typingUsers.length, 1);
|
||||
|
|
@ -139,29 +138,30 @@ void main() {
|
|||
Client.supportedGroupEncryptionAlgorithms.first);
|
||||
expect(
|
||||
matrix.rooms[1].roomAccountData['m.receipt']
|
||||
.content['@alice:example.com']['ts'],
|
||||
?.content['@alice:example.com']['ts'],
|
||||
1436451550453);
|
||||
expect(
|
||||
matrix.rooms[1].roomAccountData['m.receipt']
|
||||
.content['@alice:example.com']['event_id'],
|
||||
?.content['@alice:example.com']['event_id'],
|
||||
'7365636s6r6432:example.com');
|
||||
expect(matrix.rooms.length, 2);
|
||||
expect(matrix.rooms[1].canonicalAlias,
|
||||
"#famedlyContactDiscovery:${matrix.userID.split(":")[1]}");
|
||||
expect(matrix.presences['@alice:example.com'].presence.presence,
|
||||
"#famedlyContactDiscovery:${matrix.userID!.split(":")[1]}");
|
||||
expect(matrix.presences['@alice:example.com']?.presence.presence,
|
||||
PresenceType.online);
|
||||
expect(presenceCounter, 1);
|
||||
expect(accountDataCounter, 9);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(matrix.userDeviceKeys.length, 4);
|
||||
expect(matrix.userDeviceKeys['@alice:example.com'].outdated, false);
|
||||
expect(matrix.userDeviceKeys['@alice:example.com'].deviceKeys.length, 2);
|
||||
expect(matrix.userDeviceKeys['@alice:example.com']?.outdated, false);
|
||||
expect(matrix.userDeviceKeys['@alice:example.com']?.deviceKeys.length, 2);
|
||||
expect(
|
||||
matrix.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||
.verified,
|
||||
matrix.userDeviceKeys['@alice:example.com']?.deviceKeys['JLAFKJWSCS']
|
||||
?.verified,
|
||||
false);
|
||||
|
||||
await matrix.handleSync(SyncUpdate.fromJson({
|
||||
'next_batch': 'fakesync',
|
||||
'device_lists': {
|
||||
'changed': [
|
||||
'@alice:example.com',
|
||||
|
|
@ -173,9 +173,10 @@ void main() {
|
|||
}));
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(matrix.userDeviceKeys.length, 3);
|
||||
expect(matrix.userDeviceKeys['@alice:example.com'].outdated, true);
|
||||
expect(matrix.userDeviceKeys['@alice:example.com']?.outdated, true);
|
||||
|
||||
await matrix.handleSync(SyncUpdate.fromJson({
|
||||
'next_batch': 'fakesync',
|
||||
'rooms': {
|
||||
'join': {
|
||||
'!726s6s6q:example.com': {
|
||||
|
|
@ -199,7 +200,7 @@ void main() {
|
|||
|
||||
expect(
|
||||
matrix.getRoomByAlias(
|
||||
"#famedlyContactDiscovery:${matrix.userID.split(":")[1]}"),
|
||||
"#famedlyContactDiscovery:${matrix.userID!.split(":")[1]}"),
|
||||
null);
|
||||
});
|
||||
|
||||
|
|
@ -310,7 +311,7 @@ void main() {
|
|||
identifier: AuthenticationUserIdentifier(user: 'test'),
|
||||
password: '1234');
|
||||
|
||||
expect(loginResp != null, true);
|
||||
expect(loginResp.userId != null, true);
|
||||
});
|
||||
|
||||
test('setAvatar', () async {
|
||||
|
|
@ -340,7 +341,7 @@ void main() {
|
|||
expect(archive[0].id, '!5345234234:example.com');
|
||||
expect(archive[0].membership, Membership.leave);
|
||||
expect(archive[0].name, 'The room name');
|
||||
expect(archive[0].lastEvent.body, 'This is an example text message');
|
||||
expect(archive[0].lastEvent?.body, 'This is an example text message');
|
||||
expect(archive[0].roomAccountData.length, 1);
|
||||
expect(archive[1].id, '!5345234235:example.com');
|
||||
expect(archive[1].membership, Membership.leave);
|
||||
|
|
@ -364,7 +365,7 @@ void main() {
|
|||
}
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await matrix.sendToDeviceEncrypted(
|
||||
matrix.userDeviceKeys['@alice:example.com'].deviceKeys.values
|
||||
matrix.userDeviceKeys['@alice:example.com']!.deviceKeys.values
|
||||
.toList(),
|
||||
'm.message',
|
||||
{
|
||||
|
|
@ -382,7 +383,7 @@ void main() {
|
|||
}
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await matrix.sendToDeviceEncryptedChunked(
|
||||
matrix.userDeviceKeys['@alice:example.com'].deviceKeys.values
|
||||
matrix.userDeviceKeys['@alice:example.com']!.deviceKeys.values
|
||||
.toList(),
|
||||
'm.message',
|
||||
{
|
||||
|
|
@ -483,11 +484,11 @@ void main() {
|
|||
expect(
|
||||
json.decode(FakeMatrixApi
|
||||
.calledEndpoints['/client/r0/sendToDevice/foxies/floof_txnid']
|
||||
[0])['messages'],
|
||||
?[0])['messages'],
|
||||
foxContent);
|
||||
expect(
|
||||
json.decode(FakeMatrixApi.calledEndpoints[
|
||||
'/client/r0/sendToDevice/raccoon/raccoon_txnid'][0])['messages'],
|
||||
'/client/r0/sendToDevice/raccoon/raccoon_txnid']?[0])['messages'],
|
||||
raccoonContent);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.sendToDevice('bunny', 'bunny_txnid', bunnyContent);
|
||||
|
|
@ -502,7 +503,7 @@ void main() {
|
|||
expect(
|
||||
json.decode(FakeMatrixApi
|
||||
.calledEndpoints['/client/r0/sendToDevice/bunny/bunny_txnid']
|
||||
[0])['messages'],
|
||||
?[0])['messages'],
|
||||
bunnyContent);
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
|
|
@ -546,16 +547,16 @@ void main() {
|
|||
expect(
|
||||
json.decode(FakeMatrixApi
|
||||
.calledEndpoints['/client/r0/sendToDevice/foxies/floof_txnid']
|
||||
[0])['messages'],
|
||||
?[0])['messages'],
|
||||
foxContent);
|
||||
expect(
|
||||
json.decode(FakeMatrixApi.calledEndpoints[
|
||||
'/client/r0/sendToDevice/raccoon/raccoon_txnid'][0])['messages'],
|
||||
'/client/r0/sendToDevice/raccoon/raccoon_txnid']?[0])['messages'],
|
||||
raccoonContent);
|
||||
expect(
|
||||
json.decode(FakeMatrixApi
|
||||
.calledEndpoints['/client/r0/sendToDevice/bunny/bunny_txnid']
|
||||
[0])['messages'],
|
||||
?[0])['messages'],
|
||||
bunnyContent);
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
|
|
@ -596,10 +597,12 @@ void main() {
|
|||
expect(client2.homeserver, client1.homeserver);
|
||||
expect(client2.deviceID, client1.deviceID);
|
||||
expect(client2.deviceName, client1.deviceName);
|
||||
expect(client2.rooms.length, 2);
|
||||
if (client2.encryptionEnabled) {
|
||||
expect(client2.encryption.fingerprintKey,
|
||||
client1.encryption.fingerprintKey);
|
||||
expect(client2.encryption.identityKey, client1.encryption.identityKey);
|
||||
expect(client2.encryption?.fingerprintKey,
|
||||
client1.encryption?.fingerprintKey);
|
||||
expect(
|
||||
client2.encryption?.identityKey, client1.encryption?.identityKey);
|
||||
expect(client2.rooms[1].id, client1.rooms[1].id);
|
||||
}
|
||||
|
||||
|
|
@ -628,16 +631,18 @@ void main() {
|
|||
final response =
|
||||
await client.uploadContent(Uint8List(0), filename: 'file.jpeg');
|
||||
expect(response.toString(), 'mxc://example.com/AQwafuaFswefuhsfAFAgsw');
|
||||
expect(await client.database.getFile(response) != null,
|
||||
client.database.supportsFileStoring);
|
||||
expect(await client.database?.getFile(response) != null,
|
||||
client.database?.supportsFileStoring);
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
|
||||
test('object equality', () async {
|
||||
final time1 = DateTime.fromMillisecondsSinceEpoch(1);
|
||||
final time2 = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
final user1 = User('@user1:example.org', room: Room(id: '!room1'));
|
||||
final user2 = User('@user2:example.org', room: Room(id: '!room1'));
|
||||
final user1 =
|
||||
User('@user1:example.org', room: Room(id: '!room1', client: matrix));
|
||||
final user2 =
|
||||
User('@user2:example.org', room: Room(id: '!room1', client: matrix));
|
||||
// receipts
|
||||
expect(Receipt(user1, time1) == Receipt(user1, time1), true);
|
||||
expect(Receipt(user1, time1) == Receipt(user1, time2), false);
|
||||
|
|
@ -648,19 +653,29 @@ void main() {
|
|||
expect(user1 == user1, true);
|
||||
expect(user1 == user2, false);
|
||||
expect(
|
||||
user1 == User('@user1:example.org', room: Room(id: '!room2')), false);
|
||||
user1 ==
|
||||
User('@user1:example.org',
|
||||
room: Room(id: '!room2', client: matrix)),
|
||||
false);
|
||||
expect(
|
||||
user1 ==
|
||||
User('@user1:example.org',
|
||||
room: Room(id: '!room1'), membership: 'leave'),
|
||||
room: Room(id: '!room1', client: matrix),
|
||||
membership: 'leave'),
|
||||
false);
|
||||
// ignore: unrelated_type_equality_checks
|
||||
expect(user1 == 'beep', false);
|
||||
// rooms
|
||||
expect(Room(id: '!room1') == Room(id: '!room1'), true);
|
||||
expect(Room(id: '!room1') == Room(id: '!room2'), false);
|
||||
expect(
|
||||
Room(id: '!room1', client: matrix) ==
|
||||
Room(id: '!room1', client: matrix),
|
||||
true);
|
||||
expect(
|
||||
Room(id: '!room1', client: matrix) ==
|
||||
Room(id: '!room2', client: matrix),
|
||||
false);
|
||||
// ignore: unrelated_type_equality_checks
|
||||
expect(Room(id: '!room1') == 'beep', false);
|
||||
expect(Room(id: '!room1', client: matrix) == 'beep', false);
|
||||
});
|
||||
|
||||
test('clearCache', () async {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2021 Famedly GmbH
|
||||
|
|
@ -27,16 +26,16 @@ import 'fake_matrix_api.dart';
|
|||
|
||||
void main() {
|
||||
group('Commands', () {
|
||||
Client client;
|
||||
Room room;
|
||||
late Client client;
|
||||
late Room room;
|
||||
var olmEnabled = true;
|
||||
|
||||
final getLastMessagePayload =
|
||||
([String type = 'm.room.message', String stateKey]) {
|
||||
([String type = 'm.room.message', String? stateKey]) {
|
||||
final state = stateKey != null;
|
||||
return json.decode(FakeMatrixApi.calledEndpoints.entries
|
||||
.firstWhere((e) => e.key.startsWith(
|
||||
'/client/r0/rooms/${Uri.encodeComponent(room.id)}/${state ? 'state' : 'send'}/${Uri.encodeComponent(type)}${state && stateKey.isNotEmpty ? '/' + Uri.encodeComponent(stateKey) : ''}'))
|
||||
'/client/r0/rooms/${Uri.encodeComponent(room.id)}/${state ? 'state' : 'send'}/${Uri.encodeComponent(type)}${state && stateKey?.isNotEmpty == true ? '/' + Uri.encodeComponent(stateKey!) : ''}'))
|
||||
.value
|
||||
.first);
|
||||
};
|
||||
|
|
@ -55,12 +54,18 @@ void main() {
|
|||
content: {},
|
||||
room: room,
|
||||
stateKey: '',
|
||||
eventId: '\$fakeeventid',
|
||||
originServerTs: DateTime.now(),
|
||||
senderId: '\@fakeuser:fakeServer.notExisting',
|
||||
));
|
||||
room.setState(Event(
|
||||
type: 'm.room.member',
|
||||
content: {'membership': 'join'},
|
||||
room: room,
|
||||
stateKey: client.userID,
|
||||
eventId: '\$fakeeventid',
|
||||
originServerTs: DateTime.now(),
|
||||
senderId: '\@fakeuser:fakeServer.notExisting',
|
||||
));
|
||||
});
|
||||
|
||||
|
|
@ -135,7 +140,18 @@ void main() {
|
|||
test('react', () async {
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await room.sendTextEvent('/react 🦊',
|
||||
inReplyTo: Event(eventId: '\$event'));
|
||||
inReplyTo: Event(
|
||||
eventId: '\$event',
|
||||
type: 'm.room.message',
|
||||
content: {
|
||||
'msgtype': 'm.text',
|
||||
'body': '<b>yay</b>',
|
||||
'format': 'org.matrix.custom.html',
|
||||
'formatted_body': '<b>yay</b>',
|
||||
},
|
||||
originServerTs: DateTime.now(),
|
||||
senderId: client.userID!,
|
||||
));
|
||||
final sent = getLastMessagePayload('m.reaction');
|
||||
expect(sent, {
|
||||
'm.relates_to': {
|
||||
|
|
@ -152,7 +168,7 @@ void main() {
|
|||
expect(
|
||||
FakeMatrixApi
|
||||
.calledEndpoints['/client/r0/join/!newroom%3Aexample.com']
|
||||
.first !=
|
||||
?.first !=
|
||||
null,
|
||||
true);
|
||||
});
|
||||
|
|
@ -164,7 +180,7 @@ void main() {
|
|||
FakeMatrixApi
|
||||
.calledEndpoints[
|
||||
'/client/r0/rooms/!1234%3AfakeServer.notExisting/leave']
|
||||
.first !=
|
||||
?.first !=
|
||||
null,
|
||||
true);
|
||||
});
|
||||
|
|
@ -192,7 +208,7 @@ void main() {
|
|||
json.decode(FakeMatrixApi
|
||||
.calledEndpoints[
|
||||
'/client/r0/rooms/!1234%3AfakeServer.notExisting/kick']
|
||||
.first),
|
||||
?.first),
|
||||
{
|
||||
'user_id': '@baduser:example.org',
|
||||
});
|
||||
|
|
@ -205,7 +221,7 @@ void main() {
|
|||
json.decode(FakeMatrixApi
|
||||
.calledEndpoints[
|
||||
'/client/r0/rooms/!1234%3AfakeServer.notExisting/ban']
|
||||
.first),
|
||||
?.first),
|
||||
{
|
||||
'user_id': '@baduser:example.org',
|
||||
});
|
||||
|
|
@ -218,7 +234,7 @@ void main() {
|
|||
json.decode(FakeMatrixApi
|
||||
.calledEndpoints[
|
||||
'/client/r0/rooms/!1234%3AfakeServer.notExisting/unban']
|
||||
.first),
|
||||
?.first),
|
||||
{
|
||||
'user_id': '@baduser:example.org',
|
||||
});
|
||||
|
|
@ -231,7 +247,7 @@ void main() {
|
|||
json.decode(FakeMatrixApi
|
||||
.calledEndpoints[
|
||||
'/client/r0/rooms/!1234%3AfakeServer.notExisting/invite']
|
||||
.first),
|
||||
?.first),
|
||||
{
|
||||
'user_id': '@baduser:example.org',
|
||||
});
|
||||
|
|
@ -259,14 +275,14 @@ void main() {
|
|||
|
||||
test('discardsession', () async {
|
||||
if (olmEnabled) {
|
||||
await client.encryption.keyManager.createOutboundGroupSession(room.id);
|
||||
await client.encryption?.keyManager.createOutboundGroupSession(room.id);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(room.id) !=
|
||||
client.encryption?.keyManager.getOutboundGroupSession(room.id) !=
|
||||
null,
|
||||
true);
|
||||
await room.sendTextEvent('/discardsession');
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(room.id) !=
|
||||
client.encryption?.keyManager.getOutboundGroupSession(room.id) !=
|
||||
null,
|
||||
false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -49,8 +48,8 @@ Future<bool> olmEnabled() async {
|
|||
void testDatabase(
|
||||
Future<DatabaseApi> futureDatabase,
|
||||
) {
|
||||
DatabaseApi database;
|
||||
int toDeviceQueueIndex;
|
||||
late DatabaseApi database;
|
||||
late int toDeviceQueueIndex;
|
||||
test('Open', () async {
|
||||
database = await futureDatabase;
|
||||
});
|
||||
|
|
@ -115,8 +114,9 @@ void testDatabase(
|
|||
'limited_timeline': false,
|
||||
'membership': Membership.join,
|
||||
});
|
||||
await database.storeRoomUpdate('!testroom', roomUpdate);
|
||||
final rooms = await database.getRoomList(Client('testclient'));
|
||||
final client = Client('testclient');
|
||||
await database.storeRoomUpdate('!testroom', roomUpdate, client);
|
||||
final rooms = await database.getRoomList(client);
|
||||
expect(rooms.single.id, '!testroom');
|
||||
});
|
||||
test('getRoomList', () async {
|
||||
|
|
@ -124,8 +124,9 @@ void testDatabase(
|
|||
expect(list.single.id, '!testroom');
|
||||
});
|
||||
test('setRoomPrevBatch', () async {
|
||||
await database.setRoomPrevBatch('1234', '!testroom');
|
||||
final rooms = await database.getRoomList(Client('testclient'));
|
||||
final client = Client('testclient');
|
||||
await database.setRoomPrevBatch('1234', '!testroom', client);
|
||||
final rooms = await database.getRoomList(client);
|
||||
expect(rooms.single.prev_batch, '1234');
|
||||
});
|
||||
test('forgetRoom', () async {
|
||||
|
|
@ -149,7 +150,7 @@ void testDatabase(
|
|||
);
|
||||
|
||||
final client = await database.getClient('name');
|
||||
expect(client['token'], 'token');
|
||||
expect(client?['token'], 'token');
|
||||
});
|
||||
test('updateClient', () async {
|
||||
await database.updateClient(
|
||||
|
|
@ -162,21 +163,21 @@ void testDatabase(
|
|||
'olmAccount',
|
||||
);
|
||||
final client = await database.getClient('name');
|
||||
expect(client['token'], 'token_different');
|
||||
expect(client?['token'], 'token_different');
|
||||
});
|
||||
test('updateClientKeys', () async {
|
||||
await database.updateClientKeys(
|
||||
'olmAccount2',
|
||||
);
|
||||
final client = await database.getClient('name');
|
||||
expect(client['olm_account'], 'olmAccount2');
|
||||
expect(client?['olm_account'], 'olmAccount2');
|
||||
});
|
||||
test('storeSyncFilterId', () async {
|
||||
await database.storeSyncFilterId(
|
||||
'1234',
|
||||
);
|
||||
final client = await database.getClient('name');
|
||||
expect(client['sync_filter_id'], '1234');
|
||||
expect(client?['sync_filter_id'], '1234');
|
||||
});
|
||||
test('getAccountData', () async {
|
||||
await database.getAccountData();
|
||||
|
|
@ -192,52 +193,53 @@ void testDatabase(
|
|||
});
|
||||
test('storeEventUpdate', () async {
|
||||
await database.storeEventUpdate(
|
||||
EventUpdate(
|
||||
roomID: '!testroom:example.com',
|
||||
type: EventUpdateType.timeline,
|
||||
content: {
|
||||
'type': EventTypes.Message,
|
||||
'content': {
|
||||
'body': '* edit 3',
|
||||
'msgtype': 'm.text',
|
||||
'm.new_content': {
|
||||
'body': 'edit 3',
|
||||
EventUpdate(
|
||||
roomID: '!testroom:example.com',
|
||||
type: EventUpdateType.timeline,
|
||||
content: {
|
||||
'type': EventTypes.Message,
|
||||
'content': {
|
||||
'body': '* edit 3',
|
||||
'msgtype': 'm.text',
|
||||
'm.new_content': {
|
||||
'body': 'edit 3',
|
||||
'msgtype': 'm.text',
|
||||
},
|
||||
'm.relates_to': {
|
||||
'event_id': '\$source',
|
||||
'rel_type': RelationshipTypes.edit,
|
||||
},
|
||||
},
|
||||
'm.relates_to': {
|
||||
'event_id': '\$source',
|
||||
'rel_type': RelationshipTypes.edit,
|
||||
},
|
||||
'event_id': '\$event:example.com',
|
||||
'sender': '@bob:example.org',
|
||||
},
|
||||
'event_id': '\$event:example.com',
|
||||
'sender': '@bob:example.org',
|
||||
},
|
||||
),
|
||||
);
|
||||
),
|
||||
Client('testclient'));
|
||||
});
|
||||
test('getEventById', () async {
|
||||
final event = await database.getEventById(
|
||||
'\$event:example.com', Room(id: '!testroom:example.com'));
|
||||
expect(event.type, EventTypes.Message);
|
||||
final event = await database.getEventById('\$event:example.com',
|
||||
Room(id: '!testroom:example.com', client: Client('testclient')));
|
||||
expect(event?.type, EventTypes.Message);
|
||||
});
|
||||
test('getEventList', () async {
|
||||
final events =
|
||||
await database.getEventList(Room(id: '!testroom:example.com'));
|
||||
final events = await database.getEventList(
|
||||
Room(id: '!testroom:example.com', client: Client('testclient')));
|
||||
expect(events.single.type, EventTypes.Message);
|
||||
});
|
||||
test('getUser', () async {
|
||||
final user = await database.getUser(
|
||||
'@bob:example.org', Room(id: '!testroom:example.com'));
|
||||
final user = await database.getUser('@bob:example.org',
|
||||
Room(id: '!testroom:example.com', client: Client('testclient')));
|
||||
expect(user, null);
|
||||
});
|
||||
test('getUsers', () async {
|
||||
final users = await database.getUsers(Room(id: '!testroom:example.com'));
|
||||
final users = await database.getUsers(
|
||||
Room(id: '!testroom:example.com', client: Client('testclient')));
|
||||
expect(users.isEmpty, true);
|
||||
});
|
||||
test('removeEvent', () async {
|
||||
await database.removeEvent('\$event:example.com', '!testroom:example.com');
|
||||
final event = await database.getEventById(
|
||||
'\$event:example.com', Room(id: '!testroom:example.com'));
|
||||
final event = await database.getEventById('\$event:example.com',
|
||||
Room(id: '!testroom:example.com', client: Client('testclient')));
|
||||
expect(event, null);
|
||||
});
|
||||
test('getAllInboundGroupSessions', () async {
|
||||
|
|
@ -265,7 +267,7 @@ void testDatabase(
|
|||
'!testroom:example.com',
|
||||
'sessionId',
|
||||
);
|
||||
expect(jsonDecode(session.content)['foo'], 'bar');
|
||||
expect(jsonDecode(session!.content)['foo'], 'bar');
|
||||
});
|
||||
test('markInboundGroupSessionAsUploaded', () async {
|
||||
await database.markInboundGroupSessionAsUploaded(
|
||||
|
|
@ -294,7 +296,7 @@ void testDatabase(
|
|||
});
|
||||
test('storeSSSSCache', () async {
|
||||
await database.storeSSSSCache('type', 'keyId', 'ciphertext', '{}');
|
||||
final cache = await database.getSSSSCache('type');
|
||||
final cache = (await database.getSSSSCache('type'))!;
|
||||
expect(cache.type, 'type');
|
||||
expect(cache.keyId, 'keyId');
|
||||
expect(cache.ciphertext, 'ciphertext');
|
||||
|
|
@ -347,7 +349,7 @@ void testDatabase(
|
|||
'!testroom:example.com',
|
||||
'@alice:example.com',
|
||||
);
|
||||
expect(session.devices.isEmpty, true);
|
||||
expect(session?.devices.isEmpty, true);
|
||||
});
|
||||
test('getLastSentMessageUserDeviceKey', () async {
|
||||
final list = await database.getLastSentMessageUserDeviceKey(
|
||||
|
|
@ -359,7 +361,7 @@ void testDatabase(
|
|||
test('getUnimportantRoomEventStatesForRoom', () async {
|
||||
final events = await database.getUnimportantRoomEventStatesForRoom(
|
||||
['events'],
|
||||
Room(id: '!mep'),
|
||||
Room(id: '!mep', client: Client('testclient')),
|
||||
);
|
||||
expect(events.isEmpty, true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -34,7 +33,7 @@ void main() {
|
|||
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
late Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
|
|
@ -135,8 +134,8 @@ void main() {
|
|||
test('set blocked / verified', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key =
|
||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||
client.userDeviceKeys[client.userID].deviceKeys['UNSIGNEDDEVICE'] =
|
||||
client.userDeviceKeys[client.userID]!.deviceKeys['OTHERDEVICE']!;
|
||||
client.userDeviceKeys[client.userID]?.deviceKeys['UNSIGNEDDEVICE'] =
|
||||
DeviceKeys.fromJson({
|
||||
'user_id': '@test:fakeServer.notExisting',
|
||||
'device_id': 'UNSIGNEDDEVICE',
|
||||
|
|
@ -157,10 +156,10 @@ void main() {
|
|||
},
|
||||
},
|
||||
}, client);
|
||||
final masterKey = client.userDeviceKeys[client.userID].masterKey;
|
||||
final masterKey = client.userDeviceKeys[client.userID]!.masterKey!;
|
||||
masterKey.setDirectVerified(true);
|
||||
// we need to populate the ssss cache to be able to test signing easily
|
||||
final handle = client.encryption.ssss.open();
|
||||
final handle = client.encryption!.ssss.open();
|
||||
await handle.unlock(recoveryKey: ssssKey);
|
||||
await handle.maybeCacheAll();
|
||||
|
||||
|
|
@ -174,16 +173,16 @@ void main() {
|
|||
expect(key.verified, true); // still verified via cross-sgining
|
||||
expect(key.encryptToDevice, true);
|
||||
expect(
|
||||
client.userDeviceKeys[client.userID].deviceKeys['UNSIGNEDDEVICE']
|
||||
.encryptToDevice,
|
||||
client.userDeviceKeys[client.userID]?.deviceKeys['UNSIGNEDDEVICE']
|
||||
?.encryptToDevice,
|
||||
false);
|
||||
|
||||
expect(masterKey.verified, true);
|
||||
await masterKey.setBlocked(true);
|
||||
expect(masterKey.verified, false);
|
||||
expect(
|
||||
client.userDeviceKeys[client.userID].deviceKeys['UNSIGNEDDEVICE']
|
||||
.encryptToDevice,
|
||||
client.userDeviceKeys[client.userID]?.deviceKeys['UNSIGNEDDEVICE']
|
||||
?.encryptToDevice,
|
||||
true);
|
||||
await masterKey.setBlocked(false);
|
||||
expect(masterKey.verified, true);
|
||||
|
|
@ -205,57 +204,57 @@ void main() {
|
|||
.any((k) => k == '/client/r0/keys/signatures/upload'),
|
||||
false);
|
||||
expect(key.directVerified, false);
|
||||
client.userDeviceKeys[client.userID].deviceKeys.remove('UNSIGNEDDEVICE');
|
||||
client.userDeviceKeys[client.userID]?.deviceKeys.remove('UNSIGNEDDEVICE');
|
||||
});
|
||||
|
||||
test('verification based on signatures', () async {
|
||||
if (!olmEnabled) return;
|
||||
final user = client.userDeviceKeys[client.userID];
|
||||
user.masterKey.setDirectVerified(true);
|
||||
expect(user.deviceKeys['GHTYAJCE'].crossVerified, true);
|
||||
expect(user.deviceKeys['GHTYAJCE'].signed, true);
|
||||
expect(user.getKey('GHTYAJCE').crossVerified, true);
|
||||
expect(user.deviceKeys['OTHERDEVICE'].crossVerified, true);
|
||||
expect(user.selfSigningKey.crossVerified, true);
|
||||
final user = client.userDeviceKeys[client.userID]!;
|
||||
user.masterKey?.setDirectVerified(true);
|
||||
expect(user.deviceKeys['GHTYAJCE']?.crossVerified, true);
|
||||
expect(user.deviceKeys['GHTYAJCE']?.signed, true);
|
||||
expect(user.getKey('GHTYAJCE')?.crossVerified, true);
|
||||
expect(user.deviceKeys['OTHERDEVICE']?.crossVerified, true);
|
||||
expect(user.selfSigningKey?.crossVerified, true);
|
||||
expect(
|
||||
user
|
||||
.getKey('F9ypFzgbISXCzxQhhSnXMkc1vq12Luna3Nw5rqViOJY')
|
||||
.crossVerified,
|
||||
?.crossVerified,
|
||||
true);
|
||||
expect(user.userSigningKey.crossVerified, true);
|
||||
expect(user.userSigningKey?.crossVerified, true);
|
||||
expect(user.verified, UserVerifiedStatus.verified);
|
||||
user.masterKey.setDirectVerified(false);
|
||||
expect(user.deviceKeys['GHTYAJCE'].crossVerified, false);
|
||||
expect(user.deviceKeys['OTHERDEVICE'].crossVerified, false);
|
||||
user.masterKey?.setDirectVerified(false);
|
||||
expect(user.deviceKeys['GHTYAJCE']?.crossVerified, false);
|
||||
expect(user.deviceKeys['OTHERDEVICE']?.crossVerified, false);
|
||||
expect(user.verified, UserVerifiedStatus.unknown);
|
||||
|
||||
user.deviceKeys['OTHERDEVICE'].setDirectVerified(true);
|
||||
user.deviceKeys['OTHERDEVICE']?.setDirectVerified(true);
|
||||
expect(user.verified, UserVerifiedStatus.verified);
|
||||
user.deviceKeys['OTHERDEVICE'].setDirectVerified(false);
|
||||
user.deviceKeys['OTHERDEVICE']?.setDirectVerified(false);
|
||||
|
||||
user.masterKey.setDirectVerified(true);
|
||||
user.deviceKeys['GHTYAJCE'].signatures[client.userID]
|
||||
.removeWhere((k, v) => k != 'ed25519:GHTYAJCE');
|
||||
expect(user.deviceKeys['GHTYAJCE'].verified,
|
||||
user.masterKey?.setDirectVerified(true);
|
||||
user.deviceKeys['GHTYAJCE']?.signatures?[client.userID]
|
||||
?.removeWhere((k, v) => k != 'ed25519:GHTYAJCE');
|
||||
expect(user.deviceKeys['GHTYAJCE']?.verified,
|
||||
true); // it's our own device, should be direct verified
|
||||
expect(
|
||||
user.deviceKeys['GHTYAJCE'].signed, false); // not verified for others
|
||||
user.deviceKeys['OTHERDEVICE'].signatures.clear();
|
||||
expect(user.deviceKeys['GHTYAJCE']?.signed,
|
||||
false); // not verified for others
|
||||
user.deviceKeys['OTHERDEVICE']?.signatures?.clear();
|
||||
expect(user.verified, UserVerifiedStatus.unknownDevice);
|
||||
});
|
||||
|
||||
test('start verification', () async {
|
||||
if (!olmEnabled) return;
|
||||
var req = client
|
||||
.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||
.startVerification();
|
||||
.userDeviceKeys['@alice:example.com']?.deviceKeys['JLAFKJWSCS']
|
||||
?.startVerification();
|
||||
expect(req != null, true);
|
||||
expect(req.room != null, false);
|
||||
expect(req?.room != null, false);
|
||||
|
||||
req =
|
||||
await client.userDeviceKeys['@alice:example.com'].startVerification();
|
||||
req = await client.userDeviceKeys['@alice:example.com']
|
||||
?.startVerification();
|
||||
expect(req != null, true);
|
||||
expect(req.room != null, true);
|
||||
expect(req?.room != null, true);
|
||||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -33,9 +32,9 @@ void main() {
|
|||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
Map<String, dynamic> oldSecret;
|
||||
String origKeyId;
|
||||
late Client client;
|
||||
late Map<String, dynamic> oldSecret;
|
||||
late String origKeyId;
|
||||
|
||||
test('setupClient', () async {
|
||||
client = await getClient();
|
||||
|
|
@ -53,8 +52,8 @@ void main() {
|
|||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Bootstrap bootstrap;
|
||||
bootstrap = client.encryption.bootstrap(
|
||||
Bootstrap? bootstrap;
|
||||
bootstrap = client.encryption!.bootstrap(
|
||||
onUpdate: () async {
|
||||
while (bootstrap == null) {
|
||||
await Future.delayed(Duration(milliseconds: 5));
|
||||
|
|
@ -82,7 +81,7 @@ void main() {
|
|||
while (bootstrap.state != BootstrapState.done) {
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
}
|
||||
final defaultKey = client.encryption.ssss.open();
|
||||
final defaultKey = client.encryption!.ssss.open();
|
||||
await defaultKey.unlock(passphrase: 'foxies');
|
||||
|
||||
// test all the x-signing keys match up
|
||||
|
|
@ -95,8 +94,8 @@ void main() {
|
|||
expect(
|
||||
pubKey,
|
||||
client.userDeviceKeys[client.userID]
|
||||
.getCrossSigningKey(keyType)
|
||||
.publicKey);
|
||||
?.getCrossSigningKey(keyType)
|
||||
?.publicKey);
|
||||
} finally {
|
||||
keyObj.free();
|
||||
}
|
||||
|
|
@ -104,14 +103,15 @@ void main() {
|
|||
|
||||
await defaultKey.store('foxes', 'floof');
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
oldSecret = json.decode(json.encode(client.accountData['foxes'].content));
|
||||
oldSecret =
|
||||
json.decode(json.encode(client.accountData['foxes']!.content));
|
||||
origKeyId = defaultKey.keyId;
|
||||
}, timeout: Timeout(Duration(minutes: 2)));
|
||||
|
||||
test('change recovery passphrase', () async {
|
||||
if (!olmEnabled) return;
|
||||
Bootstrap bootstrap;
|
||||
bootstrap = client.encryption.bootstrap(
|
||||
Bootstrap? bootstrap;
|
||||
bootstrap = client.encryption!.bootstrap(
|
||||
onUpdate: () async {
|
||||
while (bootstrap == null) {
|
||||
await Future.delayed(Duration(milliseconds: 5));
|
||||
|
|
@ -121,7 +121,7 @@ void main() {
|
|||
} else if (bootstrap.state == BootstrapState.askUseExistingSsss) {
|
||||
bootstrap.useExistingSsss(false);
|
||||
} else if (bootstrap.state == BootstrapState.askUnlockSsss) {
|
||||
await bootstrap.oldSsssKeys[client.encryption.ssss.defaultKeyId]
|
||||
await bootstrap.oldSsssKeys![client.encryption!.ssss.defaultKeyId]!
|
||||
.unlock(passphrase: 'foxies');
|
||||
bootstrap.unlockedSsss();
|
||||
} else if (bootstrap.state == BootstrapState.askNewSsss) {
|
||||
|
|
@ -136,7 +136,7 @@ void main() {
|
|||
while (bootstrap.state != BootstrapState.done) {
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
}
|
||||
final defaultKey = client.encryption.ssss.open();
|
||||
final defaultKey = client.encryption!.ssss.open();
|
||||
await defaultKey.unlock(passphrase: 'newfoxies');
|
||||
|
||||
// test all the x-signing keys match up
|
||||
|
|
@ -149,8 +149,8 @@ void main() {
|
|||
expect(
|
||||
pubKey,
|
||||
client.userDeviceKeys[client.userID]
|
||||
.getCrossSigningKey(keyType)
|
||||
.publicKey);
|
||||
?.getCrossSigningKey(keyType)
|
||||
?.publicKey);
|
||||
} finally {
|
||||
keyObj.free();
|
||||
}
|
||||
|
|
@ -161,11 +161,11 @@ void main() {
|
|||
|
||||
test('change passphrase with multiple keys', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.setAccountData(client.userID, 'foxes', oldSecret);
|
||||
await client.setAccountData(client.userID!, 'foxes', oldSecret);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
|
||||
Bootstrap bootstrap;
|
||||
bootstrap = client.encryption.bootstrap(
|
||||
Bootstrap? bootstrap;
|
||||
bootstrap = client.encryption!.bootstrap(
|
||||
onUpdate: () async {
|
||||
while (bootstrap == null) {
|
||||
await Future.delayed(Duration(milliseconds: 5));
|
||||
|
|
@ -175,9 +175,10 @@ void main() {
|
|||
} else if (bootstrap.state == BootstrapState.askUseExistingSsss) {
|
||||
bootstrap.useExistingSsss(false);
|
||||
} else if (bootstrap.state == BootstrapState.askUnlockSsss) {
|
||||
await bootstrap.oldSsssKeys[client.encryption.ssss.defaultKeyId]
|
||||
await bootstrap.oldSsssKeys![client.encryption!.ssss.defaultKeyId]!
|
||||
.unlock(passphrase: 'newfoxies');
|
||||
await bootstrap.oldSsssKeys[origKeyId].unlock(passphrase: 'foxies');
|
||||
await bootstrap.oldSsssKeys![origKeyId]!
|
||||
.unlock(passphrase: 'foxies');
|
||||
bootstrap.unlockedSsss();
|
||||
} else if (bootstrap.state == BootstrapState.askNewSsss) {
|
||||
await bootstrap.newSsss('supernewfoxies');
|
||||
|
|
@ -191,7 +192,7 @@ void main() {
|
|||
while (bootstrap.state != BootstrapState.done) {
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
}
|
||||
final defaultKey = client.encryption.ssss.open();
|
||||
final defaultKey = client.encryption!.ssss.open();
|
||||
await defaultKey.unlock(passphrase: 'supernewfoxies');
|
||||
|
||||
// test all the x-signing keys match up
|
||||
|
|
@ -204,8 +205,8 @@ void main() {
|
|||
expect(
|
||||
pubKey,
|
||||
client.userDeviceKeys[client.userID]
|
||||
.getCrossSigningKey(keyType)
|
||||
.publicKey);
|
||||
?.getCrossSigningKey(keyType)
|
||||
?.publicKey);
|
||||
} finally {
|
||||
keyObj.free();
|
||||
}
|
||||
|
|
@ -217,8 +218,8 @@ void main() {
|
|||
test('setup new ssss', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.accountData.clear();
|
||||
Bootstrap bootstrap;
|
||||
bootstrap = client.encryption.bootstrap(
|
||||
Bootstrap? bootstrap;
|
||||
bootstrap = client.encryption!.bootstrap(
|
||||
onUpdate: () async {
|
||||
while (bootstrap == null) {
|
||||
await Future.delayed(Duration(milliseconds: 5));
|
||||
|
|
@ -236,18 +237,18 @@ void main() {
|
|||
while (bootstrap.state != BootstrapState.done) {
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
}
|
||||
final defaultKey = client.encryption.ssss.open();
|
||||
final defaultKey = client.encryption!.ssss.open();
|
||||
await defaultKey.unlock(passphrase: 'thenewestfoxies');
|
||||
}, timeout: Timeout(Duration(minutes: 2)));
|
||||
|
||||
test('bad ssss', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.accountData.clear();
|
||||
await client.setAccountData(client.userID, 'foxes', oldSecret);
|
||||
await client.setAccountData(client.userID!, 'foxes', oldSecret);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
var askedBadSsss = false;
|
||||
Bootstrap bootstrap;
|
||||
bootstrap = client.encryption.bootstrap(
|
||||
Bootstrap? bootstrap;
|
||||
bootstrap = client.encryption!.bootstrap(
|
||||
onUpdate: () async {
|
||||
while (bootstrap == null) {
|
||||
await Future.delayed(Duration(milliseconds: 5));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -32,7 +31,7 @@ void main() {
|
|||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
late Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
|
|
@ -50,41 +49,43 @@ void main() {
|
|||
|
||||
test('basic things', () async {
|
||||
if (!olmEnabled) return;
|
||||
expect(client.encryption.crossSigning.enabled, true);
|
||||
expect(client.encryption?.crossSigning.enabled, true);
|
||||
});
|
||||
|
||||
test('selfSign', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key = client.userDeviceKeys[client.userID].masterKey;
|
||||
final key = client.userDeviceKeys[client.userID]!.masterKey!;
|
||||
key.setDirectVerified(false);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.crossSigning.selfSign(recoveryKey: ssssKey);
|
||||
await client.encryption!.crossSigning.selfSign(recoveryKey: ssssKey);
|
||||
expect(key.directVerified, true);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints
|
||||
.containsKey('/client/r0/keys/signatures/upload'),
|
||||
true);
|
||||
expect(await client.encryption.crossSigning.isCached(), true);
|
||||
expect(await client.encryption!.crossSigning.isCached(), true);
|
||||
});
|
||||
|
||||
test('signable', () async {
|
||||
if (!olmEnabled) return;
|
||||
expect(
|
||||
client.encryption.crossSigning
|
||||
.signable([client.userDeviceKeys[client.userID].masterKey]),
|
||||
client.encryption!.crossSigning
|
||||
.signable([client.userDeviceKeys[client.userID!]!.masterKey!]),
|
||||
true);
|
||||
expect(
|
||||
client.encryption.crossSigning.signable([
|
||||
client.userDeviceKeys[client.userID].deviceKeys[client.deviceID]
|
||||
client.encryption!.crossSigning.signable([
|
||||
client.userDeviceKeys[client.userID!]!.deviceKeys[client.deviceID!]!
|
||||
]),
|
||||
false);
|
||||
expect(
|
||||
client.encryption.crossSigning.signable(
|
||||
[client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE']]),
|
||||
client.encryption!.crossSigning.signable([
|
||||
client.userDeviceKeys[client.userID!]!.deviceKeys['OTHERDEVICE']!
|
||||
]),
|
||||
true);
|
||||
expect(
|
||||
client.encryption.crossSigning.signable([
|
||||
client.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||
client.encryption!.crossSigning.signable([
|
||||
client
|
||||
.userDeviceKeys['@alice:example.com']!.deviceKeys['JLAFKJWSCS']!
|
||||
]),
|
||||
false);
|
||||
});
|
||||
|
|
@ -92,24 +93,24 @@ void main() {
|
|||
test('sign', () async {
|
||||
if (!olmEnabled) return;
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.crossSigning.sign([
|
||||
client.userDeviceKeys[client.userID].masterKey,
|
||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'],
|
||||
client.userDeviceKeys['@othertest:fakeServer.notExisting'].masterKey
|
||||
await client.encryption!.crossSigning.sign([
|
||||
client.userDeviceKeys[client.userID!]!.masterKey!,
|
||||
client.userDeviceKeys[client.userID!]!.deviceKeys['OTHERDEVICE']!,
|
||||
client.userDeviceKeys['@othertest:fakeServer.notExisting']!.masterKey!
|
||||
]);
|
||||
final body = json.decode(FakeMatrixApi
|
||||
.calledEndpoints['/client/r0/keys/signatures/upload'].first);
|
||||
.calledEndpoints['/client/r0/keys/signatures/upload']!.first);
|
||||
expect(body['@test:fakeServer.notExisting']?.containsKey('OTHERDEVICE'),
|
||||
true);
|
||||
expect(
|
||||
body['@test:fakeServer.notExisting'].containsKey(
|
||||
client.userDeviceKeys[client.userID].masterKey.publicKey),
|
||||
client.userDeviceKeys[client.userID]!.masterKey!.publicKey),
|
||||
true);
|
||||
expect(
|
||||
body['@othertest:fakeServer.notExisting'].containsKey(client
|
||||
.userDeviceKeys['@othertest:fakeServer.notExisting']
|
||||
.masterKey
|
||||
.publicKey),
|
||||
?.masterKey
|
||||
?.publicKey),
|
||||
true);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -29,10 +28,10 @@ void main() {
|
|||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
late Client client;
|
||||
final roomId = '!726s6s6q:example.com';
|
||||
Room room;
|
||||
Map<String, dynamic> payload;
|
||||
late Room room;
|
||||
late Map<String, dynamic> payload;
|
||||
final now = DateTime.now();
|
||||
|
||||
test('setupClient', () async {
|
||||
|
|
@ -47,12 +46,12 @@ void main() {
|
|||
if (!olmEnabled) return;
|
||||
|
||||
client = await getClient();
|
||||
room = client.getRoomById(roomId);
|
||||
room = client.getRoomById(roomId)!;
|
||||
});
|
||||
|
||||
test('encrypt payload', () async {
|
||||
if (!olmEnabled) return;
|
||||
payload = await client.encryption.encryptGroupMessagePayload(roomId, {
|
||||
payload = await client.encryption!.encryptGroupMessagePayload(roomId, {
|
||||
'msgtype': 'm.text',
|
||||
'text': 'Hello foxies!',
|
||||
});
|
||||
|
|
@ -72,9 +71,10 @@ void main() {
|
|||
room: room,
|
||||
originServerTs: now,
|
||||
eventId: '\$event',
|
||||
senderId: client.userID!,
|
||||
);
|
||||
final decryptedEvent =
|
||||
await client.encryption.decryptRoomEvent(roomId, encryptedEvent);
|
||||
await client.encryption!.decryptRoomEvent(roomId, encryptedEvent);
|
||||
expect(decryptedEvent.type, 'm.room.message');
|
||||
expect(decryptedEvent.content['msgtype'], 'm.text');
|
||||
expect(decryptedEvent.content['text'], 'Hello foxies!');
|
||||
|
|
@ -82,7 +82,7 @@ void main() {
|
|||
|
||||
test('decrypt payload nocache', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.encryption.keyManager.clearInboundGroupSessions();
|
||||
client.encryption!.keyManager.clearInboundGroupSessions();
|
||||
final encryptedEvent = Event(
|
||||
type: EventTypes.Encrypted,
|
||||
content: payload,
|
||||
|
|
@ -93,11 +93,11 @@ void main() {
|
|||
senderId: '@alice:example.com',
|
||||
);
|
||||
final decryptedEvent =
|
||||
await client.encryption.decryptRoomEvent(roomId, encryptedEvent);
|
||||
await client.encryption!.decryptRoomEvent(roomId, encryptedEvent);
|
||||
expect(decryptedEvent.type, 'm.room.message');
|
||||
expect(decryptedEvent.content['msgtype'], 'm.text');
|
||||
expect(decryptedEvent.content['text'], 'Hello foxies!');
|
||||
await client.encryption
|
||||
await client.encryption!
|
||||
.decryptRoomEvent(roomId, encryptedEvent, store: true);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -35,11 +34,11 @@ void main() {
|
|||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
late Client client;
|
||||
final otherClient = Client('othertestclient',
|
||||
httpClient: FakeMatrixApi(), databaseBuilder: getDatabase);
|
||||
DeviceKeys device;
|
||||
Map<String, dynamic> payload;
|
||||
late DeviceKeys device;
|
||||
late Map<String, dynamic> payload;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
|
|
@ -83,7 +82,7 @@ void main() {
|
|||
|
||||
test('encryptToDeviceMessage', () async {
|
||||
if (!olmEnabled) return;
|
||||
payload = await otherClient.encryption
|
||||
payload = await otherClient.encryption!
|
||||
.encryptToDeviceMessage([device], 'm.to_device', {'hello': 'foxies'});
|
||||
});
|
||||
|
||||
|
|
@ -95,15 +94,15 @@ void main() {
|
|||
content: payload[client.userID][client.deviceID],
|
||||
);
|
||||
final decryptedEvent =
|
||||
await client.encryption.decryptToDeviceEvent(encryptedEvent);
|
||||
await client.encryption!.decryptToDeviceEvent(encryptedEvent);
|
||||
expect(decryptedEvent.type, 'm.to_device');
|
||||
expect(decryptedEvent.content['hello'], 'foxies');
|
||||
});
|
||||
|
||||
test('decryptToDeviceEvent nocache', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.encryption.olmManager.olmSessions.clear();
|
||||
payload = await otherClient.encryption.encryptToDeviceMessage(
|
||||
client.encryption!.olmManager.olmSessions.clear();
|
||||
payload = await otherClient.encryption!.encryptToDeviceMessage(
|
||||
[device], 'm.to_device', {'hello': 'superfoxies'});
|
||||
final encryptedEvent = ToDeviceEvent(
|
||||
sender: '@othertest:fakeServer.notExisting',
|
||||
|
|
@ -111,7 +110,7 @@ void main() {
|
|||
content: payload[client.userID][client.deviceID],
|
||||
);
|
||||
final decryptedEvent =
|
||||
await client.encryption.decryptToDeviceEvent(encryptedEvent);
|
||||
await client.encryption!.decryptToDeviceEvent(encryptedEvent);
|
||||
expect(decryptedEvent.type, 'm.to_device');
|
||||
expect(decryptedEvent.content['hello'], 'superfoxies');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -32,7 +31,7 @@ void main() {
|
|||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
late Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
|
|
@ -55,7 +54,7 @@ void main() {
|
|||
final sessionKey =
|
||||
'AgAAAAAQcQ6XrFJk6Prm8FikZDqfry/NbDz8Xw7T6e+/9Yf/q3YHIPEQlzv7IZMNcYb51ifkRzFejVvtphS7wwG2FaXIp4XS2obla14iKISR0X74ugB2vyb1AydIHE/zbBQ1ic5s3kgjMFlWpu/S3FQCnCrv+DPFGEt3ERGWxIl3Bl5X53IjPyVkz65oljz2TZESwz0GH/QFvyOOm8ci0q/gceaF3S7Dmafg3dwTKYwcA5xkcc+BLyrLRzB6Hn+oMAqSNSscnm4mTeT5zYibIhrzqyUTMWr32spFtI9dNR/RFSzfCw';
|
||||
|
||||
client.encryption.keyManager.clearInboundGroupSessions();
|
||||
client.encryption!.keyManager.clearInboundGroupSessions();
|
||||
var event = ToDeviceEvent(
|
||||
sender: '@alice:example.com',
|
||||
type: 'm.room_key',
|
||||
|
|
@ -68,9 +67,9 @@ void main() {
|
|||
encryptedContent: {
|
||||
'sender_key': validSenderKey,
|
||||
});
|
||||
await client.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await client.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
client.encryption.keyManager.getInboundGroupSession(
|
||||
client.encryption!.keyManager.getInboundGroupSession(
|
||||
'!726s6s6q:example.com', validSessionId, validSenderKey) !=
|
||||
null,
|
||||
true);
|
||||
|
|
@ -78,7 +77,7 @@ void main() {
|
|||
// now test a few invalid scenarios
|
||||
|
||||
// not encrypted
|
||||
client.encryption.keyManager.clearInboundGroupSessions();
|
||||
client.encryption!.keyManager.clearInboundGroupSessions();
|
||||
event = ToDeviceEvent(
|
||||
sender: '@alice:example.com',
|
||||
type: 'm.room_key',
|
||||
|
|
@ -88,9 +87,9 @@ void main() {
|
|||
'session_id': validSessionId,
|
||||
'session_key': sessionKey,
|
||||
});
|
||||
await client.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await client.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
client.encryption.keyManager.getInboundGroupSession(
|
||||
client.encryption!.keyManager.getInboundGroupSession(
|
||||
'!726s6s6q:example.com', validSessionId, validSenderKey) !=
|
||||
null,
|
||||
false);
|
||||
|
|
@ -100,99 +99,104 @@ void main() {
|
|||
if (!olmEnabled) return;
|
||||
final roomId = '!726s6s6q:example.com';
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
false);
|
||||
var sess =
|
||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||
var sess = await client.encryption!.keyManager
|
||||
.createOutboundGroupSession(roomId);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
true);
|
||||
await client.encryption.keyManager.clearOrUseOutboundGroupSession(roomId);
|
||||
await client.encryption!.keyManager
|
||||
.clearOrUseOutboundGroupSession(roomId);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
true);
|
||||
var inbound = client.encryption.keyManager.getInboundGroupSession(
|
||||
roomId, sess.outboundGroupSession.session_id(), client.identityKey);
|
||||
var inbound = client.encryption!.keyManager.getInboundGroupSession(
|
||||
roomId, sess.outboundGroupSession!.session_id(), client.identityKey);
|
||||
expect(inbound != null, true);
|
||||
expect(
|
||||
inbound.allowedAtIndex['@alice:example.com']
|
||||
['L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8'],
|
||||
inbound!.allowedAtIndex['@alice:example.com']
|
||||
?['L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8'],
|
||||
0);
|
||||
expect(
|
||||
inbound.allowedAtIndex['@alice:example.com']
|
||||
['wMIDhiQl5jEXQrTB03ePOSQfR8sA/KMrW0CIfFfXKEE'],
|
||||
?['wMIDhiQl5jEXQrTB03ePOSQfR8sA/KMrW0CIfFfXKEE'],
|
||||
0);
|
||||
|
||||
// rotate after too many messages
|
||||
Iterable.generate(300).forEach((_) {
|
||||
sess.outboundGroupSession.encrypt('some string');
|
||||
sess.outboundGroupSession!.encrypt('some string');
|
||||
});
|
||||
await client.encryption.keyManager.clearOrUseOutboundGroupSession(roomId);
|
||||
await client.encryption!.keyManager
|
||||
.clearOrUseOutboundGroupSession(roomId);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
false);
|
||||
|
||||
// rotate if device is blocked
|
||||
sess =
|
||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||
client.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||
sess = await client.encryption!.keyManager
|
||||
.createOutboundGroupSession(roomId);
|
||||
client.userDeviceKeys['@alice:example.com']!.deviceKeys['JLAFKJWSCS']!
|
||||
.blocked = true;
|
||||
await client.encryption.keyManager.clearOrUseOutboundGroupSession(roomId);
|
||||
await client.encryption!.keyManager
|
||||
.clearOrUseOutboundGroupSession(roomId);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
false);
|
||||
client.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||
client.userDeviceKeys['@alice:example.com']!.deviceKeys['JLAFKJWSCS']!
|
||||
.blocked = false;
|
||||
|
||||
// lazy-create if it would rotate
|
||||
sess =
|
||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||
final oldSessKey = sess.outboundGroupSession.session_key();
|
||||
client.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||
sess = await client.encryption!.keyManager
|
||||
.createOutboundGroupSession(roomId);
|
||||
final oldSessKey = sess.outboundGroupSession!.session_key();
|
||||
client.userDeviceKeys['@alice:example.com']!.deviceKeys['JLAFKJWSCS']!
|
||||
.blocked = true;
|
||||
await client.encryption.keyManager.prepareOutboundGroupSession(roomId);
|
||||
await client.encryption!.keyManager.prepareOutboundGroupSession(roomId);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
true);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
.getOutboundGroupSession(roomId)
|
||||
.outboundGroupSession
|
||||
client.encryption!.keyManager
|
||||
.getOutboundGroupSession(roomId)!
|
||||
.outboundGroupSession!
|
||||
.session_key() !=
|
||||
oldSessKey,
|
||||
true);
|
||||
client.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||
client.userDeviceKeys['@alice:example.com']!.deviceKeys['JLAFKJWSCS']!
|
||||
.blocked = false;
|
||||
|
||||
// rotate if too far in the past
|
||||
sess =
|
||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||
sess = await client.encryption!.keyManager
|
||||
.createOutboundGroupSession(roomId);
|
||||
sess.creationTime = DateTime.now().subtract(Duration(days: 30));
|
||||
await client.encryption.keyManager.clearOrUseOutboundGroupSession(roomId);
|
||||
await client.encryption!.keyManager
|
||||
.clearOrUseOutboundGroupSession(roomId);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
false);
|
||||
|
||||
// rotate if user leaves
|
||||
sess =
|
||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||
final room = client.getRoomById(roomId);
|
||||
sess = await client.encryption!.keyManager
|
||||
.createOutboundGroupSession(roomId);
|
||||
final room = client.getRoomById(roomId)!;
|
||||
final member = room.getState('m.room.member', '@alice:example.com');
|
||||
member.content['membership'] = 'leave';
|
||||
room.summary.mJoinedMemberCount--;
|
||||
await client.encryption.keyManager.clearOrUseOutboundGroupSession(roomId);
|
||||
member!.content['membership'] = 'leave';
|
||||
room.summary.mJoinedMemberCount = room.summary.mJoinedMemberCount! - 1;
|
||||
await client.encryption!.keyManager
|
||||
.clearOrUseOutboundGroupSession(roomId);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
false);
|
||||
member.content['membership'] = 'join';
|
||||
room.summary.mJoinedMemberCount++;
|
||||
room.summary.mJoinedMemberCount = room.summary.mJoinedMemberCount! + 1;
|
||||
|
||||
// do not rotate if new device is added
|
||||
sess =
|
||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||
sess.outboundGroupSession.encrypt(
|
||||
sess = await client.encryption!.keyManager
|
||||
.createOutboundGroupSession(roomId);
|
||||
sess.outboundGroupSession!.encrypt(
|
||||
'foxies'); // so that the new device will have a different index
|
||||
client.userDeviceKeys['@alice:example.com'].deviceKeys['NEWDEVICE'] =
|
||||
client.userDeviceKeys['@alice:example.com']?.deviceKeys['NEWDEVICE'] =
|
||||
DeviceKeys.fromJson({
|
||||
'user_id': '@alice:example.com',
|
||||
'device_id': 'NEWDEVICE',
|
||||
|
|
@ -211,56 +215,58 @@ void main() {
|
|||
}
|
||||
}
|
||||
}, client);
|
||||
await client.encryption.keyManager.clearOrUseOutboundGroupSession(roomId);
|
||||
await client.encryption!.keyManager
|
||||
.clearOrUseOutboundGroupSession(roomId);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
true);
|
||||
inbound = client.encryption.keyManager.getInboundGroupSession(
|
||||
roomId, sess.outboundGroupSession.session_id(), client.identityKey);
|
||||
inbound = client.encryption!.keyManager.getInboundGroupSession(
|
||||
roomId, sess.outboundGroupSession!.session_id(), client.identityKey);
|
||||
expect(
|
||||
inbound.allowedAtIndex['@alice:example.com']
|
||||
['L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8'],
|
||||
inbound!.allowedAtIndex['@alice:example.com']
|
||||
?['L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8'],
|
||||
0);
|
||||
expect(
|
||||
inbound.allowedAtIndex['@alice:example.com']
|
||||
['wMIDhiQl5jEXQrTB03ePOSQfR8sA/KMrW0CIfFfXKEE'],
|
||||
?['wMIDhiQl5jEXQrTB03ePOSQfR8sA/KMrW0CIfFfXKEE'],
|
||||
0);
|
||||
expect(
|
||||
inbound.allowedAtIndex['@alice:example.com']
|
||||
['bnKQp6pPW0l9cGoIgHpBoK5OUi4h0gylJ7upc4asFV8'],
|
||||
?['bnKQp6pPW0l9cGoIgHpBoK5OUi4h0gylJ7upc4asFV8'],
|
||||
1);
|
||||
|
||||
// do not rotate if new user is added
|
||||
member.content['membership'] = 'leave';
|
||||
room.summary.mJoinedMemberCount--;
|
||||
sess =
|
||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||
room.summary.mJoinedMemberCount = room.summary.mJoinedMemberCount! - 1;
|
||||
sess = await client.encryption!.keyManager
|
||||
.createOutboundGroupSession(roomId);
|
||||
member.content['membership'] = 'join';
|
||||
room.summary.mJoinedMemberCount++;
|
||||
await client.encryption.keyManager.clearOrUseOutboundGroupSession(roomId);
|
||||
room.summary.mJoinedMemberCount = room.summary.mJoinedMemberCount! + 1;
|
||||
await client.encryption!.keyManager
|
||||
.clearOrUseOutboundGroupSession(roomId);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
true);
|
||||
|
||||
// force wipe
|
||||
sess =
|
||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||
await client.encryption.keyManager
|
||||
sess = await client.encryption!.keyManager
|
||||
.createOutboundGroupSession(roomId);
|
||||
await client.encryption!.keyManager
|
||||
.clearOrUseOutboundGroupSession(roomId, wipe: true);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
false);
|
||||
|
||||
// load from database
|
||||
sess =
|
||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||
client.encryption.keyManager.clearOutboundGroupSessions();
|
||||
sess = await client.encryption!.keyManager
|
||||
.createOutboundGroupSession(roomId);
|
||||
client.encryption!.keyManager.clearOutboundGroupSessions();
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
false);
|
||||
await client.encryption.keyManager.loadOutboundGroupSession(roomId);
|
||||
await client.encryption!.keyManager.loadOutboundGroupSession(roomId);
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
true);
|
||||
});
|
||||
|
||||
|
|
@ -276,71 +282,71 @@ void main() {
|
|||
'session_key':
|
||||
'AgAAAAAQcQ6XrFJk6Prm8FikZDqfry/NbDz8Xw7T6e+/9Yf/q3YHIPEQlzv7IZMNcYb51ifkRzFejVvtphS7wwG2FaXIp4XS2obla14iKISR0X74ugB2vyb1AydIHE/zbBQ1ic5s3kgjMFlWpu/S3FQCnCrv+DPFGEt3ERGWxIl3Bl5X53IjPyVkz65oljz2TZESwz0GH/QFvyOOm8ci0q/gceaF3S7Dmafg3dwTKYwcA5xkcc+BLyrLRzB6Hn+oMAqSNSscnm4mTeT5zYibIhrzqyUTMWr32spFtI9dNR/RFSzfCw'
|
||||
};
|
||||
client.encryption.keyManager.clearInboundGroupSessions();
|
||||
client.encryption!.keyManager.clearInboundGroupSessions();
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey) !=
|
||||
null,
|
||||
false);
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.setInboundGroupSession(roomId, sessionId, senderKey, sessionContent);
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey) !=
|
||||
null,
|
||||
true);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, 'invalid') !=
|
||||
null,
|
||||
false);
|
||||
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey) !=
|
||||
null,
|
||||
true);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession('otherroom', sessionId, senderKey) !=
|
||||
null,
|
||||
true);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession('otherroom', sessionId, 'invalid') !=
|
||||
null,
|
||||
false);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession('otherroom', 'invalid', senderKey) !=
|
||||
null,
|
||||
false);
|
||||
|
||||
client.encryption.keyManager.clearInboundGroupSessions();
|
||||
client.encryption!.keyManager.clearInboundGroupSessions();
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey) !=
|
||||
null,
|
||||
false);
|
||||
await client.encryption.keyManager
|
||||
await client.encryption!.keyManager
|
||||
.loadInboundGroupSession(roomId, sessionId, senderKey);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey) !=
|
||||
null,
|
||||
true);
|
||||
|
||||
client.encryption.keyManager.clearInboundGroupSessions();
|
||||
client.encryption!.keyManager.clearInboundGroupSessions();
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey) !=
|
||||
null,
|
||||
false);
|
||||
await client.encryption.keyManager
|
||||
await client.encryption!.keyManager
|
||||
.loadInboundGroupSession(roomId, sessionId, 'invalid');
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, 'invalid') !=
|
||||
null,
|
||||
false);
|
||||
|
|
@ -379,7 +385,7 @@ void main() {
|
|||
stateKey: '',
|
||||
),
|
||||
);
|
||||
expect(room.lastEvent.type, 'm.room.encrypted');
|
||||
expect(room.lastEvent?.type, 'm.room.encrypted');
|
||||
// set a payload...
|
||||
var sessionPayload = <String, dynamic>{
|
||||
'algorithm': AlgorithmTypes.megolmV1AesSha2,
|
||||
|
|
@ -390,19 +396,19 @@ void main() {
|
|||
'sender_key': senderKey,
|
||||
'sender_claimed_ed25519_key': client.fingerprintKey,
|
||||
};
|
||||
client.encryption.keyManager.setInboundGroupSession(
|
||||
client.encryption!.keyManager.setInboundGroupSession(
|
||||
roomId, sessionId, senderKey, sessionPayload,
|
||||
forwarded: true);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey)
|
||||
.inboundGroupSession
|
||||
.first_known_index(),
|
||||
?.inboundGroupSession
|
||||
?.first_known_index(),
|
||||
1);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey)
|
||||
.forwardingCurve25519KeyChain
|
||||
?.forwardingCurve25519KeyChain
|
||||
.length,
|
||||
1);
|
||||
|
||||
|
|
@ -416,19 +422,19 @@ void main() {
|
|||
'sender_key': senderKey,
|
||||
'sender_claimed_ed25519_key': client.fingerprintKey,
|
||||
};
|
||||
client.encryption.keyManager.setInboundGroupSession(
|
||||
client.encryption!.keyManager.setInboundGroupSession(
|
||||
roomId, sessionId, senderKey, sessionPayload,
|
||||
forwarded: true);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey)
|
||||
.inboundGroupSession
|
||||
.first_known_index(),
|
||||
?.inboundGroupSession
|
||||
?.first_known_index(),
|
||||
1);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey)
|
||||
.forwardingCurve25519KeyChain
|
||||
?.forwardingCurve25519KeyChain
|
||||
.length,
|
||||
1);
|
||||
|
||||
|
|
@ -442,19 +448,19 @@ void main() {
|
|||
'sender_key': senderKey,
|
||||
'sender_claimed_ed25519_key': client.fingerprintKey,
|
||||
};
|
||||
client.encryption.keyManager.setInboundGroupSession(
|
||||
client.encryption!.keyManager.setInboundGroupSession(
|
||||
roomId, sessionId, senderKey, sessionPayload,
|
||||
forwarded: true);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey)
|
||||
.inboundGroupSession
|
||||
.first_known_index(),
|
||||
?.inboundGroupSession
|
||||
?.first_known_index(),
|
||||
0);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey)
|
||||
.forwardingCurve25519KeyChain
|
||||
?.forwardingCurve25519KeyChain
|
||||
.length,
|
||||
1);
|
||||
|
||||
|
|
@ -468,19 +474,19 @@ void main() {
|
|||
'sender_key': senderKey,
|
||||
'sender_claimed_ed25519_key': client.fingerprintKey,
|
||||
};
|
||||
client.encryption.keyManager.setInboundGroupSession(
|
||||
client.encryption!.keyManager.setInboundGroupSession(
|
||||
roomId, sessionId, senderKey, sessionPayload,
|
||||
forwarded: true);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey)
|
||||
.inboundGroupSession
|
||||
.first_known_index(),
|
||||
?.inboundGroupSession
|
||||
?.first_known_index(),
|
||||
0);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey)
|
||||
.forwardingCurve25519KeyChain
|
||||
?.forwardingCurve25519KeyChain
|
||||
.length,
|
||||
1);
|
||||
|
||||
|
|
@ -494,25 +500,25 @@ void main() {
|
|||
'sender_key': senderKey,
|
||||
'sender_claimed_ed25519_key': client.fingerprintKey,
|
||||
};
|
||||
client.encryption.keyManager.setInboundGroupSession(
|
||||
client.encryption!.keyManager.setInboundGroupSession(
|
||||
roomId, sessionId, senderKey, sessionPayload,
|
||||
forwarded: true);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey)
|
||||
.inboundGroupSession
|
||||
.first_known_index(),
|
||||
?.inboundGroupSession
|
||||
?.first_known_index(),
|
||||
0);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey)
|
||||
.forwardingCurve25519KeyChain
|
||||
?.forwardingCurve25519KeyChain
|
||||
.length,
|
||||
0);
|
||||
|
||||
// test that it decrypted the last event
|
||||
expect(room.lastEvent.type, 'm.room.message');
|
||||
expect(room.lastEvent.content['body'], 'foxies');
|
||||
expect(room.lastEvent?.type, 'm.room.message');
|
||||
expect(room.lastEvent?.content['body'], 'foxies');
|
||||
|
||||
inbound.free();
|
||||
session.free();
|
||||
|
|
@ -521,22 +527,21 @@ void main() {
|
|||
test('Reused deviceID attack', () async {
|
||||
if (!olmEnabled) return;
|
||||
Logs().level = Level.warning;
|
||||
client ??= await getClient();
|
||||
|
||||
// Ensure the device came from sync
|
||||
expect(
|
||||
client.userDeviceKeys['@alice:example.com']
|
||||
.deviceKeys['JLAFKJWSCS'] !=
|
||||
?.deviceKeys['JLAFKJWSCS'] !=
|
||||
null,
|
||||
true);
|
||||
|
||||
// Alice removes her device
|
||||
client.userDeviceKeys['@alice:example.com'].deviceKeys
|
||||
client.userDeviceKeys['@alice:example.com']?.deviceKeys
|
||||
.remove('JLAFKJWSCS');
|
||||
|
||||
// Alice adds her device with same device ID but different keys
|
||||
final oldResp = FakeMatrixApi.api['POST']['/client/r0/keys/query'](null);
|
||||
FakeMatrixApi.api['POST']['/client/r0/keys/query'] = (_) {
|
||||
final oldResp = FakeMatrixApi.api['POST']?['/client/r0/keys/query'](null);
|
||||
FakeMatrixApi.api['POST']?['/client/r0/keys/query'] = (_) {
|
||||
oldResp['device_keys']['@alice:example.com']['JLAFKJWSCS'] = {
|
||||
'user_id': '@alice:example.com',
|
||||
'device_id': 'JLAFKJWSCS',
|
||||
|
|
@ -558,10 +563,10 @@ void main() {
|
|||
};
|
||||
return oldResp;
|
||||
};
|
||||
client.userDeviceKeys['@alice:example.com'].outdated = true;
|
||||
client.userDeviceKeys['@alice:example.com']!.outdated = true;
|
||||
await client.updateUserDeviceKeys();
|
||||
expect(
|
||||
client.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS'],
|
||||
client.userDeviceKeys['@alice:example.com']?.deviceKeys['JLAFKJWSCS'],
|
||||
null);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -58,8 +57,8 @@ void main() {
|
|||
if (!olmEnabled) return;
|
||||
|
||||
final matrix = await getClient();
|
||||
final requestRoom = matrix.getRoomById('!726s6s6q:example.com');
|
||||
await matrix.encryption.keyManager.request(
|
||||
final requestRoom = matrix.getRoomById('!726s6s6q:example.com')!;
|
||||
await matrix.encryption!.keyManager.request(
|
||||
requestRoom, 'sessionId', validSenderKey,
|
||||
tryOnlineBackup: false);
|
||||
var foundEvent = false;
|
||||
|
|
@ -89,12 +88,12 @@ void main() {
|
|||
matrix.setUserId('@alice:example.com'); // we need to pretend to be alice
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await matrix
|
||||
.userDeviceKeys['@alice:example.com'].deviceKeys['OTHERDEVICE']
|
||||
.userDeviceKeys['@alice:example.com']!.deviceKeys['OTHERDEVICE']!
|
||||
.setBlocked(false);
|
||||
await matrix
|
||||
.userDeviceKeys['@alice:example.com'].deviceKeys['OTHERDEVICE']
|
||||
.userDeviceKeys['@alice:example.com']!.deviceKeys['OTHERDEVICE']!
|
||||
.setVerified(true);
|
||||
final session = await matrix.encryption.keyManager
|
||||
final session = await matrix.encryption!.keyManager
|
||||
.loadInboundGroupSession(
|
||||
'!726s6s6q:example.com', validSessionId, validSenderKey);
|
||||
// test a successful share
|
||||
|
|
@ -112,7 +111,7 @@ void main() {
|
|||
'request_id': 'request_1',
|
||||
'requesting_device_id': 'OTHERDEVICE',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
Logs().i(FakeMatrixApi.calledEndpoints.keys.toString());
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
|
|
@ -121,9 +120,9 @@ void main() {
|
|||
|
||||
// test a successful foreign share
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
session.allowedAtIndex['@test:fakeServer.notExisting'] = <String, int>{
|
||||
matrix.userDeviceKeys['@test:fakeServer.notExisting']
|
||||
.deviceKeys['OTHERDEVICE'].curve25519Key: 0,
|
||||
session!.allowedAtIndex['@test:fakeServer.notExisting'] = <String, int>{
|
||||
matrix.userDeviceKeys['@test:fakeServer.notExisting']!
|
||||
.deviceKeys['OTHERDEVICE']!.curve25519Key!: 0,
|
||||
};
|
||||
event = ToDeviceEvent(
|
||||
sender: '@test:fakeServer.notExisting',
|
||||
|
|
@ -139,7 +138,7 @@ void main() {
|
|||
'request_id': 'request_a1',
|
||||
'requesting_device_id': 'OTHERDEVICE',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
Logs().i(FakeMatrixApi.calledEndpoints.keys.toString());
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
|
|
@ -165,7 +164,7 @@ void main() {
|
|||
'request_id': 'request_a2',
|
||||
'requesting_device_id': 'OTHERDEVICE',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
Logs().i(FakeMatrixApi.calledEndpoints.keys.toString());
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
|
|
@ -182,7 +181,7 @@ void main() {
|
|||
'request_id': 'request_2',
|
||||
'requesting_device_id': 'OTHERDEVICE',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -204,7 +203,7 @@ void main() {
|
|||
'request_id': 'request_3',
|
||||
'requesting_device_id': 'JLAFKJWSCS',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -226,7 +225,7 @@ void main() {
|
|||
'request_id': 'request_4',
|
||||
'requesting_device_id': 'blubb',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -248,7 +247,7 @@ void main() {
|
|||
'request_id': 'request_5',
|
||||
'requesting_device_id': 'OTHERDEVICE',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -270,7 +269,7 @@ void main() {
|
|||
'request_id': 'request_6',
|
||||
'requesting_device_id': 'OTHERDEVICE',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -282,17 +281,17 @@ void main() {
|
|||
test('Receive shared keys', () async {
|
||||
if (!olmEnabled) return;
|
||||
final matrix = await getClient();
|
||||
final requestRoom = matrix.getRoomById('!726s6s6q:example.com');
|
||||
await matrix.encryption.keyManager.request(
|
||||
final requestRoom = matrix.getRoomById('!726s6s6q:example.com')!;
|
||||
await matrix.encryption!.keyManager.request(
|
||||
requestRoom, validSessionId, validSenderKey,
|
||||
tryOnlineBackup: false);
|
||||
|
||||
final session = await matrix.encryption.keyManager
|
||||
final session = (await matrix.encryption!.keyManager
|
||||
.loadInboundGroupSession(
|
||||
requestRoom.id, validSessionId, validSenderKey);
|
||||
final sessionKey = session.inboundGroupSession
|
||||
.export_session(session.inboundGroupSession.first_known_index());
|
||||
matrix.encryption.keyManager.clearInboundGroupSessions();
|
||||
requestRoom.id, validSessionId, validSenderKey))!;
|
||||
final sessionKey = session.inboundGroupSession!
|
||||
.export_session(session.inboundGroupSession!.first_known_index());
|
||||
matrix.encryption!.keyManager.clearInboundGroupSessions();
|
||||
var event = ToDeviceEvent(
|
||||
sender: '@alice:example.com',
|
||||
type: 'm.forwarded_room_key',
|
||||
|
|
@ -303,13 +302,15 @@ void main() {
|
|||
'session_key': sessionKey,
|
||||
'sender_key': validSenderKey,
|
||||
'forwarding_curve25519_key_chain': [],
|
||||
'sender_claimed_ed25519_key':
|
||||
'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
|
||||
},
|
||||
encryptedContent: {
|
||||
'sender_key': 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
matrix.encryption.keyManager.getInboundGroupSession(
|
||||
matrix.encryption!.keyManager.getInboundGroupSession(
|
||||
requestRoom.id, validSessionId, validSenderKey) !=
|
||||
null,
|
||||
true);
|
||||
|
|
@ -317,7 +318,7 @@ void main() {
|
|||
// now test a few invalid scenarios
|
||||
|
||||
// request not found
|
||||
matrix.encryption.keyManager.clearInboundGroupSessions();
|
||||
matrix.encryption!.keyManager.clearInboundGroupSessions();
|
||||
event = ToDeviceEvent(
|
||||
sender: '@alice:example.com',
|
||||
type: 'm.forwarded_room_key',
|
||||
|
|
@ -328,22 +329,24 @@ void main() {
|
|||
'session_key': sessionKey,
|
||||
'sender_key': validSenderKey,
|
||||
'forwarding_curve25519_key_chain': [],
|
||||
'sender_claimed_ed25519_key':
|
||||
'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
|
||||
},
|
||||
encryptedContent: {
|
||||
'sender_key': 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
matrix.encryption.keyManager.getInboundGroupSession(
|
||||
matrix.encryption!.keyManager.getInboundGroupSession(
|
||||
requestRoom.id, validSessionId, validSenderKey) !=
|
||||
null,
|
||||
false);
|
||||
|
||||
// unknown device
|
||||
await matrix.encryption.keyManager.request(
|
||||
await matrix.encryption!.keyManager.request(
|
||||
requestRoom, validSessionId, validSenderKey,
|
||||
tryOnlineBackup: false);
|
||||
matrix.encryption.keyManager.clearInboundGroupSessions();
|
||||
matrix.encryption!.keyManager.clearInboundGroupSessions();
|
||||
event = ToDeviceEvent(
|
||||
sender: '@alice:example.com',
|
||||
type: 'm.forwarded_room_key',
|
||||
|
|
@ -354,22 +357,24 @@ void main() {
|
|||
'session_key': sessionKey,
|
||||
'sender_key': validSenderKey,
|
||||
'forwarding_curve25519_key_chain': [],
|
||||
'sender_claimed_ed25519_key':
|
||||
'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
|
||||
},
|
||||
encryptedContent: {
|
||||
'sender_key': 'invalid',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
matrix.encryption.keyManager.getInboundGroupSession(
|
||||
matrix.encryption!.keyManager.getInboundGroupSession(
|
||||
requestRoom.id, validSessionId, validSenderKey) !=
|
||||
null,
|
||||
false);
|
||||
|
||||
// no encrypted content
|
||||
await matrix.encryption.keyManager.request(
|
||||
await matrix.encryption!.keyManager.request(
|
||||
requestRoom, validSessionId, validSenderKey,
|
||||
tryOnlineBackup: false);
|
||||
matrix.encryption.keyManager.clearInboundGroupSessions();
|
||||
matrix.encryption!.keyManager.clearInboundGroupSessions();
|
||||
event = ToDeviceEvent(
|
||||
sender: '@alice:example.com',
|
||||
type: 'm.forwarded_room_key',
|
||||
|
|
@ -380,10 +385,12 @@ void main() {
|
|||
'session_key': sessionKey,
|
||||
'sender_key': validSenderKey,
|
||||
'forwarding_curve25519_key_chain': [],
|
||||
'sender_claimed_ed25519_key':
|
||||
'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
|
||||
});
|
||||
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||
await matrix.encryption!.keyManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
matrix.encryption.keyManager.getInboundGroupSession(
|
||||
matrix.encryption!.keyManager.getInboundGroupSession(
|
||||
requestRoom.id, validSessionId, validSenderKey) !=
|
||||
null,
|
||||
false);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -34,7 +33,7 @@ class MockSSSS extends SSSS {
|
|||
|
||||
bool requestedSecrets = false;
|
||||
@override
|
||||
Future<void> maybeRequestAll([List<DeviceKeys> devices]) async {
|
||||
Future<void> maybeRequestAll([List<DeviceKeys>? devices]) async {
|
||||
requestedSecrets = true;
|
||||
final handle = open();
|
||||
await handle.unlock(recoveryKey: ssssKey);
|
||||
|
|
@ -56,7 +55,7 @@ EventUpdate getLastSentEvent(KeyVerification req) {
|
|||
'sender': req.client.userID,
|
||||
},
|
||||
type: EventUpdateType.timeline,
|
||||
roomID: req.room.id,
|
||||
roomID: req.room!.id,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -70,8 +69,8 @@ void main() {
|
|||
const otherPickledOlmAccount =
|
||||
'VWhVApbkcilKAEGppsPDf9nNVjaK8/IxT3asSR0sYg0S5KgbfE8vXEPwoiKBX2cEvwX3OessOBOkk+ZE7TTbjlrh/KEd31p8Wo+47qj0AP+Ky+pabnhi+/rTBvZy+gfzTqUfCxZrkzfXI9Op4JnP6gYmy7dVX2lMYIIs9WCO1jcmIXiXum5jnfXu1WLfc7PZtO2hH+k9CDKosOFaXRBmsu8k/BGXPSoWqUpvu6WpEG9t5STk4FeAzA';
|
||||
|
||||
Client client1;
|
||||
Client client2;
|
||||
late Client client1;
|
||||
late Client client2;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
|
|
@ -117,24 +116,24 @@ void main() {
|
|||
// because then we can easily intercept the payloads and inject in the other client
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
// make sure our master key is *not* verified to not triger SSSS for now
|
||||
client1.userDeviceKeys[client1.userID].masterKey.setDirectVerified(false);
|
||||
client1.userDeviceKeys[client1.userID]!.masterKey!
|
||||
.setDirectVerified(false);
|
||||
final req1 =
|
||||
await client1.userDeviceKeys[client2.userID].startVerification();
|
||||
await client1.userDeviceKeys[client2.userID]!.startVerification();
|
||||
var evt = getLastSentEvent(req1);
|
||||
expect(req1.state, KeyVerificationState.waitingAccept);
|
||||
|
||||
KeyVerification req2;
|
||||
late KeyVerification req2;
|
||||
final sub = client2.onKeyVerificationRequest.stream.listen((req) {
|
||||
req2 = req;
|
||||
});
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
await sub.cancel();
|
||||
expect(req2 != null, true);
|
||||
|
||||
expect(
|
||||
client2.encryption.keyVerificationManager
|
||||
.getRequest(req2.transactionId),
|
||||
client2.encryption!.keyVerificationManager
|
||||
.getRequest(req2.transactionId!),
|
||||
req2);
|
||||
|
||||
// send ready
|
||||
|
|
@ -145,27 +144,27 @@ void main() {
|
|||
|
||||
// send start
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req1);
|
||||
|
||||
// send accept
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req2);
|
||||
|
||||
// send key
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req1);
|
||||
|
||||
// send key
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req2);
|
||||
|
||||
// receive last key
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
|
||||
// compare emoji
|
||||
expect(req1.state, KeyVerificationState.askSas);
|
||||
|
|
@ -194,64 +193,66 @@ void main() {
|
|||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await req1.acceptSas();
|
||||
evt = getLastSentEvent(req1);
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
expect(req1.state, KeyVerificationState.waitingSas);
|
||||
|
||||
// send mac
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await req2.acceptSas();
|
||||
evt = getLastSentEvent(req2);
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
|
||||
expect(req1.state, KeyVerificationState.done);
|
||||
expect(req2.state, KeyVerificationState.done);
|
||||
expect(
|
||||
client1.userDeviceKeys[client2.userID].deviceKeys[client2.deviceID]
|
||||
.directVerified,
|
||||
client1.userDeviceKeys[client2.userID]?.deviceKeys[client2.deviceID]
|
||||
?.directVerified,
|
||||
true);
|
||||
expect(
|
||||
client2.userDeviceKeys[client1.userID].deviceKeys[client1.deviceID]
|
||||
.directVerified,
|
||||
client2.userDeviceKeys[client1.userID]?.deviceKeys[client1.deviceID]
|
||||
?.directVerified,
|
||||
true);
|
||||
await client1.encryption.keyVerificationManager.cleanup();
|
||||
await client2.encryption.keyVerificationManager.cleanup();
|
||||
await client1.encryption!.keyVerificationManager.cleanup();
|
||||
await client2.encryption!.keyVerificationManager.cleanup();
|
||||
});
|
||||
|
||||
test('ask SSSS start', () async {
|
||||
if (!olmEnabled) return;
|
||||
client1.userDeviceKeys[client1.userID].masterKey.setDirectVerified(true);
|
||||
await client1.encryption.ssss.clearCache();
|
||||
client1.userDeviceKeys[client1.userID]!.masterKey!
|
||||
.setDirectVerified(true);
|
||||
await client1.encryption!.ssss.clearCache();
|
||||
final req1 =
|
||||
await client1.userDeviceKeys[client2.userID].startVerification();
|
||||
await client1.userDeviceKeys[client2.userID]!.startVerification();
|
||||
expect(req1.state, KeyVerificationState.askSSSS);
|
||||
await req1.openSSSS(recoveryKey: ssssKey);
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
expect(req1.state, KeyVerificationState.waitingAccept);
|
||||
|
||||
await req1.cancel();
|
||||
await client1.encryption.keyVerificationManager.cleanup();
|
||||
await client1.encryption!.keyVerificationManager.cleanup();
|
||||
});
|
||||
|
||||
test('ask SSSS end', () async {
|
||||
if (!olmEnabled) return;
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
// make sure our master key is *not* verified to not triger SSSS for now
|
||||
client1.userDeviceKeys[client1.userID].masterKey.setDirectVerified(false);
|
||||
client1.userDeviceKeys[client1.userID]!.masterKey!
|
||||
.setDirectVerified(false);
|
||||
// the other one has to have their master key verified to trigger asking for ssss
|
||||
client2.userDeviceKeys[client2.userID].masterKey.setDirectVerified(true);
|
||||
client2.userDeviceKeys[client2.userID]!.masterKey!
|
||||
.setDirectVerified(true);
|
||||
final req1 =
|
||||
await client1.userDeviceKeys[client2.userID].startVerification();
|
||||
await client1.userDeviceKeys[client2.userID]!.startVerification();
|
||||
var evt = getLastSentEvent(req1);
|
||||
expect(req1.state, KeyVerificationState.waitingAccept);
|
||||
|
||||
KeyVerification req2;
|
||||
late KeyVerification req2;
|
||||
final sub = client2.onKeyVerificationRequest.stream.listen((req) {
|
||||
req2 = req;
|
||||
});
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
await sub.cancel();
|
||||
expect(req2 != null, true);
|
||||
|
||||
// send ready
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
|
|
@ -261,27 +262,27 @@ void main() {
|
|||
|
||||
// send start
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req1);
|
||||
|
||||
// send accept
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req2);
|
||||
|
||||
// send key
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req1);
|
||||
|
||||
// send key
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req2);
|
||||
|
||||
// receive last key
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
|
||||
// compare emoji
|
||||
expect(req1.state, KeyVerificationState.askSas);
|
||||
|
|
@ -301,21 +302,22 @@ void main() {
|
|||
}
|
||||
|
||||
// alright, they match
|
||||
client1.userDeviceKeys[client1.userID].masterKey.setDirectVerified(true);
|
||||
await client1.encryption.ssss.clearCache();
|
||||
client1.userDeviceKeys[client1.userID]!.masterKey!
|
||||
.setDirectVerified(true);
|
||||
await client1.encryption!.ssss.clearCache();
|
||||
|
||||
// send mac
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await req1.acceptSas();
|
||||
evt = getLastSentEvent(req1);
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
expect(req1.state, KeyVerificationState.waitingSas);
|
||||
|
||||
// send mac
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await req2.acceptSas();
|
||||
evt = getLastSentEvent(req2);
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
|
||||
expect(req1.state, KeyVerificationState.askSSSS);
|
||||
expect(req2.state, KeyVerificationState.done);
|
||||
|
|
@ -324,66 +326,67 @@ void main() {
|
|||
await Future.delayed(Duration(milliseconds: 10));
|
||||
expect(req1.state, KeyVerificationState.done);
|
||||
|
||||
client1.encryption.ssss = MockSSSS(client1.encryption);
|
||||
(client1.encryption.ssss as MockSSSS).requestedSecrets = false;
|
||||
await client1.encryption.ssss.clearCache();
|
||||
client1.encryption!.ssss = MockSSSS(client1.encryption!);
|
||||
(client1.encryption!.ssss as MockSSSS).requestedSecrets = false;
|
||||
await client1.encryption!.ssss.clearCache();
|
||||
await req1.maybeRequestSSSSSecrets();
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
expect((client1.encryption.ssss as MockSSSS).requestedSecrets, true);
|
||||
expect((client1.encryption!.ssss as MockSSSS).requestedSecrets, true);
|
||||
// delay for 12 seconds to be sure no other tests clear the ssss cache
|
||||
await Future.delayed(Duration(seconds: 12));
|
||||
|
||||
await client1.encryption.keyVerificationManager.cleanup();
|
||||
await client2.encryption.keyVerificationManager.cleanup();
|
||||
await client1.encryption!.keyVerificationManager.cleanup();
|
||||
await client2.encryption!.keyVerificationManager.cleanup();
|
||||
});
|
||||
|
||||
test('reject verification', () async {
|
||||
if (!olmEnabled) return;
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
// make sure our master key is *not* verified to not triger SSSS for now
|
||||
client1.userDeviceKeys[client1.userID].masterKey.setDirectVerified(false);
|
||||
client1.userDeviceKeys[client1.userID]!.masterKey!
|
||||
.setDirectVerified(false);
|
||||
final req1 =
|
||||
await client1.userDeviceKeys[client2.userID].startVerification();
|
||||
await client1.userDeviceKeys[client2.userID]!.startVerification();
|
||||
var evt = getLastSentEvent(req1);
|
||||
expect(req1.state, KeyVerificationState.waitingAccept);
|
||||
|
||||
KeyVerification req2;
|
||||
late KeyVerification req2;
|
||||
final sub = client2.onKeyVerificationRequest.stream.listen((req) {
|
||||
req2 = req;
|
||||
});
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
await sub.cancel();
|
||||
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await req2.rejectVerification();
|
||||
evt = getLastSentEvent(req2);
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
expect(req1.state, KeyVerificationState.error);
|
||||
expect(req2.state, KeyVerificationState.error);
|
||||
|
||||
await client1.encryption.keyVerificationManager.cleanup();
|
||||
await client2.encryption.keyVerificationManager.cleanup();
|
||||
await client1.encryption!.keyVerificationManager.cleanup();
|
||||
await client2.encryption!.keyVerificationManager.cleanup();
|
||||
});
|
||||
|
||||
test('reject sas', () async {
|
||||
if (!olmEnabled) return;
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
// make sure our master key is *not* verified to not triger SSSS for now
|
||||
client1.userDeviceKeys[client1.userID].masterKey.setDirectVerified(false);
|
||||
client1.userDeviceKeys[client1.userID]!.masterKey!
|
||||
.setDirectVerified(false);
|
||||
final req1 =
|
||||
await client1.userDeviceKeys[client2.userID].startVerification();
|
||||
await client1.userDeviceKeys[client2.userID]!.startVerification();
|
||||
var evt = getLastSentEvent(req1);
|
||||
expect(req1.state, KeyVerificationState.waitingAccept);
|
||||
|
||||
KeyVerification req2;
|
||||
late KeyVerification req2;
|
||||
final sub = client2.onKeyVerificationRequest.stream.listen((req) {
|
||||
req2 = req;
|
||||
});
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
await sub.cancel();
|
||||
expect(req2 != null, true);
|
||||
|
||||
// send ready
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
|
|
@ -393,60 +396,60 @@ void main() {
|
|||
|
||||
// send start
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req1);
|
||||
|
||||
// send accept
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req2);
|
||||
|
||||
// send key
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req1);
|
||||
|
||||
// send key
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
evt = getLastSentEvent(req2);
|
||||
|
||||
// receive last key
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
|
||||
await req1.acceptSas();
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await req2.rejectSas();
|
||||
evt = getLastSentEvent(req2);
|
||||
await client1.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client1.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
expect(req1.state, KeyVerificationState.error);
|
||||
expect(req2.state, KeyVerificationState.error);
|
||||
|
||||
await client1.encryption.keyVerificationManager.cleanup();
|
||||
await client2.encryption.keyVerificationManager.cleanup();
|
||||
await client1.encryption!.keyVerificationManager.cleanup();
|
||||
await client2.encryption!.keyVerificationManager.cleanup();
|
||||
});
|
||||
|
||||
test('other device accepted', () async {
|
||||
if (!olmEnabled) return;
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
// make sure our master key is *not* verified to not triger SSSS for now
|
||||
client1.userDeviceKeys[client1.userID].masterKey.setDirectVerified(false);
|
||||
client1.userDeviceKeys[client1.userID]!.masterKey!
|
||||
.setDirectVerified(false);
|
||||
final req1 =
|
||||
await client1.userDeviceKeys[client2.userID].startVerification();
|
||||
await client1.userDeviceKeys[client2.userID]!.startVerification();
|
||||
final evt = getLastSentEvent(req1);
|
||||
expect(req1.state, KeyVerificationState.waitingAccept);
|
||||
|
||||
KeyVerification req2;
|
||||
late KeyVerification req2;
|
||||
final sub = client2.onKeyVerificationRequest.stream.listen((req) {
|
||||
req2 = req;
|
||||
});
|
||||
await client2.encryption.keyVerificationManager.handleEventUpdate(evt);
|
||||
await client2.encryption!.keyVerificationManager.handleEventUpdate(evt);
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
await sub.cancel();
|
||||
expect(req2 != null, true);
|
||||
|
||||
await client2.encryption.keyVerificationManager
|
||||
await client2.encryption!.keyVerificationManager
|
||||
.handleEventUpdate(EventUpdate(
|
||||
content: {
|
||||
'event_id': req2.transactionId,
|
||||
|
|
@ -463,13 +466,13 @@ void main() {
|
|||
'sender': client2.userID,
|
||||
},
|
||||
type: EventUpdateType.timeline,
|
||||
roomID: req2.room.id,
|
||||
roomID: req2.room!.id,
|
||||
));
|
||||
expect(req2.state, KeyVerificationState.error);
|
||||
|
||||
await req2.cancel();
|
||||
await client1.encryption.keyVerificationManager.cleanup();
|
||||
await client2.encryption.keyVerificationManager.cleanup();
|
||||
await client1.encryption!.keyVerificationManager.cleanup();
|
||||
await client2.encryption!.keyVerificationManager.cleanup();
|
||||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020, 2021 Famedly GmbH
|
||||
|
|
@ -32,7 +31,7 @@ void main() {
|
|||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
late Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
|
|
@ -53,37 +52,37 @@ void main() {
|
|||
final payload = <String, dynamic>{
|
||||
'fox': 'floof',
|
||||
};
|
||||
final signedPayload = client.encryption.olmManager.signJson(payload);
|
||||
final signedPayload = client.encryption!.olmManager.signJson(payload);
|
||||
expect(
|
||||
signedPayload.checkJsonSignature(
|
||||
client.fingerprintKey, client.userID, client.deviceID),
|
||||
client.fingerprintKey, client.userID!, client.deviceID!),
|
||||
true);
|
||||
});
|
||||
|
||||
test('uploadKeys', () async {
|
||||
if (!olmEnabled) return;
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
final res =
|
||||
await client.encryption.olmManager.uploadKeys(uploadDeviceKeys: true);
|
||||
final res = await client.encryption!.olmManager
|
||||
.uploadKeys(uploadDeviceKeys: true);
|
||||
expect(res, true);
|
||||
var sent = json.decode(
|
||||
FakeMatrixApi.calledEndpoints['/client/r0/keys/upload'].first);
|
||||
FakeMatrixApi.calledEndpoints['/client/r0/keys/upload']!.first);
|
||||
expect(sent['device_keys'] != null, true);
|
||||
expect(sent['one_time_keys'] != null, true);
|
||||
expect(sent['one_time_keys'].keys.length, 66);
|
||||
expect(sent['fallback_keys'] != null, true);
|
||||
expect(sent['fallback_keys'].keys.length, 1);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.olmManager.uploadKeys();
|
||||
await client.encryption!.olmManager.uploadKeys();
|
||||
sent = json.decode(
|
||||
FakeMatrixApi.calledEndpoints['/client/r0/keys/upload'].first);
|
||||
FakeMatrixApi.calledEndpoints['/client/r0/keys/upload']!.first);
|
||||
expect(sent['device_keys'] != null, false);
|
||||
expect(sent['fallback_keys'].keys.length, 1);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.olmManager
|
||||
await client.encryption!.olmManager
|
||||
.uploadKeys(oldKeyCount: 20, unusedFallbackKey: true);
|
||||
sent = json.decode(
|
||||
FakeMatrixApi.calledEndpoints['/client/r0/keys/upload'].first);
|
||||
FakeMatrixApi.calledEndpoints['/client/r0/keys/upload']!.first);
|
||||
expect(sent['one_time_keys'].keys.length, 46);
|
||||
expect(sent['fallback_keys'].keys.length, 0);
|
||||
});
|
||||
|
|
@ -91,7 +90,7 @@ void main() {
|
|||
test('handleDeviceOneTimeKeysCount', () async {
|
||||
if (!olmEnabled) return;
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
client.encryption.olmManager
|
||||
client.encryption!.olmManager
|
||||
.handleDeviceOneTimeKeysCount({'signed_curve25519': 20}, null);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(
|
||||
|
|
@ -99,7 +98,7 @@ void main() {
|
|||
true);
|
||||
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
client.encryption.olmManager
|
||||
client.encryption!.olmManager
|
||||
.handleDeviceOneTimeKeysCount({'signed_curve25519': 70}, null);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(
|
||||
|
|
@ -107,7 +106,7 @@ void main() {
|
|||
false);
|
||||
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
client.encryption.olmManager.handleDeviceOneTimeKeysCount(null, []);
|
||||
client.encryption!.olmManager.handleDeviceOneTimeKeysCount(null, []);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.containsKey('/client/r0/keys/upload'),
|
||||
|
|
@ -115,7 +114,7 @@ void main() {
|
|||
|
||||
// this will upload keys because we assume the key count is 0, if the server doesn't send one
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
client.encryption.olmManager
|
||||
client.encryption!.olmManager
|
||||
.handleDeviceOneTimeKeysCount(null, ['signed_curve25519']);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(
|
||||
|
|
@ -125,30 +124,31 @@ void main() {
|
|||
|
||||
test('restoreOlmSession', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.encryption.olmManager.olmSessions.clear();
|
||||
await client.encryption.olmManager
|
||||
.restoreOlmSession(client.userID, client.identityKey);
|
||||
expect(client.encryption.olmManager.olmSessions.length, 1);
|
||||
client.encryption!.olmManager.olmSessions.clear();
|
||||
await client.encryption!.olmManager
|
||||
.restoreOlmSession(client.userID!, client.identityKey);
|
||||
expect(client.encryption!.olmManager.olmSessions.length, 1);
|
||||
|
||||
client.encryption.olmManager.olmSessions.clear();
|
||||
await client.encryption.olmManager
|
||||
.restoreOlmSession(client.userID, 'invalid');
|
||||
expect(client.encryption.olmManager.olmSessions.length, 0);
|
||||
client.encryption!.olmManager.olmSessions.clear();
|
||||
await client.encryption!.olmManager
|
||||
.restoreOlmSession(client.userID!, 'invalid');
|
||||
expect(client.encryption!.olmManager.olmSessions.length, 0);
|
||||
|
||||
client.encryption.olmManager.olmSessions.clear();
|
||||
await client.encryption.olmManager
|
||||
client.encryption!.olmManager.olmSessions.clear();
|
||||
await client.encryption!.olmManager
|
||||
.restoreOlmSession('invalid', client.identityKey);
|
||||
expect(client.encryption.olmManager.olmSessions.length, 0);
|
||||
expect(client.encryption!.olmManager.olmSessions.length, 0);
|
||||
});
|
||||
|
||||
test('startOutgoingOlmSessions', () async {
|
||||
if (!olmEnabled) return;
|
||||
// start an olm session.....with ourself!
|
||||
client.encryption.olmManager.olmSessions.clear();
|
||||
await client.encryption.olmManager.startOutgoingOlmSessions(
|
||||
[client.userDeviceKeys[client.userID].deviceKeys[client.deviceID]]);
|
||||
client.encryption!.olmManager.olmSessions.clear();
|
||||
await client.encryption!.olmManager.startOutgoingOlmSessions([
|
||||
client.userDeviceKeys[client.userID!]!.deviceKeys[client.deviceID]!
|
||||
]);
|
||||
expect(
|
||||
client.encryption.olmManager.olmSessions
|
||||
client.encryption!.olmManager.olmSessions
|
||||
.containsKey(client.identityKey),
|
||||
true);
|
||||
});
|
||||
|
|
@ -159,7 +159,7 @@ void main() {
|
|||
final deviceId = 'JLAFKJWSCS';
|
||||
final senderKey = 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8';
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.database.setLastSentMessageUserDeviceKey(
|
||||
await client.database!.setLastSentMessageUserDeviceKey(
|
||||
json.encode({
|
||||
'type': 'm.foxies',
|
||||
'content': {
|
||||
|
|
@ -176,7 +176,7 @@ void main() {
|
|||
'sender_key': senderKey,
|
||||
},
|
||||
);
|
||||
await client.encryption.olmManager.handleToDeviceEvent(event);
|
||||
await client.encryption!.olmManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -186,7 +186,7 @@ void main() {
|
|||
|
||||
// not encrypted
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.database.setLastSentMessageUserDeviceKey(
|
||||
await client.database!.setLastSentMessageUserDeviceKey(
|
||||
json.encode({
|
||||
'type': 'm.foxies',
|
||||
'content': {
|
||||
|
|
@ -201,7 +201,7 @@ void main() {
|
|||
content: {},
|
||||
encryptedContent: null,
|
||||
);
|
||||
await client.encryption.olmManager.handleToDeviceEvent(event);
|
||||
await client.encryption!.olmManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -209,7 +209,7 @@ void main() {
|
|||
|
||||
// device not found
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.database.setLastSentMessageUserDeviceKey(
|
||||
await client.database!.setLastSentMessageUserDeviceKey(
|
||||
json.encode({
|
||||
'type': 'm.foxies',
|
||||
'content': {
|
||||
|
|
@ -226,7 +226,7 @@ void main() {
|
|||
'sender_key': 'invalid',
|
||||
},
|
||||
);
|
||||
await client.encryption.olmManager.handleToDeviceEvent(event);
|
||||
await client.encryption!.olmManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -234,7 +234,7 @@ void main() {
|
|||
|
||||
// don't replay if the last event is m.dummy itself
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.database.setLastSentMessageUserDeviceKey(
|
||||
await client.database!.setLastSentMessageUserDeviceKey(
|
||||
json.encode({
|
||||
'type': 'm.dummy',
|
||||
'content': {},
|
||||
|
|
@ -249,7 +249,7 @@ void main() {
|
|||
'sender_key': senderKey,
|
||||
},
|
||||
);
|
||||
await client.encryption.olmManager.handleToDeviceEvent(event);
|
||||
await client.encryption!.olmManager.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -32,7 +31,7 @@ void main() {
|
|||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
late Client client;
|
||||
|
||||
final roomId = '!726s6s6q:example.com';
|
||||
final sessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU';
|
||||
|
|
@ -54,21 +53,21 @@ void main() {
|
|||
|
||||
test('basic things', () async {
|
||||
if (!olmEnabled) return;
|
||||
expect(client.encryption.keyManager.enabled, true);
|
||||
expect(await client.encryption.keyManager.isCached(), false);
|
||||
final handle = client.encryption.ssss.open();
|
||||
expect(client.encryption!.keyManager.enabled, true);
|
||||
expect(await client.encryption!.keyManager.isCached(), false);
|
||||
final handle = client.encryption!.ssss.open();
|
||||
await handle.unlock(recoveryKey: ssssKey);
|
||||
await handle.maybeCacheAll();
|
||||
expect(await client.encryption.keyManager.isCached(), true);
|
||||
expect(await client.encryption!.keyManager.isCached(), true);
|
||||
});
|
||||
|
||||
test('load key', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.encryption.keyManager.clearInboundGroupSessions();
|
||||
await client.encryption.keyManager
|
||||
.request(client.getRoomById(roomId), sessionId, senderKey);
|
||||
client.encryption!.keyManager.clearInboundGroupSessions();
|
||||
await client.encryption!.keyManager
|
||||
.request(client.getRoomById(roomId)!, sessionId, senderKey);
|
||||
expect(
|
||||
client.encryption.keyManager
|
||||
client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey) !=
|
||||
null,
|
||||
true);
|
||||
|
|
@ -94,25 +93,25 @@ void main() {
|
|||
'sender_claimed_ed25519_key': client.fingerprintKey,
|
||||
};
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
client.encryption.keyManager.setInboundGroupSession(
|
||||
client.encryption!.keyManager.setInboundGroupSession(
|
||||
roomId, sessionId, senderKey, sessionPayload,
|
||||
forwarded: true);
|
||||
await Future.delayed(Duration(milliseconds: 500));
|
||||
var dbSessions = await client.database.getInboundGroupSessionsToUpload();
|
||||
var dbSessions = await client.database!.getInboundGroupSessionsToUpload();
|
||||
expect(dbSessions.isNotEmpty, true);
|
||||
await client.encryption.keyManager.backgroundTasks();
|
||||
await client.encryption!.keyManager.backgroundTasks();
|
||||
final payload = FakeMatrixApi
|
||||
.calledEndpoints['/client/unstable/room_keys/keys?version=5'].first;
|
||||
dbSessions = await client.database.getInboundGroupSessionsToUpload();
|
||||
.calledEndpoints['/client/unstable/room_keys/keys?version=5']!.first;
|
||||
dbSessions = await client.database!.getInboundGroupSessionsToUpload();
|
||||
expect(dbSessions.isEmpty, true);
|
||||
|
||||
final onlineKeys = RoomKeys.fromJson(json.decode(payload));
|
||||
client.encryption.keyManager.clearInboundGroupSessions();
|
||||
var ret = client.encryption.keyManager
|
||||
client.encryption!.keyManager.clearInboundGroupSessions();
|
||||
var ret = client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey);
|
||||
expect(ret, null);
|
||||
await client.encryption.keyManager.loadFromResponse(onlineKeys);
|
||||
ret = client.encryption.keyManager
|
||||
await client.encryption!.keyManager.loadFromResponse(onlineKeys);
|
||||
ret = client.encryption!.keyManager
|
||||
.getInboundGroupSession(roomId, sessionId, senderKey);
|
||||
expect(ret != null, true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -42,7 +41,7 @@ class MockSSSS extends SSSS {
|
|||
|
||||
bool requestedSecrets = false;
|
||||
@override
|
||||
Future<void> maybeRequestAll([List<DeviceKeys> devices]) async {
|
||||
Future<void> maybeRequestAll([List<DeviceKeys>? devices]) async {
|
||||
requestedSecrets = true;
|
||||
final handle = open();
|
||||
await handle.unlock(recoveryKey: ssssKey);
|
||||
|
|
@ -55,7 +54,7 @@ void main() {
|
|||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
late Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
|
|
@ -73,7 +72,7 @@ void main() {
|
|||
|
||||
test('basic things', () async {
|
||||
if (!olmEnabled) return;
|
||||
expect(client.encryption.ssss.defaultKeyId,
|
||||
expect(client.encryption!.ssss.defaultKeyId,
|
||||
'0FajDWYaM6wQ4O60OZnLvwZfsBNu4Bu3');
|
||||
});
|
||||
|
||||
|
|
@ -88,7 +87,7 @@ void main() {
|
|||
|
||||
test('store', () async {
|
||||
if (!olmEnabled) return;
|
||||
final handle = client.encryption.ssss.open();
|
||||
final handle = client.encryption!.ssss.open();
|
||||
var failed = false;
|
||||
try {
|
||||
await handle.unlock(passphrase: 'invalid');
|
||||
|
|
@ -114,7 +113,7 @@ void main() {
|
|||
// account_data for this test
|
||||
final content = FakeMatrixApi
|
||||
.calledEndpoints[
|
||||
'/client/r0/user/%40test%3AfakeServer.notExisting/account_data/best%20animal']
|
||||
'/client/r0/user/%40test%3AfakeServer.notExisting/account_data/best%20animal']!
|
||||
.first;
|
||||
client.accountData['best animal'] = BasicEvent.fromJson({
|
||||
'type': 'best animal',
|
||||
|
|
@ -130,77 +129,78 @@ void main() {
|
|||
final decoded = SSSS.decodeRecoveryKey(encoded);
|
||||
expect(key, decoded);
|
||||
|
||||
final handle = client.encryption.ssss.open();
|
||||
final handle = client.encryption!.ssss.open();
|
||||
await handle.unlock(recoveryKey: ssssKey);
|
||||
expect(handle.recoveryKey, ssssKey);
|
||||
});
|
||||
|
||||
test('cache', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.encryption.ssss.clearCache();
|
||||
await client.encryption!.ssss.clearCache();
|
||||
final handle =
|
||||
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);
|
||||
client.encryption!.ssss.open(EventTypes.CrossSigningSelfSigning);
|
||||
await handle.unlock(recoveryKey: ssssKey, postUnlock: false);
|
||||
expect(
|
||||
(await client.encryption.ssss
|
||||
(await client.encryption!.ssss
|
||||
.getCached(EventTypes.CrossSigningSelfSigning)) !=
|
||||
null,
|
||||
false);
|
||||
expect(
|
||||
(await client.encryption.ssss
|
||||
(await client.encryption!.ssss
|
||||
.getCached(EventTypes.CrossSigningUserSigning)) !=
|
||||
null,
|
||||
false);
|
||||
await handle.getStored(EventTypes.CrossSigningSelfSigning);
|
||||
expect(
|
||||
(await client.encryption.ssss
|
||||
(await client.encryption!.ssss
|
||||
.getCached(EventTypes.CrossSigningSelfSigning)) !=
|
||||
null,
|
||||
true);
|
||||
await handle.maybeCacheAll();
|
||||
expect(
|
||||
(await client.encryption.ssss
|
||||
(await client.encryption!.ssss
|
||||
.getCached(EventTypes.CrossSigningUserSigning)) !=
|
||||
null,
|
||||
true);
|
||||
expect(
|
||||
(await client.encryption.ssss.getCached(EventTypes.MegolmBackup)) !=
|
||||
(await client.encryption!.ssss.getCached(EventTypes.MegolmBackup)) !=
|
||||
null,
|
||||
true);
|
||||
});
|
||||
|
||||
test('postUnlock', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.encryption.ssss.clearCache();
|
||||
client.userDeviceKeys[client.userID].masterKey.setDirectVerified(false);
|
||||
await client.encryption!.ssss.clearCache();
|
||||
client.userDeviceKeys[client.userID!]!.masterKey!
|
||||
.setDirectVerified(false);
|
||||
final handle =
|
||||
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);
|
||||
client.encryption!.ssss.open(EventTypes.CrossSigningSelfSigning);
|
||||
await handle.unlock(recoveryKey: ssssKey);
|
||||
expect(
|
||||
(await client.encryption.ssss
|
||||
(await client.encryption!.ssss
|
||||
.getCached(EventTypes.CrossSigningSelfSigning)) !=
|
||||
null,
|
||||
true);
|
||||
expect(
|
||||
(await client.encryption.ssss
|
||||
(await client.encryption!.ssss
|
||||
.getCached(EventTypes.CrossSigningUserSigning)) !=
|
||||
null,
|
||||
true);
|
||||
expect(
|
||||
(await client.encryption.ssss.getCached(EventTypes.MegolmBackup)) !=
|
||||
(await client.encryption!.ssss.getCached(EventTypes.MegolmBackup)) !=
|
||||
null,
|
||||
true);
|
||||
expect(
|
||||
client.userDeviceKeys[client.userID].masterKey.directVerified, true);
|
||||
expect(client.userDeviceKeys[client.userID!]!.masterKey!.directVerified,
|
||||
true);
|
||||
});
|
||||
|
||||
test('make share requests', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key =
|
||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||
client.userDeviceKeys[client.userID!]!.deviceKeys['OTHERDEVICE']!;
|
||||
key.setDirectVerified(true);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.ssss.request('some.type', [key]);
|
||||
await client.encryption!.ssss.request('some.type', [key]);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -210,7 +210,7 @@ void main() {
|
|||
test('answer to share requests', () async {
|
||||
if (!olmEnabled) return;
|
||||
var event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.request',
|
||||
content: {
|
||||
'action': 'request',
|
||||
|
|
@ -220,7 +220,7 @@ void main() {
|
|||
},
|
||||
);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -240,7 +240,7 @@ void main() {
|
|||
},
|
||||
);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -248,7 +248,7 @@ void main() {
|
|||
|
||||
// secret not cached
|
||||
event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.request',
|
||||
content: {
|
||||
'action': 'request',
|
||||
|
|
@ -258,7 +258,7 @@ void main() {
|
|||
},
|
||||
);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -266,7 +266,7 @@ void main() {
|
|||
|
||||
// is a cancelation
|
||||
event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.request',
|
||||
content: {
|
||||
'action': 'request_cancellation',
|
||||
|
|
@ -276,7 +276,7 @@ void main() {
|
|||
},
|
||||
);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -284,11 +284,12 @@ void main() {
|
|||
|
||||
// device not verified
|
||||
final key =
|
||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||
client.userDeviceKeys[client.userID!]!.deviceKeys['OTHERDEVICE']!;
|
||||
key.setDirectVerified(false);
|
||||
client.userDeviceKeys[client.userID].masterKey.setDirectVerified(false);
|
||||
client.userDeviceKeys[client.userID!]!.masterKey!
|
||||
.setDirectVerified(false);
|
||||
event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.request',
|
||||
content: {
|
||||
'action': 'request',
|
||||
|
|
@ -298,7 +299,7 @@ void main() {
|
|||
},
|
||||
);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.keys.any(
|
||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||
|
|
@ -309,28 +310,28 @@ void main() {
|
|||
test('receive share requests', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key =
|
||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||
client.userDeviceKeys[client.userID!]!.deviceKeys['OTHERDEVICE']!;
|
||||
key.setDirectVerified(true);
|
||||
final handle =
|
||||
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);
|
||||
client.encryption!.ssss.open(EventTypes.CrossSigningSelfSigning);
|
||||
await handle.unlock(recoveryKey: ssssKey);
|
||||
|
||||
await client.encryption.ssss.clearCache();
|
||||
client.encryption.ssss.pendingShareRequests.clear();
|
||||
await client.encryption.ssss.request('best animal', [key]);
|
||||
await client.encryption!.ssss.clearCache();
|
||||
client.encryption!.ssss.pendingShareRequests.clear();
|
||||
await client.encryption!.ssss.request('best animal', [key]);
|
||||
var event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.send',
|
||||
content: {
|
||||
'request_id': client.encryption.ssss.pendingShareRequests.keys.first,
|
||||
'request_id': client.encryption!.ssss.pendingShareRequests.keys.first,
|
||||
'secret': 'foxies!',
|
||||
},
|
||||
encryptedContent: {
|
||||
'sender_key': key.curve25519Key,
|
||||
},
|
||||
);
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption.ssss.getCached('best animal'), 'foxies!');
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption!.ssss.getCached('best animal'), 'foxies!');
|
||||
|
||||
// test the different validators
|
||||
for (final type in [
|
||||
|
|
@ -339,48 +340,48 @@ void main() {
|
|||
EventTypes.MegolmBackup
|
||||
]) {
|
||||
final secret = await handle.getStored(type);
|
||||
await client.encryption.ssss.clearCache();
|
||||
client.encryption.ssss.pendingShareRequests.clear();
|
||||
await client.encryption.ssss.request(type, [key]);
|
||||
await client.encryption!.ssss.clearCache();
|
||||
client.encryption!.ssss.pendingShareRequests.clear();
|
||||
await client.encryption!.ssss.request(type, [key]);
|
||||
event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.send',
|
||||
content: {
|
||||
'request_id':
|
||||
client.encryption.ssss.pendingShareRequests.keys.first,
|
||||
client.encryption!.ssss.pendingShareRequests.keys.first,
|
||||
'secret': secret,
|
||||
},
|
||||
encryptedContent: {
|
||||
'sender_key': key.curve25519Key,
|
||||
},
|
||||
);
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption.ssss.getCached(type), secret);
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption!.ssss.getCached(type), secret);
|
||||
}
|
||||
|
||||
// test different fail scenarios
|
||||
|
||||
// not encrypted
|
||||
await client.encryption.ssss.clearCache();
|
||||
client.encryption.ssss.pendingShareRequests.clear();
|
||||
await client.encryption.ssss.request('best animal', [key]);
|
||||
await client.encryption!.ssss.clearCache();
|
||||
client.encryption!.ssss.pendingShareRequests.clear();
|
||||
await client.encryption!.ssss.request('best animal', [key]);
|
||||
event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.send',
|
||||
content: {
|
||||
'request_id': client.encryption.ssss.pendingShareRequests.keys.first,
|
||||
'request_id': client.encryption!.ssss.pendingShareRequests.keys.first,
|
||||
'secret': 'foxies!',
|
||||
},
|
||||
);
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption.ssss.getCached('best animal'), null);
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption!.ssss.getCached('best animal'), null);
|
||||
|
||||
// unknown request id
|
||||
await client.encryption.ssss.clearCache();
|
||||
client.encryption.ssss.pendingShareRequests.clear();
|
||||
await client.encryption.ssss.request('best animal', [key]);
|
||||
await client.encryption!.ssss.clearCache();
|
||||
client.encryption!.ssss.pendingShareRequests.clear();
|
||||
await client.encryption!.ssss.request('best animal', [key]);
|
||||
event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.send',
|
||||
content: {
|
||||
'request_id': 'invalid',
|
||||
|
|
@ -390,103 +391,103 @@ void main() {
|
|||
'sender_key': key.curve25519Key,
|
||||
},
|
||||
);
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption.ssss.getCached('best animal'), null);
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption!.ssss.getCached('best animal'), null);
|
||||
|
||||
// not from a device we sent the request to
|
||||
await client.encryption.ssss.clearCache();
|
||||
client.encryption.ssss.pendingShareRequests.clear();
|
||||
await client.encryption.ssss.request('best animal', [key]);
|
||||
await client.encryption!.ssss.clearCache();
|
||||
client.encryption!.ssss.pendingShareRequests.clear();
|
||||
await client.encryption!.ssss.request('best animal', [key]);
|
||||
event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.send',
|
||||
content: {
|
||||
'request_id': client.encryption.ssss.pendingShareRequests.keys.first,
|
||||
'request_id': client.encryption!.ssss.pendingShareRequests.keys.first,
|
||||
'secret': 'foxies!',
|
||||
},
|
||||
encryptedContent: {
|
||||
'sender_key': 'invalid',
|
||||
},
|
||||
);
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption.ssss.getCached('best animal'), null);
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption!.ssss.getCached('best animal'), null);
|
||||
|
||||
// secret not a string
|
||||
await client.encryption.ssss.clearCache();
|
||||
client.encryption.ssss.pendingShareRequests.clear();
|
||||
await client.encryption.ssss.request('best animal', [key]);
|
||||
await client.encryption!.ssss.clearCache();
|
||||
client.encryption!.ssss.pendingShareRequests.clear();
|
||||
await client.encryption!.ssss.request('best animal', [key]);
|
||||
event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.send',
|
||||
content: {
|
||||
'request_id': client.encryption.ssss.pendingShareRequests.keys.first,
|
||||
'request_id': client.encryption!.ssss.pendingShareRequests.keys.first,
|
||||
'secret': 42,
|
||||
},
|
||||
encryptedContent: {
|
||||
'sender_key': key.curve25519Key,
|
||||
},
|
||||
);
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption.ssss.getCached('best animal'), null);
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption!.ssss.getCached('best animal'), null);
|
||||
|
||||
// validator doesn't check out
|
||||
await client.encryption.ssss.clearCache();
|
||||
client.encryption.ssss.pendingShareRequests.clear();
|
||||
await client.encryption.ssss.request(EventTypes.MegolmBackup, [key]);
|
||||
await client.encryption!.ssss.clearCache();
|
||||
client.encryption!.ssss.pendingShareRequests.clear();
|
||||
await client.encryption!.ssss.request(EventTypes.MegolmBackup, [key]);
|
||||
event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
sender: client.userID!,
|
||||
type: 'm.secret.send',
|
||||
content: {
|
||||
'request_id': client.encryption.ssss.pendingShareRequests.keys.first,
|
||||
'request_id': client.encryption!.ssss.pendingShareRequests.keys.first,
|
||||
'secret': 'foxies!',
|
||||
},
|
||||
encryptedContent: {
|
||||
'sender_key': key.curve25519Key,
|
||||
},
|
||||
);
|
||||
await client.encryption.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption.ssss.getCached(EventTypes.MegolmBackup),
|
||||
await client.encryption!.ssss.handleToDeviceEvent(event);
|
||||
expect(await client.encryption!.ssss.getCached(EventTypes.MegolmBackup),
|
||||
null);
|
||||
});
|
||||
|
||||
test('request all', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key =
|
||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||
client.userDeviceKeys[client.userID!]!.deviceKeys['OTHERDEVICE']!;
|
||||
key.setDirectVerified(true);
|
||||
await client.encryption.ssss.clearCache();
|
||||
client.encryption.ssss.pendingShareRequests.clear();
|
||||
await client.encryption.ssss.maybeRequestAll([key]);
|
||||
expect(client.encryption.ssss.pendingShareRequests.length, 3);
|
||||
await client.encryption!.ssss.clearCache();
|
||||
client.encryption!.ssss.pendingShareRequests.clear();
|
||||
await client.encryption!.ssss.maybeRequestAll([key]);
|
||||
expect(client.encryption!.ssss.pendingShareRequests.length, 3);
|
||||
});
|
||||
|
||||
test('periodicallyRequestMissingCache', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.userDeviceKeys[client.userID].masterKey.setDirectVerified(true);
|
||||
client.encryption.ssss = MockSSSS(client.encryption);
|
||||
(client.encryption.ssss as MockSSSS).requestedSecrets = false;
|
||||
await client.encryption.ssss.periodicallyRequestMissingCache();
|
||||
expect((client.encryption.ssss as MockSSSS).requestedSecrets, true);
|
||||
client.userDeviceKeys[client.userID!]!.masterKey!.setDirectVerified(true);
|
||||
client.encryption!.ssss = MockSSSS(client.encryption!);
|
||||
(client.encryption!.ssss as MockSSSS).requestedSecrets = false;
|
||||
await client.encryption!.ssss.periodicallyRequestMissingCache();
|
||||
expect((client.encryption!.ssss as MockSSSS).requestedSecrets, true);
|
||||
// it should only retry once every 15 min
|
||||
(client.encryption.ssss as MockSSSS).requestedSecrets = false;
|
||||
await client.encryption.ssss.periodicallyRequestMissingCache();
|
||||
expect((client.encryption.ssss as MockSSSS).requestedSecrets, false);
|
||||
(client.encryption!.ssss as MockSSSS).requestedSecrets = false;
|
||||
await client.encryption!.ssss.periodicallyRequestMissingCache();
|
||||
expect((client.encryption!.ssss as MockSSSS).requestedSecrets, false);
|
||||
});
|
||||
|
||||
test('createKey', () async {
|
||||
if (!olmEnabled) return;
|
||||
// with passphrase
|
||||
var newKey = await client.encryption.ssss.createKey('test');
|
||||
expect(client.encryption.ssss.isKeyValid(newKey.keyId), true);
|
||||
var testKey = client.encryption.ssss.open(newKey.keyId);
|
||||
var newKey = await client.encryption!.ssss.createKey('test');
|
||||
expect(client.encryption!.ssss.isKeyValid(newKey.keyId), true);
|
||||
var testKey = client.encryption!.ssss.open(newKey.keyId);
|
||||
await testKey.unlock(passphrase: 'test');
|
||||
await testKey.setPrivateKey(newKey.privateKey);
|
||||
await testKey.setPrivateKey(newKey.privateKey!);
|
||||
|
||||
// without passphrase
|
||||
newKey = await client.encryption.ssss.createKey();
|
||||
expect(client.encryption.ssss.isKeyValid(newKey.keyId), true);
|
||||
testKey = client.encryption.ssss.open(newKey.keyId);
|
||||
await testKey.setPrivateKey(newKey.privateKey);
|
||||
newKey = await client.encryption!.ssss.createKey();
|
||||
expect(client.encryption!.ssss.isKeyValid(newKey.keyId), true);
|
||||
testKey = client.encryption!.ssss.open(newKey.keyId);
|
||||
await testKey.setPrivateKey(newKey.privateKey!);
|
||||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -29,7 +28,7 @@ import 'package:test/test.dart';
|
|||
|
||||
import 'fake_client.dart';
|
||||
import 'fake_matrix_api.dart';
|
||||
import 'fake_matrix_localizations.dart';
|
||||
import 'matrix_default_localizations.dart';
|
||||
|
||||
void main() {
|
||||
/// All Tests related to the Event
|
||||
|
|
@ -249,10 +248,10 @@ void main() {
|
|||
final event = Event.fromJson(redactJsonObj, room);
|
||||
event.setRedactionEvent(redactedBecause);
|
||||
expect(event.redacted, true);
|
||||
expect(event.redactedBecause.toJson(), redactedBecause.toJson());
|
||||
expect(event.redactedBecause?.toJson(), redactedBecause.toJson());
|
||||
expect(event.content.isEmpty, true);
|
||||
redactionEventJson.remove('redacts');
|
||||
expect(event.unsigned['redacted_because'], redactionEventJson);
|
||||
expect(event.unsigned?['redacted_because'], redactionEventJson);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -280,7 +279,7 @@ void main() {
|
|||
event.status = EventStatus.error;
|
||||
final resp2 = await event.sendAgain(txid: '1234');
|
||||
expect(resp1, null);
|
||||
expect(resp2.startsWith('\$event'), true);
|
||||
expect(resp2?.startsWith('\$event'), true);
|
||||
|
||||
await matrix.dispose(closeDatabase: true);
|
||||
});
|
||||
|
|
@ -295,7 +294,7 @@ void main() {
|
|||
|
||||
final event = Event.fromJson(
|
||||
jsonObj, Room(id: '!1234:example.com', client: matrix));
|
||||
String exception;
|
||||
String? exception;
|
||||
try {
|
||||
await event.requestKey();
|
||||
} catch (e) {
|
||||
|
|
@ -330,7 +329,7 @@ void main() {
|
|||
jsonObj['state_key'] = '@alice:example.com';
|
||||
final event = Event.fromJson(
|
||||
jsonObj, Room(id: '!localpart:server.abc', client: client));
|
||||
expect(event.stateKeyUser.id, '@alice:example.com');
|
||||
expect(event.stateKeyUser?.id, '@alice:example.com');
|
||||
});
|
||||
test('canRedact', () async {
|
||||
expect(event.canRedact, true);
|
||||
|
|
@ -364,7 +363,8 @@ void main() {
|
|||
}
|
||||
}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Removed by Example');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -392,7 +392,8 @@ void main() {
|
|||
'type': 'm.sticker',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example sent a sticker');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -405,7 +406,8 @@ void main() {
|
|||
'type': 'm.room.redaction',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example redacted an event');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -420,7 +422,8 @@ void main() {
|
|||
'type': 'm.room.aliases',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example changed the room aliases');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -435,7 +438,8 @@ void main() {
|
|||
'type': 'm.room.aliases',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example changed the room aliases');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -448,7 +452,8 @@ void main() {
|
|||
'type': 'm.room.canonical_alias',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example changed the room invitation link');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -469,7 +474,8 @@ void main() {
|
|||
'type': 'm.room.create',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example created the chat');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -485,7 +491,8 @@ void main() {
|
|||
'type': 'm.room.tombstone',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Room has been upgraded');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -498,7 +505,8 @@ void main() {
|
|||
'type': 'm.room.join_rules',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example changed the join rules to Anyone can join');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -515,7 +523,8 @@ void main() {
|
|||
'type': 'm.room.member',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Alice joined the chat');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -527,7 +536,8 @@ void main() {
|
|||
'state_key': '@alice:example.org',
|
||||
'type': 'm.room.member'
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example has invited Alice');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -542,7 +552,8 @@ void main() {
|
|||
'prev_content': {'membership': 'join'},
|
||||
}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example kicked Alice');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -557,7 +568,8 @@ void main() {
|
|||
'prev_content': {'membership': 'join'},
|
||||
}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example banned Alice');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -572,7 +584,8 @@ void main() {
|
|||
'prev_content': {'membership': 'invite'},
|
||||
}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Alice accepted the invitation');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -587,7 +600,8 @@ void main() {
|
|||
'prev_content': {'membership': 'join'},
|
||||
}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example has invited Alice');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -602,7 +616,8 @@ void main() {
|
|||
'prev_content': {'membership': 'invite'},
|
||||
}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example has withdrawn the invitation for Alice');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -617,7 +632,8 @@ void main() {
|
|||
'prev_content': {'membership': 'invite'},
|
||||
}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Alice rejected the invitation');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -641,7 +657,8 @@ void main() {
|
|||
'type': 'm.room.power_levels',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example changed the chat permissions');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -654,7 +671,8 @@ void main() {
|
|||
'type': 'm.room.name',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example changed the chat name to The room name');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -667,7 +685,8 @@ void main() {
|
|||
'type': 'm.room.topic',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example changed the chat description to A room topic');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -683,7 +702,8 @@ void main() {
|
|||
'type': 'm.room.avatar',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example changed the chat avatar');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -696,7 +716,8 @@ void main() {
|
|||
'type': 'm.room.history_visibility',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example changed the history visibility to Visible for all participants');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -713,8 +734,8 @@ void main() {
|
|||
'type': 'm.room.encryption',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()),
|
||||
'Example activatedEndToEndEncryption. needPantalaimonWarning');
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example activated end to end encryption. Need pantalaimon');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -731,7 +752,7 @@ void main() {
|
|||
'type': 'm.room.message',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()),
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'This is an example text message');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
|
|
@ -749,7 +770,7 @@ void main() {
|
|||
'type': 'm.room.message',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()),
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'* thinks this is an example emote');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
|
|
@ -767,7 +788,7 @@ void main() {
|
|||
'type': 'm.room.message',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()),
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'This is an example notice');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
|
|
@ -785,7 +806,8 @@ void main() {
|
|||
'type': 'm.room.message',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example sent a picture');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -803,7 +825,8 @@ void main() {
|
|||
'type': 'm.room.message',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example sent a file');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -824,7 +847,8 @@ void main() {
|
|||
'type': 'm.room.message',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example sent an audio');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -849,7 +873,8 @@ void main() {
|
|||
'type': 'm.room.message',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example shared the location');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -879,7 +904,8 @@ void main() {
|
|||
'type': 'm.room.message',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Example sent a video');
|
||||
expect(event.isEventTypeKnown, true);
|
||||
|
||||
event = Event.fromJson({
|
||||
|
|
@ -891,7 +917,8 @@ void main() {
|
|||
'type': 'unknown.event.type',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations()), null);
|
||||
expect(event.getLocalizedBody(MatrixDefaultLocalizations()),
|
||||
'Unknown event unknown.event.type');
|
||||
expect(event.isEventTypeKnown, false);
|
||||
});
|
||||
|
||||
|
|
@ -913,7 +940,7 @@ void main() {
|
|||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(
|
||||
event.getLocalizedBody(FakeMatrixLocalizations(),
|
||||
event.getLocalizedBody(MatrixDefaultLocalizations(),
|
||||
plaintextBody: true),
|
||||
'**This is an example text message**');
|
||||
|
||||
|
|
@ -941,10 +968,11 @@ void main() {
|
|||
'type': 'm.room.message',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations(), hideEdit: true),
|
||||
expect(
|
||||
event.getLocalizedBody(MatrixDefaultLocalizations(), hideEdit: true),
|
||||
'This is an example text message');
|
||||
expect(
|
||||
event.getLocalizedBody(FakeMatrixLocalizations(),
|
||||
event.getLocalizedBody(MatrixDefaultLocalizations(),
|
||||
hideEdit: true, plaintextBody: true),
|
||||
'**This is an example text message**');
|
||||
|
||||
|
|
@ -962,10 +990,11 @@ void main() {
|
|||
'type': 'm.room.message',
|
||||
'unsigned': {'age': 1234}
|
||||
}, room);
|
||||
expect(event.getLocalizedBody(FakeMatrixLocalizations(), hideReply: true),
|
||||
expect(
|
||||
event.getLocalizedBody(MatrixDefaultLocalizations(), hideReply: true),
|
||||
'hmm, fox');
|
||||
expect(
|
||||
event.getLocalizedBody(FakeMatrixLocalizations(),
|
||||
event.getLocalizedBody(MatrixDefaultLocalizations(),
|
||||
hideReply: true, plaintextBody: true),
|
||||
'hmm, *fox*');
|
||||
});
|
||||
|
|
@ -976,6 +1005,8 @@ void main() {
|
|||
'body': 'blah',
|
||||
'msgtype': 'm.text',
|
||||
},
|
||||
'type': 'm.room.message',
|
||||
'sender': '@example:example.org',
|
||||
'event_id': '\$source',
|
||||
}, null);
|
||||
final edit1 = Event.fromJson({
|
||||
|
|
@ -987,6 +1018,8 @@ void main() {
|
|||
'rel_type': RelationshipTypes.edit,
|
||||
},
|
||||
},
|
||||
'type': 'm.room.message',
|
||||
'sender': '@example:example.org',
|
||||
'event_id': '\$edit1',
|
||||
}, null);
|
||||
final edit2 = Event.fromJson({
|
||||
|
|
@ -998,9 +1031,11 @@ void main() {
|
|||
'rel_type': RelationshipTypes.edit,
|
||||
},
|
||||
},
|
||||
'type': 'm.room.message',
|
||||
'sender': '@example:example.org',
|
||||
'event_id': '\$edit2',
|
||||
}, null);
|
||||
final room = Room(client: client);
|
||||
final room = Room(client: client, id: '!id:fakeserver.nonexisting');
|
||||
final timeline =
|
||||
Timeline(events: <Event>[event, edit1, edit2], room: room);
|
||||
expect(event.hasAggregatedEvents(timeline, RelationshipTypes.edit), true);
|
||||
|
|
@ -1096,7 +1131,7 @@ void main() {
|
|||
'event_id': '\$edit3',
|
||||
'sender': '@bob:example.org',
|
||||
}, null);
|
||||
final room = Room(client: client);
|
||||
final room = Room(id: '!localpart:server.abc', client: client);
|
||||
// no edits
|
||||
var displayEvent =
|
||||
event.getDisplayEvent(Timeline(events: <Event>[event], room: room));
|
||||
|
|
@ -1127,8 +1162,9 @@ void main() {
|
|||
'sender': '@alice:example.org',
|
||||
'unsigned': {
|
||||
'redacted_because': {
|
||||
'evnet_id': '\$redact',
|
||||
'event_id': '\$redact',
|
||||
'sender': '@alice:example.org',
|
||||
'type': 'm.room.redaction',
|
||||
},
|
||||
},
|
||||
}, null);
|
||||
|
|
@ -1143,7 +1179,7 @@ void main() {
|
|||
return {
|
||||
'/_matrix/media/r0/download/example.org/file': FILE_BUFF,
|
||||
'/_matrix/media/r0/download/example.org/thumb': THUMBNAIL_BUFF,
|
||||
}[uri.path];
|
||||
}[uri.path]!;
|
||||
};
|
||||
await client.checkHomeserver('https://fakeserver.notexisting',
|
||||
checkWellKnown: false);
|
||||
|
|
@ -1160,7 +1196,7 @@ void main() {
|
|||
}, room);
|
||||
var buffer = await event.downloadAndDecryptAttachment(
|
||||
downloadCallback: downloadCallback);
|
||||
expect(buffer.bytes, FILE_BUFF);
|
||||
expect(buffer?.bytes, FILE_BUFF);
|
||||
expect(event.attachmentOrThumbnailMxcUrl().toString(),
|
||||
'mxc://example.org/file');
|
||||
expect(event.attachmentOrThumbnailMxcUrl(getThumbnail: true).toString(),
|
||||
|
|
@ -1215,11 +1251,11 @@ void main() {
|
|||
|
||||
buffer = await event.downloadAndDecryptAttachment(
|
||||
downloadCallback: downloadCallback);
|
||||
expect(buffer.bytes, FILE_BUFF);
|
||||
expect(buffer?.bytes, FILE_BUFF);
|
||||
|
||||
buffer = await event.downloadAndDecryptAttachment(
|
||||
getThumbnail: true, downloadCallback: downloadCallback);
|
||||
expect(buffer.bytes, THUMBNAIL_BUFF);
|
||||
expect(buffer?.bytes, THUMBNAIL_BUFF);
|
||||
});
|
||||
test('encrypted attachments', () async {
|
||||
if (!olmEnabled) return;
|
||||
|
|
@ -1234,7 +1270,7 @@ void main() {
|
|||
return {
|
||||
'/_matrix/media/r0/download/example.com/file': FILE_BUFF_ENC,
|
||||
'/_matrix/media/r0/download/example.com/thumb': THUMB_BUFF_ENC,
|
||||
}[uri.path];
|
||||
}[uri.path]!;
|
||||
};
|
||||
final room = Room(id: '!localpart:server.abc', client: await getClient());
|
||||
var event = Event.fromJson({
|
||||
|
|
@ -1262,7 +1298,7 @@ void main() {
|
|||
}, room);
|
||||
var buffer = await event.downloadAndDecryptAttachment(
|
||||
downloadCallback: downloadCallback);
|
||||
expect(buffer.bytes, FILE_BUFF_DEC);
|
||||
expect(buffer?.bytes, FILE_BUFF_DEC);
|
||||
|
||||
event = Event.fromJson({
|
||||
'type': EventTypes.Message,
|
||||
|
|
@ -1315,11 +1351,11 @@ void main() {
|
|||
expect(event.thumbnailMxcUrl.toString(), 'mxc://example.com/thumb');
|
||||
buffer = await event.downloadAndDecryptAttachment(
|
||||
downloadCallback: downloadCallback);
|
||||
expect(buffer.bytes, FILE_BUFF_DEC);
|
||||
expect(buffer?.bytes, FILE_BUFF_DEC);
|
||||
|
||||
buffer = await event.downloadAndDecryptAttachment(
|
||||
getThumbnail: true, downloadCallback: downloadCallback);
|
||||
expect(buffer.bytes, THUMB_BUFF_DEC);
|
||||
expect(buffer?.bytes, THUMB_BUFF_DEC);
|
||||
|
||||
await room.client.dispose(closeDatabase: true);
|
||||
});
|
||||
|
|
@ -1330,7 +1366,7 @@ void main() {
|
|||
serverHits++;
|
||||
return {
|
||||
'/_matrix/media/r0/download/example.org/newfile': FILE_BUFF,
|
||||
}[uri.path];
|
||||
}[uri.path]!;
|
||||
};
|
||||
await client.checkHomeserver('https://fakeserver.notexisting',
|
||||
checkWellKnown: false);
|
||||
|
|
@ -1352,14 +1388,14 @@ void main() {
|
|||
var buffer = await event.downloadAndDecryptAttachment(
|
||||
downloadCallback: downloadCallback);
|
||||
expect(await event.isAttachmentInLocalStore(),
|
||||
event.room.client.database.supportsFileStoring);
|
||||
expect(buffer.bytes, FILE_BUFF);
|
||||
event.room?.client.database?.supportsFileStoring);
|
||||
expect(buffer?.bytes, FILE_BUFF);
|
||||
expect(serverHits, 1);
|
||||
buffer = await event.downloadAndDecryptAttachment(
|
||||
downloadCallback: downloadCallback);
|
||||
expect(buffer.bytes, FILE_BUFF);
|
||||
expect(buffer?.bytes, FILE_BUFF);
|
||||
expect(
|
||||
serverHits, event.room.client.database.supportsFileStoring ? 1 : 2);
|
||||
serverHits, event.room!.client.database!.supportsFileStoring ? 1 : 2);
|
||||
|
||||
await room.client.dispose(closeDatabase: true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -25,11 +24,11 @@ import 'package:matrix/src/database/hive_database.dart';
|
|||
import 'package:file/memory.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
Future<DatabaseApi> getDatabase(Client _) => getHiveDatabase(_);
|
||||
Future<DatabaseApi> getDatabase(Client? _) => getHiveDatabase(_);
|
||||
|
||||
bool hiveInitialized = false;
|
||||
|
||||
Future<FamedlySdkHiveDatabase> getHiveDatabase(Client c) async {
|
||||
Future<FamedlySdkHiveDatabase> getHiveDatabase(Client? c) async {
|
||||
if (!hiveInitialized) {
|
||||
final fileSystem = MemoryFileSystem();
|
||||
final testHivePath =
|
||||
|
|
@ -38,7 +37,7 @@ Future<FamedlySdkHiveDatabase> getHiveDatabase(Client c) async {
|
|||
Hive.init(testHivePath);
|
||||
hiveInitialized = true;
|
||||
}
|
||||
final db = FamedlySdkHiveDatabase('unit_test.${c.hashCode}');
|
||||
final db = FamedlySdkHiveDatabase('unit_test.${c?.hashCode}');
|
||||
await db.open();
|
||||
return db;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -39,7 +38,7 @@ Map<String, dynamic> decodeJson(dynamic data) {
|
|||
class FakeMatrixApi extends MockClient {
|
||||
static final calledEndpoints = <String, List<dynamic>>{};
|
||||
static int eventCounter = 0;
|
||||
static sdk.Client client;
|
||||
static sdk.Client? client;
|
||||
static bool failToDevice = false;
|
||||
|
||||
FakeMatrixApi()
|
||||
|
|
@ -85,9 +84,10 @@ class FakeMatrixApi extends MockClient {
|
|||
if (!calledEndpoints.containsKey(action)) {
|
||||
calledEndpoints[action] = <dynamic>[];
|
||||
}
|
||||
calledEndpoints[action].add(data);
|
||||
if (api.containsKey(method) && api[method].containsKey(action)) {
|
||||
res = api[method][action](data);
|
||||
calledEndpoints[action]?.add(data);
|
||||
final act = api[method]?[action];
|
||||
if (act != null) {
|
||||
res = act(data);
|
||||
if (res is Map && res.containsKey('errcode')) {
|
||||
if (res['errcode'] == 'M_NOT_FOUND') {
|
||||
statusCode = 404;
|
||||
|
|
@ -126,12 +126,12 @@ class FakeMatrixApi extends MockClient {
|
|||
..accountData = [
|
||||
sdk.BasicEvent(content: decodeJson(data), type: type)
|
||||
];
|
||||
if (client.database != null) {
|
||||
await client.database.transaction(() async {
|
||||
await client.handleSync(syncUpdate);
|
||||
if (client?.database != null) {
|
||||
await client?.database?.transaction(() async {
|
||||
await client?.handleSync(syncUpdate);
|
||||
});
|
||||
} else {
|
||||
await client.handleSync(syncUpdate);
|
||||
await client?.handleSync(syncUpdate);
|
||||
}
|
||||
res = {};
|
||||
} else {
|
||||
|
|
@ -2101,15 +2101,15 @@ class FakeMatrixApi extends MockClient {
|
|||
}) {
|
||||
if (jsonBody[keyType] != null) {
|
||||
final key =
|
||||
sdk.CrossSigningKey.fromJson(jsonBody[keyType], client);
|
||||
client.userDeviceKeys[client.userID].crossSigningKeys
|
||||
sdk.CrossSigningKey.fromJson(jsonBody[keyType], client!);
|
||||
client!.userDeviceKeys[client!.userID!]?.crossSigningKeys
|
||||
.removeWhere((k, v) => v.usage.contains(key.usage.first));
|
||||
client.userDeviceKeys[client.userID]
|
||||
.crossSigningKeys[key.publicKey] = key;
|
||||
client!.userDeviceKeys[client!.userID!]
|
||||
?.crossSigningKeys[key.publicKey!] = key;
|
||||
}
|
||||
}
|
||||
// and generate a fake sync
|
||||
client.handleSync(sdk.SyncUpdate(nextBatch: ''));
|
||||
client!.handleSync(sdk.SyncUpdate(nextBatch: ''));
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
|
@ -2124,35 +2124,35 @@ class FakeMatrixApi extends MockClient {
|
|||
'/client/r0/pushrules/global/content/nocake/enabled': (var req) => {},
|
||||
'/client/r0/pushrules/global/content/nocake/actions': (var req) => {},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/state/m.room.history_visibility':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/state/m.room.join_rules':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/state/m.room.guest_access':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/m.call.invite/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/m.call.answer/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/m.call.select_answer/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/m.call.reject/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/m.call.negotiate/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/m.call.candidates/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/m.call.hangup/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/m.call.replaces/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/m.call.asserted_identity/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/m.call.sdp_stream_metadata_changed/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/org.matrix.call.sdp_stream_metadata_changed/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!localpart%3Aserver.abc/send/org.matrix.call.asserted_identity/1234':
|
||||
(var req) => {},
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/rooms/!1234%3Aexample.com/redact/1143273582443PhrSn%3Aexample.org/1234':
|
||||
(var req) => {'event_id': '1234'},
|
||||
'/client/r0/pushrules/global/room/!localpart%3Aserver.abc': (var req) =>
|
||||
|
|
|
|||
|
|
@ -1,334 +0,0 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
class FakeMatrixLocalizations extends MatrixLocalizations {
|
||||
@override
|
||||
String acceptedTheInvitation(String targetName) {
|
||||
// TODO: implement acceptedTheInvitation
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String activatedEndToEndEncryption(String senderName) {
|
||||
// TODO: implement activatedEndToEndEncryption
|
||||
return '$senderName activatedEndToEndEncryption';
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement anyoneCanJoin
|
||||
String get anyoneCanJoin => null;
|
||||
|
||||
@override
|
||||
String bannedUser(String senderName, String targetName) {
|
||||
// TODO: implement bannedUser
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheChatAvatar(String senderName) {
|
||||
// TODO: implement changedTheChatAvatar
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheChatDescriptionTo(String senderName, String content) {
|
||||
// TODO: implement changedTheChatDescriptionTo
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheChatNameTo(String senderName, String content) {
|
||||
// TODO: implement changedTheChatNameTo
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheChatPermissions(String senderName) {
|
||||
// TODO: implement changedTheChatPermissions
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheDisplaynameTo(String targetName, String newDisplayname) {
|
||||
// TODO: implement changedTheDisplaynameTo
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheGuestAccessRules(String senderName) {
|
||||
// TODO: implement changedTheGuestAccessRules
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheGuestAccessRulesTo(
|
||||
String senderName, String localizedString) {
|
||||
// TODO: implement changedTheGuestAccessRulesTo
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheHistoryVisibility(String senderName) {
|
||||
// TODO: implement changedTheHistoryVisibility
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheHistoryVisibilityTo(
|
||||
String senderName, String localizedString) {
|
||||
// TODO: implement changedTheHistoryVisibilityTo
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheJoinRules(String senderName) {
|
||||
// TODO: implement changedTheJoinRules
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheJoinRulesTo(String senderName, String localizedString) {
|
||||
// TODO: implement changedTheJoinRulesTo
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheProfileAvatar(String targetName) {
|
||||
// TODO: implement changedTheProfileAvatar
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheRoomAliases(String senderName) {
|
||||
// TODO: implement changedTheRoomAliases
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheRoomInvitationLink(String senderName) {
|
||||
// TODO: implement changedTheRoomInvitationLink
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement channelCorruptedDecryptError
|
||||
String get channelCorruptedDecryptError => null;
|
||||
|
||||
@override
|
||||
String couldNotDecryptMessage(String errorText) {
|
||||
// TODO: implement couldNotDecryptMessage
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String createdTheChat(String senderName) {
|
||||
// TODO: implement createdTheChat
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement emptyChat
|
||||
String get emptyChat => null;
|
||||
|
||||
@override
|
||||
// TODO: implement encryptionNotEnabled
|
||||
String get encryptionNotEnabled => null;
|
||||
|
||||
@override
|
||||
// TODO: implement fromJoining
|
||||
String get fromJoining => null;
|
||||
|
||||
@override
|
||||
// TODO: implement fromTheInvitation
|
||||
String get fromTheInvitation => null;
|
||||
|
||||
@override
|
||||
String groupWith(String displayname) {
|
||||
// TODO: implement groupWith
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement guestsAreForbidden
|
||||
String get guestsAreForbidden => null;
|
||||
|
||||
@override
|
||||
// TODO: implement guestsCanJoin
|
||||
String get guestsCanJoin => null;
|
||||
|
||||
@override
|
||||
String hasWithdrawnTheInvitationFor(String senderName, String targetName) {
|
||||
// TODO: implement hasWithdrawnTheInvitationFor
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String invitedUser(String senderName, String targetName) {
|
||||
// TODO: implement invitedUser
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement invitedUsersOnly
|
||||
String get invitedUsersOnly => null;
|
||||
|
||||
@override
|
||||
String joinedTheChat(String targetName) {
|
||||
// TODO: implement joinedTheChat
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String kicked(String senderName, String targetName) {
|
||||
// TODO: implement kicked
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String kickedAndBanned(String senderName, String targetName) {
|
||||
// TODO: implement kickedAndBanned
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement needPantalaimonWarning
|
||||
String get needPantalaimonWarning => 'needPantalaimonWarning';
|
||||
|
||||
@override
|
||||
// TODO: implement noPermission
|
||||
String get noPermission => 'noPermission';
|
||||
|
||||
@override
|
||||
String redactedAnEvent(String senderName) {
|
||||
// TODO: implement redactedAnEvent
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String rejectedTheInvitation(String targetName) {
|
||||
// TODO: implement rejectedTheInvitation
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String removedBy(String calcDisplayname) {
|
||||
// TODO: implement removedBy
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement roomHasBeenUpgraded
|
||||
String get roomHasBeenUpgraded => null;
|
||||
|
||||
@override
|
||||
String sentAFile(String senderName) {
|
||||
// TODO: implement sentAFile
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String sentAPicture(String senderName) {
|
||||
// TODO: implement sentAPicture
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String sentASticker(String senderName) {
|
||||
// TODO: implement sentASticker
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String sentAVideo(String senderName) {
|
||||
// TODO: implement sentAVideo
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String sentAnAudio(String senderName) {
|
||||
// TODO: implement sentAnAudio
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String sharedTheLocation(String senderName) {
|
||||
// TODO: implement sharedTheLocation
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String unbannedUser(String senderName, String targetName) {
|
||||
// TODO: implement unbannedUser
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement unknownEncryptionAlgorithm
|
||||
String get unknownEncryptionAlgorithm => null;
|
||||
|
||||
@override
|
||||
String unknownEvent(String typeKey) {
|
||||
// TODO: implement unknownEvent
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String userLeftTheChat(String targetName) {
|
||||
// TODO: implement userLeftTheChat
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement visibleForAllParticipants
|
||||
String get visibleForAllParticipants => null;
|
||||
|
||||
@override
|
||||
// TODO: implement visibleForEveryone
|
||||
String get visibleForEveryone => null;
|
||||
|
||||
@override
|
||||
// TODO: implement you
|
||||
String get you => null;
|
||||
|
||||
@override
|
||||
String answeredTheCall(String senderName) {
|
||||
// TODO: implement answeredTheCall
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String endedTheCall(String senderName) {
|
||||
// TODO: implement endedTheCall
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String sentCallInformations(String senderName) {
|
||||
// TODO: implement sentCallInformations
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String startedACall(String senderName) {
|
||||
// TODO: implement startedACall
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2021 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2021 Famedly GmbH
|
||||
|
|
@ -23,9 +22,9 @@ import 'fake_client.dart';
|
|||
|
||||
void main() {
|
||||
group('Image Pack', () {
|
||||
Client client;
|
||||
Room room;
|
||||
Room room2;
|
||||
late Client client;
|
||||
late Room room;
|
||||
late Room room2;
|
||||
|
||||
test('setupClient', () async {
|
||||
client = await getClient();
|
||||
|
|
@ -36,24 +35,36 @@ void main() {
|
|||
content: {},
|
||||
room: room,
|
||||
stateKey: '',
|
||||
senderId: client.userID!,
|
||||
eventId: '\$fakeid1:fakeServer.notExisting',
|
||||
originServerTs: DateTime.now(),
|
||||
));
|
||||
room.setState(Event(
|
||||
type: 'm.room.member',
|
||||
content: {'membership': 'join'},
|
||||
room: room,
|
||||
stateKey: client.userID,
|
||||
senderId: '\@fakeuser:fakeServer.notExisting',
|
||||
eventId: '\$fakeid2:fakeServer.notExisting',
|
||||
originServerTs: DateTime.now(),
|
||||
));
|
||||
room2.setState(Event(
|
||||
type: 'm.room.power_levels',
|
||||
content: {},
|
||||
room: room,
|
||||
stateKey: '',
|
||||
senderId: client.userID!,
|
||||
eventId: '\$fakeid3:fakeServer.notExisting',
|
||||
originServerTs: DateTime.now(),
|
||||
));
|
||||
room2.setState(Event(
|
||||
type: 'm.room.member',
|
||||
content: {'membership': 'join'},
|
||||
room: room,
|
||||
stateKey: client.userID,
|
||||
senderId: '\@fakeuser:fakeServer.notExisting',
|
||||
eventId: '\$fakeid4:fakeServer.notExisting',
|
||||
originServerTs: DateTime.now(),
|
||||
));
|
||||
client.rooms.add(room);
|
||||
client.rooms.add(room2);
|
||||
|
|
@ -69,11 +80,14 @@ void main() {
|
|||
},
|
||||
room: room,
|
||||
stateKey: '',
|
||||
senderId: '\@fakeuser:fakeServer.notExisting',
|
||||
eventId: '\$fakeid5:fakeServer.notExisting',
|
||||
originServerTs: DateTime.now(),
|
||||
));
|
||||
final packs = room.getImagePacks();
|
||||
expect(packs.length, 1);
|
||||
expect(packs['room'].images.length, 1);
|
||||
expect(packs['room'].images['room_plain'].url.toString(),
|
||||
expect(packs['room']?.images.length, 1);
|
||||
expect(packs['room']?.images['room_plain']?.url.toString(),
|
||||
'mxc://room_plain');
|
||||
var packsFlat = room.getImagePacksFlat();
|
||||
expect(packsFlat, {
|
||||
|
|
@ -95,6 +109,9 @@ void main() {
|
|||
},
|
||||
room: room,
|
||||
stateKey: '',
|
||||
senderId: '\@fakeuser:fakeServer.notExisting',
|
||||
eventId: '\$fakeid6:fakeServer.notExisting',
|
||||
originServerTs: DateTime.now(),
|
||||
));
|
||||
packsFlat = room.getImagePacksFlat(ImagePackUsage.emoticon);
|
||||
expect(packsFlat, {
|
||||
|
|
@ -117,6 +134,9 @@ void main() {
|
|||
},
|
||||
room: room,
|
||||
stateKey: '',
|
||||
senderId: '\@fakeuser:fakeServer.notExisting',
|
||||
eventId: '\$fakeid7:fakeServer.notExisting',
|
||||
originServerTs: DateTime.now(),
|
||||
));
|
||||
packsFlat = room.getImagePacksFlat(ImagePackUsage.emoticon);
|
||||
expect(packsFlat, {
|
||||
|
|
@ -137,6 +157,9 @@ void main() {
|
|||
},
|
||||
room: room,
|
||||
stateKey: 'fox',
|
||||
senderId: '\@fakeuser:fakeServer.notExisting',
|
||||
eventId: '\$fakeid8:fakeServer.notExisting',
|
||||
originServerTs: DateTime.now(),
|
||||
));
|
||||
packsFlat = room.getImagePacksFlat(ImagePackUsage.emoticon);
|
||||
expect(packsFlat, {
|
||||
|
|
@ -177,6 +200,9 @@ void main() {
|
|||
},
|
||||
room: room2,
|
||||
stateKey: '',
|
||||
senderId: '\@fakeuser:fakeServer.notExisting',
|
||||
eventId: '\$fakeid9:fakeServer.notExisting',
|
||||
originServerTs: DateTime.now(),
|
||||
));
|
||||
client.accountData['im.ponies.emote_rooms'] = BasicEvent.fromJson({
|
||||
'type': 'im.ponies.emote_rooms',
|
||||
|
|
@ -207,6 +233,9 @@ void main() {
|
|||
},
|
||||
room: room2,
|
||||
stateKey: 'fox',
|
||||
senderId: '\@fakeuser:fakeServer.notExisting',
|
||||
eventId: '\$fakeid10:fakeServer.notExisting',
|
||||
originServerTs: DateTime.now(),
|
||||
));
|
||||
client.accountData['im.ponies.emote_rooms'] = BasicEvent.fromJson({
|
||||
'type': 'im.ponies.emote_rooms',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -27,7 +26,7 @@ import 'fake_database.dart';
|
|||
void main() {
|
||||
group('Databse', () {
|
||||
Logs().level = Level.error;
|
||||
final room = Room(id: '!room:blubb');
|
||||
final room = Room(id: '!room:blubb', client: Client('testclient'));
|
||||
test('setupDatabase', () async {
|
||||
final database = await getDatabase(null);
|
||||
await database.insertClient(
|
||||
|
|
@ -43,7 +42,8 @@ void main() {
|
|||
});
|
||||
|
||||
test('storeEventUpdate', () async {
|
||||
final database = await getDatabase(null);
|
||||
final client = Client('testclient');
|
||||
final database = await getDatabase(client);
|
||||
// store a simple update
|
||||
var update = EventUpdate(
|
||||
type: EventUpdateType.timeline,
|
||||
|
|
@ -56,9 +56,9 @@ void main() {
|
|||
'sender': '@blah:blubb',
|
||||
},
|
||||
);
|
||||
await database.storeEventUpdate(update);
|
||||
await database.storeEventUpdate(update, client);
|
||||
var event = await database.getEventById('\$event-1', room);
|
||||
expect(event.eventId, '\$event-1');
|
||||
expect(event?.eventId, '\$event-1');
|
||||
|
||||
// insert a transaction id
|
||||
update = EventUpdate(
|
||||
|
|
@ -73,9 +73,9 @@ void main() {
|
|||
'status': EventStatus.sending.intValue,
|
||||
},
|
||||
);
|
||||
await database.storeEventUpdate(update);
|
||||
await database.storeEventUpdate(update, client);
|
||||
event = await database.getEventById('transaction-1', room);
|
||||
expect(event.eventId, 'transaction-1');
|
||||
expect(event?.eventId, 'transaction-1');
|
||||
update = EventUpdate(
|
||||
type: EventUpdateType.timeline,
|
||||
roomID: room.id,
|
||||
|
|
@ -91,7 +91,7 @@ void main() {
|
|||
'status': EventStatus.sent.intValue,
|
||||
},
|
||||
);
|
||||
await database.storeEventUpdate(update);
|
||||
await database.storeEventUpdate(update, client);
|
||||
event = await database.getEventById('transaction-1', room);
|
||||
expect(event, null);
|
||||
event = await database.getEventById('\$event-2', room);
|
||||
|
|
@ -109,9 +109,9 @@ void main() {
|
|||
'status': EventStatus.sending.intValue,
|
||||
},
|
||||
);
|
||||
await database.storeEventUpdate(update);
|
||||
await database.storeEventUpdate(update, client);
|
||||
event = await database.getEventById('\$event-3', room);
|
||||
expect(event.eventId, '\$event-3');
|
||||
expect(event?.eventId, '\$event-3');
|
||||
update = EventUpdate(
|
||||
type: EventUpdateType.timeline,
|
||||
roomID: room.id,
|
||||
|
|
@ -127,10 +127,10 @@ void main() {
|
|||
},
|
||||
},
|
||||
);
|
||||
await database.storeEventUpdate(update);
|
||||
await database.storeEventUpdate(update, client);
|
||||
event = await database.getEventById('\$event-3', room);
|
||||
expect(event.eventId, '\$event-3');
|
||||
expect(event.status, EventStatus.sent);
|
||||
expect(event?.eventId, '\$event-3');
|
||||
expect(event?.status, EventStatus.sent);
|
||||
event = await database.getEventById('transaction-2', room);
|
||||
expect(event, null);
|
||||
|
||||
|
|
@ -147,9 +147,9 @@ void main() {
|
|||
'status': EventStatus.synced.intValue,
|
||||
},
|
||||
);
|
||||
await database.storeEventUpdate(update);
|
||||
await database.storeEventUpdate(update, client);
|
||||
event = await database.getEventById('\$event-4', room);
|
||||
expect(event.eventId, '\$event-4');
|
||||
expect(event?.eventId, '\$event-4');
|
||||
update = EventUpdate(
|
||||
type: EventUpdateType.timeline,
|
||||
roomID: room.id,
|
||||
|
|
@ -165,10 +165,10 @@ void main() {
|
|||
},
|
||||
},
|
||||
);
|
||||
await database.storeEventUpdate(update);
|
||||
await database.storeEventUpdate(update, client);
|
||||
event = await database.getEventById('\$event-4', room);
|
||||
expect(event.eventId, '\$event-4');
|
||||
expect(event.status, EventStatus.synced);
|
||||
expect(event?.eventId, '\$event-4');
|
||||
expect(event?.status, EventStatus.synced);
|
||||
event = await database.getEventById('transaction-3', room);
|
||||
expect(event, null);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -34,11 +33,11 @@ void main() {
|
|||
);
|
||||
expect(matrixException.errcode, 'M_FORBIDDEN');
|
||||
final flows = matrixException.authenticationFlows;
|
||||
expect(flows.length, 1);
|
||||
expect(flows.first.stages.length, 1);
|
||||
expect(flows.first.stages.first, 'example.type.foo');
|
||||
expect(flows?.length, 1);
|
||||
expect(flows?.first.stages.length, 1);
|
||||
expect(flows?.first.stages.first, 'example.type.foo');
|
||||
expect(
|
||||
matrixException.authenticationParams['example.type.baz'],
|
||||
matrixException.authenticationParams?['example.type.baz'],
|
||||
{'example_key': 'foobar'},
|
||||
);
|
||||
expect(matrixException.completedAuthenticationFlows.length, 1);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -43,7 +42,7 @@ void main() {
|
|||
}
|
||||
if (olmEnabled) {
|
||||
final encryptedFile = await file.encrypt();
|
||||
expect(encryptedFile != null, true);
|
||||
expect(encryptedFile.data.isNotEmpty, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -48,77 +47,73 @@ void main() {
|
|||
expect('@user:domain:8448'.domain, 'domain:8448');
|
||||
});
|
||||
test('parseIdentifierIntoParts', () {
|
||||
var res = '#alias:beep'.parseIdentifierIntoParts();
|
||||
var res = '#alias:beep'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#alias:beep');
|
||||
expect(res.secondaryIdentifier, null);
|
||||
expect(res.queryString, null);
|
||||
res = 'blha'.parseIdentifierIntoParts();
|
||||
expect(res, null);
|
||||
res = '#alias:beep/\$event'.parseIdentifierIntoParts();
|
||||
expect('blha'.parseIdentifierIntoParts(), null);
|
||||
res = '#alias:beep/\$event'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#alias:beep');
|
||||
expect(res.secondaryIdentifier, '\$event');
|
||||
expect(res.queryString, null);
|
||||
res = '#alias:beep?blubb'.parseIdentifierIntoParts();
|
||||
res = '#alias:beep?blubb'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#alias:beep');
|
||||
expect(res.secondaryIdentifier, null);
|
||||
expect(res.queryString, 'blubb');
|
||||
res = '#alias:beep/\$event?blubb'.parseIdentifierIntoParts();
|
||||
res = '#alias:beep/\$event?blubb'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#alias:beep');
|
||||
expect(res.secondaryIdentifier, '\$event');
|
||||
expect(res.queryString, 'blubb');
|
||||
res = '#/\$?:beep/\$event?blubb?b'.parseIdentifierIntoParts();
|
||||
res = '#/\$?:beep/\$event?blubb?b'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#/\$?:beep');
|
||||
expect(res.secondaryIdentifier, '\$event');
|
||||
expect(res.queryString, 'blubb?b');
|
||||
|
||||
res = 'https://matrix.to/#/#alias:beep'.parseIdentifierIntoParts();
|
||||
res = 'https://matrix.to/#/#alias:beep'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#alias:beep');
|
||||
expect(res.secondaryIdentifier, null);
|
||||
expect(res.queryString, null);
|
||||
res = 'https://matrix.to/#/#🦊:beep'.parseIdentifierIntoParts();
|
||||
res = 'https://matrix.to/#/#🦊:beep'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#🦊:beep');
|
||||
expect(res.secondaryIdentifier, null);
|
||||
expect(res.queryString, null);
|
||||
res = 'https://matrix.to/#/%23alias%3abeep'.parseIdentifierIntoParts();
|
||||
res = 'https://matrix.to/#/%23alias%3abeep'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#alias:beep');
|
||||
expect(res.secondaryIdentifier, null);
|
||||
expect(res.queryString, null);
|
||||
res = 'https://matrix.to/#/%23alias%3abeep?boop%F0%9F%A7%A1%F0%9F%A6%8A'
|
||||
.parseIdentifierIntoParts();
|
||||
.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#alias:beep');
|
||||
expect(res.secondaryIdentifier, null);
|
||||
expect(res.queryString, 'boop%F0%9F%A7%A1%F0%9F%A6%8A');
|
||||
|
||||
res = 'https://matrix.to/#/#alias:beep?via=fox.com&via=fox.org'
|
||||
.parseIdentifierIntoParts();
|
||||
.parseIdentifierIntoParts()!;
|
||||
expect(res.via, <String>{'fox.com', 'fox.org'});
|
||||
|
||||
res = 'matrix:u/her:example.org'.parseIdentifierIntoParts();
|
||||
res = 'matrix:u/her:example.org'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '@her:example.org');
|
||||
expect(res.secondaryIdentifier, null);
|
||||
res = 'matrix:u/bad'.parseIdentifierIntoParts();
|
||||
expect(res, null);
|
||||
res = 'matrix:roomid/rid:example.org'.parseIdentifierIntoParts();
|
||||
expect('matrix:u/bad'.parseIdentifierIntoParts(), null);
|
||||
res = 'matrix:roomid/rid:example.org'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '!rid:example.org');
|
||||
expect(res.secondaryIdentifier, null);
|
||||
expect(res.action, null);
|
||||
res = 'matrix:r/us:example.org?action=chat'.parseIdentifierIntoParts();
|
||||
res = 'matrix:r/us:example.org?action=chat'.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#us:example.org');
|
||||
expect(res.secondaryIdentifier, null);
|
||||
expect(res.action, 'chat');
|
||||
res = 'matrix:r/us:example.org/e/lol823y4bcp3qo4'
|
||||
.parseIdentifierIntoParts();
|
||||
.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '#us:example.org');
|
||||
expect(res.secondaryIdentifier, '\$lol823y4bcp3qo4');
|
||||
res = 'matrix:roomid/rid:example.org?via=fox.com&via=fox.org'
|
||||
.parseIdentifierIntoParts();
|
||||
.parseIdentifierIntoParts()!;
|
||||
expect(res.primaryIdentifier, '!rid:example.org');
|
||||
expect(res.secondaryIdentifier, null);
|
||||
expect(res.via, <String>{'fox.com', 'fox.org'});
|
||||
res = 'matrix:beep/boop:example.org'.parseIdentifierIntoParts();
|
||||
expect(res, null);
|
||||
res = 'matrix:boop'.parseIdentifierIntoParts();
|
||||
expect(res, null);
|
||||
expect('matrix:beep/boop:example.org'.parseIdentifierIntoParts(), null);
|
||||
expect('matrix:boop'.parseIdentifierIntoParts(), null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2021 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -33,8 +32,8 @@ import 'fake_client.dart';
|
|||
import 'fake_matrix_api.dart';
|
||||
|
||||
void main() {
|
||||
Client matrix;
|
||||
Room room;
|
||||
late Client matrix;
|
||||
late Room room;
|
||||
|
||||
/// All Tests related to the Event
|
||||
group('Room', () {
|
||||
|
|
@ -96,8 +95,9 @@ void main() {
|
|||
expect(room.summary.mInvitedMemberCount, notificationCount);
|
||||
expect(room.summary.mHeroes, heroes);
|
||||
expect(room.displayname, 'Alice, Bob, Charley');
|
||||
expect(room.getState('m.room.join_rules').content['join_rule'], 'public');
|
||||
expect(room.roomAccountData['com.test.foo'].content['foo'], 'bar');
|
||||
expect(
|
||||
room.getState('m.room.join_rules')?.content['join_rule'], 'public');
|
||||
expect(room.roomAccountData['com.test.foo']?.content['foo'], 'bar');
|
||||
|
||||
room.setState(
|
||||
Event(
|
||||
|
|
@ -107,6 +107,7 @@ void main() {
|
|||
room: room,
|
||||
eventId: '123',
|
||||
content: {'alias': '#testalias:example.com'},
|
||||
originServerTs: DateTime.now(),
|
||||
stateKey: ''),
|
||||
);
|
||||
expect(room.displayname, 'testalias');
|
||||
|
|
@ -120,6 +121,7 @@ void main() {
|
|||
room: room,
|
||||
eventId: '123',
|
||||
content: {'name': 'testname'},
|
||||
originServerTs: DateTime.now(),
|
||||
stateKey: ''),
|
||||
);
|
||||
expect(room.displayname, 'testname');
|
||||
|
|
@ -133,6 +135,7 @@ void main() {
|
|||
room: room,
|
||||
eventId: '123',
|
||||
content: {'topic': 'testtopic'},
|
||||
originServerTs: DateTime.now(),
|
||||
stateKey: ''),
|
||||
);
|
||||
expect(room.topic, 'testtopic');
|
||||
|
|
@ -146,6 +149,7 @@ void main() {
|
|||
room: room,
|
||||
eventId: '123',
|
||||
content: {'url': 'mxc://testurl'},
|
||||
originServerTs: DateTime.now(),
|
||||
stateKey: ''),
|
||||
);
|
||||
expect(room.avatar.toString(), 'mxc://testurl');
|
||||
|
|
@ -161,6 +165,7 @@ void main() {
|
|||
content: {
|
||||
'pinned': ['1234']
|
||||
},
|
||||
originServerTs: DateTime.now(),
|
||||
stateKey: ''),
|
||||
);
|
||||
expect(room.pinnedEventIds.first, '1234');
|
||||
|
|
@ -176,9 +181,9 @@ void main() {
|
|||
stateKey: '',
|
||||
),
|
||||
);
|
||||
expect(room.lastEvent.eventId, '12345');
|
||||
expect(room.lastEvent.body, 'abc');
|
||||
expect(room.timeCreated, room.lastEvent.originServerTs);
|
||||
expect(room.lastEvent?.eventId, '12345');
|
||||
expect(room.lastEvent?.body, 'abc');
|
||||
expect(room.timeCreated, room.lastEvent?.originServerTs);
|
||||
});
|
||||
|
||||
test('lastEvent is set properly', () {
|
||||
|
|
@ -194,7 +199,7 @@ void main() {
|
|||
stateKey: '',
|
||||
),
|
||||
);
|
||||
expect(room.lastEvent.body, 'cd');
|
||||
expect(room.lastEvent?.body, 'cd');
|
||||
room.setState(
|
||||
Event(
|
||||
senderId: '@test:example.com',
|
||||
|
|
@ -207,7 +212,7 @@ void main() {
|
|||
stateKey: '',
|
||||
),
|
||||
);
|
||||
expect(room.lastEvent.body, 'cdc');
|
||||
expect(room.lastEvent?.body, 'cdc');
|
||||
room.setState(
|
||||
Event(
|
||||
senderId: '@test:example.com',
|
||||
|
|
@ -225,7 +230,7 @@ void main() {
|
|||
stateKey: '',
|
||||
),
|
||||
);
|
||||
expect(room.lastEvent.body, 'cdc'); // because we edited the "cd" message
|
||||
expect(room.lastEvent?.body, 'cdc'); // because we edited the "cd" message
|
||||
room.setState(
|
||||
Event(
|
||||
senderId: '@test:example.com',
|
||||
|
|
@ -243,7 +248,7 @@ void main() {
|
|||
stateKey: '',
|
||||
),
|
||||
);
|
||||
expect(room.lastEvent.body, 'edited cdc');
|
||||
expect(room.lastEvent?.body, 'edited cdc');
|
||||
});
|
||||
test('lastEvent when reply parent edited', () async {
|
||||
room.setState(
|
||||
|
|
@ -258,7 +263,7 @@ void main() {
|
|||
stateKey: '',
|
||||
),
|
||||
);
|
||||
expect(room.lastEvent.body, 'A');
|
||||
expect(room.lastEvent?.body, 'A');
|
||||
|
||||
room.setState(
|
||||
Event(
|
||||
|
|
@ -276,7 +281,7 @@ void main() {
|
|||
stateKey: '',
|
||||
),
|
||||
);
|
||||
expect(room.lastEvent.body, 'B');
|
||||
expect(room.lastEvent?.body, 'B');
|
||||
room.setState(
|
||||
Event(
|
||||
senderId: '@test:example.com',
|
||||
|
|
@ -294,7 +299,7 @@ void main() {
|
|||
stateKey: '',
|
||||
),
|
||||
);
|
||||
expect(room.lastEvent.body, 'B');
|
||||
expect(room.lastEvent?.body, 'B');
|
||||
});
|
||||
test('sendReadMarker', () async {
|
||||
await room.setReadMarker('§1234:fakeServer.notExisting');
|
||||
|
|
@ -308,12 +313,12 @@ void main() {
|
|||
expect(user.displayName, 'Alice Margatroid');
|
||||
expect(user.membership, Membership.join);
|
||||
expect(user.avatarUrl.toString(), 'mxc://example.org/SEsfnsuifSDFSSEF');
|
||||
expect(user.room.id, '!localpart:server.abc');
|
||||
expect(user.room?.id, '!localpart:server.abc');
|
||||
});
|
||||
|
||||
test('getEventByID', () async {
|
||||
final event = await room.getEventById('1234');
|
||||
expect(event.eventId, '143273582443PhrSn:example.org');
|
||||
expect(event?.eventId, '143273582443PhrSn:example.org');
|
||||
});
|
||||
|
||||
test('setName', () async {
|
||||
|
|
@ -358,10 +363,11 @@ void main() {
|
|||
'users': {'@test:fakeServer.notExisting': 100},
|
||||
'users_default': 10
|
||||
},
|
||||
originServerTs: DateTime.now(),
|
||||
stateKey: ''),
|
||||
);
|
||||
expect(room.ownPowerLevel, 100);
|
||||
expect(room.getPowerLevelByUserId(matrix.userID), room.ownPowerLevel);
|
||||
expect(room.getPowerLevelByUserId(matrix.userID!), room.ownPowerLevel);
|
||||
expect(room.getPowerLevelByUserId('@nouser:example.com'), 10);
|
||||
expect(room.ownPowerLevel, 100);
|
||||
expect(room.canBan, true);
|
||||
|
|
@ -375,7 +381,7 @@ void main() {
|
|||
expect(room.canSendEvent('m.room.power_levels'), true);
|
||||
expect(room.canSendEvent('m.room.member'), true);
|
||||
expect(room.powerLevels,
|
||||
room.getState('m.room.power_levels').content['users']);
|
||||
room.getState('m.room.power_levels')?.content['users']);
|
||||
|
||||
room.setState(
|
||||
Event(
|
||||
|
|
@ -396,6 +402,7 @@ void main() {
|
|||
'users': {},
|
||||
'users_default': 0
|
||||
},
|
||||
originServerTs: DateTime.now(),
|
||||
stateKey: '',
|
||||
),
|
||||
);
|
||||
|
|
@ -447,12 +454,12 @@ void main() {
|
|||
});
|
||||
|
||||
test('getUserByMXID', () async {
|
||||
User user;
|
||||
User? user;
|
||||
try {
|
||||
user = await room.requestUser('@getme:example.com');
|
||||
} catch (_) {}
|
||||
expect(user.stateKey, '@getme:example.com');
|
||||
expect(user.calcDisplayname(), 'Getme');
|
||||
expect(user?.stateKey, '@getme:example.com');
|
||||
expect(user?.calcDisplayname(), 'Getme');
|
||||
});
|
||||
|
||||
test('setAvatar', () async {
|
||||
|
|
@ -465,14 +472,14 @@ void main() {
|
|||
final dynamic resp = await room.sendEvent(
|
||||
{'msgtype': 'm.text', 'body': 'hello world'},
|
||||
txid: 'testtxid');
|
||||
expect(resp.startsWith('\$event'), true);
|
||||
expect(resp?.startsWith('\$event'), true);
|
||||
});
|
||||
|
||||
test('sendEvent', () async {
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
final dynamic resp =
|
||||
await room.sendTextEvent('Hello world', txid: 'testtxid');
|
||||
expect(resp.startsWith('\$event'), true);
|
||||
expect(resp?.startsWith('\$event'), true);
|
||||
final entry = FakeMatrixApi.calledEndpoints.entries
|
||||
.firstWhere((p) => p.key.contains('/send/m.room.message/'));
|
||||
final content = json.decode(entry.value.first);
|
||||
|
|
@ -486,7 +493,7 @@ void main() {
|
|||
FakeMatrixApi.calledEndpoints.clear();
|
||||
final dynamic resp = await room.sendTextEvent('Hello world',
|
||||
txid: 'testtxid', editEventId: '\$otherEvent');
|
||||
expect(resp.startsWith('\$event'), true);
|
||||
expect(resp?.startsWith('\$event'), true);
|
||||
final entry = FakeMatrixApi.calledEndpoints.entries
|
||||
.firstWhere((p) => p.key.contains('/send/m.room.message/'));
|
||||
final content = json.decode(entry.value.first);
|
||||
|
|
@ -517,7 +524,7 @@ void main() {
|
|||
FakeMatrixApi.calledEndpoints.clear();
|
||||
var resp = await room.sendTextEvent('Hello world',
|
||||
txid: 'testtxid', inReplyTo: event);
|
||||
expect(resp.startsWith('\$event'), true);
|
||||
expect(resp?.startsWith('\$event'), true);
|
||||
var entry = FakeMatrixApi.calledEndpoints.entries
|
||||
.firstWhere((p) => p.key.contains('/send/m.room.message/'));
|
||||
var content = json.decode(entry.value.first);
|
||||
|
|
@ -546,7 +553,7 @@ void main() {
|
|||
FakeMatrixApi.calledEndpoints.clear();
|
||||
resp = await room.sendTextEvent('Hello world\nfox',
|
||||
txid: 'testtxid', inReplyTo: event);
|
||||
expect(resp.startsWith('\$event'), true);
|
||||
expect(resp?.startsWith('\$event'), true);
|
||||
entry = FakeMatrixApi.calledEndpoints.entries
|
||||
.firstWhere((p) => p.key.contains('/send/m.room.message/'));
|
||||
content = json.decode(entry.value.first);
|
||||
|
|
@ -578,7 +585,7 @@ void main() {
|
|||
FakeMatrixApi.calledEndpoints.clear();
|
||||
resp = await room.sendTextEvent('Hello world',
|
||||
txid: 'testtxid', inReplyTo: event);
|
||||
expect(resp.startsWith('\$event'), true);
|
||||
expect(resp?.startsWith('\$event'), true);
|
||||
entry = FakeMatrixApi.calledEndpoints.entries
|
||||
.firstWhere((p) => p.key.contains('/send/m.room.message/'));
|
||||
content = json.decode(entry.value.first);
|
||||
|
|
@ -607,7 +614,7 @@ void main() {
|
|||
FakeMatrixApi.calledEndpoints.clear();
|
||||
resp = await room.sendTextEvent('Hello world',
|
||||
txid: 'testtxid', inReplyTo: event);
|
||||
expect(resp.startsWith('\$event'), true);
|
||||
expect(resp?.startsWith('\$event'), true);
|
||||
entry = FakeMatrixApi.calledEndpoints.entries
|
||||
.firstWhere((p) => p.key.contains('/send/m.room.message/'));
|
||||
content = json.decode(entry.value.first);
|
||||
|
|
@ -629,7 +636,7 @@ void main() {
|
|||
FakeMatrixApi.calledEndpoints.clear();
|
||||
final dynamic resp =
|
||||
await room.sendReaction('\$otherEvent', '🦊', txid: 'testtxid');
|
||||
expect(resp.startsWith('\$event'), true);
|
||||
expect(resp?.startsWith('\$event'), true);
|
||||
final entry = FakeMatrixApi.calledEndpoints.entries
|
||||
.firstWhere((p) => p.key.contains('/send/m.reaction/'));
|
||||
final content = json.decode(entry.value.first);
|
||||
|
|
@ -649,7 +656,7 @@ void main() {
|
|||
final geoUri = 'geo:0.0,0.0';
|
||||
final dynamic resp =
|
||||
await room.sendLocation(body, geoUri, txid: 'testtxid');
|
||||
expect(resp.startsWith('\$event'), true);
|
||||
expect(resp?.startsWith('\$event'), true);
|
||||
|
||||
final entry = FakeMatrixApi.calledEndpoints.entries
|
||||
.firstWhere((p) => p.key.contains('/send/m.room.message/'));
|
||||
|
|
@ -677,8 +684,8 @@ void main() {
|
|||
|
||||
test('pushRuleState', () async {
|
||||
expect(room.pushRuleState, PushRuleState.mentionsOnly);
|
||||
matrix.accountData['m.push_rules'].content['global']['override']
|
||||
.add(matrix.accountData['m.push_rules'].content['global']['room'][0]);
|
||||
matrix.accountData['m.push_rules']?.content['global']['override'].add(
|
||||
matrix.accountData['m.push_rules']?.content['global']['room'][0]);
|
||||
expect(room.pushRuleState, PushRuleState.dontNotify);
|
||||
});
|
||||
|
||||
|
|
@ -749,7 +756,7 @@ void main() {
|
|||
'type': 'm.tag'
|
||||
});
|
||||
expect(room.tags.length, 1);
|
||||
expect(room.tags[TagType.favourite].order, 0.1);
|
||||
expect(room.tags[TagType.favourite]?.order, 0.1);
|
||||
expect(room.isFavourite, true);
|
||||
await room.setFavourite(false);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
@ -119,6 +118,7 @@ const updates = {
|
|||
'events': [
|
||||
{
|
||||
'type': 'beep',
|
||||
'sender': '@example:localhost',
|
||||
'content': {
|
||||
'blah': 'blubb',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -37,9 +36,9 @@ void main() {
|
|||
final insertList = <int>[];
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
Room room;
|
||||
Timeline timeline;
|
||||
late Client client;
|
||||
late Room room;
|
||||
late Timeline timeline;
|
||||
test('create stuff', () async {
|
||||
try {
|
||||
await olm.init();
|
||||
|
|
@ -233,18 +232,18 @@ void main() {
|
|||
|
||||
test('getEventById', () async {
|
||||
var event = await timeline.getEventById('abc');
|
||||
expect(event.content, {'msgtype': 'm.text', 'body': 'Testcase'});
|
||||
expect(event?.content, {'msgtype': 'm.text', 'body': 'Testcase'});
|
||||
|
||||
event = await timeline.getEventById('not_found');
|
||||
expect(event, null);
|
||||
|
||||
event = await timeline.getEventById('unencrypted_event');
|
||||
expect(event.body, 'This is an example text message');
|
||||
expect(event?.body, 'This is an example text message');
|
||||
|
||||
if (olmEnabled) {
|
||||
event = await timeline.getEventById('encrypted_event');
|
||||
// the event is invalid but should have traces of attempting to decrypt
|
||||
expect(event.messageType, MessageTypes.BadEncrypted);
|
||||
expect(event?.messageType, MessageTypes.BadEncrypted);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||
|
|
@ -123,6 +122,7 @@ void main() {
|
|||
});
|
||||
test('getPresence', () async {
|
||||
await client.handleSync(SyncUpdate.fromJson({
|
||||
'next_batch': 'fake',
|
||||
'presence': {
|
||||
'events': [
|
||||
{
|
||||
|
|
@ -133,7 +133,7 @@ void main() {
|
|||
]
|
||||
}
|
||||
}));
|
||||
expect(user1.presence.presence.presence, PresenceType.online);
|
||||
expect(user1.presence?.presence.presence, PresenceType.online);
|
||||
});
|
||||
test('canBan', () async {
|
||||
expect(user1.canBan, false);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// @dart=2.9
|
||||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
|
||||
|
|
@ -30,7 +29,7 @@ const String testMessage5 = 'Hello earth';
|
|||
const String testMessage6 = 'Hello mars';
|
||||
|
||||
void test() async {
|
||||
Client testClientA, testClientB;
|
||||
Client? testClientA, testClientB;
|
||||
|
||||
try {
|
||||
await olm.init();
|
||||
|
|
@ -56,7 +55,7 @@ void test() async {
|
|||
Logs().i('++++ (Alice) Leave all rooms ++++');
|
||||
while (testClientA.rooms.isNotEmpty) {
|
||||
final room = testClientA.rooms.first;
|
||||
if (room.canonicalAlias?.isNotEmpty ?? false) {
|
||||
if (room.canonicalAlias.isNotEmpty) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
|
|
@ -78,29 +77,28 @@ void test() async {
|
|||
|
||||
Logs().i('++++ Check if own olm device is verified by default ++++');
|
||||
assert(testClientA.userDeviceKeys.containsKey(TestUser.username));
|
||||
assert(testClientA.userDeviceKeys[TestUser.username].deviceKeys
|
||||
assert(testClientA.userDeviceKeys[TestUser.username]!.deviceKeys
|
||||
.containsKey(testClientA.deviceID));
|
||||
assert(testClientA.userDeviceKeys[TestUser.username]
|
||||
.deviceKeys[testClientA.deviceID].verified);
|
||||
assert(!testClientA.userDeviceKeys[TestUser.username]
|
||||
.deviceKeys[testClientA.deviceID].blocked);
|
||||
assert(testClientA.userDeviceKeys[TestUser.username]!
|
||||
.deviceKeys[testClientA.deviceID!]!.verified);
|
||||
assert(!testClientA.userDeviceKeys[TestUser.username]!
|
||||
.deviceKeys[testClientA.deviceID!]!.blocked);
|
||||
assert(testClientB.userDeviceKeys.containsKey(TestUser.username2));
|
||||
assert(testClientB.userDeviceKeys[TestUser.username2].deviceKeys
|
||||
assert(testClientB.userDeviceKeys[TestUser.username2]!.deviceKeys
|
||||
.containsKey(testClientB.deviceID));
|
||||
assert(testClientB.userDeviceKeys[TestUser.username2]
|
||||
.deviceKeys[testClientB.deviceID].verified);
|
||||
assert(!testClientB.userDeviceKeys[TestUser.username2]
|
||||
.deviceKeys[testClientB.deviceID].blocked);
|
||||
assert(testClientB.userDeviceKeys[TestUser.username2]!
|
||||
.deviceKeys[testClientB.deviceID!]!.verified);
|
||||
assert(!testClientB.userDeviceKeys[TestUser.username2]!
|
||||
.deviceKeys[testClientB.deviceID!]!.blocked);
|
||||
|
||||
Logs().i('++++ (Alice) Create room and invite Bob ++++');
|
||||
await testClientA.createRoom(invite: [TestUser.username2]);
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
final room = testClientA.rooms.first;
|
||||
assert(room != null);
|
||||
final roomId = room.id;
|
||||
|
||||
Logs().i('++++ (Bob) Join room ++++');
|
||||
final inviteRoom = testClientB.getRoomById(roomId);
|
||||
final inviteRoom = testClientB.getRoomById(roomId)!;
|
||||
await inviteRoom.join();
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
assert(inviteRoom.membership == Membership.join);
|
||||
|
|
@ -110,116 +108,118 @@ void test() async {
|
|||
await room.enableEncryption();
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
assert(room.encrypted == true);
|
||||
assert(room.client.encryption.keyManager.getOutboundGroupSession(room.id) ==
|
||||
null);
|
||||
assert(
|
||||
room.client.encryption!.keyManager.getOutboundGroupSession(room.id) ==
|
||||
null);
|
||||
|
||||
Logs().i('++++ (Alice) Check known olm devices ++++');
|
||||
assert(testClientA.userDeviceKeys.containsKey(TestUser.username2));
|
||||
assert(testClientA.userDeviceKeys[TestUser.username2].deviceKeys
|
||||
assert(testClientA.userDeviceKeys[TestUser.username2]!.deviceKeys
|
||||
.containsKey(testClientB.deviceID));
|
||||
assert(!testClientA.userDeviceKeys[TestUser.username2]
|
||||
.deviceKeys[testClientB.deviceID].verified);
|
||||
assert(!testClientA.userDeviceKeys[TestUser.username2]
|
||||
.deviceKeys[testClientB.deviceID].blocked);
|
||||
assert(!testClientA.userDeviceKeys[TestUser.username2]!
|
||||
.deviceKeys[testClientB.deviceID!]!.verified);
|
||||
assert(!testClientA.userDeviceKeys[TestUser.username2]!
|
||||
.deviceKeys[testClientB.deviceID!]!.blocked);
|
||||
assert(testClientB.userDeviceKeys.containsKey(TestUser.username));
|
||||
assert(testClientB.userDeviceKeys[TestUser.username].deviceKeys
|
||||
assert(testClientB.userDeviceKeys[TestUser.username]!.deviceKeys
|
||||
.containsKey(testClientA.deviceID));
|
||||
assert(!testClientB.userDeviceKeys[TestUser.username]
|
||||
.deviceKeys[testClientA.deviceID].verified);
|
||||
assert(!testClientB.userDeviceKeys[TestUser.username]
|
||||
.deviceKeys[testClientA.deviceID].blocked);
|
||||
assert(!testClientB.userDeviceKeys[TestUser.username]!
|
||||
.deviceKeys[testClientA.deviceID!]!.verified);
|
||||
assert(!testClientB.userDeviceKeys[TestUser.username]!
|
||||
.deviceKeys[testClientA.deviceID!]!.blocked);
|
||||
await testClientA
|
||||
.userDeviceKeys[TestUser.username2].deviceKeys[testClientB.deviceID]
|
||||
.userDeviceKeys[TestUser.username2]!.deviceKeys[testClientB.deviceID!]!
|
||||
.setVerified(true);
|
||||
|
||||
Logs().i('++++ Check if own olm device is verified by default ++++');
|
||||
assert(testClientA.userDeviceKeys.containsKey(TestUser.username));
|
||||
assert(testClientA.userDeviceKeys[TestUser.username].deviceKeys
|
||||
assert(testClientA.userDeviceKeys[TestUser.username]!.deviceKeys
|
||||
.containsKey(testClientA.deviceID));
|
||||
assert(testClientA.userDeviceKeys[TestUser.username]
|
||||
.deviceKeys[testClientA.deviceID].verified);
|
||||
assert(testClientA.userDeviceKeys[TestUser.username]!
|
||||
.deviceKeys[testClientA.deviceID!]!.verified);
|
||||
assert(testClientB.userDeviceKeys.containsKey(TestUser.username2));
|
||||
assert(testClientB.userDeviceKeys[TestUser.username2].deviceKeys
|
||||
assert(testClientB.userDeviceKeys[TestUser.username2]!.deviceKeys
|
||||
.containsKey(testClientB.deviceID));
|
||||
assert(testClientB.userDeviceKeys[TestUser.username2]
|
||||
.deviceKeys[testClientB.deviceID].verified);
|
||||
assert(testClientB.userDeviceKeys[TestUser.username2]!
|
||||
.deviceKeys[testClientB.deviceID!]!.verified);
|
||||
|
||||
Logs().i("++++ (Alice) Send encrypted message: '$testMessage' ++++");
|
||||
await room.sendTextEvent(testMessage);
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
assert(room.client.encryption.keyManager.getOutboundGroupSession(room.id) !=
|
||||
null);
|
||||
var currentSessionIdA = room.client.encryption.keyManager
|
||||
.getOutboundGroupSession(room.id)
|
||||
.outboundGroupSession
|
||||
assert(
|
||||
room.client.encryption!.keyManager.getOutboundGroupSession(room.id) !=
|
||||
null);
|
||||
var currentSessionIdA = room.client.encryption!.keyManager
|
||||
.getOutboundGroupSession(room.id)!
|
||||
.outboundGroupSession!
|
||||
.session_id();
|
||||
/*assert(room.client.encryption.keyManager
|
||||
.getInboundGroupSession(room.id, currentSessionIdA, '') !=
|
||||
null);*/
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientB.identityKey].length ==
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientB.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientB.encryption.olmManager
|
||||
.olmSessions[testClientA.identityKey].length ==
|
||||
assert(testClientB.encryption!.olmManager
|
||||
.olmSessions[testClientA.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientB.identityKey].first.sessionId ==
|
||||
testClientB.encryption.olmManager.olmSessions[testClientA.identityKey]
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientB.identityKey]!.first.sessionId ==
|
||||
testClientB.encryption!.olmManager.olmSessions[testClientA.identityKey]!
|
||||
.first.sessionId);
|
||||
/*assert(inviteRoom.client.encryption.keyManager
|
||||
.getInboundGroupSession(inviteRoom.id, currentSessionIdA, '') !=
|
||||
null);*/
|
||||
assert(room.lastEvent.body == testMessage);
|
||||
assert(inviteRoom.lastEvent.body == testMessage);
|
||||
assert(room.lastEvent!.body == testMessage);
|
||||
assert(inviteRoom.lastEvent!.body == testMessage);
|
||||
Logs().i(
|
||||
"++++ (Bob) Received decrypted message: '${inviteRoom.lastEvent.body}' ++++");
|
||||
"++++ (Bob) Received decrypted message: '${inviteRoom.lastEvent!.body}' ++++");
|
||||
|
||||
Logs().i("++++ (Alice) Send again encrypted message: '$testMessage2' ++++");
|
||||
await room.sendTextEvent(testMessage2);
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientB.identityKey].length ==
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientB.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientB.encryption.olmManager
|
||||
.olmSessions[testClientA.identityKey].length ==
|
||||
assert(testClientB.encryption!.olmManager
|
||||
.olmSessions[testClientA.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientB.identityKey].first.sessionId ==
|
||||
testClientB.encryption.olmManager.olmSessions[testClientA.identityKey]
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientB.identityKey]!.first.sessionId ==
|
||||
testClientB.encryption!.olmManager.olmSessions[testClientA.identityKey]!
|
||||
.first.sessionId);
|
||||
|
||||
assert(room.client.encryption.keyManager
|
||||
.getOutboundGroupSession(room.id)
|
||||
.outboundGroupSession
|
||||
assert(room.client.encryption!.keyManager
|
||||
.getOutboundGroupSession(room.id)!
|
||||
.outboundGroupSession!
|
||||
.session_id() ==
|
||||
currentSessionIdA);
|
||||
/*assert(room.client.encryption.keyManager
|
||||
.getInboundGroupSession(room.id, currentSessionIdA, '') !=
|
||||
null);*/
|
||||
assert(room.lastEvent.body == testMessage2);
|
||||
assert(inviteRoom.lastEvent.body == testMessage2);
|
||||
assert(room.lastEvent!.body == testMessage2);
|
||||
assert(inviteRoom.lastEvent!.body == testMessage2);
|
||||
Logs().i(
|
||||
"++++ (Bob) Received decrypted message: '${inviteRoom.lastEvent.body}' ++++");
|
||||
"++++ (Bob) Received decrypted message: '${inviteRoom.lastEvent!.body}' ++++");
|
||||
|
||||
Logs().i("++++ (Bob) Send again encrypted message: '$testMessage3' ++++");
|
||||
await inviteRoom.sendTextEvent(testMessage3);
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientB.identityKey].length ==
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientB.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientB.encryption.olmManager
|
||||
.olmSessions[testClientA.identityKey].length ==
|
||||
assert(testClientB.encryption!.olmManager
|
||||
.olmSessions[testClientA.identityKey]!.length ==
|
||||
1);
|
||||
assert(room.client.encryption.keyManager
|
||||
.getOutboundGroupSession(room.id)
|
||||
.outboundGroupSession
|
||||
assert(room.client.encryption!.keyManager
|
||||
.getOutboundGroupSession(room.id)!
|
||||
.outboundGroupSession!
|
||||
.session_id() ==
|
||||
currentSessionIdA);
|
||||
final inviteRoomOutboundGroupSession = inviteRoom
|
||||
.client.encryption.keyManager
|
||||
.getOutboundGroupSession(inviteRoom.id);
|
||||
.client.encryption!.keyManager
|
||||
.getOutboundGroupSession(inviteRoom.id)!;
|
||||
|
||||
assert(inviteRoomOutboundGroupSession != null);
|
||||
assert(inviteRoomOutboundGroupSession.isValid);
|
||||
/*assert(inviteRoom.client.encryption.keyManager.getInboundGroupSession(
|
||||
inviteRoom.id,
|
||||
inviteRoomOutboundGroupSession.outboundGroupSession.session_id(),
|
||||
|
|
@ -230,13 +230,13 @@ void test() async {
|
|||
inviteRoomOutboundGroupSession.outboundGroupSession.session_id(),
|
||||
'') !=
|
||||
null);*/
|
||||
assert(inviteRoom.lastEvent.body == testMessage3);
|
||||
assert(room.lastEvent.body == testMessage3);
|
||||
assert(inviteRoom.lastEvent!.body == testMessage3);
|
||||
assert(room.lastEvent!.body == testMessage3);
|
||||
Logs().i(
|
||||
"++++ (Alice) Received decrypted message: '${room.lastEvent.body}' ++++");
|
||||
"++++ (Alice) Received decrypted message: '${room.lastEvent!.body}' ++++");
|
||||
|
||||
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.login(LoginType.mLoginPassword,
|
||||
identifier: AuthenticationUserIdentifier(user: TestUser.username2),
|
||||
|
|
@ -246,78 +246,77 @@ void test() async {
|
|||
Logs().i("++++ (Alice) Send again encrypted message: '$testMessage4' ++++");
|
||||
await room.sendTextEvent(testMessage4);
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientB.identityKey].length ==
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientB.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientB.encryption.olmManager
|
||||
.olmSessions[testClientA.identityKey].length ==
|
||||
assert(testClientB.encryption!.olmManager
|
||||
.olmSessions[testClientA.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientB.identityKey].first.sessionId ==
|
||||
testClientB.encryption.olmManager.olmSessions[testClientA.identityKey]
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientB.identityKey]!.first.sessionId ==
|
||||
testClientB.encryption!.olmManager.olmSessions[testClientA.identityKey]!
|
||||
.first.sessionId);
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientC.identityKey].length ==
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientC.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientC.encryption.olmManager
|
||||
.olmSessions[testClientA.identityKey].length ==
|
||||
assert(testClientC.encryption!.olmManager
|
||||
.olmSessions[testClientA.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientC.identityKey].first.sessionId ==
|
||||
testClientC.encryption.olmManager.olmSessions[testClientA.identityKey]
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientC.identityKey]!.first.sessionId ==
|
||||
testClientC.encryption!.olmManager.olmSessions[testClientA.identityKey]!
|
||||
.first.sessionId);
|
||||
assert(room.client.encryption.keyManager
|
||||
.getOutboundGroupSession(room.id)
|
||||
.outboundGroupSession
|
||||
assert(room.client.encryption!.keyManager
|
||||
.getOutboundGroupSession(room.id)!
|
||||
.outboundGroupSession!
|
||||
.session_id() !=
|
||||
currentSessionIdA);
|
||||
currentSessionIdA = room.client.encryption.keyManager
|
||||
.getOutboundGroupSession(room.id)
|
||||
.outboundGroupSession
|
||||
currentSessionIdA = room.client.encryption!.keyManager
|
||||
.getOutboundGroupSession(room.id)!
|
||||
.outboundGroupSession!
|
||||
.session_id();
|
||||
/*assert(inviteRoom.client.encryption.keyManager
|
||||
.getInboundGroupSession(inviteRoom.id, currentSessionIdA, '') !=
|
||||
null);*/
|
||||
assert(room.lastEvent.body == testMessage4);
|
||||
assert(inviteRoom.lastEvent.body == testMessage4);
|
||||
assert(room.lastEvent!.body == testMessage4);
|
||||
assert(inviteRoom.lastEvent!.body == testMessage4);
|
||||
Logs().i(
|
||||
"++++ (Bob) Received decrypted message: '${inviteRoom.lastEvent.body}' ++++");
|
||||
"++++ (Bob) Received decrypted message: '${inviteRoom.lastEvent!.body}' ++++");
|
||||
|
||||
Logs().i('++++ Logout Bob another client ++++');
|
||||
await testClientC.dispose(closeDatabase: false);
|
||||
await testClientC.logout();
|
||||
testClientC = null;
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
|
||||
Logs().i("++++ (Alice) Send again encrypted message: '$testMessage6' ++++");
|
||||
await room.sendTextEvent(testMessage6);
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientB.identityKey].length ==
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientB.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientB.encryption.olmManager
|
||||
.olmSessions[testClientA.identityKey].length ==
|
||||
assert(testClientB.encryption!.olmManager
|
||||
.olmSessions[testClientA.identityKey]!.length ==
|
||||
1);
|
||||
assert(testClientA.encryption.olmManager
|
||||
.olmSessions[testClientB.identityKey].first.sessionId ==
|
||||
testClientB.encryption.olmManager.olmSessions[testClientA.identityKey]
|
||||
assert(testClientA.encryption!.olmManager
|
||||
.olmSessions[testClientB.identityKey]!.first.sessionId ==
|
||||
testClientB.encryption!.olmManager.olmSessions[testClientA.identityKey]!
|
||||
.first.sessionId);
|
||||
assert(room.client.encryption.keyManager
|
||||
.getOutboundGroupSession(room.id)
|
||||
.outboundGroupSession
|
||||
assert(room.client.encryption!.keyManager
|
||||
.getOutboundGroupSession(room.id)!
|
||||
.outboundGroupSession!
|
||||
.session_id() !=
|
||||
currentSessionIdA);
|
||||
currentSessionIdA = room.client.encryption.keyManager
|
||||
.getOutboundGroupSession(room.id)
|
||||
.outboundGroupSession
|
||||
currentSessionIdA = room.client.encryption!.keyManager
|
||||
.getOutboundGroupSession(room.id)!
|
||||
.outboundGroupSession!
|
||||
.session_id();
|
||||
/*assert(inviteRoom.client.encryption.keyManager
|
||||
.getInboundGroupSession(inviteRoom.id, currentSessionIdA, '') !=
|
||||
null);*/
|
||||
assert(room.lastEvent.body == testMessage6);
|
||||
assert(inviteRoom.lastEvent.body == testMessage6);
|
||||
assert(room.lastEvent!.body == testMessage6);
|
||||
assert(inviteRoom.lastEvent!.body == testMessage6);
|
||||
Logs().i(
|
||||
"++++ (Bob) Received decrypted message: '${inviteRoom.lastEvent.body}' ++++");
|
||||
"++++ (Bob) Received decrypted message: '${inviteRoom.lastEvent!.body}' ++++");
|
||||
|
||||
await room.leave();
|
||||
await room.forget();
|
||||
|
|
@ -329,8 +328,8 @@ void test() async {
|
|||
rethrow;
|
||||
} finally {
|
||||
Logs().i('++++ Logout Alice and Bob ++++');
|
||||
if (testClientA?.isLogged() ?? false) await testClientA.logoutAll();
|
||||
if (testClientA?.isLogged() ?? false) await testClientB.logoutAll();
|
||||
if (testClientA?.isLogged() ?? false) await testClientA!.logoutAll();
|
||||
if (testClientA?.isLogged() ?? false) await testClientB!.logoutAll();
|
||||
await testClientA?.dispose(closeDatabase: false);
|
||||
await testClientB?.dispose(closeDatabase: false);
|
||||
testClientA = null;
|
||||
|
|
|
|||
Loading…
Reference in New Issue