fetch from online key backup
This commit is contained in:
parent
15be6c5244
commit
a7bb8375dc
|
@ -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();
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue