Merge branch 'soru/megolm-session-on-typing' into 'main'
feat: Start megolm sessions while typing See merge request famedly/famedlysdk!589
This commit is contained in:
commit
71fb80aa1f
|
|
@ -271,7 +271,7 @@ class KeyManager {
|
||||||
/// devices have been changed. Returns false if the session has not been cleared because
|
/// devices have been changed. Returns false if the session has not been cleared because
|
||||||
/// it wasn't necessary. Otherwise returns true.
|
/// it wasn't necessary. Otherwise returns true.
|
||||||
Future<bool> clearOrUseOutboundGroupSession(String roomId,
|
Future<bool> clearOrUseOutboundGroupSession(String roomId,
|
||||||
{bool wipe = false}) async {
|
{bool wipe = false, bool use = true}) async {
|
||||||
final room = client.getRoomById(roomId);
|
final room = client.getRoomById(roomId);
|
||||||
final sess = getOutboundGroupSession(roomId);
|
final sess = getOutboundGroupSession(roomId);
|
||||||
if (room == null || sess == null) {
|
if (room == null || sess == null) {
|
||||||
|
|
@ -334,8 +334,13 @@ class KeyManager {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// and now add all the new devices!
|
// and now add all the new devices!
|
||||||
final oldDeviceIds = Set.from(sess.devices[userId].keys);
|
final oldDeviceIds = Set.from(sess.devices[userId].entries
|
||||||
final newDeviceIds = Set.from(newDeviceKeyIds[userId].keys);
|
.where((e) => !e.value)
|
||||||
|
.map((e) => e.key));
|
||||||
|
final newDeviceIds = Set.from(newDeviceKeyIds[userId]
|
||||||
|
.entries
|
||||||
|
.where((e) => !e.value)
|
||||||
|
.map((e) => e.key));
|
||||||
final newDevices = newDeviceIds.difference(oldDeviceIds);
|
final newDevices = newDeviceIds.difference(oldDeviceIds);
|
||||||
if (newDeviceIds.isNotEmpty) {
|
if (newDeviceIds.isNotEmpty) {
|
||||||
devicesToReceive.addAll(newDeviceKeys.where(
|
devicesToReceive.addAll(newDeviceKeys.where(
|
||||||
|
|
@ -345,6 +350,9 @@ class KeyManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wipe) {
|
if (!wipe) {
|
||||||
|
if (!use) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// okay, we use the outbound group session!
|
// okay, we use the outbound group session!
|
||||||
sess.sentMessages++;
|
sess.sentMessages++;
|
||||||
sess.devices = newDeviceKeyIds;
|
sess.devices = newDeviceKeyIds;
|
||||||
|
|
@ -355,7 +363,7 @@ class KeyManager {
|
||||||
'session_key': sess.outboundGroupSession.session_key(),
|
'session_key': sess.outboundGroupSession.session_key(),
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
devicesToReceive.removeWhere((k) => k.blocked);
|
devicesToReceive.removeWhere((k) => !k.encryptToDevice);
|
||||||
if (devicesToReceive.isNotEmpty) {
|
if (devicesToReceive.isNotEmpty) {
|
||||||
// update allowedAtIndex
|
// update allowedAtIndex
|
||||||
for (final device in devicesToReceive) {
|
for (final device in devicesToReceive) {
|
||||||
|
|
@ -394,6 +402,7 @@ class KeyManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Store an outbound group session in the database
|
||||||
Future<void> storeOutboundGroupSession(
|
Future<void> storeOutboundGroupSession(
|
||||||
String roomId, OutboundGroupSession sess) async {
|
String roomId, OutboundGroupSession sess) async {
|
||||||
if (sess == null) {
|
if (sess == null) {
|
||||||
|
|
@ -411,6 +420,7 @@ class KeyManager {
|
||||||
final Map<String, Future<OutboundGroupSession>>
|
final Map<String, Future<OutboundGroupSession>>
|
||||||
_pendingNewOutboundGroupSessions = {};
|
_pendingNewOutboundGroupSessions = {};
|
||||||
|
|
||||||
|
/// Creates an outbound group session for a given room id
|
||||||
Future<OutboundGroupSession> createOutboundGroupSession(String roomId) async {
|
Future<OutboundGroupSession> createOutboundGroupSession(String roomId) async {
|
||||||
if (_pendingNewOutboundGroupSessions.containsKey(roomId)) {
|
if (_pendingNewOutboundGroupSessions.containsKey(roomId)) {
|
||||||
return _pendingNewOutboundGroupSessions[roomId];
|
return _pendingNewOutboundGroupSessions[roomId];
|
||||||
|
|
@ -421,6 +431,18 @@ class KeyManager {
|
||||||
return _pendingNewOutboundGroupSessions.remove(roomId);
|
return _pendingNewOutboundGroupSessions.remove(roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prepares an outbound group session for a given room ID. That is, load it from
|
||||||
|
/// the database, cycle it if needed and create it if absent.
|
||||||
|
Future<void> prepareOutboundGroupSession(String roomId) async {
|
||||||
|
if (getOutboundGroupSession(roomId) == null) {
|
||||||
|
await loadOutboundGroupSession(roomId);
|
||||||
|
}
|
||||||
|
await clearOrUseOutboundGroupSession(roomId, use: false);
|
||||||
|
if (getOutboundGroupSession(roomId) == null) {
|
||||||
|
await createOutboundGroupSession(roomId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<OutboundGroupSession> _createOutboundGroupSession(
|
Future<OutboundGroupSession> _createOutboundGroupSession(
|
||||||
String roomId) async {
|
String roomId) async {
|
||||||
await clearOrUseOutboundGroupSession(roomId, wipe: true);
|
await clearOrUseOutboundGroupSession(roomId, wipe: true);
|
||||||
|
|
@ -477,10 +499,12 @@ class KeyManager {
|
||||||
return sess;
|
return sess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get an outbound group session for a room id
|
||||||
OutboundGroupSession getOutboundGroupSession(String roomId) {
|
OutboundGroupSession getOutboundGroupSession(String roomId) {
|
||||||
return _outboundGroupSessions[roomId];
|
return _outboundGroupSessions[roomId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load an outbound group session from database
|
||||||
Future<void> loadOutboundGroupSession(String roomId) async {
|
Future<void> loadOutboundGroupSession(String roomId) async {
|
||||||
if (_loadedOutboundGroupSessions.contains(roomId) ||
|
if (_loadedOutboundGroupSessions.contains(roomId) ||
|
||||||
_outboundGroupSessions.containsKey(roomId) ||
|
_outboundGroupSessions.containsKey(roomId) ||
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import 'dart:core';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:pedantic/pedantic.dart';
|
||||||
|
|
||||||
import '../encryption.dart';
|
import '../encryption.dart';
|
||||||
import '../famedlysdk.dart';
|
import '../famedlysdk.dart';
|
||||||
|
|
@ -542,6 +543,22 @@ class Client extends MatrixApi {
|
||||||
return mxc;
|
return mxc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sends a typing notification and initiates a megolm session, if needed
|
||||||
|
@override
|
||||||
|
Future<void> sendTypingNotification(
|
||||||
|
String userId,
|
||||||
|
String roomId,
|
||||||
|
bool typing, {
|
||||||
|
int timeout,
|
||||||
|
}) async {
|
||||||
|
await super
|
||||||
|
.sendTypingNotification(userId, roomId, typing, timeout: timeout);
|
||||||
|
final room = getRoomById(roomId);
|
||||||
|
if (typing && room != null && encryptionEnabled && room.encrypted) {
|
||||||
|
unawaited(encryption.keyManager.prepareOutboundGroupSession(roomId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Uploads a new user avatar for this user.
|
/// Uploads a new user avatar for this user.
|
||||||
Future<void> setAvatar(MatrixFile file) async {
|
Future<void> setAvatar(MatrixFile file) async {
|
||||||
final uploadResp = await upload(file.bytes, file.name);
|
final uploadResp = await upload(file.bytes, file.name);
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,26 @@ void main() {
|
||||||
client.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
client.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||||
.blocked = false;
|
.blocked = false;
|
||||||
|
|
||||||
|
// lazy-create if it would rotate
|
||||||
|
sess =
|
||||||
|
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||||
|
final oldSessKey = sess.outboundGroupSession.session_key();
|
||||||
|
client.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||||
|
.blocked = true;
|
||||||
|
await client.encryption.keyManager.prepareOutboundGroupSession(roomId);
|
||||||
|
expect(
|
||||||
|
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||||
|
true);
|
||||||
|
expect(
|
||||||
|
client.encryption.keyManager
|
||||||
|
.getOutboundGroupSession(roomId)
|
||||||
|
.outboundGroupSession
|
||||||
|
.session_key() !=
|
||||||
|
oldSessKey,
|
||||||
|
true);
|
||||||
|
client.userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS']
|
||||||
|
.blocked = false;
|
||||||
|
|
||||||
// rotate if too far in the past
|
// rotate if too far in the past
|
||||||
sess =
|
sess =
|
||||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue