diff --git a/lib/encryption/cross_signing.dart b/lib/encryption/cross_signing.dart index 685ebeea..f3949bc6 100644 --- a/lib/encryption/cross_signing.dart +++ b/lib/encryption/cross_signing.dart @@ -23,6 +23,7 @@ import 'package:olm/olm.dart' as olm; import '../famedlysdk.dart'; import 'encryption.dart'; +import 'ssss.dart'; class CrossSigning { final Encryption encryption; @@ -71,13 +72,21 @@ class CrossSigning { } Future selfSign( - {String passphrase, String recoveryKey, String keyOrPassphrase}) async { - final handle = encryption.ssss.open(EventTypes.CrossSigningMasterKey); - await handle.unlock( + {String passphrase, + String recoveryKey, + String keyOrPassphrase, + OpenSSSS openSsss}) async { + var handle = openSsss; + if (handle == null) { + handle = encryption.ssss.open(EventTypes.CrossSigningMasterKey); + await handle.unlock( passphrase: passphrase, recoveryKey: recoveryKey, - keyOrPassphrase: keyOrPassphrase); - await handle.maybeCacheAll(); + keyOrPassphrase: keyOrPassphrase, + postUnlock: false, + ); + await handle.maybeCacheAll(); + } final masterPrivateKey = base64.decode(await handle.getStored(EventTypes.CrossSigningMasterKey)); final keyObj = olm.PkSigning(); diff --git a/lib/encryption/ssss.dart b/lib/encryption/ssss.dart index e7972a34..248f233c 100644 --- a/lib/encryption/ssss.dart +++ b/lib/encryption/ssss.dart @@ -29,6 +29,7 @@ import 'package:password_hash/password_hash.dart'; import '../famedlysdk.dart'; import '../src/database/database.dart'; import '../src/utils/run_in_background.dart'; +import '../src/utils/run_in_root.dart'; import 'encryption.dart'; const CACHE_TYPES = { @@ -617,20 +618,32 @@ class OpenSSSS { Uint8List privateKey; bool get isUnlocked => privateKey != null; + bool get hasPassphrase => keyData.passphrase != null; String get recoveryKey => isUnlocked ? SSSS.encodeRecoveryKey(privateKey) : null; Future unlock( - {String passphrase, String recoveryKey, String keyOrPassphrase}) async { + {String passphrase, + String recoveryKey, + String keyOrPassphrase, + bool postUnlock = true}) async { if (keyOrPassphrase != null) { try { - await unlock(recoveryKey: keyOrPassphrase); + await unlock(recoveryKey: keyOrPassphrase, postUnlock: postUnlock); } catch (_) { - await unlock(passphrase: keyOrPassphrase); + if (hasPassphrase) { + await unlock(passphrase: keyOrPassphrase, postUnlock: postUnlock); + } else { + rethrow; + } } return; } else if (passphrase != null) { + if (!hasPassphrase) { + throw Exception( + 'Tried to unlock with passphrase while key does not have a passphrase'); + } privateKey = await runInBackground( _keyFromPassphrase, _KeyFromPassphraseArgs( @@ -647,6 +660,9 @@ class OpenSSSS { privateKey = null; throw Exception('Inalid key'); } + if (postUnlock) { + await runInRoot(() => _postUnlock()); + } } void setPrivateKey(Uint8List key) { @@ -671,6 +687,19 @@ class OpenSSSS { Future maybeCacheAll() async { await ssss.maybeCacheAll(keyId, privateKey); } + + Future _postUnlock() async { + // first try to cache all secrets that aren't cached yet + await maybeCacheAll(); + // now try to self-sign + if (ssss.encryption.crossSigning.enabled && ssss.client.isUnknownSession) { + try { + await ssss.encryption.crossSigning.selfSign(openSsss: this); + } catch (e, s) { + Logs().e('[SSSS] Failed to self-sign', e, s); + } + } + } } class _KeyFromPassphraseArgs { diff --git a/test/encryption/ssss_test.dart b/test/encryption/ssss_test.dart index 12541af3..efb8cd7f 100644 --- a/test/encryption/ssss_test.dart +++ b/test/encryption/ssss_test.dart @@ -124,9 +124,10 @@ void main() { }); test('cache', () async { + await client.encryption.ssss.clearCache(); final handle = client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning); - await handle.unlock(recoveryKey: SSSS_KEY); + await handle.unlock(recoveryKey: SSSS_KEY, postUnlock: false); expect( (await client.encryption.ssss .getCached(EventTypes.CrossSigningSelfSigning)) != @@ -155,6 +156,30 @@ void main() { true); }); + test('postUnlock', () async { + await client.encryption.ssss.clearCache(); + client.userDeviceKeys[client.userID].masterKey.setDirectVerified(false); + final handle = + client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning); + await handle.unlock(recoveryKey: SSSS_KEY); + expect( + (await client.encryption.ssss + .getCached(EventTypes.CrossSigningSelfSigning)) != + null, + true); + expect( + (await client.encryption.ssss + .getCached(EventTypes.CrossSigningUserSigning)) != + null, + true); + expect( + (await client.encryption.ssss.getCached(EventTypes.MegolmBackup)) != + null, + true); + expect( + client.userDeviceKeys[client.userID].masterKey.directVerified, true); + }); + test('make share requests', () async { final key = client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE']; @@ -245,6 +270,7 @@ void main() { final key = client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE']; key.setDirectVerified(false); + client.userDeviceKeys[client.userID].masterKey.setDirectVerified(false); event = ToDeviceEvent( sender: client.userID, type: 'm.secret.request',