Merge branch 'soru/auto-selfsign' into 'main'
feat: Auto-selfsign and auto-cache when opening ssss keys See merge request famedly/famedlysdk!650
This commit is contained in:
commit
1f7e517dbf
|
|
@ -23,6 +23,7 @@ import 'package:olm/olm.dart' as olm;
|
||||||
|
|
||||||
import '../famedlysdk.dart';
|
import '../famedlysdk.dart';
|
||||||
import 'encryption.dart';
|
import 'encryption.dart';
|
||||||
|
import 'ssss.dart';
|
||||||
|
|
||||||
class CrossSigning {
|
class CrossSigning {
|
||||||
final Encryption encryption;
|
final Encryption encryption;
|
||||||
|
|
@ -71,13 +72,21 @@ class CrossSigning {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> selfSign(
|
Future<void> selfSign(
|
||||||
{String passphrase, String recoveryKey, String keyOrPassphrase}) async {
|
{String passphrase,
|
||||||
final handle = encryption.ssss.open(EventTypes.CrossSigningMasterKey);
|
String recoveryKey,
|
||||||
await handle.unlock(
|
String keyOrPassphrase,
|
||||||
|
OpenSSSS openSsss}) async {
|
||||||
|
var handle = openSsss;
|
||||||
|
if (handle == null) {
|
||||||
|
handle = encryption.ssss.open(EventTypes.CrossSigningMasterKey);
|
||||||
|
await handle.unlock(
|
||||||
passphrase: passphrase,
|
passphrase: passphrase,
|
||||||
recoveryKey: recoveryKey,
|
recoveryKey: recoveryKey,
|
||||||
keyOrPassphrase: keyOrPassphrase);
|
keyOrPassphrase: keyOrPassphrase,
|
||||||
await handle.maybeCacheAll();
|
postUnlock: false,
|
||||||
|
);
|
||||||
|
await handle.maybeCacheAll();
|
||||||
|
}
|
||||||
final masterPrivateKey =
|
final masterPrivateKey =
|
||||||
base64.decode(await handle.getStored(EventTypes.CrossSigningMasterKey));
|
base64.decode(await handle.getStored(EventTypes.CrossSigningMasterKey));
|
||||||
final keyObj = olm.PkSigning();
|
final keyObj = olm.PkSigning();
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import 'package:password_hash/password_hash.dart';
|
||||||
import '../famedlysdk.dart';
|
import '../famedlysdk.dart';
|
||||||
import '../src/database/database.dart';
|
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 'encryption.dart';
|
import 'encryption.dart';
|
||||||
|
|
||||||
const CACHE_TYPES = <String>{
|
const CACHE_TYPES = <String>{
|
||||||
|
|
@ -617,20 +618,32 @@ class OpenSSSS {
|
||||||
Uint8List privateKey;
|
Uint8List privateKey;
|
||||||
|
|
||||||
bool get isUnlocked => privateKey != null;
|
bool get isUnlocked => privateKey != null;
|
||||||
|
bool get hasPassphrase => keyData.passphrase != null;
|
||||||
|
|
||||||
String get recoveryKey =>
|
String get recoveryKey =>
|
||||||
isUnlocked ? SSSS.encodeRecoveryKey(privateKey) : null;
|
isUnlocked ? SSSS.encodeRecoveryKey(privateKey) : null;
|
||||||
|
|
||||||
Future<void> unlock(
|
Future<void> unlock(
|
||||||
{String passphrase, String recoveryKey, String keyOrPassphrase}) async {
|
{String passphrase,
|
||||||
|
String recoveryKey,
|
||||||
|
String keyOrPassphrase,
|
||||||
|
bool postUnlock = true}) async {
|
||||||
if (keyOrPassphrase != null) {
|
if (keyOrPassphrase != null) {
|
||||||
try {
|
try {
|
||||||
await unlock(recoveryKey: keyOrPassphrase);
|
await unlock(recoveryKey: keyOrPassphrase, postUnlock: postUnlock);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
await unlock(passphrase: keyOrPassphrase);
|
if (hasPassphrase) {
|
||||||
|
await unlock(passphrase: keyOrPassphrase, postUnlock: postUnlock);
|
||||||
|
} else {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (passphrase != null) {
|
} else if (passphrase != null) {
|
||||||
|
if (!hasPassphrase) {
|
||||||
|
throw Exception(
|
||||||
|
'Tried to unlock with passphrase while key does not have a passphrase');
|
||||||
|
}
|
||||||
privateKey = await runInBackground(
|
privateKey = await runInBackground(
|
||||||
_keyFromPassphrase,
|
_keyFromPassphrase,
|
||||||
_KeyFromPassphraseArgs(
|
_KeyFromPassphraseArgs(
|
||||||
|
|
@ -647,6 +660,9 @@ class OpenSSSS {
|
||||||
privateKey = null;
|
privateKey = null;
|
||||||
throw Exception('Inalid key');
|
throw Exception('Inalid key');
|
||||||
}
|
}
|
||||||
|
if (postUnlock) {
|
||||||
|
await runInRoot(() => _postUnlock());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPrivateKey(Uint8List key) {
|
void setPrivateKey(Uint8List key) {
|
||||||
|
|
@ -671,6 +687,19 @@ class OpenSSSS {
|
||||||
Future<void> maybeCacheAll() async {
|
Future<void> maybeCacheAll() async {
|
||||||
await ssss.maybeCacheAll(keyId, privateKey);
|
await ssss.maybeCacheAll(keyId, privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _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 {
|
class _KeyFromPassphraseArgs {
|
||||||
|
|
|
||||||
|
|
@ -124,9 +124,10 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cache', () async {
|
test('cache', () async {
|
||||||
|
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);
|
await handle.unlock(recoveryKey: SSSS_KEY, postUnlock: false);
|
||||||
expect(
|
expect(
|
||||||
(await client.encryption.ssss
|
(await client.encryption.ssss
|
||||||
.getCached(EventTypes.CrossSigningSelfSigning)) !=
|
.getCached(EventTypes.CrossSigningSelfSigning)) !=
|
||||||
|
|
@ -155,6 +156,30 @@ void main() {
|
||||||
true);
|
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 {
|
test('make share requests', () async {
|
||||||
final key =
|
final key =
|
||||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||||
|
|
@ -245,6 +270,7 @@ void main() {
|
||||||
final key =
|
final key =
|
||||||
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE'];
|
||||||
key.setDirectVerified(false);
|
key.setDirectVerified(false);
|
||||||
|
client.userDeviceKeys[client.userID].masterKey.setDirectVerified(false);
|
||||||
event = ToDeviceEvent(
|
event = ToDeviceEvent(
|
||||||
sender: client.userID,
|
sender: client.userID,
|
||||||
type: 'm.secret.request',
|
type: 'm.secret.request',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue