Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verification request and QR listener in Crypto V2 #1663

Merged
merged 2 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MatrixSDK.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Pod::Spec.new do |s|

# Experimental / NOT production-ready Rust-based crypto library
s.subspec 'CryptoSDK' do |ss|
ss.dependency 'MatrixSDKCrypto', '0.1.6', :configurations => ["DEBUG"], :inhibit_warnings => true
ss.dependency 'MatrixSDKCrypto', '0.1.7', :configurations => ["DEBUG"], :inhibit_warnings => true
end

end
6 changes: 0 additions & 6 deletions MatrixSDK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1943,8 +1943,6 @@
ED76A4AE28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED76A4AC28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift */; };
ED79B9852940BB45008952F6 /* MXToDevicePayloadUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79B9842940BB45008952F6 /* MXToDevicePayloadUnitTests.swift */; };
ED79B9862940BB45008952F6 /* MXToDevicePayloadUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79B9842940BB45008952F6 /* MXToDevicePayloadUnitTests.swift */; };
ED79B9882940E3CA008952F6 /* MXPlaceholderQRCodeTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79B9872940E3CA008952F6 /* MXPlaceholderQRCodeTransaction.swift */; };
ED79B9892940E3CA008952F6 /* MXPlaceholderQRCodeTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79B9872940E3CA008952F6 /* MXPlaceholderQRCodeTransaction.swift */; };
ED825F8F29014EDA006A614E /* MXSession+LegacyCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED825F8E29014EDA006A614E /* MXSession+LegacyCrypto.swift */; };
ED825F9029014EDA006A614E /* MXSession+LegacyCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED825F8E29014EDA006A614E /* MXSession+LegacyCrypto.swift */; };
ED88999127F2065D00718486 /* MXRoomAliasResolution.h in Headers */ = {isa = PBXBuildFile; fileRef = ED88998F27F2065C00718486 /* MXRoomAliasResolution.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -3091,7 +3089,6 @@
ED751DAD28EDEC7E003748C3 /* MXKeyVerificationStateResolverUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationStateResolverUnitTests.swift; sourceTree = "<group>"; };
ED76A4AC28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationStateResolver.swift; sourceTree = "<group>"; };
ED79B9842940BB45008952F6 /* MXToDevicePayloadUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXToDevicePayloadUnitTests.swift; sourceTree = "<group>"; };
ED79B9872940E3CA008952F6 /* MXPlaceholderQRCodeTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXPlaceholderQRCodeTransaction.swift; sourceTree = "<group>"; };
ED825F8E29014EDA006A614E /* MXSession+LegacyCrypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MXSession+LegacyCrypto.swift"; sourceTree = "<group>"; };
ED88998F27F2065C00718486 /* MXRoomAliasResolution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXRoomAliasResolution.h; sourceTree = "<group>"; };
ED88999027F2065D00718486 /* MXRoomAliasResolution.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXRoomAliasResolution.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4841,7 +4838,6 @@
B19A309A240424BD00FB6F35 /* MXQRCodeTransaction_Private.h */,
B19A309B240424BD00FB6F35 /* MXQRCodeTransaction.m */,
ED28068628F06D360070AE9F /* MXQRCodeTransactionV2.swift */,
ED79B9872940E3CA008952F6 /* MXPlaceholderQRCodeTransaction.swift */,
);
path = QRCode;
sourceTree = "<group>";
Expand Down Expand Up @@ -6820,7 +6816,6 @@
ECBF658126DE2A8500AA3A99 /* MXMemoryRoomOutgoingMessagesStore.m in Sources */,
32F00ABD2488E1CD00131741 /* MXRecoveryService.m in Sources */,
3275FD9D21A6B60B00B9C13D /* MXLoginPolicy.m in Sources */,
ED79B9882940E3CA008952F6 /* MXPlaceholderQRCodeTransaction.swift in Sources */,
327F8DB31C6112BA00581CA3 /* MXRoomThirdPartyInvite.m in Sources */,
B17982FC2119E4A2001FD722 /* MXRoomPowerLevels.m in Sources */,
ED6DAC0228C76F0A00ECDCB6 /* MXRoomKeyInfo.swift in Sources */,
Expand Down Expand Up @@ -7468,7 +7463,6 @@
ECBF658226DE2A8500AA3A99 /* MXMemoryRoomOutgoingMessagesStore.m in Sources */,
324DD2AF246AEB7B00377005 /* MXSecretStoragePassphrase.m in Sources */,
B14EF1EF2397E90400758AF0 /* MXIdentityService.m in Sources */,
ED79B9892940E3CA008952F6 /* MXPlaceholderQRCodeTransaction.swift in Sources */,
ECF29BE62641953C0053E6D6 /* MXAssertedIdentityModel.m in Sources */,
EC8A53C625B1BC77004E0802 /* MXTurnServerResponse.m in Sources */,
ED6DAC0328C76F0A00ECDCB6 /* MXRoomKeyInfo.swift in Sources */,
Expand Down
16 changes: 2 additions & 14 deletions MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,8 @@ extension MXCryptoMachine: MXCryptoVerifying {
content: content
)
}

