Merge branch 'soru/fallback-keys' into 'main'
feat: Add fallback keys support Closes #136 See merge request famedly/famedlysdk!653
This commit is contained in:
commit
0d8bddf708
|
|
@ -20,6 +20,7 @@ import 'dart:convert';
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:pedantic/pedantic.dart';
|
||||
import 'package:olm/olm.dart' as olm;
|
||||
|
||||
import '../famedlysdk.dart';
|
||||
import '../src/utils/run_in_root.dart';
|
||||
|
|
@ -68,13 +69,27 @@ class Encryption {
|
|||
_backgroundTasks(); // start the background tasks
|
||||
}
|
||||
|
||||
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() onUpdate}) => Bootstrap(
|
||||
encryption: this,
|
||||
onUpdate: onUpdate,
|
||||
);
|
||||
|
||||
void handleDeviceOneTimeKeysCount(Map<String, int> countJson) {
|
||||
runInRoot(() => olmManager.handleDeviceOneTimeKeysCount(countJson));
|
||||
void handleDeviceOneTimeKeysCount(
|
||||
Map<String, int> countJson, List<String> unusedFallbackKeyTypes) {
|
||||
runInRoot(() => olmManager.handleDeviceOneTimeKeysCount(
|
||||
countJson, unusedFallbackKeyTypes));
|
||||
}
|
||||
|
||||
void onSync() {
|
||||
|
|
|
|||
|
|
@ -138,10 +138,12 @@ class OlmManager {
|
|||
bool _uploadKeysLock = false;
|
||||
|
||||
/// Generates new one time keys, signs everything and upload it to the server.
|
||||
Future<bool> uploadKeys(
|
||||
{bool uploadDeviceKeys = false,
|
||||
Future<bool> uploadKeys({
|
||||
bool uploadDeviceKeys = false,
|
||||
int oldKeyCount = 0,
|
||||
bool updateDatabase = true}) async {
|
||||
bool updateDatabase = true,
|
||||
bool unusedFallbackKey = false,
|
||||
}) async {
|
||||
if (!enabled) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -152,10 +154,15 @@ class OlmManager {
|
|||
_uploadKeysLock = true;
|
||||
|
||||
try {
|
||||
final signedOneTimeKeys = <String, dynamic>{};
|
||||
int uploadedOneTimeKeysCount;
|
||||
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;
|
||||
final oldOTKsNeedingUpload = json
|
||||
.decode(_olmAccount.one_time_keys())['curve25519']
|
||||
.entries
|
||||
.length;
|
||||
// generate one-time keys
|
||||
// we generate 2/3rds of max, so that other keys people may still have can
|
||||
// still be used
|
||||
|
|
@ -166,19 +173,35 @@ class OlmManager {
|
|||
if (oneTimeKeysCount > 0) {
|
||||
_olmAccount.generate_one_time_keys(oneTimeKeysCount);
|
||||
}
|
||||
uploadedOneTimeKeysCount = oneTimeKeysCount + oldOTKsNeedingUpload;
|
||||
final Map<String, dynamic> oneTimeKeys =
|
||||
json.decode(_olmAccount.one_time_keys());
|
||||
|
||||
// now sign all the one-time keys
|
||||
final signedOneTimeKeys = <String, dynamic>{};
|
||||
for (final entry in oneTimeKeys['curve25519'].entries) {
|
||||
final key = entry.key;
|
||||
final value = entry.value;
|
||||
signedOneTimeKeys['signed_curve25519:$key'] = <String, dynamic>{};
|
||||
signedOneTimeKeys['signed_curve25519:$key'] = signJson({
|
||||
'key': value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
final signedFallbackKeys = <String, dynamic>{};
|
||||
if (encryption.isMinOlmVersion(3, 2, 0) && unusedFallbackKey == false) {
|
||||
// we don't have an unused fallback key uploaded....so let's change that!
|
||||
_olmAccount.generate_fallback_key();
|
||||
final fallbackKey = json.decode(_olmAccount.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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// and now generate the payload to upload
|
||||
final keysContent = <String, dynamic>{
|
||||
|
|
@ -217,28 +240,43 @@ class OlmManager {
|
|||
? MatrixDeviceKeys.fromJson(keysContent['device_keys'])
|
||||
: null,
|
||||
oneTimeKeys: signedOneTimeKeys,
|
||||
fallbackKeys: signedFallbackKeys,
|
||||
);
|
||||
// mark the OTKs as published and save that to datbase
|
||||
_olmAccount.mark_keys_as_published();
|
||||
if (updateDatabase) {
|
||||
await client.database?.updateClientKeys(pickledOlmAccount, client.id);
|
||||
}
|
||||
return response['signed_curve25519'] == oneTimeKeysCount;
|
||||
return (uploadedOneTimeKeysCount != null &&
|
||||
response['signed_curve25519'] == uploadedOneTimeKeysCount) ||
|
||||
uploadedOneTimeKeysCount == null;
|
||||
} finally {
|
||||
_uploadKeysLock = false;
|
||||
}
|
||||
}
|
||||
|
||||
void handleDeviceOneTimeKeysCount(Map<String, int> countJson) {
|
||||
void handleDeviceOneTimeKeysCount(
|
||||
Map<String, int> countJson, List<String> unusedFallbackKeyTypes) {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
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.
|
||||
if (countJson.containsKey('signed_curve25519') &&
|
||||
if ((countJson != null &&
|
||||
((countJson.containsKey('signed_curve25519') &&
|
||||
countJson['signed_curve25519'] <
|
||||
(_olmAccount.max_number_of_one_time_keys() / 2)) {
|
||||
uploadKeys(oldKeyCount: countJson['signed_curve25519']);
|
||||
(_olmAccount.max_number_of_one_time_keys() / 2)) ||
|
||||
!countJson.containsKey('signed_curve25519'))) ||
|
||||
(haveFallbackKeys &&
|
||||
unusedFallbackKeyTypes?.contains('signed_curve25519') == false)) {
|
||||
uploadKeys(
|
||||
oldKeyCount:
|
||||
countJson != null ? (countJson['signed_curve25519'] ?? 0) : null,
|
||||
unusedFallbackKey: haveFallbackKeys
|
||||
? unusedFallbackKeyTypes?.contains('signed_curve25519')
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1076,8 +1076,11 @@ class Client extends MatrixApi {
|
|||
if (sync.deviceLists != null) {
|
||||
await _handleDeviceListsEvents(sync.deviceLists);
|
||||
}
|
||||
if (sync.deviceOneTimeKeysCount != null && encryptionEnabled) {
|
||||
encryption.handleDeviceOneTimeKeysCount(sync.deviceOneTimeKeysCount);
|
||||
if ((sync.deviceUnusedFallbackKeyTypes != null ||
|
||||
sync.deviceOneTimeKeysCount != null) &&
|
||||
encryptionEnabled) {
|
||||
encryption.handleDeviceOneTimeKeysCount(
|
||||
sync.deviceOneTimeKeysCount, sync.deviceUnusedFallbackKeyTypes);
|
||||
}
|
||||
onSync.add(sync);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ dependencies:
|
|||
crypto: ^2.1.5
|
||||
base58check: ^1.0.1
|
||||
password_hash: ^2.0.0
|
||||
olm: ^1.2.1
|
||||
olm: ^1.3.0
|
||||
matrix_file_e2ee: ^1.0.5
|
||||
isolate: ^2.0.3
|
||||
logger: ^0.9.4
|
||||
matrix_api_lite: ^0.1.8
|
||||
matrix_api_lite: ^0.1.9
|
||||
|
||||
dev_dependencies:
|
||||
test: ^1.15.7
|
||||
|
|
|
|||
|
|
@ -61,16 +61,17 @@ void main() {
|
|||
toDeviceUpdateListFuture = matrix.onToDeviceEvent.stream.toList();
|
||||
|
||||
var olmEnabled = true;
|
||||
|
||||
test('Login', () async {
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().w('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
test('Login', () async {
|
||||
var presenceCounter = 0;
|
||||
var accountDataCounter = 0;
|
||||
matrix.onPresence.stream.listen((Presence data) {
|
||||
|
|
|
|||
|
|
@ -74,24 +74,25 @@ void main() {
|
|||
});
|
||||
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
client = await getClient();
|
||||
});
|
||||
|
||||
test('reject devices without self-signature', () async {
|
||||
if (!olmEnabled) return;
|
||||
var key = DeviceKeys.fromJson({
|
||||
'user_id': '@test:fakeServer.notExisting',
|
||||
'device_id': 'BADDEVICE',
|
||||
|
|
@ -128,6 +129,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('set blocked / verified', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key =
|
||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||
client.userDeviceKeys[client.userID].deviceKeys['UNSIGNEDDEVICE'] =
|
||||
|
|
@ -203,6 +205,7 @@ void main() {
|
|||
});
|
||||
|
||||
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);
|
||||
|
|
@ -238,6 +241,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('start verification', () async {
|
||||
if (!olmEnabled) return;
|
||||
var req = client
|
||||
.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||
.startVerification();
|
||||
|
|
@ -251,6 +255,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -31,16 +31,6 @@ void main() {
|
|||
group('Bootstrap', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Client client;
|
||||
Map<String, dynamic> oldSecret;
|
||||
|
|
@ -52,6 +42,16 @@ void main() {
|
|||
});
|
||||
|
||||
test('setup', () async {
|
||||
try {
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Bootstrap bootstrap;
|
||||
bootstrap = client.encryption.bootstrap(
|
||||
onUpdate: () async {
|
||||
|
|
@ -108,6 +108,7 @@ void main() {
|
|||
}, timeout: Timeout(Duration(minutes: 2)));
|
||||
|
||||
test('change recovery passphrase', () async {
|
||||
if (!olmEnabled) return;
|
||||
Bootstrap bootstrap;
|
||||
bootstrap = client.encryption.bootstrap(
|
||||
onUpdate: () async {
|
||||
|
|
@ -158,6 +159,7 @@ void main() {
|
|||
}, timeout: Timeout(Duration(minutes: 2)));
|
||||
|
||||
test('change passphrase with multiple keys', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.setAccountData(client.userID, 'foxes', oldSecret);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
|
||||
|
|
@ -212,6 +214,7 @@ void main() {
|
|||
}, timeout: Timeout(Duration(minutes: 2)));
|
||||
|
||||
test('setup new ssss', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.accountData.clear();
|
||||
Bootstrap bootstrap;
|
||||
bootstrap = client.encryption.bootstrap(
|
||||
|
|
@ -237,6 +240,7 @@ void main() {
|
|||
}, timeout: Timeout(Duration(minutes: 2)));
|
||||
|
||||
test('bad ssss', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.accountData.clear();
|
||||
await client.setAccountData(client.userID, 'foxes', oldSecret);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
|
|
@ -262,6 +266,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,28 +30,30 @@ void main() {
|
|||
group('Cross Signing', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
client = await getClient();
|
||||
});
|
||||
|
||||
test('basic things', () async {
|
||||
if (!olmEnabled) return;
|
||||
expect(client.encryption.crossSigning.enabled, true);
|
||||
});
|
||||
|
||||
test('selfSign', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key = client.userDeviceKeys[client.userID].masterKey;
|
||||
key.setDirectVerified(false);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
|
|
@ -65,6 +67,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('signable', () async {
|
||||
if (!olmEnabled) return;
|
||||
expect(
|
||||
client.encryption.crossSigning
|
||||
.signable([client.userDeviceKeys[client.userID].masterKey]),
|
||||
|
|
@ -86,6 +89,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('sign', () async {
|
||||
if (!olmEnabled) return;
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.crossSigning.sign([
|
||||
client.userDeviceKeys[client.userID].masterKey,
|
||||
|
|
@ -109,6 +113,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,16 +27,6 @@ void main() {
|
|||
group('Encrypt/Decrypt room message', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Client client;
|
||||
final roomId = '!726s6s6q:example.com';
|
||||
|
|
@ -45,11 +35,22 @@ void main() {
|
|||
final now = DateTime.now();
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
if (!olmEnabled) return;
|
||||
|
||||
client = await getClient();
|
||||
room = client.getRoomById(roomId);
|
||||
});
|
||||
|
||||
test('encrypt payload', () async {
|
||||
if (!olmEnabled) return;
|
||||
payload = await client.encryption.encryptGroupMessagePayload(roomId, {
|
||||
'msgtype': 'm.text',
|
||||
'text': 'Hello foxies!',
|
||||
|
|
@ -62,6 +63,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('decrypt payload', () async {
|
||||
if (!olmEnabled) return;
|
||||
final encryptedEvent = Event(
|
||||
type: EventTypes.Encrypted,
|
||||
content: payload,
|
||||
|
|
@ -78,6 +80,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('decrypt payload nocache', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.encryption.keyManager.clearInboundGroupSessions();
|
||||
final encryptedEvent = Event(
|
||||
type: EventTypes.Encrypted,
|
||||
|
|
@ -98,6 +101,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,16 +33,6 @@ void main() {
|
|||
group('Encrypt/Decrypt to-device messages', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Client client;
|
||||
var otherClient = Client('othertestclient',
|
||||
|
|
@ -51,6 +41,16 @@ void main() {
|
|||
Map<String, dynamic> payload;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
if (!olmEnabled) return;
|
||||
|
||||
client = await getClient();
|
||||
await client.abortSync();
|
||||
await otherClient.checkHomeserver('https://fakeserver.notexisting',
|
||||
|
|
@ -81,11 +81,13 @@ void main() {
|
|||
});
|
||||
|
||||
test('encryptToDeviceMessage', () async {
|
||||
if (!olmEnabled) return;
|
||||
payload = await otherClient.encryption
|
||||
.encryptToDeviceMessage([device], 'm.to_device', {'hello': 'foxies'});
|
||||
});
|
||||
|
||||
test('decryptToDeviceEvent', () async {
|
||||
if (!olmEnabled) return;
|
||||
final encryptedEvent = ToDeviceEvent(
|
||||
sender: '@othertest:fakeServer.notExisting',
|
||||
type: EventTypes.Encrypted,
|
||||
|
|
@ -98,6 +100,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('decryptToDeviceEvent nocache', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.encryption.olmManager.olmSessions.clear();
|
||||
payload = await otherClient.encryption.encryptToDeviceMessage(
|
||||
[device], 'm.to_device', {'hello': 'superfoxies'});
|
||||
|
|
@ -113,6 +116,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.dispose(closeDatabase: true);
|
||||
await otherClient.dispose(closeDatabase: true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -29,24 +29,25 @@ void main() {
|
|||
group('Key Manager', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
client = await getClient();
|
||||
});
|
||||
|
||||
test('handle new m.room_key', () async {
|
||||
if (!olmEnabled) return;
|
||||
final validSessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU';
|
||||
final validSenderKey = 'JBG7ZaPn54OBC7TuIEiylW3BZ+7WcGQhFBPB9pogbAg';
|
||||
final sessionKey =
|
||||
|
|
@ -94,6 +95,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('outbound group session', () async {
|
||||
if (!olmEnabled) return;
|
||||
final roomId = '!726s6s6q:example.com';
|
||||
expect(
|
||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||
|
|
@ -244,6 +246,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('inbound group session', () async {
|
||||
if (!olmEnabled) return;
|
||||
final roomId = '!726s6s6q:example.com';
|
||||
final sessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU';
|
||||
final senderKey = 'JBG7ZaPn54OBC7TuIEiylW3BZ+7WcGQhFBPB9pogbAg';
|
||||
|
|
@ -325,6 +328,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('setInboundGroupSession', () async {
|
||||
if (!olmEnabled) return;
|
||||
final session = olm.OutboundGroupSession();
|
||||
session.create();
|
||||
final inbound = olm.InboundGroupSession();
|
||||
|
|
@ -495,6 +499,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -42,20 +42,20 @@ void main() {
|
|||
group('Key Request', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
final validSessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU';
|
||||
final validSenderKey = 'JBG7ZaPn54OBC7TuIEiylW3BZ+7WcGQhFBPB9pogbAg';
|
||||
test('Create Request', () async {
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
final validSessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU';
|
||||
final validSenderKey = 'JBG7ZaPn54OBC7TuIEiylW3BZ+7WcGQhFBPB9pogbAg';
|
||||
test('Create Request', () async {
|
||||
var matrix = await getClient();
|
||||
final requestRoom = matrix.getRoomById('!726s6s6q:example.com');
|
||||
await matrix.encryption.keyManager.request(
|
||||
|
|
@ -83,6 +83,7 @@ void main() {
|
|||
await matrix.dispose(closeDatabase: true);
|
||||
});
|
||||
test('Reply To Request', () async {
|
||||
if (!olmEnabled) return;
|
||||
var matrix = await getClient();
|
||||
matrix.setUserId('@alice:example.com'); // we need to pretend to be alice
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
|
|
@ -277,6 +278,7 @@ void main() {
|
|||
await matrix.dispose(closeDatabase: true);
|
||||
});
|
||||
test('Receive shared keys', () async {
|
||||
if (!olmEnabled) return;
|
||||
var matrix = await getClient();
|
||||
final requestRoom = matrix.getRoomById('!726s6s6q:example.com');
|
||||
await matrix.encryption.keyManager.request(
|
||||
|
|
|
|||
|
|
@ -63,16 +63,6 @@ void main() {
|
|||
group('Key Verification', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
// key @othertest:fakeServer.notExisting
|
||||
const otherPickledOlmAccount =
|
||||
|
|
@ -82,6 +72,16 @@ void main() {
|
|||
Client client2;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
if (!olmEnabled) return;
|
||||
|
||||
client1 = await getClient();
|
||||
client2 = Client('othertestclient',
|
||||
httpClient: FakeMatrixApi(),
|
||||
|
|
@ -108,6 +108,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('Run emoji / number verification', () async {
|
||||
if (!olmEnabled) return;
|
||||
// for a full run we test in-room verification in a cleartext room
|
||||
// because then we can easily intercept the payloads and inject in the other client
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
|
|
@ -208,6 +209,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('ask SSSS start', () async {
|
||||
if (!olmEnabled) return;
|
||||
client1.userDeviceKeys[client1.userID].masterKey.setDirectVerified(true);
|
||||
await client1.encryption.ssss.clearCache();
|
||||
final req1 =
|
||||
|
|
@ -222,6 +224,7 @@ void main() {
|
|||
});
|
||||
|
||||
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);
|
||||
|
|
@ -326,6 +329,7 @@ void main() {
|
|||
});
|
||||
|
||||
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);
|
||||
|
|
@ -354,6 +358,7 @@ void main() {
|
|||
});
|
||||
|
||||
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);
|
||||
|
|
@ -414,6 +419,7 @@ void main() {
|
|||
});
|
||||
|
||||
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);
|
||||
|
|
@ -458,6 +464,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client1.dispose(closeDatabase: true);
|
||||
await client2.dispose(closeDatabase: true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,24 +30,25 @@ void main() {
|
|||
group('Olm Manager', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
client = await getClient();
|
||||
});
|
||||
|
||||
test('signatures', () async {
|
||||
if (!olmEnabled) return;
|
||||
final payload = <String, dynamic>{
|
||||
'fox': 'floof',
|
||||
};
|
||||
|
|
@ -59,6 +60,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('uploadKeys', () async {
|
||||
if (!olmEnabled) return;
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
final res =
|
||||
await client.encryption.olmManager.uploadKeys(uploadDeviceKeys: true);
|
||||
|
|
@ -68,22 +70,28 @@ 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['fallback_keys'] != null, true);
|
||||
expect(sent['fallback_keys'].keys.length, 1);
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
await client.encryption.olmManager.uploadKeys();
|
||||
sent = json.decode(
|
||||
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.uploadKeys(oldKeyCount: 20);
|
||||
await client.encryption.olmManager
|
||||
.uploadKeys(oldKeyCount: 20, unusedFallbackKey: true);
|
||||
sent = json.decode(
|
||||
FakeMatrixApi.calledEndpoints['/client/r0/keys/upload'].first);
|
||||
expect(sent['one_time_keys'].keys.length, 46);
|
||||
expect(sent['fallback_keys'].keys.length, 0);
|
||||
});
|
||||
|
||||
test('handleDeviceOneTimeKeysCount', () async {
|
||||
if (!olmEnabled) return;
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
client.encryption.olmManager
|
||||
.handleDeviceOneTimeKeysCount({'signed_curve25519': 20});
|
||||
.handleDeviceOneTimeKeysCount({'signed_curve25519': 20}, null);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.containsKey('/client/r0/keys/upload'),
|
||||
|
|
@ -91,7 +99,22 @@ void main() {
|
|||
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
client.encryption.olmManager
|
||||
.handleDeviceOneTimeKeysCount({'signed_curve25519': 70});
|
||||
.handleDeviceOneTimeKeysCount({'signed_curve25519': 70}, null);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.containsKey('/client/r0/keys/upload'),
|
||||
false);
|
||||
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
client.encryption.olmManager.handleDeviceOneTimeKeysCount(null, []);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.containsKey('/client/r0/keys/upload'),
|
||||
true);
|
||||
|
||||
FakeMatrixApi.calledEndpoints.clear();
|
||||
client.encryption.olmManager
|
||||
.handleDeviceOneTimeKeysCount(null, ['signed_curve25519']);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(
|
||||
FakeMatrixApi.calledEndpoints.containsKey('/client/r0/keys/upload'),
|
||||
|
|
@ -99,6 +122,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('restoreOlmSession', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.encryption.olmManager.olmSessions.clear();
|
||||
await client.encryption.olmManager
|
||||
.restoreOlmSession(client.userID, client.identityKey);
|
||||
|
|
@ -116,6 +140,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('startOutgoingOlmSessions', () async {
|
||||
if (!olmEnabled) return;
|
||||
// start an olm session.....with ourself!
|
||||
client.encryption.olmManager.olmSessions.clear();
|
||||
await client.encryption.olmManager.startOutgoingOlmSessions(
|
||||
|
|
@ -127,6 +152,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('replay to_device events', () async {
|
||||
if (!olmEnabled) return;
|
||||
final userId = '@alice:example.com';
|
||||
final deviceId = 'JLAFKJWSCS';
|
||||
final senderKey = 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8';
|
||||
|
|
@ -209,6 +235,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,16 +30,6 @@ void main() {
|
|||
group('Online Key Backup', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Client client;
|
||||
|
||||
|
|
@ -48,10 +38,21 @@ void main() {
|
|||
final senderKey = 'JBG7ZaPn54OBC7TuIEiylW3BZ+7WcGQhFBPB9pogbAg';
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
if (!olmEnabled) return;
|
||||
|
||||
client = await getClient();
|
||||
});
|
||||
|
||||
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();
|
||||
|
|
@ -61,6 +62,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('load key', () async {
|
||||
if (!olmEnabled) return;
|
||||
client.encryption.keyManager.clearInboundGroupSessions();
|
||||
await client.encryption.keyManager
|
||||
.request(client.getRoomById(roomId), sessionId, senderKey);
|
||||
|
|
@ -72,6 +74,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('upload key', () async {
|
||||
if (!olmEnabled) return;
|
||||
final session = olm.OutboundGroupSession();
|
||||
session.create();
|
||||
final inbound = olm.InboundGroupSession();
|
||||
|
|
@ -115,6 +118,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -46,29 +46,31 @@ void main() {
|
|||
group('SSSS', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
|
||||
Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
if (!olmEnabled) return;
|
||||
|
||||
Client client;
|
||||
|
||||
test('setupClient', () async {
|
||||
client = await getClient();
|
||||
});
|
||||
|
||||
test('basic things', () async {
|
||||
if (!olmEnabled) return;
|
||||
expect(client.encryption.ssss.defaultKeyId,
|
||||
'0FajDWYaM6wQ4O60OZnLvwZfsBNu4Bu3');
|
||||
});
|
||||
|
||||
test('encrypt / decrypt', () {
|
||||
if (!olmEnabled) return;
|
||||
final key = Uint8List.fromList(SecureRandom(32).bytes);
|
||||
|
||||
final enc = SSSS.encryptAes('secret foxies', key, 'name');
|
||||
|
|
@ -77,6 +79,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('store', () async {
|
||||
if (!olmEnabled) return;
|
||||
final handle = client.encryption.ssss.open();
|
||||
var failed = false;
|
||||
try {
|
||||
|
|
@ -113,6 +116,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('encode / decode recovery key', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key = Uint8List.fromList(SecureRandom(32).bytes);
|
||||
final encoded = SSSS.encodeRecoveryKey(key);
|
||||
final decoded = SSSS.decodeRecoveryKey(encoded);
|
||||
|
|
@ -124,6 +128,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('cache', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.encryption.ssss.clearCache();
|
||||
final handle =
|
||||
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);
|
||||
|
|
@ -157,6 +162,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('postUnlock', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.encryption.ssss.clearCache();
|
||||
client.userDeviceKeys[client.userID].masterKey.setDirectVerified(false);
|
||||
final handle =
|
||||
|
|
@ -181,6 +187,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('make share requests', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key =
|
||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||
key.setDirectVerified(true);
|
||||
|
|
@ -193,6 +200,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('answer to share requests', () async {
|
||||
if (!olmEnabled) return;
|
||||
var event = ToDeviceEvent(
|
||||
sender: client.userID,
|
||||
type: 'm.secret.request',
|
||||
|
|
@ -291,6 +299,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('receive share requests', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key =
|
||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||
key.setDirectVerified(true);
|
||||
|
|
@ -433,6 +442,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('request all', () async {
|
||||
if (!olmEnabled) return;
|
||||
final key =
|
||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||
key.setDirectVerified(true);
|
||||
|
|
@ -443,6 +453,7 @@ void main() {
|
|||
});
|
||||
|
||||
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;
|
||||
|
|
@ -455,6 +466,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('createKey', () async {
|
||||
if (!olmEnabled) return;
|
||||
// with passphrase
|
||||
var newKey = await client.encryption.ssss.createKey('test');
|
||||
expect(client.encryption.ssss.isKeyValid(newKey.keyId), true);
|
||||
|
|
@ -470,6 +482,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('dispose client', () async {
|
||||
if (!olmEnabled) return;
|
||||
await client.dispose(closeDatabase: true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -35,14 +35,6 @@ void main() {
|
|||
group('Event', () {
|
||||
Logs().level = Level.error;
|
||||
var olmEnabled = true;
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final id = '!4fsdfjisjf:server.abc';
|
||||
|
|
@ -68,6 +60,17 @@ void main() {
|
|||
var event = Event.fromJson(
|
||||
jsonObj, Room(id: '!localpart:server.abc', client: client));
|
||||
|
||||
test('setup', () async {
|
||||
try {
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
});
|
||||
|
||||
test('Create from json', () async {
|
||||
jsonObj.remove('status');
|
||||
jsonObj['content'] = json.decode(contentJson);
|
||||
|
|
|
|||
|
|
@ -35,19 +35,19 @@ void main() {
|
|||
var updateCount = 0;
|
||||
var insertList = <int>[];
|
||||
var olmEnabled = true;
|
||||
try {
|
||||
olm.init();
|
||||
olm.Account();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
|
||||
Client client;
|
||||
Room room;
|
||||
Timeline timeline;
|
||||
test('create stuff', () async {
|
||||
try {
|
||||
await olm.init();
|
||||
olm.get_library_version();
|
||||
} catch (e) {
|
||||
olmEnabled = false;
|
||||
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||
}
|
||||
Logs().i('[LibOlm] Enabled: $olmEnabled');
|
||||
client = await getClient();
|
||||
client.sendMessageTimeoutSeconds = 5;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue