Skip to content

Commit

Permalink
Merge branch 'release/0.25.0/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
pixlwave committed Feb 2, 2023
2 parents 59982e0 + 2b65627 commit 6a3d8b0
Show file tree
Hide file tree
Showing 84 changed files with 1,211 additions and 707 deletions.
13 changes: 13 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## Changes in 0.25.0 (2023-02-02)

🙌 Improvements

- CryptoV2: Decrypt notifications ([#1695](https://github.com/matrix-org/matrix-ios-sdk/pull/1695))
- CryptoV2: Upload fallback keys ([#1697](https://github.com/matrix-org/matrix-ios-sdk/pull/1697))
- CryptoV2: Set passphrase for the crypto store ([#1699](https://github.com/matrix-org/matrix-ios-sdk/pull/1699))
- Backup: Import legacy backup in batches ([#1701](https://github.com/matrix-org/matrix-ios-sdk/pull/1701))
- CryptoV2: New CryptoMachine on each background operation ([#1704](https://github.com/matrix-org/matrix-ios-sdk/pull/1704))
- CryptoV2: Fix JSONDictionary of keys query responses ([#1707](https://github.com/matrix-org/matrix-ios-sdk/pull/1707))
- CryptoV2: Enable Crypto SDK for production ([#1708](https://github.com/matrix-org/matrix-ios-sdk/pull/1708))


## Changes in 0.24.8 (2023-01-24)

✨ Features
Expand Down
9 changes: 2 additions & 7 deletions MatrixSDK.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|

s.name = "MatrixSDK"
s.version = "0.24.8"
s.version = "0.25.0"
s.summary = "The iOS SDK to build apps compatible with Matrix (https://www.matrix.org)"

s.description = <<-DESC
Expand Down Expand Up @@ -45,7 +45,7 @@ Pod::Spec.new do |s|
ss.dependency 'OLMKit', '~> 3.2.5'
ss.dependency 'Realm', '10.27.0'
ss.dependency 'libbase58', '~> 0.1.4'
ss.dependency 'MatrixSDK/CryptoSDK'
ss.dependency 'MatrixSDKCrypto', '0.2.0', :configurations => ["DEBUG", "RELEASE"], :inhibit_warnings => true
end

s.subspec 'JingleCallStack' do |ss|
Expand All @@ -63,10 +63,5 @@ Pod::Spec.new do |s|
# Use WebRTC framework included in Jitsi Meet SDK
ss.ios.dependency 'JitsiMeetSDK', '5.0.2'
end

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

end
36 changes: 24 additions & 12 deletions MatrixSDK.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion MatrixSDK/Background/Crypto/MXBackgroundCrypto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import Foundation

/// Light-weight crypto protocol to be used with background services
/// that can recieve room keys and decrypt notification messages
/// that can receive room keys and decrypt notification messages
protocol MXBackgroundCrypto {
func handleSyncResponse(_ syncResponse: MXSyncResponse) async
func canDecryptEvent(_ event: MXEvent) -> Bool
Expand Down
101 changes: 70 additions & 31 deletions MatrixSDK/Background/Crypto/MXBackgroundCryptoV2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

import Foundation

#if DEBUG

import MatrixSDKCrypto

/// An implementation of `MXBackgroundCrypto` which uses [matrix-rust-sdk](https://github.com/matrix-org/matrix-rust-sdk/tree/main/crates/matrix-sdk-crypto)
Expand All @@ -27,36 +25,30 @@ class MXBackgroundCryptoV2: MXBackgroundCrypto {
case missingCredentials
}

private let machine: MXCryptoMachine
private let credentials: MXCredentials
private let restClient: MXRestClient
private let log = MXNamedLog(name: "MXBackgroundCryptoV2")

init(credentials: MXCredentials, restClient: MXRestClient) throws {
guard
let userId = credentials.userId,
let deviceId = credentials.deviceId
else {
throw Error.missingCredentials
}

// `MXCryptoMachine` will load the same store as the main application meaning that background and foreground
// sync services have access to the same data / keys. Possible race conditions are handled internally.
machine = try MXCryptoMachine(
userId: userId,
deviceId: deviceId,
restClient: restClient,
getRoomAction: { [log] _ in
log.error("The background crypto should not be accessing rooms")
return nil
}
)
init(credentials: MXCredentials, restClient: MXRestClient) {
self.credentials = credentials
self.restClient = restClient
log.debug("Initialized background crypto module")
}

func handleSyncResponse(_ syncResponse: MXSyncResponse) async {
let toDeviceCount = syncResponse.toDevice?.events.count ?? 0

log.debug("Handling new sync response with \(toDeviceCount) to-device event(s)")
let syncId = UUID().uuidString
let details = """
Handling new sync response `\(syncId)`
- to-device events : \(syncResponse.toDevice?.events.count ?? 0)
- devices changed : \(syncResponse.deviceLists?.changed?.count ?? 0)
- devices left : \(syncResponse.deviceLists?.left?.count ?? 0)
- one time keys : \(syncResponse.deviceOneTimeKeysCount?[kMXKeySignedCurve25519Type] ?? 0)
- fallback keys : \(syncResponse.unusedFallbackKeys ?? [])
"""
log.debug(details)

do {
let machine = try createMachine()
_ = try await machine.handleSyncResponse(
toDevice: syncResponse.toDevice,
deviceLists: syncResponse.deviceLists,
Expand All @@ -66,35 +58,82 @@ class MXBackgroundCryptoV2: MXBackgroundCrypto {
} catch {
log.error("Failed handling sync response", context: error)
}

log.debug("Completed handling sync response `\(syncId)`")
}

func canDecryptEvent(_ event: MXEvent) -> Bool {
let eventId = event.eventId ?? ""

if !event.isEncrypted {
log.debug("Event \(eventId) is not encrypted")
return true
}

guard
let _ = event.content["sender_key"] as? String,
let _ = event.content["session_id"] as? String
let sessionId = event.content["session_id"] as? String
else {
log.error("Event does not contain session_id", context: [
"event_id": eventId
])
return false
}

do {
// Rust-sdk does not expose api to see if we have a given session key yet (will be added in the future)
// so for the time being to find out if we can decrypt we simply perform the (more expensive) decryption
let machine = try createMachine()
_ = try machine.decryptRoomEvent(event)
log.debug("Event `\(eventId)` can be decrypted with session `\(sessionId)`")
return true
} catch DecryptionError.MissingRoomKey {
log.warning("We do not have keys to decrypt event `\(eventId)` with session `\(sessionId)`")
return false
} catch {
log.warning("We cannot decrypt event `\(eventId)` with session `\(sessionId)`")
return false
}
}

func decryptEvent(_ event: MXEvent) throws {
let decrypted = try machine.decryptRoomEvent(event)
let result = try MXEventDecryptionResult(event: decrypted)
event.setClearData(result)
let eventId = event.eventId ?? ""
log.debug("Decrypting event `\(eventId)`")

do {
let machine = try createMachine()
let decrypted = try machine.decryptRoomEvent(event)
let result = try MXEventDecryptionResult(event: decrypted)
event.setClearData(result)

log.debug("Successfully decrypted event `\(result.clearEvent["type"] ?? "unknown")` eventId `\(eventId)`")
} catch {
log.error("Failed to decrypt event", context: error)
throw error
}
}

// `MXCryptoMachine` will load the same store as the main application meaning that background and foreground
// sync services have access to the same data / keys. The machine is not fully multi-thread and multi-process
// safe, and until this is resolved we open a new instance of `MXCryptoMachine` on each background operation
// to ensure we are always up-to-date with whatever has been written by the foreground process in the meanwhile.
// See https://github.com/matrix-org/matrix-rust-sdk/issues/1415 for more details.
private func createMachine() throws -> MXCryptoMachine {
guard
let userId = credentials.userId,
let deviceId = credentials.deviceId
else {
throw Error.missingCredentials
}

return try MXCryptoMachine(
userId: userId,
deviceId: deviceId,
restClient: restClient,
getRoomAction: { [log] _ in
log.error("The background crypto should not be accessing rooms")
return nil
}
)
}
}

#endif
44 changes: 0 additions & 44 deletions MatrixSDK/Background/Crypto/MXDummyBackgroundCrypto.swift

This file was deleted.

16 changes: 6 additions & 10 deletions MatrixSDK/Background/MXBackgroundCryptoStore.m
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,6 @@ - (void)reset
}
}

- (void)open:(void (^)(void))onComplete failure:(void (^)(NSError *error))failure
{
MXWeakify(self);
[cryptoStore open:^{
MXStrongifyAndReturnIfNil(self);

[self->bgCryptoStore open:onComplete failure:failure];
} failure:failure];
}

- (instancetype)initWithCredentials:(MXCredentials *)theCredentials
{
NSAssert(NO, @"This method should be useless in the context of MXBackgroundCryptoStore");
Expand Down Expand Up @@ -531,6 +521,12 @@ - (void)storeSecret:(NSString*)secret withSecretId:(NSString*)secretId
NSAssert(NO, @"This method should be useless in the context of MXBackgroundCryptoStore");
}

- (BOOL)hasSecretWithSecretId:(NSString *)secretId
{
NSAssert(NO, @"This method should be useless in the context of MXBackgroundCryptoStore");
return NO;
}

- (NSString*)secretWithSecretId:(NSString*)secretId
{
NSAssert(NO, @"This method should be useless in the context of MXBackgroundCryptoStore");
Expand Down
20 changes: 13 additions & 7 deletions MatrixSDK/Background/MXBackgroundSyncService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,25 @@ public enum MXBackgroundSyncServiceError: Error {
let syncResponseStore = MXSyncResponseFileStore(withCredentials: credentials)
syncResponseStoreManager = MXSyncResponseStoreManager(syncResponseStore: syncResponseStore)

restClient = MXRestClient(credentials: credentials, unrecognizedCertificateHandler: nil, persistentTokenDataHandler: persistTokenDataHandler, unauthenticatedHandler: unauthenticatedHandler)
let restClient = MXRestClient(
credentials: credentials,
unrecognizedCertificateHandler: nil,
persistentTokenDataHandler: persistTokenDataHandler,
unauthenticatedHandler: unauthenticatedHandler
)
restClient.completionQueue = processingQueue
self.restClient = restClient

store = MXBackgroundStore(withCredentials: credentials)
// We can flush any crypto data if our sync response store is empty
let resetBackgroundCryptoStore = syncResponseStoreManager.syncToken() == nil

crypto = {
#if DEBUG
if MXSDKOptions.sharedInstance().isCryptoSDKAvailable && MXSDKOptions.sharedInstance().enableCryptoSDK {
// Crypto V2 is currently unable to decrypt notifications due to single-process store,
// so it uses dummy background crypto that does not do anything.
return MXDummyBackgroundCrypto()
return MXBackgroundCryptoV2(credentials: credentials, restClient: restClient)
}
#endif

MXLog.debug("[MXBackgroundSyncService] init: constructing legacy crypto \(MXSDKOptions.sharedInstance().isCryptoSDKAvailable) \(MXSDKOptions.sharedInstance().enableCryptoSDK)")
return MXLegacyBackgroundCrypto(credentials: credentials, resetBackgroundCryptoStore: resetBackgroundCryptoStore)
}()

Expand All @@ -98,6 +103,7 @@ public enum MXBackgroundSyncServiceError: Error {
} else if let accountData = store.userAccountData ?? nil {
pushRulesManager.handleAccountData(accountData)
}
MXLog.debug("[MXBackgroundSyncService] init complete")
super.init()
}

Expand Down Expand Up @@ -303,7 +309,7 @@ public enum MXBackgroundSyncServiceError: Error {
}
} else {
// we don't have keys to decrypt the event
MXLog.debug("[MXBackgroundSyncService] fetchEvent: Event needs to be decrpyted, but we don't have the keys to decrypt it.")
MXLog.debug("[MXBackgroundSyncService] fetchEvent: Event needs to be decrypted, but we don't have the keys to decrypt it.")
handleDecryptionFailure(withError: nil)
}
}
Expand Down
2 changes: 1 addition & 1 deletion MatrixSDK/Categories/MXRestClient+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public extension MXRestClient {
failure: @escaping (_ error: NSError?) -> Void) -> MXHTTPOperation {

// Do not chunk if not needed
if users.count < chunkSize {
if users.count <= chunkSize {
return self.downloadKeys(forUsers: users, token: token) { response in
switch response {
case .success(let keysQueryResponse):
Expand Down
Loading

0 comments on commit 6a3d8b0

Please sign in to comment.