try await processOutgoingRequests()
}

func handleVerificationConfirmation(_ result: ConfirmVerificationResult) async throws {
Expand Down Expand Up @@ -744,21 +746,7 @@ extension MXCryptoMachine: MXCryptoBackup {

extension MXCryptoMachine: Logger {
func log(logLine: String) {
#if DEBUG
MXLog.debug("[MXCryptoMachine] \(logLine)")
#else
// Filtering out verbose logs for non-debug builds
guard !logLine.starts(with: "DEBUG") else {
return
}
MXLog.debug("[MXCryptoMachine] \(logLine)")
#endif
}

func log(error: String) {
MXLog.error("[MXCryptoMachine] Error", context: [
"error": error
])
}
}

Expand Down
6 changes: 6 additions & 0 deletions MatrixSDK/Crypto/MXCryptoV2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,12 @@ private class MXCryptoV2: NSObject, MXCrypto {
// we need to download their keys to be able to proceed with the verification flow
try await self.machine.downloadKeys(users: [userId])
}

do {
try await self.machine.processOutgoingRequests()
} catch {
self.log.error("Error processing requests", context: error)
}
}
}
}
Expand Down
108 changes: 23 additions & 85 deletions MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,6 @@ import Foundation

import MatrixSDKCrypto

/// Result of processing updates on verification object (request or transaction)
/// after each sync loop
enum MXKeyVerificationUpdateResult {
// The object has not changed since last sync
case noUpdates
// The object's state has changed
case updated
// The object is no longer available (e.g. it was cancelled)
case removed
}

class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
enum Error: Swift.Error {
case requestNotSupported
Expand Down Expand Up @@ -220,25 +209,23 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
return transaction
}

guard let request = activeRequests[transactionId] else {
guard
let activeRequest = activeRequests[transactionId],
let request = handler.verificationRequest(userId: activeRequest.otherUser, flowId: activeRequest.requestId)
else {
log.error("There is no pending verification request")
return nil
}

do {
let qr = try activeRequest.startQrVerification()
log.debug("Starting new QR verification")
let qr = try request.startQrVerification()
return addQrTransaction(for: qr, isIncoming: false)
return addQrTransaction(for: request, qrCode: qr, isIncoming: false)
} catch {
/// Placehoder QR transaction generated in case we cannot start a QR verification flow
/// (the other device cannot scan our code) but we may be able to scan theirs
log.debug("Adding placeholder QR verification")
let transaction = MXPlaceholderQRCodeTransaction(
otherUserId: request.otherUser,
otherDeviceId: request.otherDevice ?? "",
flowId: request.requestId,
roomId: request.roomId
)
activeTransactions[transaction.transactionId] = transaction
return transaction
return addQrTransaction(for: request, qrCode: nil, isIncoming: false)
}
}

Expand All @@ -255,7 +242,6 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
@MainActor
func handleDeviceEvent(_ event: MXEvent) {
guard Self.toDeviceEventTypes.contains(event.type) else {
updatePendingVerification()
return
}

Expand All @@ -279,8 +265,6 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
default:
log.failure("Event type should not be handled by key verification", context: event.type)
}

updatePendingVerification()
}

@MainActor
Expand All @@ -291,7 +275,6 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {

if !event.isEncrypted, let roomId = event.roomId {
handler.receiveUnencryptedVerificationEvent(event: event, roomId: roomId)
updatePendingVerification()
}

if event.type == kMXEventTypeStringRoomMessage && event.content?[kMXMessageTypeKey] as? String == kMXMessageTypeKeyVerificationRequest {
Expand All @@ -302,62 +285,13 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
handleIncomingVerification(userId: event.sender, flowId: flowId)
return event.sender
} else {
updatePendingVerification()
return nil
}
}

// MARK: - Update

