feat: Add broadcast to-device verification
This commit is contained in:
parent
f9f18641e3
commit
5924e57cf1
|
|
@ -563,6 +563,7 @@ class KeyManager {
|
||||||
stacktrace);
|
stacktrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: also don't request from others if we have an index of 0 now
|
||||||
if (!hadPreviously &&
|
if (!hadPreviously &&
|
||||||
getInboundGroupSession(room.id, sessionId, senderKey) != null) {
|
getInboundGroupSession(room.id, sessionId, senderKey) != null) {
|
||||||
return; // we managed to load the session from online backup, no need to care about it now
|
return; // we managed to load the session from online backup, no need to care about it now
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,12 @@ class KeyVerificationManager {
|
||||||
return; // TODO: send cancel with unknown transaction id
|
return; // TODO: send cancel with unknown transaction id
|
||||||
}
|
}
|
||||||
if (_requests.containsKey(transactionId)) {
|
if (_requests.containsKey(transactionId)) {
|
||||||
await _requests[transactionId].handlePayload(event.type, event.content);
|
// make sure that new requests can't come from ourself
|
||||||
|
if (!{'m.key.verification.request'}.contains(event.type)) {
|
||||||
|
await _requests[transactionId].handlePayload(event.type, event.content);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!['m.key.verification.request', 'm.key.verification.start']
|
if (!{'m.key.verification.request', 'm.key.verification.start'}
|
||||||
.contains(event.type)) {
|
.contains(event.type)) {
|
||||||
return; // we can only start on these
|
return; // we can only start on these
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +118,7 @@ class KeyVerificationManager {
|
||||||
_requests.remove(transactionId);
|
_requests.remove(transactionId);
|
||||||
}
|
}
|
||||||
} else if (event['sender'] != client.userID) {
|
} else if (event['sender'] != client.userID) {
|
||||||
if (!['m.key.verification.request', 'm.key.verification.start']
|
if (!{'m.key.verification.request', 'm.key.verification.start'}
|
||||||
.contains(type)) {
|
.contains(type)) {
|
||||||
return; // we can only start on these
|
return; // we can only start on these
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,9 @@ class KeyVerification {
|
||||||
bool canceled = false;
|
bool canceled = false;
|
||||||
String canceledCode;
|
String canceledCode;
|
||||||
String canceledReason;
|
String canceledReason;
|
||||||
|
bool get isDone =>
|
||||||
|
canceled ||
|
||||||
|
{KeyVerificationState.error, KeyVerificationState.done}.contains(state);
|
||||||
|
|
||||||
KeyVerification(
|
KeyVerification(
|
||||||
{this.encryption,
|
{this.encryption,
|
||||||
|
|
@ -200,6 +203,9 @@ class KeyVerification {
|
||||||
|
|
||||||
Future<void> handlePayload(String type, Map<String, dynamic> payload,
|
Future<void> handlePayload(String type, Map<String, dynamic> payload,
|
||||||
[String eventId]) async {
|
[String eventId]) async {
|
||||||
|
if (isDone) {
|
||||||
|
return; // no need to do anything with already canceled requests
|
||||||
|
}
|
||||||
while (_handlePayloadLock) {
|
while (_handlePayloadLock) {
|
||||||
await Future.delayed(Duration(milliseconds: 50));
|
await Future.delayed(Duration(milliseconds: 50));
|
||||||
}
|
}
|
||||||
|
|
@ -235,6 +241,21 @@ class KeyVerification {
|
||||||
setState(KeyVerificationState.askAccept);
|
setState(KeyVerificationState.askAccept);
|
||||||
break;
|
break;
|
||||||
case 'm.key.verification.ready':
|
case 'm.key.verification.ready':
|
||||||
|
if (deviceId == '*') {
|
||||||
|
_deviceId = payload['from_device']; // gotta set the real device id
|
||||||
|
// and broadcast the cancel to the other devices
|
||||||
|
final devices = List<DeviceKeys>.from(
|
||||||
|
client.userDeviceKeys[userId].deviceKeys.values);
|
||||||
|
devices.removeWhere(
|
||||||
|
(d) => {deviceId, client.deviceID}.contains(d.deviceId));
|
||||||
|
final cancelPayload = <String, dynamic>{
|
||||||
|
'reason': 'Another device accepted the request',
|
||||||
|
'code': 'm.accepted',
|
||||||
|
};
|
||||||
|
makePayload(cancelPayload);
|
||||||
|
await client.sendToDeviceEncrypted(
|
||||||
|
devices, 'm.key.verification.cancel', cancelPayload);
|
||||||
|
}
|
||||||
_deviceId ??= payload['from_device'];
|
_deviceId ??= payload['from_device'];
|
||||||
possibleMethods =
|
possibleMethods =
|
||||||
_intersect(knownVerificationMethods, payload['methods']);
|
_intersect(knownVerificationMethods, payload['methods']);
|
||||||
|
|
@ -383,6 +404,9 @@ class KeyVerification {
|
||||||
|
|
||||||
/// called when the user rejects an incoming verification
|
/// called when the user rejects an incoming verification
|
||||||
Future<void> rejectVerification() async {
|
Future<void> rejectVerification() async {
|
||||||
|
if (isDone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!(await verifyLastStep(
|
if (!(await verifyLastStep(
|
||||||
['m.key.verification.request', 'm.key.verification.start']))) {
|
['m.key.verification.request', 'm.key.verification.start']))) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -557,7 +581,7 @@ class KeyVerification {
|
||||||
if (room != null) {
|
if (room != null) {
|
||||||
Logs.info(
|
Logs.info(
|
||||||
'[Key Verification] Sending to ${userId} in room ${room.id}...');
|
'[Key Verification] Sending to ${userId} in room ${room.id}...');
|
||||||
if (['m.key.verification.request'].contains(type)) {
|
if ({'m.key.verification.request'}.contains(type)) {
|
||||||
payload['msgtype'] = type;
|
payload['msgtype'] = type;
|
||||||
payload['to'] = userId;
|
payload['to'] = userId;
|
||||||
payload['body'] =
|
payload['body'] =
|
||||||
|
|
@ -572,8 +596,19 @@ class KeyVerification {
|
||||||
} else {
|
} else {
|
||||||
Logs.info(
|
Logs.info(
|
||||||
'[Key Verification] Sending to ${userId} device ${deviceId}...');
|
'[Key Verification] Sending to ${userId} device ${deviceId}...');
|
||||||
await client.sendToDeviceEncrypted(
|
if (deviceId == '*') {
|
||||||
[client.userDeviceKeys[userId].deviceKeys[deviceId]], type, payload);
|
if ({'m.key.verification.request'}.contains(type)) {
|
||||||
|
await client.sendToDevicesOfUserIds({userId}, type, payload);
|
||||||
|
} else {
|
||||||
|
Logs.error(
|
||||||
|
'[Key Verification] Tried to broadcast and un-broadcastable type: ${type}');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await client.sendToDeviceEncrypted(
|
||||||
|
[client.userDeviceKeys[userId].deviceKeys[deviceId]],
|
||||||
|
type,
|
||||||
|
payload);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,18 +54,29 @@ class DeviceKeysList {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<KeyVerification> startVerification() async {
|
Future<KeyVerification> startVerification() async {
|
||||||
final roomId =
|
if (userId != client.userID) {
|
||||||
await User(userId, room: Room(client: client)).startDirectChat();
|
// in-room verification with someone else
|
||||||
if (roomId == null) {
|
final roomId =
|
||||||
throw 'Unable to start new room';
|
await User(userId, room: Room(client: client)).startDirectChat();
|
||||||
|
if (roomId == null) {
|
||||||
|
throw 'Unable to start new room';
|
||||||
|
}
|
||||||
|
final room =
|
||||||
|
client.getRoomById(roomId) ?? Room(id: roomId, client: client);
|
||||||
|
final request = KeyVerification(
|
||||||
|
encryption: client.encryption, room: room, userId: userId);
|
||||||
|
await request.start();
|
||||||
|
// no need to add to the request client object. As we are doing a room
|
||||||
|
// verification request that'll happen automatically once we know the transaction id
|
||||||
|
return request;
|
||||||
|
} else {
|
||||||
|
// broadcast self-verification
|
||||||
|
final request = KeyVerification(
|
||||||
|
encryption: client.encryption, userId: userId, deviceId: '*');
|
||||||
|
await request.start();
|
||||||
|
client.encryption.keyVerificationManager.addRequest(request);
|
||||||
|
return request;
|
||||||
}
|
}
|
||||||
final room = client.getRoomById(roomId) ?? Room(id: roomId, client: client);
|
|
||||||
final request = KeyVerification(
|
|
||||||
encryption: client.encryption, room: room, userId: userId);
|
|
||||||
await request.start();
|
|
||||||
// no need to add to the request client object. As we are doing a room
|
|
||||||
// verification request that'll happen automatically once we know the transaction id
|
|
||||||
return request;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceKeysList.fromDb(
|
DeviceKeysList.fromDb(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue