in-room verification to verify users instead of devices
This commit is contained in:
parent
aefe029c0a
commit
dda0b17724
|
@ -1216,6 +1216,54 @@ class Client {
|
|||
}
|
||||
}
|
||||
|
||||
void _handleRoomKeyVerificationRequest(EventUpdate update) {
|
||||
final event = update.content;
|
||||
final type = event['type'].startsWith('m.key.verification.')
|
||||
? event['type']
|
||||
: event['content']['msgtype'];
|
||||
if (!type.startsWith('m.key.verification.')) {
|
||||
return;
|
||||
}
|
||||
if (type == 'm.key.verification.request') {
|
||||
event['content']['timestamp'] = event['origin_server_ts'];
|
||||
}
|
||||
final transactionId =
|
||||
KeyVerification.getTransactionId(event['content']) ?? event['event_id'];
|
||||
if (_keyVerificationRequests.containsKey(transactionId)) {
|
||||
final req = _keyVerificationRequests[transactionId];
|
||||
if (event['sender'] != userID) {
|
||||
req.handlePayload(type, event['content'], event['event_id']);
|
||||
} else if (req.userId == userID && req.deviceId == null) {
|
||||
req
|
||||
.handlePayload(type, event['content'], event['event_id'])
|
||||
.then((ret) {
|
||||
if (req.deviceId != deviceID) {
|
||||
req.otherDeviceAccepted();
|
||||
req.dispose();
|
||||
_keyVerificationRequests.remove(transactionId);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (event['sender'] != userID) {
|
||||
final room =
|
||||
getRoomById(update.roomID) ?? Room(id: update.roomID, client: this);
|
||||
final newKeyRequest =
|
||||
KeyVerification(client: this, userId: event['sender'], room: room);
|
||||
newKeyRequest
|
||||
.handlePayload(type, event['content'], event['event_id'])
|
||||
.then((res) {
|
||||
if (newKeyRequest.state != KeyVerificationState.askAccept) {
|
||||
// something went wrong, let's just dispose the request
|
||||
newKeyRequest.dispose();
|
||||
} else {
|
||||
// new request! Let's notify it and stuff
|
||||
_keyVerificationRequests[transactionId] = newKeyRequest;
|
||||
onKeyVerificationRequest.add(newKeyRequest);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleRooms(
|
||||
Map<String, dynamic> rooms, Membership membership) async {
|
||||
for (final entry in rooms.entries) {
|
||||
|
@ -1416,6 +1464,11 @@ class Client {
|
|||
await database.storeEventUpdate(id, update);
|
||||
}
|
||||
_updateRoomsByEventUpdate(update);
|
||||
if (event['type'].startsWith('m.key.verification.') ||
|
||||
(event['type'] == 'm.room.message' &&
|
||||
event['content']['msgtype'].startsWith('m.key.verification.'))) {
|
||||
_handleRoomKeyVerificationRequest(update);
|
||||
}
|
||||
onEvent.add(update);
|
||||
|
||||
if (event['type'] == 'm.call.invite') {
|
||||
|
|
|
@ -39,7 +39,10 @@ class CrossSigning {
|
|||
} finally {
|
||||
keyObj.free();
|
||||
}
|
||||
if (masterPubkey == null || !client.userDeviceKeys.containsKey(client.userID) || !client.userDeviceKeys[client.userID].deviceKeys.containsKey(client.deviceID)) {
|
||||
if (masterPubkey == null ||
|
||||
!client.userDeviceKeys.containsKey(client.userID) ||
|
||||
!client.userDeviceKeys[client.userID].deviceKeys
|
||||
.containsKey(client.deviceID)) {
|
||||
throw 'Master or user keys not found';
|
||||
}
|
||||
final masterKey = client.userDeviceKeys[client.userID].masterKey;
|
||||
|
@ -49,7 +52,10 @@ class CrossSigning {
|
|||
// master key is valid, set it to verified
|
||||
masterKey.setVerified(true, false);
|
||||
// and now sign bout our own key and our master key
|
||||
await sign([masterKey, client.userDeviceKeys[client.userID].deviceKeys[client.deviceID]]);
|
||||
await sign([
|
||||
masterKey,
|
||||
client.userDeviceKeys[client.userID].deviceKeys[client.deviceID]
|
||||
]);
|
||||
}
|
||||
|
||||
bool signable(List<SignedKey> keys) {
|
||||
|
@ -82,6 +88,7 @@ class CrossSigning {
|
|||
if (!signatures[key.userId].containsKey(key.identifier)) {
|
||||
signatures[key.userId][key.identifier] =
|
||||
Map<String, dynamic>.from(key.toJson());
|
||||
// we don't need to send all old signatures, so let's just remove them
|
||||
signatures[key.userId][key.identifier].remove('signatures');
|
||||
}
|
||||
if (!signatures[key.userId][key.identifier].containsKey('signatures')) {
|
||||
|
|
|
@ -3,6 +3,8 @@ import 'package:canonical_json/canonical_json.dart';
|
|||
import 'package:olm/olm.dart' as olm;
|
||||
|
||||
import '../client.dart';
|
||||
import '../user.dart';
|
||||
import '../room.dart';
|
||||
import '../database/database.dart'
|
||||
show DbUserDeviceKey, DbUserDeviceKeysKey, DbUserCrossSigningKey;
|
||||
import '../event.dart';
|
||||
|
@ -49,6 +51,20 @@ class DeviceKeysList {
|
|||
return UserVerifiedStatus.unknown;
|
||||
}
|
||||
|
||||
Future<KeyVerification> startVerification() async {
|
||||
final roomId =
|
||||
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(client: client, 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(
|
||||
DbUserDeviceKey dbEntry,
|
||||
List<DbUserDeviceKeysKey> childEntries,
|
||||
|
|
|
@ -83,11 +83,11 @@ List<int> _bytesToInt(Uint8List bytes, int totalBits) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
final VERIFICATION_METHODS = [_KeyVerificationMethodSas.type];
|
||||
final VERIFICATION_METHODS = ['m.sas.v1'];
|
||||
|
||||
_KeyVerificationMethod _makeVerificationMethod(
|
||||
String type, KeyVerification request) {
|
||||
if (type == _KeyVerificationMethodSas.type) {
|
||||
if (type == 'm.sas.v1') {
|
||||
return _KeyVerificationMethodSas(request: request);
|
||||
}
|
||||
throw 'Unkown method type';
|
||||
|
@ -138,7 +138,7 @@ class KeyVerification {
|
|||
Future<void> sendStart() async {
|
||||
await send('m.key.verification.request', {
|
||||
'methods': VERIFICATION_METHODS,
|
||||
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
||||
if (room == null) 'timestamp': DateTime.now().millisecondsSinceEpoch,
|
||||
});
|
||||
startedVerification = true;
|
||||
setState(KeyVerificationState.waitingAccept);
|
||||
|
@ -189,6 +189,7 @@ class KeyVerification {
|
|||
setState(KeyVerificationState.askAccept);
|
||||
break;
|
||||
case 'm.key.verification.ready':
|
||||
_deviceId ??= payload['from_device'];
|
||||
possibleMethods =
|
||||
_intersect(VERIFICATION_METHODS, payload['methods']);
|
||||
if (possibleMethods.isEmpty) {
|
||||
|
@ -205,6 +206,32 @@ class KeyVerification {
|
|||
_deviceId ??= payload['from_device'];
|
||||
print('Setting device id start: ' + _deviceId.toString());
|
||||
transactionId ??= eventId ?? payload['transaction_id'];
|
||||
if (method != null) {
|
||||
print('DUPLICATE START');
|
||||
// the other side sent us a start, even though we already sent one
|
||||
if (payload['method'] == method.type) {
|
||||
// same method. Determine priority
|
||||
final ourEntry = '${client.userID}|${client.deviceID}';
|
||||
final entries = [ourEntry, '${userId}|${deviceId}'];
|
||||
entries.sort();
|
||||
if (entries.first == ourEntry) {
|
||||
// our start won, nothing to do
|
||||
print('we won, nothing to do');
|
||||
return;
|
||||
} else {
|
||||
print('They won, handing off');
|
||||
// the other start won, let's hand off
|
||||
startedVerification = false; // it is now as if they started
|
||||
lastStep =
|
||||
'm.key.verification.request'; // we fake the last step
|
||||
method.dispose(); // in case anything got created already
|
||||
}
|
||||
} else {
|
||||
// methods don't match up, let's cancel this
|
||||
await cancel('m.unexpected_message');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!(await verifyLastStep(['m.key.verification.request', null]))) {
|
||||
return; // abort
|
||||
}
|
||||
|
@ -221,6 +248,7 @@ class KeyVerification {
|
|||
startPaylaod = payload;
|
||||
setState(KeyVerificationState.askAccept);
|
||||
} else {
|
||||
print('handling start in method.....');
|
||||
await method.handlePayload(type, payload);
|
||||
}
|
||||
break;
|
||||
|
@ -247,6 +275,13 @@ class KeyVerification {
|
|||
}
|
||||
}
|
||||
|
||||
void otherDeviceAccepted() {
|
||||
canceled = true;
|
||||
canceledCode = 'm.accepted';
|
||||
canceledReason = 'm.accepted';
|
||||
setState(KeyVerificationState.error);
|
||||
}
|
||||
|
||||
Future<void> openSSSS(
|
||||
{String password, String recoveryKey, bool skip = false}) async {
|
||||
final next = () {
|
||||
|
@ -482,6 +517,9 @@ abstract class _KeyVerificationMethod {
|
|||
return false;
|
||||
}
|
||||
|
||||
String _type;
|
||||
String get type => _type;
|
||||
|
||||
Future<void> sendStart();
|
||||
void dispose() {}
|
||||
}
|
||||
|
@ -495,7 +533,8 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
|
|||
_KeyVerificationMethodSas({KeyVerification request})
|
||||
: super(request: request);
|
||||
|
||||
static String type = 'm.sas.v1';
|
||||
@override
|
||||
String _type = 'm.sas.v1';
|
||||
|
||||
String keyAgreementProtocol;
|
||||
String hash;
|
||||
|
|
|
@ -24,7 +24,7 @@ dependencies:
|
|||
olm:
|
||||
git:
|
||||
url: https://gitlab.com/famedly/libraries/dart-olm.git
|
||||
ref: 8749474d611f02a89893e067b6e479ebfd40c51d
|
||||
ref: a6cde466e707b54e39df8d035a0a79714621bc0b
|
||||
|
||||
matrix_file_e2ee:
|
||||
path: /home/sorunome/repos/famedly/matrix_file_e2ee
|
||||
|
|
Loading…
Reference in a new issue