refactor: Constants names
This commit is contained in:
parent
3d55abdd11
commit
0ceb2b26df
|
|
@ -4,12 +4,12 @@ linter:
|
||||||
rules:
|
rules:
|
||||||
- camel_case_types
|
- camel_case_types
|
||||||
- avoid_print
|
- avoid_print
|
||||||
|
- constant_identifier_names
|
||||||
|
|
||||||
analyzer:
|
analyzer:
|
||||||
errors:
|
errors:
|
||||||
todo: ignore
|
todo: ignore
|
||||||
exclude:
|
exclude:
|
||||||
- example/main.dart
|
- example/main.dart
|
||||||
|
|
||||||
# needed until crypto packages upgrade
|
# needed until crypto packages upgrade
|
||||||
- lib/src/database/database.g.dart
|
- lib/src/database/database.g.dart
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import '../src/database/database.dart';
|
||||||
import '../src/utils/run_in_background.dart';
|
import '../src/utils/run_in_background.dart';
|
||||||
import '../src/utils/run_in_root.dart';
|
import '../src/utils/run_in_root.dart';
|
||||||
|
|
||||||
const MEGOLM_KEY = EventTypes.MegolmBackup;
|
const megolmKey = EventTypes.MegolmBackup;
|
||||||
|
|
||||||
class KeyManager {
|
class KeyManager {
|
||||||
final Encryption encryption;
|
final Encryption encryption;
|
||||||
|
|
@ -41,7 +41,7 @@ class KeyManager {
|
||||||
final Set<String> _requestedSessionIds = <String>{};
|
final Set<String> _requestedSessionIds = <String>{};
|
||||||
|
|
||||||
KeyManager(this.encryption) {
|
KeyManager(this.encryption) {
|
||||||
encryption.ssss.setValidator(MEGOLM_KEY, (String secret) async {
|
encryption.ssss.setValidator(megolmKey, (String secret) async {
|
||||||
final keyObj = olm.PkDecryption();
|
final keyObj = olm.PkDecryption();
|
||||||
try {
|
try {
|
||||||
final info = await getRoomKeysBackupInfo(false);
|
final info = await getRoomKeysBackupInfo(false);
|
||||||
|
|
@ -56,7 +56,7 @@ class KeyManager {
|
||||||
keyObj.free();
|
keyObj.free();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
encryption.ssss.setCacheCallback(MEGOLM_KEY, (String secret) {
|
encryption.ssss.setCacheCallback(megolmKey, (String secret) {
|
||||||
// we got a megolm key cached, clear our requested keys and try to re-decrypt
|
// we got a megolm key cached, clear our requested keys and try to re-decrypt
|
||||||
// last events
|
// last events
|
||||||
_requestedSessionIds.clear();
|
_requestedSessionIds.clear();
|
||||||
|
|
@ -75,7 +75,7 @@ class KeyManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get enabled => encryption.ssss.isSecret(MEGOLM_KEY);
|
bool get enabled => encryption.ssss.isSecret(megolmKey);
|
||||||
|
|
||||||
/// clear all cached inbound group sessions. useful for testing
|
/// clear all cached inbound group sessions. useful for testing
|
||||||
void clearInboundGroupSessions() {
|
void clearInboundGroupSessions() {
|
||||||
|
|
@ -522,7 +522,7 @@ class KeyManager {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (await encryption.ssss.getCached(MEGOLM_KEY)) != null;
|
return (await encryption.ssss.getCached(megolmKey)) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
RoomKeysVersionResponse _roomKeysVersionCache;
|
RoomKeysVersionResponse _roomKeysVersionCache;
|
||||||
|
|
@ -547,7 +547,7 @@ class KeyManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final privateKey =
|
final privateKey =
|
||||||
base64.decode(await encryption.ssss.getCached(MEGOLM_KEY));
|
base64.decode(await encryption.ssss.getCached(megolmKey));
|
||||||
final decryption = olm.PkDecryption();
|
final decryption = olm.PkDecryption();
|
||||||
final info = await getRoomKeysBackupInfo();
|
final info = await getRoomKeysBackupInfo();
|
||||||
String backupPubKey;
|
String backupPubKey;
|
||||||
|
|
@ -699,7 +699,7 @@ class KeyManager {
|
||||||
return; // nothing to do
|
return; // nothing to do
|
||||||
}
|
}
|
||||||
final privateKey =
|
final privateKey =
|
||||||
base64.decode(await encryption.ssss.getCached(MEGOLM_KEY));
|
base64.decode(await encryption.ssss.getCached(megolmKey));
|
||||||
// decryption is needed to calculate the public key and thus see if the claimed information is in fact valid
|
// decryption is needed to calculate the public key and thus see if the claimed information is in fact valid
|
||||||
final decryption = olm.PkDecryption();
|
final decryption = olm.PkDecryption();
|
||||||
final info = await getRoomKeysBackupInfo(false);
|
final info = await getRoomKeysBackupInfo(false);
|
||||||
|
|
|
||||||
|
|
@ -32,21 +32,21 @@ import '../src/utils/run_in_background.dart';
|
||||||
import '../src/utils/run_in_root.dart';
|
import '../src/utils/run_in_root.dart';
|
||||||
import 'encryption.dart';
|
import 'encryption.dart';
|
||||||
|
|
||||||
const CACHE_TYPES = <String>{
|
const cacheTypes = <String>{
|
||||||
EventTypes.CrossSigningSelfSigning,
|
EventTypes.CrossSigningSelfSigning,
|
||||||
EventTypes.CrossSigningUserSigning,
|
EventTypes.CrossSigningUserSigning,
|
||||||
EventTypes.MegolmBackup,
|
EventTypes.MegolmBackup,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ZERO_STR =
|
const zeroStr =
|
||||||
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
|
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
|
||||||
const BASE58_ALPHABET =
|
const base58Alphabet =
|
||||||
'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
||||||
const base58 = Base58Codec(BASE58_ALPHABET);
|
const base58 = Base58Codec(base58Alphabet);
|
||||||
const OLM_RECOVERY_KEY_PREFIX = [0x8B, 0x01];
|
const olmRecoveryKeyPrefix = [0x8B, 0x01];
|
||||||
const SSSS_KEY_LENGTH = 32;
|
const ssssKeyLength = 32;
|
||||||
const PBKDF2_DEFAULT_ITERATIONS = 500000;
|
const pbkdf2DefaultIterations = 500000;
|
||||||
const PBKDF2_SALT_LENGTH = 64;
|
const pbkdf2SaltLength = 64;
|
||||||
|
|
||||||
/// SSSS: **S**ecure **S**ecret **S**torage and **S**haring
|
/// SSSS: **S**ecure **S**ecret **S**torage and **S**haring
|
||||||
/// Read more about SSSS at:
|
/// Read more about SSSS at:
|
||||||
|
|
@ -129,23 +129,23 @@ class SSSS {
|
||||||
throw Exception('Incorrect parity');
|
throw Exception('Incorrect parity');
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < OLM_RECOVERY_KEY_PREFIX.length; i++) {
|
for (var i = 0; i < olmRecoveryKeyPrefix.length; i++) {
|
||||||
if (result[i] != OLM_RECOVERY_KEY_PREFIX[i]) {
|
if (result[i] != olmRecoveryKeyPrefix[i]) {
|
||||||
throw Exception('Incorrect prefix');
|
throw Exception('Incorrect prefix');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.length != OLM_RECOVERY_KEY_PREFIX.length + SSSS_KEY_LENGTH + 1) {
|
if (result.length != olmRecoveryKeyPrefix.length + ssssKeyLength + 1) {
|
||||||
throw Exception('Incorrect length');
|
throw Exception('Incorrect length');
|
||||||
}
|
}
|
||||||
|
|
||||||
return Uint8List.fromList(result.sublist(OLM_RECOVERY_KEY_PREFIX.length,
|
return Uint8List.fromList(result.sublist(olmRecoveryKeyPrefix.length,
|
||||||
OLM_RECOVERY_KEY_PREFIX.length + SSSS_KEY_LENGTH));
|
olmRecoveryKeyPrefix.length + ssssKeyLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
static String encodeRecoveryKey(Uint8List recoveryKey) {
|
static String encodeRecoveryKey(Uint8List recoveryKey) {
|
||||||
final keyToEncode = <int>[];
|
final keyToEncode = <int>[];
|
||||||
for (final b in OLM_RECOVERY_KEY_PREFIX) {
|
for (final b in olmRecoveryKeyPrefix) {
|
||||||
keyToEncode.add(b);
|
keyToEncode.add(b);
|
||||||
}
|
}
|
||||||
keyToEncode.addAll(recoveryKey);
|
keyToEncode.addAll(recoveryKey);
|
||||||
|
|
@ -208,10 +208,10 @@ class SSSS {
|
||||||
// we need to derive the key off of the passphrase
|
// we need to derive the key off of the passphrase
|
||||||
content.passphrase = PassphraseInfo();
|
content.passphrase = PassphraseInfo();
|
||||||
content.passphrase.algorithm = AlgorithmTypes.pbkdf2;
|
content.passphrase.algorithm = AlgorithmTypes.pbkdf2;
|
||||||
content.passphrase.salt = base64
|
content.passphrase.salt =
|
||||||
.encode(SecureRandom(PBKDF2_SALT_LENGTH).bytes); // generate salt
|
base64.encode(SecureRandom(pbkdf2SaltLength).bytes); // generate salt
|
||||||
content.passphrase.iterations = PBKDF2_DEFAULT_ITERATIONS;
|
content.passphrase.iterations = pbkdf2DefaultIterations;
|
||||||
content.passphrase.bits = SSSS_KEY_LENGTH * 8;
|
content.passphrase.bits = ssssKeyLength * 8;
|
||||||
privateKey = await runInBackground(
|
privateKey = await runInBackground(
|
||||||
_keyFromPassphrase,
|
_keyFromPassphrase,
|
||||||
_KeyFromPassphraseArgs(
|
_KeyFromPassphraseArgs(
|
||||||
|
|
@ -222,20 +222,20 @@ class SSSS {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// we need to just generate a new key from scratch
|
// we need to just generate a new key from scratch
|
||||||
privateKey = Uint8List.fromList(SecureRandom(SSSS_KEY_LENGTH).bytes);
|
privateKey = Uint8List.fromList(SecureRandom(ssssKeyLength).bytes);
|
||||||
}
|
}
|
||||||
// now that we have the private key, let's create the iv and mac
|
// now that we have the private key, let's create the iv and mac
|
||||||
final encrypted = encryptAes(ZERO_STR, privateKey, '');
|
final encrypted = encryptAes(zeroStr, privateKey, '');
|
||||||
content.iv = encrypted.iv;
|
content.iv = encrypted.iv;
|
||||||
content.mac = encrypted.mac;
|
content.mac = encrypted.mac;
|
||||||
content.algorithm = AlgorithmTypes.secretStorageV1AesHmcSha2;
|
content.algorithm = AlgorithmTypes.secretStorageV1AesHmcSha2;
|
||||||
|
|
||||||
const KEYID_BYTE_LENGTH = 24;
|
const keyidByteLength = 24;
|
||||||
|
|
||||||
// make sure we generate a unique key id
|
// make sure we generate a unique key id
|
||||||
var keyId = base64.encode(SecureRandom(KEYID_BYTE_LENGTH).bytes);
|
var keyId = base64.encode(SecureRandom(keyidByteLength).bytes);
|
||||||
while (getKey(keyId) != null) {
|
while (getKey(keyId) != null) {
|
||||||
keyId = base64.encode(SecureRandom(KEYID_BYTE_LENGTH).bytes);
|
keyId = base64.encode(SecureRandom(keyidByteLength).bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
final accountDataType = EventTypes.secretStorageKey(keyId);
|
final accountDataType = EventTypes.secretStorageKey(keyId);
|
||||||
|
|
@ -255,7 +255,7 @@ class SSSS {
|
||||||
bool checkKey(Uint8List key, SecretStorageKeyContent info) {
|
bool checkKey(Uint8List key, SecretStorageKeyContent info) {
|
||||||
if (info.algorithm == AlgorithmTypes.secretStorageV1AesHmcSha2) {
|
if (info.algorithm == AlgorithmTypes.secretStorageV1AesHmcSha2) {
|
||||||
if ((info.mac is String) && (info.iv is String)) {
|
if ((info.mac is String) && (info.iv is String)) {
|
||||||
final encrypted = encryptAes(ZERO_STR, key, '', info.iv);
|
final encrypted = encryptAes(zeroStr, key, '', info.iv);
|
||||||
return info.mac.replaceAll(RegExp(r'=+$'), '') ==
|
return info.mac.replaceAll(RegExp(r'=+$'), '') ==
|
||||||
encrypted.mac.replaceAll(RegExp(r'=+$'), '');
|
encrypted.mac.replaceAll(RegExp(r'=+$'), '');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -314,7 +314,7 @@ class SSSS {
|
||||||
final encryptInfo = _Encrypted(
|
final encryptInfo = _Encrypted(
|
||||||
iv: enc['iv'], ciphertext: enc['ciphertext'], mac: enc['mac']);
|
iv: enc['iv'], ciphertext: enc['ciphertext'], mac: enc['mac']);
|
||||||
final decrypted = decryptAes(encryptInfo, key, type);
|
final decrypted = decryptAes(encryptInfo, key, type);
|
||||||
if (CACHE_TYPES.contains(type) && client.database != null) {
|
if (cacheTypes.contains(type) && client.database != null) {
|
||||||
// cache the thing
|
// cache the thing
|
||||||
await client.database
|
await client.database
|
||||||
.storeSSSSCache(client.id, type, keyId, enc['ciphertext'], decrypted);
|
.storeSSSSCache(client.id, type, keyId, enc['ciphertext'], decrypted);
|
||||||
|
|
@ -347,7 +347,7 @@ class SSSS {
|
||||||
};
|
};
|
||||||
// store the thing in your account data
|
// store the thing in your account data
|
||||||
await client.setAccountData(client.userID, type, content);
|
await client.setAccountData(client.userID, type, content);
|
||||||
if (CACHE_TYPES.contains(type) && client.database != null) {
|
if (cacheTypes.contains(type) && client.database != null) {
|
||||||
// cache the thing
|
// cache the thing
|
||||||
await client.database
|
await client.database
|
||||||
.storeSSSSCache(client.id, type, keyId, encrypted.ciphertext, secret);
|
.storeSSSSCache(client.id, type, keyId, encrypted.ciphertext, secret);
|
||||||
|
|
@ -373,7 +373,7 @@ class SSSS {
|
||||||
}
|
}
|
||||||
// store the thing in your account data
|
// store the thing in your account data
|
||||||
await client.setAccountData(client.userID, type, content);
|
await client.setAccountData(client.userID, type, content);
|
||||||
if (CACHE_TYPES.contains(type) && client.database != null) {
|
if (cacheTypes.contains(type) && client.database != null) {
|
||||||
// cache the thing
|
// cache the thing
|
||||||
await client.database.storeSSSSCache(client.id, type, keyId,
|
await client.database.storeSSSSCache(client.id, type, keyId,
|
||||||
content['encrypted'][keyId]['ciphertext'], secret);
|
content['encrypted'][keyId]['ciphertext'], secret);
|
||||||
|
|
@ -381,7 +381,7 @@ class SSSS {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> maybeCacheAll(String keyId, Uint8List key) async {
|
Future<void> maybeCacheAll(String keyId, Uint8List key) async {
|
||||||
for (final type in CACHE_TYPES) {
|
for (final type in cacheTypes) {
|
||||||
final secret = await getCached(type);
|
final secret = await getCached(type);
|
||||||
if (secret == null) {
|
if (secret == null) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -394,7 +394,7 @@ class SSSS {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> maybeRequestAll([List<DeviceKeys> devices]) async {
|
Future<void> maybeRequestAll([List<DeviceKeys> devices]) async {
|
||||||
for (final type in CACHE_TYPES) {
|
for (final type in cacheTypes) {
|
||||||
if (keyIdsFromType(type) != null) {
|
if (keyIdsFromType(type) != null) {
|
||||||
final secret = await getCached(type);
|
final secret = await getCached(type);
|
||||||
if (secret == null) {
|
if (secret == null) {
|
||||||
|
|
|
||||||
|
|
@ -568,7 +568,7 @@ class Bootstrap {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Logs().v('Store the secret...');
|
Logs().v('Store the secret...');
|
||||||
await newSsssKey.store(MEGOLM_KEY, base64.encode(privKey));
|
await newSsssKey.store(megolmKey, base64.encode(privKey));
|
||||||
Logs().v(
|
Logs().v(
|
||||||
'And finally set all megolm keys as needing to be uploaded again...');
|
'And finally set all megolm keys as needing to be uploaded again...');
|
||||||
await client.database?.markInboundGroupSessionsAsNeedingUpload(client.id);
|
await client.database?.markInboundGroupSessionsAsNeedingUpload(client.id);
|
||||||
|
|
|
||||||
|
|
@ -648,9 +648,9 @@ abstract class _KeyVerificationMethod {
|
||||||
void dispose() {}
|
void dispose() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const KNOWN_KEY_AGREEMENT_PROTOCOLS = ['curve25519-hkdf-sha256', 'curve25519'];
|
const knownKeyAgreementProtocols = ['curve25519-hkdf-sha256', 'curve25519'];
|
||||||
const KNOWN_HASHES = ['sha256'];
|
const knownHashes = ['sha256'];
|
||||||
const KNOWN_MESSAGE_AUTHENTIFICATION_CODES = ['hkdf-hmac-sha256'];
|
const knownHashesAuthentificationCodes = ['hkdf-hmac-sha256'];
|
||||||
|
|
||||||
class _KeyVerificationMethodSas extends _KeyVerificationMethod {
|
class _KeyVerificationMethodSas extends _KeyVerificationMethod {
|
||||||
_KeyVerificationMethodSas({KeyVerification request})
|
_KeyVerificationMethodSas({KeyVerification request})
|
||||||
|
|
@ -768,9 +768,9 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
|
||||||
Future<void> sendStart() async {
|
Future<void> sendStart() async {
|
||||||
final payload = <String, dynamic>{
|
final payload = <String, dynamic>{
|
||||||
'method': type,
|
'method': type,
|
||||||
'key_agreement_protocols': KNOWN_KEY_AGREEMENT_PROTOCOLS,
|
'key_agreement_protocols': knownKeyAgreementProtocols,
|
||||||
'hashes': KNOWN_HASHES,
|
'hashes': knownHashes,
|
||||||
'message_authentication_codes': KNOWN_MESSAGE_AUTHENTIFICATION_CODES,
|
'message_authentication_codes': knownHashesAuthentificationCodes,
|
||||||
'short_authentication_string': knownAuthentificationTypes,
|
'short_authentication_string': knownAuthentificationTypes,
|
||||||
};
|
};
|
||||||
request.makePayload(payload);
|
request.makePayload(payload);
|
||||||
|
|
@ -785,18 +785,18 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final possibleKeyAgreementProtocols = _intersect(
|
final possibleKeyAgreementProtocols = _intersect(
|
||||||
KNOWN_KEY_AGREEMENT_PROTOCOLS, payload['key_agreement_protocols']);
|
knownKeyAgreementProtocols, payload['key_agreement_protocols']);
|
||||||
if (possibleKeyAgreementProtocols.isEmpty) {
|
if (possibleKeyAgreementProtocols.isEmpty) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
keyAgreementProtocol = possibleKeyAgreementProtocols.first;
|
keyAgreementProtocol = possibleKeyAgreementProtocols.first;
|
||||||
final possibleHashes = _intersect(KNOWN_HASHES, payload['hashes']);
|
final possibleHashes = _intersect(knownHashes, payload['hashes']);
|
||||||
if (possibleHashes.isEmpty) {
|
if (possibleHashes.isEmpty) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hash = possibleHashes.first;
|
hash = possibleHashes.first;
|
||||||
final possibleMessageAuthenticationCodes = _intersect(
|
final possibleMessageAuthenticationCodes = _intersect(
|
||||||
KNOWN_MESSAGE_AUTHENTIFICATION_CODES,
|
knownHashesAuthentificationCodes,
|
||||||
payload['message_authentication_codes']);
|
payload['message_authentication_codes']);
|
||||||
if (possibleMessageAuthenticationCodes.isEmpty) {
|
if (possibleMessageAuthenticationCodes.isEmpty) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -826,16 +826,16 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _handleAccept(Map<String, dynamic> payload) {
|
bool _handleAccept(Map<String, dynamic> payload) {
|
||||||
if (!KNOWN_KEY_AGREEMENT_PROTOCOLS
|
if (!knownKeyAgreementProtocols
|
||||||
.contains(payload['key_agreement_protocol'])) {
|
.contains(payload['key_agreement_protocol'])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
keyAgreementProtocol = payload['key_agreement_protocol'];
|
keyAgreementProtocol = payload['key_agreement_protocol'];
|
||||||
if (!KNOWN_HASHES.contains(payload['hash'])) {
|
if (!knownHashes.contains(payload['hash'])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hash = payload['hash'];
|
hash = payload['hash'];
|
||||||
if (!KNOWN_MESSAGE_AUTHENTIFICATION_CODES
|
if (!knownHashesAuthentificationCodes
|
||||||
.contains(payload['message_authentication_code'])) {
|
.contains(payload['message_authentication_code'])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,7 @@ class Database extends _$Database {
|
||||||
// we limit to only fetching 500 rooms at once.
|
// we limit to only fetching 500 rooms at once.
|
||||||
// This value might be fine-tune-able to be larger (and thus increase performance more for very large accounts),
|
// This value might be fine-tune-able to be larger (and thus increase performance more for very large accounts),
|
||||||
// however this very conservative value should be on the safe side.
|
// however this very conservative value should be on the safe side.
|
||||||
const MAX_ROOMS_PER_QUERY = 500;
|
const maxRoomsPerQuery = 500;
|
||||||
// as we iterate over our entries in separate chunks one-by-one we use an iterator
|
// as we iterate over our entries in separate chunks one-by-one we use an iterator
|
||||||
// which persists accross the chunks, and thus we just re-sume iteration at the place
|
// which persists accross the chunks, and thus we just re-sume iteration at the place
|
||||||
// we prreviously left off.
|
// we prreviously left off.
|
||||||
|
|
@ -315,7 +315,7 @@ class Database extends _$Database {
|
||||||
// now we iterate over all our 500-room-chunks...
|
// now we iterate over all our 500-room-chunks...
|
||||||
for (var i = 0;
|
for (var i = 0;
|
||||||
i < allMembersToPostload.keys.length;
|
i < allMembersToPostload.keys.length;
|
||||||
i += MAX_ROOMS_PER_QUERY) {
|
i += maxRoomsPerQuery) {
|
||||||
// query the current chunk and build the query
|
// query the current chunk and build the query
|
||||||
final membersRes = await (select(roomStates)
|
final membersRes = await (select(roomStates)
|
||||||
..where((s) {
|
..where((s) {
|
||||||
|
|
@ -330,7 +330,7 @@ class Database extends _$Database {
|
||||||
// we must check for if our chunk is done *before* progressing the
|
// we must check for if our chunk is done *before* progressing the
|
||||||
// iterator, else we might progress it twice around chunk edges, missing on rooms
|
// iterator, else we might progress it twice around chunk edges, missing on rooms
|
||||||
for (var j = 0;
|
for (var j = 0;
|
||||||
j < MAX_ROOMS_PER_QUERY && entriesIterator.moveNext();
|
j < maxRoomsPerQuery && entriesIterator.moveNext();
|
||||||
j++) {
|
j++) {
|
||||||
final entry = entriesIterator.current;
|
final entry = entriesIterator.current;
|
||||||
// builds room_id = '!roomId1' AND state_key IN ('@member')
|
// builds room_id = '!roomId1' AND state_key IN ('@member')
|
||||||
|
|
@ -468,8 +468,8 @@ class Database extends _$Database {
|
||||||
// calculate the status
|
// calculate the status
|
||||||
var status = 2;
|
var status = 2;
|
||||||
if (eventContent['unsigned'] is Map<String, dynamic> &&
|
if (eventContent['unsigned'] is Map<String, dynamic> &&
|
||||||
eventContent['unsigned'][MessageSendingStatusKey] is num) {
|
eventContent['unsigned'][messageSendingStatusKey] is num) {
|
||||||
status = eventContent['unsigned'][MessageSendingStatusKey];
|
status = eventContent['unsigned'][messageSendingStatusKey];
|
||||||
}
|
}
|
||||||
if (eventContent['status'] is num) status = eventContent['status'];
|
if (eventContent['status'] is num) status = eventContent['status'];
|
||||||
var storeNewEvent = !((status == 1 || status == -1) &&
|
var storeNewEvent = !((status == 1 || status == -1) &&
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,9 @@ import 'utils/run_in_background.dart';
|
||||||
import 'utils/event_localizations.dart';
|
import 'utils/event_localizations.dart';
|
||||||
|
|
||||||
abstract class RelationshipTypes {
|
abstract class RelationshipTypes {
|
||||||
static const String Reply = 'm.in_reply_to';
|
static const String reply = 'm.in_reply_to';
|
||||||
static const String Edit = 'm.replace';
|
static const String edit = 'm.replace';
|
||||||
static const String Reaction = 'm.annotation';
|
static const String reaction = 'm.annotation';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All data exchanged over Matrix is expressed as an "event". Typically each client action (e.g. sending a message) correlates with exactly one event.
|
/// All data exchanged over Matrix is expressed as an "event". Typically each client action (e.g. sending a message) correlates with exactly one event.
|
||||||
|
|
@ -61,12 +61,12 @@ class Event extends MatrixEvent {
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
static const int defaultStatus = 2;
|
static const int defaultStatus = 2;
|
||||||
static const Map<String, int> STATUS_TYPE = {
|
static const Map<String, int> statusType = {
|
||||||
'ERROR': -1,
|
'error': -1,
|
||||||
'SENDING': 0,
|
'sending': 0,
|
||||||
'SENT': 1,
|
'sent': 1,
|
||||||
'TIMELINE': 2,
|
'timeline': 2,
|
||||||
'ROOM_STATE': 3,
|
'roomState': 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Optional. The event that redacted this event, if any. Otherwise null.
|
/// Optional. The event that redacted this event, if any. Otherwise null.
|
||||||
|
|
@ -160,7 +160,7 @@ class Event extends MatrixEvent {
|
||||||
final prevContent = Event.getMapFromPayload(jsonPayload['prev_content']);
|
final prevContent = Event.getMapFromPayload(jsonPayload['prev_content']);
|
||||||
return Event(
|
return Event(
|
||||||
status: jsonPayload['status'] ??
|
status: jsonPayload['status'] ??
|
||||||
unsigned[MessageSendingStatusKey] ??
|
unsigned[messageSendingStatusKey] ??
|
||||||
defaultStatus,
|
defaultStatus,
|
||||||
stateKey: jsonPayload['state_key'],
|
stateKey: jsonPayload['state_key'],
|
||||||
prevContent: prevContent,
|
prevContent: prevContent,
|
||||||
|
|
@ -352,7 +352,7 @@ class Event extends MatrixEvent {
|
||||||
|
|
||||||
/// Searches for the reply event in the given timeline.
|
/// 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;
|
if (relationshipType != RelationshipTypes.reply) return null;
|
||||||
return await timeline.getEventById(relationshipEventId);
|
return await timeline.getEventById(relationshipEventId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -630,7 +630,7 @@ class Event extends MatrixEvent {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (content['m.relates_to'].containsKey('m.in_reply_to')) {
|
if (content['m.relates_to'].containsKey('m.in_reply_to')) {
|
||||||
return RelationshipTypes.Reply;
|
return RelationshipTypes.reply;
|
||||||
}
|
}
|
||||||
return content
|
return content
|
||||||
.tryGet<Map<String, dynamic>>('m.relates_to')
|
.tryGet<Map<String, dynamic>>('m.relates_to')
|
||||||
|
|
@ -671,9 +671,9 @@ class Event extends MatrixEvent {
|
||||||
if (redacted) {
|
if (redacted) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
if (hasAggregatedEvents(timeline, RelationshipTypes.Edit)) {
|
if (hasAggregatedEvents(timeline, RelationshipTypes.edit)) {
|
||||||
// alright, we have an edit
|
// alright, we have an edit
|
||||||
final allEditEvents = aggregatedEvents(timeline, RelationshipTypes.Edit)
|
final allEditEvents = aggregatedEvents(timeline, RelationshipTypes.edit)
|
||||||
// we only allow edits made by the original author themself
|
// we only allow edits made by the original author themself
|
||||||
.where((e) => e.senderId == senderId && e.type == EventTypes.Message)
|
.where((e) => e.senderId == senderId && e.type == EventTypes.Message)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,24 @@ import 'utils/marked_unread.dart';
|
||||||
import 'utils/matrix_file.dart';
|
import 'utils/matrix_file.dart';
|
||||||
import 'utils/matrix_localizations.dart';
|
import 'utils/matrix_localizations.dart';
|
||||||
|
|
||||||
enum PushRuleState { notify, mentions_only, dont_notify }
|
enum PushRuleState { notify, mentionsOnly, dontNotify }
|
||||||
enum JoinRules { public, knock, invite, private }
|
enum JoinRules { public, knock, invite, private }
|
||||||
enum GuestAccess { can_join, forbidden }
|
enum GuestAccess { canJoin, forbidden }
|
||||||
enum HistoryVisibility { invited, joined, shared, world_readable }
|
enum HistoryVisibility { invited, joined, shared, worldReadable }
|
||||||
|
|
||||||
const String MessageSendingStatusKey =
|
const Map<GuestAccess, String> _guestAccessMap = {
|
||||||
|
GuestAccess.canJoin: 'can_join',
|
||||||
|
GuestAccess.forbidden: 'forbidden',
|
||||||
|
};
|
||||||
|
|
||||||
|
const Map<HistoryVisibility, String> _historyVisibilityMap = {
|
||||||
|
HistoryVisibility.invited: 'invited',
|
||||||
|
HistoryVisibility.joined: 'joined',
|
||||||
|
HistoryVisibility.shared: 'shared',
|
||||||
|
HistoryVisibility.worldReadable: 'world_readable',
|
||||||
|
};
|
||||||
|
|
||||||
|
const String messageSendingStatusKey =
|
||||||
'com.famedly.famedlysdk.message_sending_status';
|
'com.famedly.famedlysdk.message_sending_status';
|
||||||
|
|
||||||
/// Represents a Matrix room.
|
/// Represents a Matrix room.
|
||||||
|
|
@ -345,7 +357,7 @@ class Room {
|
||||||
|
|
||||||
/// The default count of how much events should be requested when requesting the
|
/// The default count of how much events should be requested when requesting the
|
||||||
/// history of this room.
|
/// history of this room.
|
||||||
static const int DefaultHistoryCount = 100;
|
static const int defaultHistoryCount = 100;
|
||||||
|
|
||||||
/// Calculates the displayname. First checks if there is a name, then checks for a canonical alias and
|
/// Calculates the displayname. First checks if there is a name, then checks for a canonical alias and
|
||||||
/// then generates a name from the heroes.
|
/// then generates a name from the heroes.
|
||||||
|
|
@ -448,7 +460,7 @@ class Room {
|
||||||
|
|
||||||
bool get markedUnread {
|
bool get markedUnread {
|
||||||
return MarkedUnread.fromJson(
|
return MarkedUnread.fromJson(
|
||||||
roomAccountData[EventType.MarkedUnread]?.content ?? {})
|
roomAccountData[EventType.markedUnread]?.content ?? {})
|
||||||
.unread;
|
.unread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -467,12 +479,12 @@ class Room {
|
||||||
BasicRoomEvent()
|
BasicRoomEvent()
|
||||||
..content = content
|
..content = content
|
||||||
..roomId = id
|
..roomId = id
|
||||||
..type = EventType.MarkedUnread
|
..type = EventType.markedUnread
|
||||||
])))));
|
])))));
|
||||||
await client.setRoomAccountData(
|
await client.setRoomAccountData(
|
||||||
client.userID,
|
client.userID,
|
||||||
id,
|
id,
|
||||||
EventType.MarkedUnread,
|
EventType.markedUnread,
|
||||||
content,
|
content,
|
||||||
);
|
);
|
||||||
if (unread == false && lastEvent != null) {
|
if (unread == false && lastEvent != null) {
|
||||||
|
|
@ -618,7 +630,7 @@ class Room {
|
||||||
Future<String> sendReaction(String eventId, String key, {String txid}) {
|
Future<String> sendReaction(String eventId, String key, {String txid}) {
|
||||||
return sendEvent({
|
return sendEvent({
|
||||||
'm.relates_to': {
|
'm.relates_to': {
|
||||||
'rel_type': RelationshipTypes.Reaction,
|
'rel_type': RelationshipTypes.reaction,
|
||||||
'event_id': eventId,
|
'event_id': eventId,
|
||||||
'key': key,
|
'key': key,
|
||||||
},
|
},
|
||||||
|
|
@ -805,7 +817,7 @@ class Room {
|
||||||
content['m.new_content'] = newContent;
|
content['m.new_content'] = newContent;
|
||||||
content['m.relates_to'] = {
|
content['m.relates_to'] = {
|
||||||
'event_id': editEventId,
|
'event_id': editEventId,
|
||||||
'rel_type': RelationshipTypes.Edit,
|
'rel_type': RelationshipTypes.edit,
|
||||||
};
|
};
|
||||||
if (content['body'] is String) {
|
if (content['body'] is String) {
|
||||||
content['body'] = '* ' + content['body'];
|
content['body'] = '* ' + content['body'];
|
||||||
|
|
@ -827,7 +839,7 @@ class Room {
|
||||||
..senderId = client.userID
|
..senderId = client.userID
|
||||||
..originServerTs = sentDate
|
..originServerTs = sentDate
|
||||||
..unsigned = {
|
..unsigned = {
|
||||||
MessageSendingStatusKey: 0,
|
messageSendingStatusKey: 0,
|
||||||
'transaction_id': messageID,
|
'transaction_id': messageID,
|
||||||
},
|
},
|
||||||
]))));
|
]))));
|
||||||
|
|
@ -853,14 +865,14 @@ class Room {
|
||||||
} else {
|
} else {
|
||||||
Logs().w('[Client] Problem while sending message', e, s);
|
Logs().w('[Client] Problem while sending message', e, s);
|
||||||
syncUpdate.rooms.join.values.first.timeline.events.first
|
syncUpdate.rooms.join.values.first.timeline.events.first
|
||||||
.unsigned[MessageSendingStatusKey] = -1;
|
.unsigned[messageSendingStatusKey] = -1;
|
||||||
await _handleFakeSync(syncUpdate);
|
await _handleFakeSync(syncUpdate);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syncUpdate.rooms.join.values.first.timeline.events.first
|
syncUpdate.rooms.join.values.first.timeline.events.first
|
||||||
.unsigned[MessageSendingStatusKey] = 1;
|
.unsigned[messageSendingStatusKey] = 1;
|
||||||
syncUpdate.rooms.join.values.first.timeline.events.first.eventId = res;
|
syncUpdate.rooms.join.values.first.timeline.events.first.eventId = res;
|
||||||
await _handleFakeSync(syncUpdate);
|
await _handleFakeSync(syncUpdate);
|
||||||
|
|
||||||
|
|
@ -952,7 +964,7 @@ class Room {
|
||||||
/// be received maximum. When the request is answered, [onHistoryReceived] will be triggered **before**
|
/// be received maximum. When the request is answered, [onHistoryReceived] will be triggered **before**
|
||||||
/// the historical events will be published in the onEvent stream.
|
/// the historical events will be published in the onEvent stream.
|
||||||
Future<void> requestHistory(
|
Future<void> requestHistory(
|
||||||
{int historyCount = DefaultHistoryCount, onHistoryReceived}) async {
|
{int historyCount = defaultHistoryCount, onHistoryReceived}) async {
|
||||||
final resp = await client.requestMessages(
|
final resp = await client.requestMessages(
|
||||||
id,
|
id,
|
||||||
prev_batch,
|
prev_batch,
|
||||||
|
|
@ -1458,7 +1470,7 @@ class Room {
|
||||||
if (globalPushRules['override'][i]['actions']
|
if (globalPushRules['override'][i]['actions']
|
||||||
.indexOf('dont_notify') !=
|
.indexOf('dont_notify') !=
|
||||||
-1) {
|
-1) {
|
||||||
return PushRuleState.dont_notify;
|
return PushRuleState.dontNotify;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1470,7 +1482,7 @@ class Room {
|
||||||
if (globalPushRules['room'][i]['rule_id'] == id) {
|
if (globalPushRules['room'][i]['rule_id'] == id) {
|
||||||
if (globalPushRules['room'][i]['actions'].indexOf('dont_notify') !=
|
if (globalPushRules['room'][i]['actions'].indexOf('dont_notify') !=
|
||||||
-1) {
|
-1) {
|
||||||
return PushRuleState.mentions_only;
|
return PushRuleState.mentionsOnly;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1488,15 +1500,15 @@ class Room {
|
||||||
switch (newState) {
|
switch (newState) {
|
||||||
// All push notifications should be sent to the user
|
// All push notifications should be sent to the user
|
||||||
case PushRuleState.notify:
|
case PushRuleState.notify:
|
||||||
if (pushRuleState == PushRuleState.dont_notify) {
|
if (pushRuleState == PushRuleState.dontNotify) {
|
||||||
await client.deletePushRule('global', PushRuleKind.override, id);
|
await client.deletePushRule('global', PushRuleKind.override, id);
|
||||||
} else if (pushRuleState == PushRuleState.mentions_only) {
|
} else if (pushRuleState == PushRuleState.mentionsOnly) {
|
||||||
await client.deletePushRule('global', PushRuleKind.room, id);
|
await client.deletePushRule('global', PushRuleKind.room, id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// Only when someone mentions the user, a push notification should be sent
|
// Only when someone mentions the user, a push notification should be sent
|
||||||
case PushRuleState.mentions_only:
|
case PushRuleState.mentionsOnly:
|
||||||
if (pushRuleState == PushRuleState.dont_notify) {
|
if (pushRuleState == PushRuleState.dontNotify) {
|
||||||
await client.deletePushRule('global', PushRuleKind.override, id);
|
await client.deletePushRule('global', PushRuleKind.override, id);
|
||||||
await client.setPushRule(
|
await client.setPushRule(
|
||||||
'global',
|
'global',
|
||||||
|
|
@ -1514,8 +1526,8 @@ class Room {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// No push notification should be ever sent for this room.
|
// No push notification should be ever sent for this room.
|
||||||
case PushRuleState.dont_notify:
|
case PushRuleState.dontNotify:
|
||||||
if (pushRuleState == PushRuleState.mentions_only) {
|
if (pushRuleState == PushRuleState.mentionsOnly) {
|
||||||
await client.deletePushRule('global', PushRuleKind.room, id);
|
await client.deletePushRule('global', PushRuleKind.room, id);
|
||||||
}
|
}
|
||||||
await client.setPushRule(
|
await client.setPushRule(
|
||||||
|
|
@ -1702,11 +1714,8 @@ class Room {
|
||||||
/// This event controls whether guest users are allowed to join rooms. If this event
|
/// This event controls whether guest users are allowed to join rooms. If this event
|
||||||
/// is absent, servers should act as if it is present and has the guest_access value "forbidden".
|
/// is absent, servers should act as if it is present and has the guest_access value "forbidden".
|
||||||
GuestAccess get guestAccess => getState(EventTypes.GuestAccess) != null
|
GuestAccess get guestAccess => getState(EventTypes.GuestAccess) != null
|
||||||
? GuestAccess.values.firstWhere(
|
? _guestAccessMap.map((k, v) => MapEntry(v, k))[
|
||||||
(r) =>
|
getState(EventTypes.GuestAccess).content['guest_access']]
|
||||||
r.toString().replaceAll('GuestAccess.', '') ==
|
|
||||||
getState(EventTypes.GuestAccess).content['guest_access'],
|
|
||||||
orElse: () => GuestAccess.forbidden)
|
|
||||||
: GuestAccess.forbidden;
|
: GuestAccess.forbidden;
|
||||||
|
|
||||||
/// Changes the guest access. You should check first if the user is able to change it.
|
/// Changes the guest access. You should check first if the user is able to change it.
|
||||||
|
|
@ -1715,7 +1724,7 @@ class Room {
|
||||||
id,
|
id,
|
||||||
EventTypes.GuestAccess,
|
EventTypes.GuestAccess,
|
||||||
{
|
{
|
||||||
'guest_access': guestAccess.toString().replaceAll('GuestAccess.', ''),
|
'guest_access': _guestAccessMap[guestAccess],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|
@ -1727,12 +1736,9 @@ class Room {
|
||||||
/// This event controls whether a user can see the events that happened in a room from before they joined.
|
/// This event controls whether a user can see the events that happened in a room from before they joined.
|
||||||
HistoryVisibility get historyVisibility =>
|
HistoryVisibility get historyVisibility =>
|
||||||
getState(EventTypes.HistoryVisibility) != null
|
getState(EventTypes.HistoryVisibility) != null
|
||||||
? HistoryVisibility.values.firstWhere(
|
? _historyVisibilityMap.map((k, v) => MapEntry(v, k))[
|
||||||
(r) =>
|
getState(EventTypes.HistoryVisibility)
|
||||||
r.toString().replaceAll('HistoryVisibility.', '') ==
|
.content['history_visibility']]
|
||||||
getState(EventTypes.HistoryVisibility)
|
|
||||||
.content['history_visibility'],
|
|
||||||
orElse: () => null)
|
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
/// Changes the history visibility. You should check first if the user is able to change it.
|
/// Changes the history visibility. You should check first if the user is able to change it.
|
||||||
|
|
@ -1741,8 +1747,7 @@ class Room {
|
||||||
id,
|
id,
|
||||||
EventTypes.HistoryVisibility,
|
EventTypes.HistoryVisibility,
|
||||||
{
|
{
|
||||||
'history_visibility':
|
'history_visibility': _historyVisibilityMap[historyVisibility],
|
||||||
historyVisibility.toString().replaceAll('HistoryVisibility.', ''),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ class Timeline {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> requestHistory(
|
Future<void> requestHistory(
|
||||||
{int historyCount = Room.DefaultHistoryCount}) async {
|
{int historyCount = Room.defaultHistoryCount}) async {
|
||||||
if (!isRequestingHistory) {
|
if (!isRequestingHistory) {
|
||||||
isRequestingHistory = true;
|
isRequestingHistory = true;
|
||||||
await room.requestHistory(
|
await room.requestHistory(
|
||||||
|
|
@ -264,7 +264,7 @@ class Timeline {
|
||||||
}
|
}
|
||||||
var status = eventUpdate.content['status'] ??
|
var status = eventUpdate.content['status'] ??
|
||||||
(eventUpdate.content['unsigned'] is Map<String, dynamic>
|
(eventUpdate.content['unsigned'] is Map<String, dynamic>
|
||||||
? eventUpdate.content['unsigned'][MessageSendingStatusKey]
|
? eventUpdate.content['unsigned'][messageSendingStatusKey]
|
||||||
: null) ??
|
: null) ??
|
||||||
2;
|
2;
|
||||||
// Redaction events are handled as modification for existing events.
|
// Redaction events are handled as modification for existing events.
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mixin EventType {
|
mixin EventType {
|
||||||
static const String MarkedUnread = 'com.famedly.marked_unread';
|
static const String markedUnread = 'com.famedly.marked_unread';
|
||||||
}
|
}
|
||||||
|
|
||||||
class MarkedUnread {
|
class MarkedUnread {
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,9 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const Set<String> VALID_SIGILS = {'@', '!', '#', '\$', '+'};
|
const Set<String> validSigils = {'@', '!', '#', '\$', '+'};
|
||||||
|
|
||||||
const int MAX_LENGTH = 255;
|
const int maxLength = 255;
|
||||||
|
|
||||||
extension MatrixIdExtension on String {
|
extension MatrixIdExtension on String {
|
||||||
List<String> _getParts() {
|
List<String> _getParts() {
|
||||||
|
|
@ -32,8 +32,8 @@ extension MatrixIdExtension on String {
|
||||||
|
|
||||||
bool get isValidMatrixId {
|
bool get isValidMatrixId {
|
||||||
if (isEmpty ?? true) return false;
|
if (isEmpty ?? true) return false;
|
||||||
if (length > MAX_LENGTH) return false;
|
if (length > maxLength) return false;
|
||||||
if (!VALID_SIGILS.contains(substring(0, 1))) {
|
if (!validSigils.contains(substring(0, 1))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// event IDs do not have to have a domain
|
// event IDs do not have to have a domain
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ extension HistoryVisibilityDisplayString on HistoryVisibility {
|
||||||
return i18n.fromJoining;
|
return i18n.fromJoining;
|
||||||
case HistoryVisibility.shared:
|
case HistoryVisibility.shared:
|
||||||
return i18n.visibleForAllParticipants;
|
return i18n.visibleForAllParticipants;
|
||||||
case HistoryVisibility.world_readable:
|
case HistoryVisibility.worldReadable:
|
||||||
return i18n.visibleForEveryone;
|
return i18n.visibleForEveryone;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -156,7 +156,7 @@ extension HistoryVisibilityDisplayString on HistoryVisibility {
|
||||||
extension GuestAccessDisplayString on GuestAccess {
|
extension GuestAccessDisplayString on GuestAccess {
|
||||||
String getLocalizedString(MatrixLocalizations i18n) {
|
String getLocalizedString(MatrixLocalizations i18n) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case GuestAccess.can_join:
|
case GuestAccess.canJoin:
|
||||||
return i18n.guestsCanJoin;
|
return i18n.guestsCanJoin;
|
||||||
case GuestAccess.forbidden:
|
case GuestAccess.forbidden:
|
||||||
return i18n.guestsAreForbidden;
|
return i18n.guestsAreForbidden;
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ void main() {
|
||||||
masterKey.setDirectVerified(true);
|
masterKey.setDirectVerified(true);
|
||||||
// we need to populate the ssss cache to be able to test signing easily
|
// 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: SSSS_KEY);
|
await handle.unlock(recoveryKey: ssssKey);
|
||||||
await handle.maybeCacheAll();
|
await handle.maybeCacheAll();
|
||||||
|
|
||||||
expect(key.verified, true);
|
expect(key.verified, true);
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ void main() {
|
||||||
final key = client.userDeviceKeys[client.userID].masterKey;
|
final key = client.userDeviceKeys[client.userID].masterKey;
|
||||||
key.setDirectVerified(false);
|
key.setDirectVerified(false);
|
||||||
FakeMatrixApi.calledEndpoints.clear();
|
FakeMatrixApi.calledEndpoints.clear();
|
||||||
await client.encryption.crossSigning.selfSign(recoveryKey: SSSS_KEY);
|
await client.encryption.crossSigning.selfSign(recoveryKey: ssssKey);
|
||||||
expect(key.directVerified, true);
|
expect(key.directVerified, true);
|
||||||
expect(
|
expect(
|
||||||
FakeMatrixApi.calledEndpoints
|
FakeMatrixApi.calledEndpoints
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class MockSSSS extends SSSS {
|
||||||
Future<void> maybeRequestAll([List<DeviceKeys> devices]) async {
|
Future<void> maybeRequestAll([List<DeviceKeys> devices]) async {
|
||||||
requestedSecrets = true;
|
requestedSecrets = true;
|
||||||
final handle = open();
|
final handle = open();
|
||||||
await handle.unlock(recoveryKey: SSSS_KEY);
|
await handle.unlock(recoveryKey: ssssKey);
|
||||||
await handle.maybeCacheAll();
|
await handle.maybeCacheAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -215,7 +215,7 @@ void main() {
|
||||||
final req1 =
|
final req1 =
|
||||||
await client1.userDeviceKeys[client2.userID].startVerification();
|
await client1.userDeviceKeys[client2.userID].startVerification();
|
||||||
expect(req1.state, KeyVerificationState.askSSSS);
|
expect(req1.state, KeyVerificationState.askSSSS);
|
||||||
await req1.openSSSS(recoveryKey: SSSS_KEY);
|
await req1.openSSSS(recoveryKey: ssssKey);
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
await Future.delayed(Duration(milliseconds: 10));
|
||||||
expect(req1.state, KeyVerificationState.waitingAccept);
|
expect(req1.state, KeyVerificationState.waitingAccept);
|
||||||
|
|
||||||
|
|
@ -311,7 +311,7 @@ void main() {
|
||||||
expect(req1.state, KeyVerificationState.askSSSS);
|
expect(req1.state, KeyVerificationState.askSSSS);
|
||||||
expect(req2.state, KeyVerificationState.done);
|
expect(req2.state, KeyVerificationState.done);
|
||||||
|
|
||||||
await req1.openSSSS(recoveryKey: SSSS_KEY);
|
await req1.openSSSS(recoveryKey: ssssKey);
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
await Future.delayed(Duration(milliseconds: 10));
|
||||||
expect(req1.state, KeyVerificationState.done);
|
expect(req1.state, KeyVerificationState.done);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ void main() {
|
||||||
expect(client.encryption.keyManager.enabled, true);
|
expect(client.encryption.keyManager.enabled, true);
|
||||||
expect(await client.encryption.keyManager.isCached(), false);
|
expect(await client.encryption.keyManager.isCached(), false);
|
||||||
final handle = client.encryption.ssss.open();
|
final handle = client.encryption.ssss.open();
|
||||||
await handle.unlock(recoveryKey: SSSS_KEY);
|
await handle.unlock(recoveryKey: ssssKey);
|
||||||
await handle.maybeCacheAll();
|
await handle.maybeCacheAll();
|
||||||
expect(await client.encryption.keyManager.isCached(), true);
|
expect(await client.encryption.keyManager.isCached(), true);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ class MockSSSS extends SSSS {
|
||||||
Future<void> maybeRequestAll([List<DeviceKeys> devices]) async {
|
Future<void> maybeRequestAll([List<DeviceKeys> devices]) async {
|
||||||
requestedSecrets = true;
|
requestedSecrets = true;
|
||||||
final handle = open();
|
final handle = open();
|
||||||
await handle.unlock(recoveryKey: SSSS_KEY);
|
await handle.unlock(recoveryKey: ssssKey);
|
||||||
await handle.maybeCacheAll();
|
await handle.maybeCacheAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,8 +97,8 @@ void main() {
|
||||||
}
|
}
|
||||||
expect(failed, true);
|
expect(failed, true);
|
||||||
expect(handle.isUnlocked, false);
|
expect(handle.isUnlocked, false);
|
||||||
await handle.unlock(passphrase: SSSS_PASSPHRASE);
|
await handle.unlock(passphrase: ssssPassphrase);
|
||||||
await handle.unlock(recoveryKey: SSSS_KEY);
|
await handle.unlock(recoveryKey: ssssKey);
|
||||||
expect(handle.isUnlocked, true);
|
expect(handle.isUnlocked, true);
|
||||||
FakeMatrixApi.calledEndpoints.clear();
|
FakeMatrixApi.calledEndpoints.clear();
|
||||||
await handle.store('best animal', 'foxies');
|
await handle.store('best animal', 'foxies');
|
||||||
|
|
@ -123,8 +123,8 @@ void main() {
|
||||||
expect(key, decoded);
|
expect(key, decoded);
|
||||||
|
|
||||||
final handle = client.encryption.ssss.open();
|
final handle = client.encryption.ssss.open();
|
||||||
await handle.unlock(recoveryKey: SSSS_KEY);
|
await handle.unlock(recoveryKey: ssssKey);
|
||||||
expect(handle.recoveryKey, SSSS_KEY);
|
expect(handle.recoveryKey, ssssKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cache', () async {
|
test('cache', () async {
|
||||||
|
|
@ -132,7 +132,7 @@ void main() {
|
||||||
await client.encryption.ssss.clearCache();
|
await client.encryption.ssss.clearCache();
|
||||||
final handle =
|
final handle =
|
||||||
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);
|
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);
|
||||||
await handle.unlock(recoveryKey: SSSS_KEY, postUnlock: false);
|
await handle.unlock(recoveryKey: ssssKey, postUnlock: false);
|
||||||
expect(
|
expect(
|
||||||
(await client.encryption.ssss
|
(await client.encryption.ssss
|
||||||
.getCached(EventTypes.CrossSigningSelfSigning)) !=
|
.getCached(EventTypes.CrossSigningSelfSigning)) !=
|
||||||
|
|
@ -167,7 +167,7 @@ void main() {
|
||||||
client.userDeviceKeys[client.userID].masterKey.setDirectVerified(false);
|
client.userDeviceKeys[client.userID].masterKey.setDirectVerified(false);
|
||||||
final handle =
|
final handle =
|
||||||
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);
|
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);
|
||||||
await handle.unlock(recoveryKey: SSSS_KEY);
|
await handle.unlock(recoveryKey: ssssKey);
|
||||||
expect(
|
expect(
|
||||||
(await client.encryption.ssss
|
(await client.encryption.ssss
|
||||||
.getCached(EventTypes.CrossSigningSelfSigning)) !=
|
.getCached(EventTypes.CrossSigningSelfSigning)) !=
|
||||||
|
|
@ -305,7 +305,7 @@ void main() {
|
||||||
key.setDirectVerified(true);
|
key.setDirectVerified(true);
|
||||||
final handle =
|
final handle =
|
||||||
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);
|
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);
|
||||||
await handle.unlock(recoveryKey: SSSS_KEY);
|
await handle.unlock(recoveryKey: ssssKey);
|
||||||
|
|
||||||
await client.encryption.ssss.clearCache();
|
await client.encryption.ssss.clearCache();
|
||||||
client.encryption.ssss.pendingShareRequests.clear();
|
client.encryption.ssss.pendingShareRequests.clear();
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ void main() {
|
||||||
expect(event.formattedText, formatted_body);
|
expect(event.formattedText, formatted_body);
|
||||||
expect(event.body, body);
|
expect(event.body, body);
|
||||||
expect(event.type, EventTypes.Message);
|
expect(event.type, EventTypes.Message);
|
||||||
expect(event.relationshipType, RelationshipTypes.Reply);
|
expect(event.relationshipType, RelationshipTypes.reply);
|
||||||
jsonObj['state_key'] = '';
|
jsonObj['state_key'] = '';
|
||||||
var state = Event.fromJson(jsonObj, null);
|
var state = Event.fromJson(jsonObj, null);
|
||||||
expect(state.eventId, id);
|
expect(state.eventId, id);
|
||||||
|
|
@ -183,7 +183,7 @@ void main() {
|
||||||
};
|
};
|
||||||
event = Event.fromJson(jsonObj, null);
|
event = Event.fromJson(jsonObj, null);
|
||||||
expect(event.messageType, MessageTypes.Text);
|
expect(event.messageType, MessageTypes.Text);
|
||||||
expect(event.relationshipType, RelationshipTypes.Reply);
|
expect(event.relationshipType, RelationshipTypes.reply);
|
||||||
expect(event.relationshipEventId, '1234');
|
expect(event.relationshipEventId, '1234');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -203,12 +203,12 @@ void main() {
|
||||||
'event_id': 'abc',
|
'event_id': 'abc',
|
||||||
};
|
};
|
||||||
event = Event.fromJson(jsonObj, null);
|
event = Event.fromJson(jsonObj, null);
|
||||||
expect(event.relationshipType, RelationshipTypes.Edit);
|
expect(event.relationshipType, RelationshipTypes.edit);
|
||||||
expect(event.relationshipEventId, 'abc');
|
expect(event.relationshipEventId, 'abc');
|
||||||
|
|
||||||
jsonObj['content']['m.relates_to']['rel_type'] = 'm.annotation';
|
jsonObj['content']['m.relates_to']['rel_type'] = 'm.annotation';
|
||||||
event = Event.fromJson(jsonObj, null);
|
event = Event.fromJson(jsonObj, null);
|
||||||
expect(event.relationshipType, RelationshipTypes.Reaction);
|
expect(event.relationshipType, RelationshipTypes.reaction);
|
||||||
expect(event.relationshipEventId, 'abc');
|
expect(event.relationshipEventId, 'abc');
|
||||||
|
|
||||||
jsonObj['content']['m.relates_to'] = {
|
jsonObj['content']['m.relates_to'] = {
|
||||||
|
|
@ -217,7 +217,7 @@ void main() {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
event = Event.fromJson(jsonObj, null);
|
event = Event.fromJson(jsonObj, null);
|
||||||
expect(event.relationshipType, RelationshipTypes.Reply);
|
expect(event.relationshipType, RelationshipTypes.reply);
|
||||||
expect(event.relationshipEventId, 'def');
|
expect(event.relationshipEventId, 'def');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -908,7 +908,7 @@ void main() {
|
||||||
'msgtype': 'm.text',
|
'msgtype': 'm.text',
|
||||||
'm.relates_to': {
|
'm.relates_to': {
|
||||||
'event_id': '\$source',
|
'event_id': '\$source',
|
||||||
'rel_type': RelationshipTypes.Edit,
|
'rel_type': RelationshipTypes.edit,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'event_id': '\$edit1',
|
'event_id': '\$edit1',
|
||||||
|
|
@ -919,30 +919,30 @@ void main() {
|
||||||
'msgtype': 'm.text',
|
'msgtype': 'm.text',
|
||||||
'm.relates_to': {
|
'm.relates_to': {
|
||||||
'event_id': '\$source',
|
'event_id': '\$source',
|
||||||
'rel_type': RelationshipTypes.Edit,
|
'rel_type': RelationshipTypes.edit,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'event_id': '\$edit2',
|
'event_id': '\$edit2',
|
||||||
}, null);
|
}, null);
|
||||||
var room = Room(client: client);
|
var room = Room(client: client);
|
||||||
var timeline = Timeline(events: <Event>[event, edit1, edit2], room: room);
|
var timeline = Timeline(events: <Event>[event, edit1, edit2], room: room);
|
||||||
expect(event.hasAggregatedEvents(timeline, RelationshipTypes.Edit), true);
|
expect(event.hasAggregatedEvents(timeline, RelationshipTypes.edit), true);
|
||||||
expect(event.aggregatedEvents(timeline, RelationshipTypes.Edit),
|
expect(event.aggregatedEvents(timeline, RelationshipTypes.edit),
|
||||||
{edit1, edit2});
|
{edit1, edit2});
|
||||||
expect(event.aggregatedEvents(timeline, RelationshipTypes.Reaction),
|
expect(event.aggregatedEvents(timeline, RelationshipTypes.reaction),
|
||||||
<Event>{});
|
<Event>{});
|
||||||
expect(event.hasAggregatedEvents(timeline, RelationshipTypes.Reaction),
|
expect(event.hasAggregatedEvents(timeline, RelationshipTypes.reaction),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
timeline.removeAggregatedEvent(edit2);
|
timeline.removeAggregatedEvent(edit2);
|
||||||
expect(event.aggregatedEvents(timeline, RelationshipTypes.Edit), {edit1});
|
expect(event.aggregatedEvents(timeline, RelationshipTypes.edit), {edit1});
|
||||||
timeline.addAggregatedEvent(edit2);
|
timeline.addAggregatedEvent(edit2);
|
||||||
expect(event.aggregatedEvents(timeline, RelationshipTypes.Edit),
|
expect(event.aggregatedEvents(timeline, RelationshipTypes.edit),
|
||||||
{edit1, edit2});
|
{edit1, edit2});
|
||||||
|
|
||||||
timeline.removeAggregatedEvent(event);
|
timeline.removeAggregatedEvent(event);
|
||||||
expect(
|
expect(
|
||||||
event.aggregatedEvents(timeline, RelationshipTypes.Edit), <Event>{});
|
event.aggregatedEvents(timeline, RelationshipTypes.edit), <Event>{});
|
||||||
});
|
});
|
||||||
test('getDisplayEvent', () {
|
test('getDisplayEvent', () {
|
||||||
var event = Event.fromJson({
|
var event = Event.fromJson({
|
||||||
|
|
@ -966,7 +966,7 @@ void main() {
|
||||||
},
|
},
|
||||||
'm.relates_to': {
|
'm.relates_to': {
|
||||||
'event_id': '\$source',
|
'event_id': '\$source',
|
||||||
'rel_type': RelationshipTypes.Edit,
|
'rel_type': RelationshipTypes.edit,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'event_id': '\$edit1',
|
'event_id': '\$edit1',
|
||||||
|
|
@ -984,7 +984,7 @@ void main() {
|
||||||
},
|
},
|
||||||
'm.relates_to': {
|
'm.relates_to': {
|
||||||
'event_id': '\$source',
|
'event_id': '\$source',
|
||||||
'rel_type': RelationshipTypes.Edit,
|
'rel_type': RelationshipTypes.edit,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'event_id': '\$edit2',
|
'event_id': '\$edit2',
|
||||||
|
|
@ -1002,7 +1002,7 @@ void main() {
|
||||||
},
|
},
|
||||||
'm.relates_to': {
|
'm.relates_to': {
|
||||||
'event_id': '\$source',
|
'event_id': '\$source',
|
||||||
'rel_type': RelationshipTypes.Edit,
|
'rel_type': RelationshipTypes.edit,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'event_id': '\$edit3',
|
'event_id': '\$edit3',
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import 'package:famedlysdk/famedlysdk.dart';
|
||||||
import 'fake_matrix_api.dart';
|
import 'fake_matrix_api.dart';
|
||||||
import 'fake_database.dart';
|
import 'fake_database.dart';
|
||||||
|
|
||||||
const SSSS_PASSPHRASE = 'nae7ahDiequ7ohniufah3ieS2je1thohX4xeeka7aixohsho9O';
|
const ssssPassphrase = 'nae7ahDiequ7ohniufah3ieS2je1thohX4xeeka7aixohsho9O';
|
||||||
const SSSS_KEY = 'EsT9 RzbW VhPW yqNp cC7j ViiW 5TZB LuY4 ryyv 9guN Ysmr WDPH';
|
const ssssKey = 'EsT9 RzbW VhPW yqNp cC7j ViiW 5TZB LuY4 ryyv 9guN Ysmr WDPH';
|
||||||
|
|
||||||
// key @test:fakeServer.notExisting
|
// key @test:fakeServer.notExisting
|
||||||
const pickledOlmAccount =
|
const pickledOlmAccount =
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,11 @@ void main() {
|
||||||
.getLocalizedString(MatrixDefaultLocalizations()),
|
.getLocalizedString(MatrixDefaultLocalizations()),
|
||||||
'Visible for all participants');
|
'Visible for all participants');
|
||||||
expect(
|
expect(
|
||||||
HistoryVisibility.world_readable
|
HistoryVisibility.worldReadable
|
||||||
.getLocalizedString(MatrixDefaultLocalizations()),
|
.getLocalizedString(MatrixDefaultLocalizations()),
|
||||||
'Visible for everyone');
|
'Visible for everyone');
|
||||||
expect(
|
expect(
|
||||||
GuestAccess.can_join.getLocalizedString(MatrixDefaultLocalizations()),
|
GuestAccess.canJoin.getLocalizedString(MatrixDefaultLocalizations()),
|
||||||
'Guests can join');
|
'Guests can join');
|
||||||
expect(
|
expect(
|
||||||
GuestAccess.forbidden
|
GuestAccess.forbidden
|
||||||
|
|
|
||||||
|
|
@ -603,10 +603,10 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('pushRuleState', () async {
|
test('pushRuleState', () async {
|
||||||
expect(room.pushRuleState, PushRuleState.mentions_only);
|
expect(room.pushRuleState, PushRuleState.mentionsOnly);
|
||||||
matrix.accountData['m.push_rules'].content['global']['override']
|
matrix.accountData['m.push_rules'].content['global']['override']
|
||||||
.add(matrix.accountData['m.push_rules'].content['global']['room'][0]);
|
.add(matrix.accountData['m.push_rules'].content['global']['room'][0]);
|
||||||
expect(room.pushRuleState, PushRuleState.dont_notify);
|
expect(room.pushRuleState, PushRuleState.dontNotify);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test call methods', () async {
|
test('Test call methods', () async {
|
||||||
|
|
@ -642,8 +642,8 @@ void main() {
|
||||||
|
|
||||||
test('setPushRuleState', () async {
|
test('setPushRuleState', () async {
|
||||||
await room.setPushRuleState(PushRuleState.notify);
|
await room.setPushRuleState(PushRuleState.notify);
|
||||||
await room.setPushRuleState(PushRuleState.dont_notify);
|
await room.setPushRuleState(PushRuleState.dontNotify);
|
||||||
await room.setPushRuleState(PushRuleState.mentions_only);
|
await room.setPushRuleState(PushRuleState.mentionsOnly);
|
||||||
await room.setPushRuleState(PushRuleState.notify);
|
await room.setPushRuleState(PushRuleState.notify);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -708,8 +708,8 @@ void main() {
|
||||||
'type': 'm.room.guest_access',
|
'type': 'm.room.guest_access',
|
||||||
'unsigned': {'age': 1234}
|
'unsigned': {'age': 1234}
|
||||||
}, room, 1432735824653.0));
|
}, room, 1432735824653.0));
|
||||||
expect(room.guestAccess, GuestAccess.can_join);
|
expect(room.guestAccess, GuestAccess.canJoin);
|
||||||
await room.setGuestAccess(GuestAccess.can_join);
|
await room.setGuestAccess(GuestAccess.canJoin);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('historyVisibility', () async {
|
test('historyVisibility', () async {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import 'package:famedlysdk/famedlysdk.dart';
|
||||||
import 'package:logger/logger.dart';
|
import 'package:logger/logger.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
const UPDATES = {
|
const updates = {
|
||||||
'empty': {
|
'empty': {
|
||||||
'next_batch': 'blah',
|
'next_batch': 'blah',
|
||||||
'account_data': {
|
'account_data': {
|
||||||
|
|
@ -128,7 +128,7 @@ const UPDATES = {
|
||||||
};
|
};
|
||||||
|
|
||||||
void testUpdates(bool Function(SyncUpdate s) test, Map<String, bool> expected) {
|
void testUpdates(bool Function(SyncUpdate s) test, Map<String, bool> expected) {
|
||||||
for (final update in UPDATES.entries) {
|
for (final update in updates.entries) {
|
||||||
var sync = SyncUpdate.fromJson(update.value);
|
var sync = SyncUpdate.fromJson(update.value);
|
||||||
expect(test(sync), expected[update.key]);
|
expect(test(sync), expected[update.key]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -432,7 +432,7 @@ void main() {
|
||||||
'event_id': 'transaction',
|
'event_id': 'transaction',
|
||||||
'origin_server_ts': testTimeStamp,
|
'origin_server_ts': testTimeStamp,
|
||||||
'unsigned': {
|
'unsigned': {
|
||||||
MessageSendingStatusKey: 0,
|
messageSendingStatusKey: 0,
|
||||||
'transaction_id': 'transaction',
|
'transaction_id': 'transaction',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -451,7 +451,7 @@ void main() {
|
||||||
'origin_server_ts': testTimeStamp,
|
'origin_server_ts': testTimeStamp,
|
||||||
'unsigned': {
|
'unsigned': {
|
||||||
'transaction_id': 'transaction',
|
'transaction_id': 'transaction',
|
||||||
MessageSendingStatusKey: 2,
|
messageSendingStatusKey: 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sortOrder: room.newSortOrder));
|
sortOrder: room.newSortOrder));
|
||||||
|
|
@ -469,7 +469,7 @@ void main() {
|
||||||
'origin_server_ts': testTimeStamp,
|
'origin_server_ts': testTimeStamp,
|
||||||
'unsigned': {
|
'unsigned': {
|
||||||
'transaction_id': 'transaction',
|
'transaction_id': 'transaction',
|
||||||
MessageSendingStatusKey: 1,
|
messageSendingStatusKey: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sortOrder: room.newSortOrder));
|
sortOrder: room.newSortOrder));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue