fetch from online key backup

This commit is contained in:
Sorunome 2020-05-29 10:21:36 +02:00
parent 15be6c5244
commit a7bb8375dc
No known key found for this signature in database
GPG key ID: B19471D07FC9BE9C
3 changed files with 113 additions and 3 deletions

View file

@ -1,8 +1,15 @@
import 'dart:core';
import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'client.dart'; import 'client.dart';
import 'room.dart'; import 'room.dart';
import 'utils/to_device_event.dart'; import 'utils/to_device_event.dart';
import 'utils/device_keys_list.dart'; import 'utils/device_keys_list.dart';
const MEGOLM_KEY = 'm.megolm_backup.v1';
class KeyManager { class KeyManager {
final Client client; final Client client;
final outgoingShareRequests = <String, KeyManagerKeyShareRequest>{}; final outgoingShareRequests = <String, KeyManagerKeyShareRequest>{};
@ -10,8 +17,109 @@ class KeyManager {
KeyManager(this.client); KeyManager(this.client);
bool get enabled => client.accountData[MEGOLM_KEY] != null;
Future<Map<String, dynamic>> getRoomKeysInfo() async {
return await client.jsonRequest(
type: HTTPType.GET,
action: '/client/r0/room_keys/version',
);
}
Future<bool> isCached() async {
if (!enabled) {
return false;
}
return (await client.ssss.getCached(MEGOLM_KEY)) != null;
}
Future<void> loadFromResponse(Map<String, dynamic> payload) async {
if (!(await isCached())) {
return;
}
if (!(payload['rooms'] is Map)) {
return;
}
final privateKey = base64.decode(await client.ssss.getCached(MEGOLM_KEY));
final decryption = olm.PkDecryption();
String backupPubKey;
try {
backupPubKey = decryption.init_with_private_key(privateKey);
} catch (_) {
decryption.free();
rethrow;
}
if (backupPubKey == null) {
decryption.free();
return;
}
// TODO: check if pubkey is valid
for (final roomEntries in payload['rooms'].entries) {
final roomId = roomEntries.key;
if (!(roomEntries.value is Map) || !(roomEntries.value['sessions'] is Map)) {
continue;
}
for (final sessionEntries in roomEntries.value['sessions'].entries) {
final sessionId = sessionEntries.key;
final rawEncryptedSession = sessionEntries.value;
if (!(rawEncryptedSession is Map)) {
continue;
}
final firstMessageIndex = rawEncryptedSession['first_message_index'] is int ? rawEncryptedSession['first_message_index'] : null;
final forwardedCount = rawEncryptedSession['forwarded_count'] is int ? rawEncryptedSession['forwarded_count'] : null;
final isVerified = rawEncryptedSession['is_verified'] is bool ? rawEncryptedSession['is_verified'] : null;
final sessionData = rawEncryptedSession['session_data'];
if (firstMessageIndex == null || forwardedCount == null || isVerified == null || !(sessionData is Map)) {
continue;
}
final senderKey = sessionData['sender_key'];
Map<String, dynamic> decrypted;
try {
decrypted = json.decode(decryption.decrypt(sessionData['ephemeral'], sessionData['mac'], sessionData['ciphertext']));
} catch (err) {
print('[LibOlm] Error decrypting room key: ' + err.toString());
}
if (decrypted != null) {
decrypted['session_id'] = sessionId;
decrypted['room_id'] = roomId;
final room = client.getRoomById(roomId) ?? Room(id: roomId, client: client);
room.setInboundGroupSession(sessionId, decrypted, forwarded: true);
}
}
}
}
Future<void> loadSingleKey(String roomId, String sessionId) async {
final info = await getRoomKeysInfo();
final ret = await client.jsonRequest(
type: HTTPType.GET,
action: '/client/r0/room_keys/keys/${Uri.encodeComponent(roomId)}/${Uri.encodeComponent(sessionId)}?version=${info['version']}',
);
await loadFromResponse({
'rooms': {
roomId: {
'sessions': {
sessionId: ret,
},
},
},
});
}
/// Request a certain key from another device /// Request a certain key from another device
Future<void> request(Room room, String sessionId, String senderKey) async { Future<void> request(Room room, String sessionId, String senderKey) async {
// let's first check our online key backup store thingy...
var hadPreviously = room.inboundGroupSessions.containsKey(sessionId);
try {
await loadSingleKey(room.id, sessionId);
} catch (err, stacktrace) {
print('++++++++++++++++++');
print(err.toString());
print(stacktrace);
}
if (!hadPreviously && room.inboundGroupSessions.containsKey(sessionId)) {
return; // we managed to load the session from online backup, no need to care about it now
}
// while we just send the to-device event to '*', we still need to save the // while we just send the to-device event to '*', we still need to save the
// devices themself to know where to send the cancel to after receiving a reply // devices themself to know where to send the cancel to after receiving a reply
final devices = await room.getUserDeviceKeys(); final devices = await room.getUserDeviceKeys();

View file

@ -251,6 +251,7 @@ class Room {
inboundGroupSession = null; inboundGroupSession = null;
print('[LibOlm] Could not create new InboundGroupSession: ' + print('[LibOlm] Could not create new InboundGroupSession: ' +
e.toString()); e.toString());
return;
} }
} }
_inboundGroupSessions[sessionId] = SessionKey( _inboundGroupSessions[sessionId] = SessionKey(

View file

@ -22,9 +22,10 @@ dependencies:
password_hash: ^2.0.0 password_hash: ^2.0.0
olm: olm:
git: path: /home/sorunome/repos/famedly/dart-olm
url: https://gitlab.com/famedly/libraries/dart-olm.git # git:
ref: 0c612a525511652a7760126b058de8c924fe8900 # url: https://gitlab.com/famedly/libraries/dart-olm.git
# ref: 0c612a525511652a7760126b058de8c924fe8900
matrix_file_e2ee: matrix_file_e2ee:
path: /home/sorunome/repos/famedly/matrix_file_e2ee path: /home/sorunome/repos/famedly/matrix_file_e2ee