refactor: Migrate olm account to vodozemac
This commit is contained in:
parent
98fcd683a6
commit
5fdcbf8006
|
|
@ -19,7 +19,7 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:olm/olm.dart' as olm;
|
||||
import 'package:vodozemac/vodozemac.dart' as vod;
|
||||
|
||||
import 'package:matrix/encryption/cross_signing.dart';
|
||||
import 'package:matrix/encryption/key_manager.dart';
|
||||
|
|
@ -87,18 +87,6 @@ class Encryption {
|
|||
if (!isDehydratedDevice) keyManager.startAutoUploadKeys();
|
||||
}
|
||||
|
||||
bool isMinOlmVersion(int major, int minor, int patch) {
|
||||
try {
|
||||
final version = olm.get_library_version();
|
||||
return version[0] > major ||
|
||||
(version[0] == major &&
|
||||
(version[1] > minor ||
|
||||
(version[1] == minor && version[2] >= patch)));
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Bootstrap bootstrap({void Function(Bootstrap)? onUpdate}) => Bootstrap(
|
||||
encryption: this,
|
||||
onUpdate: onUpdate,
|
||||
|
|
|
|||
|
|
@ -21,11 +21,12 @@ import 'dart:convert';
|
|||
import 'package:async/async.dart';
|
||||
import 'package:canonical_json/canonical_json.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:olm/olm.dart' as olm;
|
||||
import 'package:vodozemac/vodozemac.dart' as vod;
|
||||
|
||||
import 'package:matrix/encryption/encryption.dart';
|
||||
import 'package:matrix/encryption/utils/json_signature_check_extension.dart';
|
||||
import 'package:matrix/encryption/utils/olm_session.dart';
|
||||
import 'package:matrix/encryption/utils/pickle_key.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:matrix/msc_extensions/msc_3814_dehydrated_devices/api.dart';
|
||||
import 'package:matrix/src/utils/run_benchmarked.dart';
|
||||
|
|
@ -34,20 +35,24 @@ import 'package:matrix/src/utils/run_in_root.dart';
|
|||
class OlmManager {
|
||||
final Encryption encryption;
|
||||
Client get client => encryption.client;
|
||||
olm.Account? _olmAccount;
|
||||
vod.Account? _olmAccount;
|
||||
String? ourDeviceId;
|
||||
|
||||
/// 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;
|
||||
String? get pickledOlmAccount {
|
||||
return enabled
|
||||
? _olmAccount!.toPickleEncrypted(client.userID!.toPickleKey())
|
||||
: null;
|
||||
}
|
||||
|
||||
String? get fingerprintKey =>
|
||||
enabled ? json.decode(_olmAccount!.identity_keys())['ed25519'] : null;
|
||||
enabled ? _olmAccount!.identityKeys.ed25519.toBase64() : null;
|
||||
String? get identityKey =>
|
||||
enabled ? json.decode(_olmAccount!.identity_keys())['curve25519'] : null;
|
||||
enabled ? _olmAccount!.identityKeys.curve25519.toBase64() : null;
|
||||
|
||||
String? pickleOlmAccountWithKey(String key) =>
|
||||
enabled ? _olmAccount!.pickle(key) : null;
|
||||
enabled ? _olmAccount!.toPickleEncrypted(key.toPickleKey()) : null;
|
||||
|
||||
bool get enabled => _olmAccount != null;
|
||||
|
||||
|
|
@ -66,33 +71,31 @@ class OlmManager {
|
|||
}) async {
|
||||
ourDeviceId = deviceId;
|
||||
if (olmAccount == null) {
|
||||
try {
|
||||
await olm.init();
|
||||
_olmAccount = olm.Account();
|
||||
_olmAccount!.create();
|
||||
if (!await uploadKeys(
|
||||
uploadDeviceKeys: true,
|
||||
updateDatabase: false,
|
||||
dehydratedDeviceAlgorithm: dehydratedDeviceAlgorithm,
|
||||
dehydratedDevicePickleKey:
|
||||
dehydratedDeviceAlgorithm != null ? pickleKey : null,
|
||||
)) {
|
||||
throw ('Upload key failed');
|
||||
}
|
||||
} catch (_) {
|
||||
_olmAccount?.free();
|
||||
_olmAccount = null;
|
||||
rethrow;
|
||||
_olmAccount = vod.Account();
|
||||
if (!await uploadKeys(
|
||||
uploadDeviceKeys: true,
|
||||
updateDatabase: false,
|
||||
dehydratedDeviceAlgorithm: dehydratedDeviceAlgorithm,
|
||||
dehydratedDevicePickleKey:
|
||||
dehydratedDeviceAlgorithm != null ? pickleKey : null,
|
||||
)) {
|
||||
throw ('Upload key failed');
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await olm.init();
|
||||
_olmAccount = olm.Account();
|
||||
_olmAccount!.unpickle(pickleKey ?? client.userID!, olmAccount);
|
||||
} catch (_) {
|
||||
_olmAccount?.free();
|
||||
_olmAccount = null;
|
||||
rethrow;
|
||||
_olmAccount = vod.Account.fromPickleEncrypted(
|
||||
pickle: olmAccount,
|
||||
pickleKey: (pickleKey ?? client.userID!).toPickleKey(),
|
||||
);
|
||||
} catch (e) {
|
||||
Logs().d(
|
||||
'Unable to unpickle account in vodozemac format. Trying Olm format...',
|
||||
e,
|
||||
);
|
||||
_olmAccount = vod.Account.fromOlmPickleEncrypted(
|
||||
pickle: olmAccount,
|
||||
pickleKey: utf8.encode(pickleKey ?? client.userID!),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -115,7 +118,8 @@ class OlmManager {
|
|||
if (!payload['signatures'].containsKey(client.userID)) {
|
||||
payload['signatures'][client.userID] = <String, dynamic>{};
|
||||
}
|
||||
payload['signatures'][client.userID]['ed25519:$ourDeviceId'] = signature;
|
||||
payload['signatures'][client.userID]['ed25519:$ourDeviceId'] =
|
||||
signature.toBase64();
|
||||
if (unsigned != null) {
|
||||
payload['unsigned'] = unsigned;
|
||||
}
|
||||
|
|
@ -123,13 +127,13 @@ class OlmManager {
|
|||
}
|
||||
|
||||
String signString(String s) {
|
||||
return _olmAccount!.sign(s);
|
||||
return _olmAccount!.sign(s).toBase64();
|
||||
}
|
||||
|
||||
bool _uploadKeysLock = false;
|
||||
CancelableOperation<Map<String, int>>? currentUpload;
|
||||
|
||||
int? get maxNumberOfOneTimeKeys => _olmAccount?.max_number_of_one_time_keys();
|
||||
int? get maxNumberOfOneTimeKeys => _olmAccount?.maxNumberOfOneTimeKeys;
|
||||
|
||||
/// Generates new one time keys, signs everything and upload it to the server.
|
||||
/// If `retry` is > 0, the request will be retried with new OTKs on upload failure.
|
||||
|
|
@ -158,26 +162,24 @@ class OlmManager {
|
|||
if (oldKeyCount != null) {
|
||||
// check if we have OTKs that still need uploading. If we do, we don't try to generate new ones,
|
||||
// instead we try to upload the old ones first
|
||||
final oldOTKsNeedingUpload = json
|
||||
.decode(olmAccount.one_time_keys())['curve25519']
|
||||
.entries
|
||||
.length as int;
|
||||
final oldOTKsNeedingUpload = olmAccount.oneTimeKeys.length;
|
||||
|
||||
// generate one-time keys
|
||||
// we generate 2/3rds of max, so that other keys people may still have can
|
||||
// still be used
|
||||
final oneTimeKeysCount =
|
||||
(olmAccount.max_number_of_one_time_keys() * 2 / 3).floor() -
|
||||
(olmAccount.maxNumberOfOneTimeKeys * 2 / 3).floor() -
|
||||
oldKeyCount -
|
||||
oldOTKsNeedingUpload;
|
||||
if (oneTimeKeysCount > 0) {
|
||||
olmAccount.generate_one_time_keys(oneTimeKeysCount);
|
||||
olmAccount.generateOneTimeKeys(oneTimeKeysCount);
|
||||
}
|
||||
uploadedOneTimeKeysCount = oneTimeKeysCount + oldOTKsNeedingUpload;
|
||||
}
|
||||
|
||||
if (encryption.isMinOlmVersion(3, 2, 7) && unusedFallbackKey == false) {
|
||||
if (unusedFallbackKey == false) {
|
||||
// we don't have an unused fallback key uploaded....so let's change that!
|
||||
olmAccount.generate_fallback_key();
|
||||
olmAccount.generateFallbackKey();
|
||||
}
|
||||
|
||||
// we save the generated OTKs into the database.
|
||||
|
|
@ -199,38 +201,32 @@ class OlmManager {
|
|||
};
|
||||
|
||||
if (uploadDeviceKeys) {
|
||||
final Map<String, dynamic> keys =
|
||||
json.decode(olmAccount.identity_keys());
|
||||
for (final entry in keys.entries) {
|
||||
final algorithm = entry.key;
|
||||
final value = entry.value;
|
||||
deviceKeys['keys']['$algorithm:$ourDeviceId'] = value;
|
||||
}
|
||||
final keys = olmAccount.identityKeys;
|
||||
deviceKeys['keys']['curve25519:$ourDeviceId'] =
|
||||
keys.curve25519.toBase64();
|
||||
deviceKeys['keys']['ed25519:$ourDeviceId'] = keys.ed25519.toBase64();
|
||||
deviceKeys = signJson(deviceKeys);
|
||||
}
|
||||
|
||||
// now sign all the one-time keys
|
||||
for (final entry
|
||||
in json.decode(olmAccount.one_time_keys())['curve25519'].entries) {
|
||||
for (final entry in olmAccount.oneTimeKeys.entries) {
|
||||
final key = entry.key;
|
||||
final value = entry.value;
|
||||
final value = entry.value.toBase64();
|
||||
signedOneTimeKeys['signed_curve25519:$key'] = signJson({
|
||||
'key': value,
|
||||
});
|
||||
}
|
||||
|
||||
final signedFallbackKeys = <String, dynamic>{};
|
||||
if (encryption.isMinOlmVersion(3, 2, 7)) {
|
||||
final fallbackKey = json.decode(olmAccount.unpublished_fallback_key());
|
||||
// now sign all the fallback keys
|
||||
for (final entry in fallbackKey['curve25519'].entries) {
|
||||
final key = entry.key;
|
||||
final value = entry.value;
|
||||
signedFallbackKeys['signed_curve25519:$key'] = signJson({
|
||||
'key': value,
|
||||
'fallback': true,
|
||||
});
|
||||
}
|
||||
final fallbackKey = olmAccount.fallbackKey;
|
||||
// now sign all the fallback keys
|
||||
for (final entry in fallbackKey.entries) {
|
||||
final key = entry.key;
|
||||
final value = entry.value.toBase64();
|
||||
signedFallbackKeys['signed_curve25519:$key'] = signJson({
|
||||
'key': value,
|
||||
'fallback': true,
|
||||
});
|
||||
}
|
||||
|
||||
if (signedFallbackKeys.isEmpty &&
|
||||
|
|
@ -281,7 +277,7 @@ class OlmManager {
|
|||
}
|
||||
|
||||
// mark the OTKs as published and save that to datbase
|
||||
olmAccount.mark_keys_as_published();
|
||||
olmAccount.markKeysAsPublished();
|
||||
if (updateDatabase) {
|
||||
await encryption.olmDatabase?.updateClientKeys(pickledOlmAccount!);
|
||||
}
|
||||
|
|
@ -301,17 +297,14 @@ class OlmManager {
|
|||
Logs().w('Rotating otks because upload failed', exception);
|
||||
for (final otk in signedOneTimeKeys.values) {
|
||||
// Keys can only be removed by creating a session...
|
||||
final session = olm.Session();
|
||||
try {
|
||||
final String identity =
|
||||
json.decode(olmAccount.identity_keys())['curve25519'];
|
||||
final key = otk.tryGet<String>('key');
|
||||
if (key != null) {
|
||||
session.create_outbound(_olmAccount!, identity, key);
|
||||
olmAccount.remove_one_time_keys(session);
|
||||
}
|
||||
} finally {
|
||||
session.free();
|
||||
|
||||
final identity = olmAccount.identityKeys.curve25519.toBase64();
|
||||
final key = otk.tryGet<String>('key');
|
||||
if (key != null) {
|
||||
olmAccount.createOutboundSession(
|
||||
identityKey: vod.Curve25519PublicKey.fromBase64(identity),
|
||||
oneTimeKey: vod.Curve25519PublicKey.fromBase64(key),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -342,7 +335,6 @@ class OlmManager {
|
|||
|
||||
await _otkUpdateDedup.fetch(
|
||||
() => runBenchmarked('handleOtkUpdate', () async {
|
||||
final haveFallbackKeys = encryption.isMinOlmVersion(3, 2, 0);
|
||||
// Check if there are at least half of max_number_of_one_time_keys left on the server
|
||||
// and generate and upload more if not.
|
||||
|
||||
|
|
@ -357,7 +349,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()) {
|
||||
if (keyCount > _olmAccount!.maxNumberOfOneTimeKeys) {
|
||||
final requestingKeysFrom = {
|
||||
client.userID!: {ourDeviceId!: 'signed_curve25519'},
|
||||
};
|
||||
|
|
@ -365,14 +357,13 @@ class OlmManager {
|
|||
}
|
||||
|
||||
// Only upload keys if they are less than half of the max or we have no unused fallback key
|
||||
if (keyCount < (_olmAccount!.max_number_of_one_time_keys() / 2) ||
|
||||
if (keyCount < (_olmAccount!.maxNumberOfOneTimeKeys / 2) ||
|
||||
!unusedFallbackKey) {
|
||||
await uploadKeys(
|
||||
oldKeyCount:
|
||||
keyCount < (_olmAccount!.max_number_of_one_time_keys() / 2)
|
||||
? keyCount
|
||||
: null,
|
||||
unusedFallbackKey: haveFallbackKeys ? unusedFallbackKey : null,
|
||||
oldKeyCount: keyCount < (_olmAccount!.maxNumberOfOneTimeKeys / 2)
|
||||
? keyCount
|
||||
: null,
|
||||
unusedFallbackKey: unusedFallbackKey,
|
||||
);
|
||||
}
|
||||
}),
|
||||
|
|
@ -449,9 +440,12 @@ class OlmManager {
|
|||
if (session.session == null) {
|
||||
continue;
|
||||
}
|
||||
if (type == 0 && session.session!.matches_inbound(body)) {
|
||||
if (type == 0) {
|
||||
try {
|
||||
plaintext = session.session!.decrypt(type, body);
|
||||
plaintext = session.session!.decrypt(
|
||||
messageType: type,
|
||||
ciphertext: body,
|
||||
);
|
||||
} catch (e) {
|
||||
// The message was encrypted during this session, but is unable to decrypt
|
||||
throw DecryptException(
|
||||
|
|
@ -463,7 +457,10 @@ class OlmManager {
|
|||
break;
|
||||
} else if (type == 1) {
|
||||
try {
|
||||
plaintext = session.session!.decrypt(type, body);
|
||||
plaintext = session.session!.decrypt(
|
||||
messageType: type,
|
||||
ciphertext: body,
|
||||
);
|
||||
await updateSessionUsage(session);
|
||||
break;
|
||||
} catch (_) {
|
||||
|
|
@ -477,26 +474,27 @@ class OlmManager {
|
|||
}
|
||||
|
||||
if (plaintext == null) {
|
||||
final newSession = olm.Session();
|
||||
try {
|
||||
newSession.create_inbound_from(_olmAccount!, senderKey, body);
|
||||
_olmAccount!.remove_one_time_keys(newSession);
|
||||
await encryption.olmDatabase?.updateClientKeys(pickledOlmAccount!);
|
||||
final result = _olmAccount!.createInboundSession(
|
||||
theirIdentityKey: vod.Curve25519PublicKey.fromBase64(senderKey),
|
||||
preKeyMessageBase64: body,
|
||||
);
|
||||
plaintext = result.plaintext;
|
||||
final newSession = result.session;
|
||||
|
||||
plaintext = newSession.decrypt(type, body);
|
||||
await encryption.olmDatabase?.updateClientKeys(pickledOlmAccount!);
|
||||
|
||||
await storeOlmSession(
|
||||
OlmSession(
|
||||
key: client.userID!,
|
||||
identityKey: senderKey,
|
||||
sessionId: newSession.session_id(),
|
||||
sessionId: newSession.sessionId,
|
||||
session: newSession,
|
||||
lastReceived: DateTime.now(),
|
||||
),
|
||||
);
|
||||
await updateSessionUsage();
|
||||
} catch (e) {
|
||||
newSession.free();
|
||||
throw DecryptException(DecryptException.decryptionFailed, e.toString());
|
||||
}
|
||||
}
|
||||
|
|
@ -660,25 +658,25 @@ class OlmManager {
|
|||
continue;
|
||||
}
|
||||
Logs().v('[OlmManager] Starting session with $userId:$deviceId');
|
||||
final session = olm.Session();
|
||||
try {
|
||||
session.create_outbound(
|
||||
_olmAccount!,
|
||||
identityKey,
|
||||
deviceKey.tryGet<String>('key')!,
|
||||
final session = _olmAccount!.createOutboundSession(
|
||||
identityKey: vod.Curve25519PublicKey.fromBase64(identityKey),
|
||||
oneTimeKey: vod.Curve25519PublicKey.fromBase64(
|
||||
deviceKey.tryGet<String>('key')!,
|
||||
),
|
||||
);
|
||||
|
||||
await storeOlmSession(
|
||||
OlmSession(
|
||||
key: client.userID!,
|
||||
identityKey: identityKey,
|
||||
sessionId: session.session_id(),
|
||||
sessionId: session.sessionId,
|
||||
session: session,
|
||||
lastReceived:
|
||||
DateTime.now(), // we want to use a newly created session
|
||||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
session.free();
|
||||
Logs()
|
||||
.e('[LibOlm] Could not create new outbound olm session', e, s);
|
||||
}
|
||||
|
|
@ -733,8 +731,8 @@ class OlmManager {
|
|||
'ciphertext': <String, dynamic>{},
|
||||
};
|
||||
encryptedBody['ciphertext'][device.curve25519Key] = {
|
||||
'type': encryptResult.type,
|
||||
'body': encryptResult.body,
|
||||
'type': encryptResult.messageType,
|
||||
'body': encryptResult.ciphertext,
|
||||
};
|
||||
return encryptedBody;
|
||||
}
|
||||
|
|
@ -820,13 +818,6 @@ class OlmManager {
|
|||
|
||||
Future<void> dispose() async {
|
||||
await currentUpload?.cancel();
|
||||
for (final sessions in olmSessions.values) {
|
||||
for (final sess in sessions) {
|
||||
sess.dispose();
|
||||
}
|
||||
}
|
||||
_olmAccount?.free();
|
||||
_olmAccount = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,17 +16,20 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'package:olm/olm.dart' as olm;
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:vodozemac/vodozemac.dart' as vod;
|
||||
|
||||
import 'package:matrix/encryption/utils/pickle_key.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
class OlmSession {
|
||||
String identityKey;
|
||||
String? sessionId;
|
||||
olm.Session? session;
|
||||
vod.Session? session;
|
||||
DateTime? lastReceived;
|
||||
final String key;
|
||||
String? get pickledSession => session?.pickle(key);
|
||||
String? get pickledSession => session?.toPickleEncrypted(key.toPickleKey());
|
||||
|
||||
bool get isValid => session != null;
|
||||
|
||||
|
|
@ -40,21 +43,24 @@ class OlmSession {
|
|||
|
||||
OlmSession.fromJson(Map<String, dynamic> dbEntry, this.key)
|
||||
: identityKey = dbEntry['identity_key'] ?? '' {
|
||||
session = olm.Session();
|
||||
try {
|
||||
session!.unpickle(key, dbEntry['pickle']);
|
||||
try {
|
||||
session = vod.Session.fromPickleEncrypted(
|
||||
pickleKey: key.toPickleKey(),
|
||||
pickle: dbEntry['pickle'],
|
||||
);
|
||||
} catch (_) {
|
||||
session = vod.Session.fromOlmPickleEncrypted(
|
||||
pickleKey: utf8.encode(key),
|
||||
pickle: dbEntry['pickle'],
|
||||
);
|
||||
}
|
||||
sessionId = dbEntry['session_id'];
|
||||
lastReceived =
|
||||
DateTime.fromMillisecondsSinceEpoch(dbEntry['last_received'] ?? 0);
|
||||
assert(sessionId == session!.session_id());
|
||||
assert(sessionId == session!.sessionId);
|
||||
} catch (e, s) {
|
||||
Logs().e('[LibOlm] Could not unpickle olm session', e, s);
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
session?.free();
|
||||
session = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import 'package:async/async.dart';
|
|||
import 'package:collection/collection.dart' show IterableExtension;
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mime/mime.dart';
|
||||
import 'package:olm/olm.dart' as olm;
|
||||
import 'package:random_string/random_string.dart';
|
||||
|
||||
import 'package:matrix/encryption.dart';
|
||||
|
|
@ -2102,9 +2101,6 @@ class Client extends MatrixApi {
|
|||
|
||||
await encryption?.dispose();
|
||||
try {
|
||||
// make sure to throw an exception if libolm doesn't exist
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
_encryption = Encryption(client: this);
|
||||
} catch (e) {
|
||||
Logs().e('Error initializing encryption $e');
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import 'package:collection/collection.dart';
|
|||
import 'package:olm/olm.dart' as olm;
|
||||
import 'package:path/path.dart' show join;
|
||||
import 'package:test/test.dart';
|
||||
import 'package:vodozemac/vodozemac.dart' as vod;
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:matrix/src/utils/client_init_exception.dart';
|
||||
|
|
@ -36,7 +35,7 @@ import 'fake_database.dart';
|
|||
void main() {
|
||||
// key @test:fakeServer.notExisting
|
||||
const pickledOlmAccount =
|
||||
'N2v1MkIFGcl0mQpo2OCwSopxPQJ0wnl7oe7PKiT4141AijfdTIhRu+ceXzXKy3Kr00nLqXtRv7kid6hU4a+V0rfJWLL0Y51+3Rp/ORDVnQy+SSeo6Fn4FHcXrxifJEJ0djla5u98fBcJ8BSkhIDmtXRPi5/oJAvpiYn+8zMjFHobOeZUAxYR0VfQ9JzSYBsSovoQ7uFkNks1M4EDUvHtuyg3RxViwdNxs3718fyAqQ/VSwbXsY0Nl+qQbF+nlVGHenGqk5SuNl1P6e1PzZxcR0IfXA94Xij1Ob5gDv5YH4UCn9wRMG0abZsQP0YzpDM0FLaHSCyo9i5JD/vMlhH+nZWrgAzPPCTNGYewNV8/h3c+VyJh8ZTx/fVi6Yq46Fv+27Ga2ETRZ3Qn+Oyx6dLBjnBZ9iUvIhqpe2XqaGA1PopOz8iDnaZitw';
|
||||
'huxcPifHlyiQsX7cZeMMITbka3hLeUT3ss6DLL6dV7knaD4wgAYK6gcWknkixnX8C5KMIyxzytxiNqAOhDFRE5NsET8hr2dQ8OvXX7M95eQ7/3dPi7FkPUIbvneTSGgJYNDxJdHsDJ8OBHZ3BoqUJFDbTzFfVJjEzN4G9XQwPDafZ2p5WyerOK8Twj/rvk5N+ERmkt1XgVLQl66we/BO1ugTeM3YpDHm5lTzFUitJGTIuuONsKG9mmzdAmVUJ9YIrSxwmOBdegbGA+LAl5acg5VOol3KxRgZUMJQRQ58zpBAs72oauHizv1QVoQ7uIUiCUeb9lym+TEjmApvhru/1CPHU90K5jHNZ57wb/4V9VsqBWuoNibzDWG35YTFLcx0o+1lrCIjm1QjuC0777G+L1HNw5wnppV3z/k0YujjuPS3wvOA30TjHg';
|
||||
const identityKey = '7rvl3jORJkBiK4XX1e5TnGnqz068XfYJ0W++Ml63rgk';
|
||||
const fingerprintKey = 'gjL//fyaFHADt9KBADGag8g7F8Up78B/K1zXeiEPLJo';
|
||||
|
||||
|
|
@ -1752,7 +1751,10 @@ void main() {
|
|||
expect(error.homeserver, Uri.parse('https://test.server'));
|
||||
expect(error.olmAccount, 'abcd');
|
||||
expect(error.userId, '@user:server');
|
||||
expect(error.toString(), 'Exception: BAD_ACCOUNT_KEY');
|
||||
expect(
|
||||
error.originalException.runtimeType.toString(),
|
||||
'AnyhowException',
|
||||
);
|
||||
}
|
||||
await customClient.dispose(closeDatabase: true);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -25,10 +25,8 @@ import '../fake_client.dart';
|
|||
import '../fake_database.dart';
|
||||
|
||||
void main() async {
|
||||
// key @othertest:fakeServer.notExisting
|
||||
const otherPickledOlmAccount =
|
||||
'VWhVApbkcilKAEGppsPDf9nNVjaK8/IxT3asSR0sYg0S5KgbfE8vXEPwoiKBX2cEvwX3OessOBOkk+ZE7TTbjlrh/KEd31p8Wo+47qj0AP+Ky+pabnhi+/rTBvZy+gfzTqUfCxZrkzfXI9Op4JnP6gYmy7dVX2lMYIIs9WCO1jcmIXiXum5jnfXu1WLfc7PZtO2hH+k9CDKosOFaXRBmsu8k/BGXPSoWqUpvu6WpEG9t5STk4FeAzA';
|
||||
final database = await getDatabase();
|
||||
|
||||
group('Encrypt/Decrypt to-device messages', tags: 'olm', () {
|
||||
Logs().level = Level.error;
|
||||
|
||||
|
|
@ -64,7 +62,6 @@ void main() async {
|
|||
newHomeserver: otherClient.homeserver,
|
||||
newDeviceName: 'Text Matrix Client',
|
||||
newDeviceID: 'FOXDEVICE',
|
||||
newOlmAccount: otherPickledOlmAccount,
|
||||
);
|
||||
await otherClient.abortSync();
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ void main() async {
|
|||
|
||||
// key @othertest:fakeServer.notExisting
|
||||
const otherPickledOlmAccount =
|
||||
'VWhVApbkcilKAEGppsPDf9nNVjaK8/IxT3asSR0sYg0S5KgbfE8vXEPwoiKBX2cEvwX3OessOBOkk+ZE7TTbjlrh/KEd31p8Wo+47qj0AP+Ky+pabnhi+/rTBvZy+gfzTqUfCxZrkzfXI9Op4JnP6gYmy7dVX2lMYIIs9WCO1jcmIXiXum5jnfXu1WLfc7PZtO2hH+k9CDKosOFaXRBmsu8k/BGXPSoWqUpvu6WpEG9t5STk4FeAzA';
|
||||
'0aFMkSgJhj0kVLxVnactRpl3L2kgIR8bAqICFtDkvp/mkinITZjr1Vh6Jy9FmJzvhLfFUtjU2j/2bqrFn61CSrvRbRaLP6rCFegGJHNGpVfw+c24NthCwGF/SN10aPjPo6yQ3er9bc42I6AmJz5HgyfU6C4bE+LdWrML93C0iEnmQN/SYHnS1KHPXNl6NpFGITggbZQ9jwHOFILWo8wzJ4iqlJtMrNaOOLAAB7By7Fbxl4xoNz2K+w';
|
||||
|
||||
late Client client1;
|
||||
late Client client2;
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ void main() {
|
|||
);
|
||||
expect(sent['device_keys'] != null, true);
|
||||
expect(sent['one_time_keys'] != null, true);
|
||||
expect(sent['one_time_keys'].keys.length, 66);
|
||||
expect(sent['one_time_keys'].keys.length, 33);
|
||||
expect(sent['fallback_keys'] != null, true);
|
||||
expect(sent['fallback_keys'].keys.length, 1);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
|
|
@ -83,7 +83,7 @@ void main() {
|
|||
sent = json.decode(
|
||||
FakeMatrixApi.calledEndpoints['/client/v3/keys/upload']!.first,
|
||||
);
|
||||
expect(sent['one_time_keys'].keys.length, 46);
|
||||
expect(sent['one_time_keys'].keys.length, 13);
|
||||
expect(sent['fallback_keys'].keys.length, 0);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import 'dart:convert';
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:vodozemac/vodozemac.dart' as vod;
|
||||
|
||||
import 'package:matrix/encryption.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
|
@ -276,6 +277,15 @@ void main() async {
|
|||
});
|
||||
|
||||
test('sendAgain', () async {
|
||||
try {
|
||||
vodInit ??= vod.init(
|
||||
wasmPath: './pkg/',
|
||||
libraryPath: './rust/target/debug/',
|
||||
);
|
||||
await vodInit;
|
||||
} catch (_) {
|
||||
Logs().d('Encryption via Vodozemac not enabled');
|
||||
}
|
||||
final matrix = Client(
|
||||
'testclient',
|
||||
httpClient: FakeMatrixApi(),
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:vodozemac/vodozemac.dart' as vod;
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'fake_database.dart';
|
||||
|
||||
const ssssPassphrase = 'nae7ahDiequ7ohniufah3ieS2je1thohX4xeeka7aixohsho9O';
|
||||
|
|
@ -25,7 +26,7 @@ const ssssKey = 'EsT9 RzbW VhPW yqNp cC7j ViiW 5TZB LuY4 ryyv 9guN Ysmr WDPH';
|
|||
|
||||
// key @test:fakeServer.notExisting
|
||||
const pickledOlmAccount =
|
||||
'N2v1MkIFGcl0mQpo2OCwSopxPQJ0wnl7oe7PKiT4141AijfdTIhRu+ceXzXKy3Kr00nLqXtRv7kid6hU4a+V0rfJWLL0Y51+3Rp/ORDVnQy+SSeo6Fn4FHcXrxifJEJ0djla5u98fBcJ8BSkhIDmtXRPi5/oJAvpiYn+8zMjFHobOeZUAxYR0VfQ9JzSYBsSovoQ7uFkNks1M4EDUvHtuyg3RxViwdNxs3718fyAqQ/VSwbXsY0Nl+qQbF+nlVGHenGqk5SuNl1P6e1PzZxcR0IfXA94Xij1Ob5gDv5YH4UCn9wRMG0abZsQP0YzpDM0FLaHSCyo9i5JD/vMlhH+nZWrgAzPPCTNGYewNV8/h3c+VyJh8ZTx/fVi6Yq46Fv+27Ga2ETRZ3Qn+Oyx6dLBjnBZ9iUvIhqpe2XqaGA1PopOz8iDnaZitw';
|
||||
'huxcPifHlyiQsX7cZeMMITbka3hLeUT3ss6DLL6dV7knaD4wgAYK6gcWknkixnX8C5KMIyxzytxiNqAOhDFRE5NsET8hr2dQ8OvXX7M95eQ7/3dPi7FkPUIbvneTSGgJYNDxJdHsDJ8OBHZ3BoqUJFDbTzFfVJjEzN4G9XQwPDafZ2p5WyerOK8Twj/rvk5N+ERmkt1XgVLQl66we/BO1ugTeM3YpDHm5lTzFUitJGTIuuONsKG9mmzdAmVUJ9YIrSxwmOBdegbGA+LAl5acg5VOol3KxRgZUMJQRQ58zpBAs72oauHizv1QVoQ7uIUiCUeb9lym+TEjmApvhru/1CPHU90K5jHNZ57wb/4V9VsqBWuoNibzDWG35YTFLcx0o+1lrCIjm1QjuC0777G+L1HNw5wnppV3z/k0YujjuPS3wvOA30TjHg';
|
||||
|
||||
Future? vodInit;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import 'dart:math';
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:vodozemac/vodozemac.dart' as vod;
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'fake_client.dart';
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:vodozemac/vodozemac.dart' as vod;
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'fake_database.dart';
|
||||
|
|
@ -27,7 +28,17 @@ void main() async {
|
|||
late Client client;
|
||||
late Room room;
|
||||
late User user1, user2;
|
||||
Future? vodInit;
|
||||
setUp(() async {
|
||||
try {
|
||||
vodInit ??= vod.init(
|
||||
wasmPath: './pkg/',
|
||||
libraryPath: './rust/target/debug/',
|
||||
);
|
||||
await vodInit;
|
||||
} catch (_) {
|
||||
Logs().d('Encryption via Vodozemac not enabled');
|
||||
}
|
||||
client = Client(
|
||||
'testclient',
|
||||
httpClient: FakeMatrixApi(),
|
||||
|
|
|
|||
Loading…
Reference in New Issue