@MainActor
func updatePendingVerification() {
if !activeRequests.isEmpty {
log.debug("Processing \(activeRequests.count) pending requests")
}

let completedStates = Set([
MXKeyVerificationRequestStateAccepted.rawValue,
MXKeyVerificationRequestStateExpired.rawValue,
MXKeyVerificationRequestStateCancelled.rawValue,
MXKeyVerificationRequestStateCancelledByMe.rawValue
])
for request in activeRequests.values {
switch request.processUpdates() {
case .noUpdates:
break
case .updated:
NotificationCenter.default.post(name: .MXKeyVerificationRequestDidChange, object: request)
case .removed:
NotificationCenter.default.post(name: .MXKeyVerificationRequestDidChange, object: request)
activeRequests[request.requestId] = nil
}

if completedStates.contains(request.state.rawValue) {
NotificationCenter.default.post(name: .MXKeyVerificationRequestDidChange, object: request)
activeRequests[request.requestId] = nil
}
}

// QR code transactions do not yet have `changes` listener, so have to manage updates manually
for transaction in activeTransactions.values {
guard let transaction = transaction as? MXQRCodeTransactionV2 else {
continue
}

switch transaction.processUpdates() {
case .noUpdates:
break
case .updated:
NotificationCenter.default.post(name: .MXKeyVerificationTransactionDidChange, object: transaction)
case .removed:
NotificationCenter.default.post(name: .MXKeyVerificationTransactionDidChange, object: transaction)
activeTransactions[transaction.transactionId] = nil
}
}
}

// MARK: - Verification requests

@MainActor
func requestVerificationByToDevice(
withUserId userId: String,
deviceIds: [String]?,
Expand All @@ -379,6 +313,7 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
}
}

@MainActor
private func requestVerification(userId: String, roomId: String, methods: [String]) async throws -> MXKeyVerificationRequest {
log.debug("->")

Expand All @@ -387,9 +322,10 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
roomId: roomId,
methods: methods
)
return await addRequest(for: request)
return addRequest(for: request)
}

@MainActor
private func requestVerification(userId: String, deviceId: String, methods: [String]) async throws -> MXKeyVerificationRequest {
log.debug("->")

Expand All @@ -398,14 +334,15 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
deviceId: deviceId,
methods: methods
)
return await addRequest(for: request)
return addRequest(for: request)
}

@MainActor
private func requestSelfVerification(methods: [String]) async throws -> MXKeyVerificationRequest {
log.debug("->")

let request = try await handler.requestSelfVerification(methods: methods)
return await addRequest(for: request)
return addRequest(for: request)
}

@MainActor
Expand Down Expand Up @@ -464,7 +401,10 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
private func handleIncomingVerification(userId: String, flowId: String) {
log.debug(flowId)

guard let verification = handler.verification(userId: userId, flowId: flowId) else {
guard
let request = handler.verificationRequest(userId: userId, flowId: flowId),
let verification = handler.verification(userId: userId, flowId: flowId)
else {
log.error("Verification is not known", context: [
"flow_id": flowId
])
Expand All @@ -478,17 +418,15 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
if activeRequests[transaction.transactionId] != nil {
log.debug("Auto-accepting transaction that matches a pending request")
transaction.accept()
updatePendingVerification()
}
case .qrCode(let qrCode):
if activeTransactions[flowId] is MXQRCodeTransaction {
// This flow may happen if we have previously started a QR verification, but so has the other side,
// and we scanned their code which now takes over the verification flow
log.debug("Updating existing QR verification transaction")
updatePendingVerification()
} else {
log.debug("Tracking new QR verification transaction")
_ = addQrTransaction(for: qrCode, isIncoming: true)
_ = addQrTransaction(for: request, qrCode: qrCode, isIncoming: true)
}
}
}
Expand All @@ -501,8 +439,8 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
}

@MainActor
private func addQrTransaction(for qrCode: QrCodeProtocol, isIncoming: Bool) -> MXQRCodeTransactionV2 {
let transaction = MXQRCodeTransactionV2(qrCode: qrCode, isIncoming: isIncoming, handler: handler)
private func addQrTransaction(for request: VerificationRequestProtocol, qrCode: QrCodeProtocol?, isIncoming: Bool) -> MXQRCodeTransactionV2 {
let transaction = MXQRCodeTransactionV2(request: request, qrCode: qrCode, isIncoming: isIncoming, handler: handler)
activeTransactions[transaction.transactionId] = transaction
return transaction
}
Expand Down
Loading