From d873f601b93029ebf13a80014e62500b86423331 Mon Sep 17 00:00:00 2001 From: Denisia Enasescu <145033489+denasescu@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:33:22 +0300 Subject: [PATCH] BER-395: Sync origin with upstream v0.27.13 (#8) * Prepare for new sprint * version++ * finish version++ * Prepare for new sprint * Add own device creation ts in crypto API * deviceCreationTs should be readonly * version++ * finish version++ * Prepare for new sprint * Sorting room list alphabetically case-insensitive. (#1851) * Sort Room list alphabetically but caseInsensitive Signed-off-by: Nicolas Buquet * Sort Room list alphabetically but caseInsensitive Signed-off-by: Nicolas Buquet * Sort Room list alphabetically but caseInsensitive Signed-off-by: Nicolas Buquet --------- Signed-off-by: Nicolas Buquet Co-authored-by: Nicolas Buquet * Bump rust crypto sdk version 0.4.1 * update minimum ios platform 13.0 * Update min deployment target to 13.0 * Update osx min platform * update podfile lock * Fix test compilation * Add changelog * Invalidate crypto store cache when entering foreground * Bump crypto sdk to 0.4.2 * Fix warnings * Bump the Crypto version in the podspec as well * version++ * finish version++ * Prepare for new sprint * Fix | Share room keys with dehydrated devices with rust stack * Add RestClient method for reporting rooms through MSC4151 * version++ * finish version++ * Prepare for new sprint * Add a new state event type: "m.room.retention" # Conflicts: # MatrixSDK/Contrib/Swift/JSONModels/MXEvent.swift # MatrixSDK/JSONModels/MXEvent.h # MatrixSDK/JSONModels/MXEvent.m # MatrixSDK/Utils/MXTools.m * added some functions to remove messages before a certain timestamp * remove all messages sent * fixing a compilation error * version++ * finish version++ * Prepare for new sprint * Update README. (#1863) * fix store issue * version++ * finish version++ * Prepare for new sprint * Fix CallKit audio session late init Signed-off-by: Nicolas Buquet * Expose MXRoomPowerLevels Swift wrappers to Element (#1869) Signed-off-by: Nicolas Buquet Co-authored-by: Nicolas Buquet * implemented for the preview url API * removing return used for testing * using rest client instead of the home server directly * added the access token to the media loader request * implementation based on the server version * access token fix and using the stable endpoint prefix * documentation * code improvement * version++ * finish version++ * Prepare for new sprint * Add UTC timestamps to console logs * Create 7472.change * Bring in line with foundation DCO (#1875) * bring in line with foundation DCO * add changelog entry --------- Co-authored-by: Josh Simmons * Update format to include the time, Z cannot be applied to NSLog timestamps and doesn't do anything by itself * Use the codecov token. (#1877) * Use the codecov token. * Use codecov v4? * version++ * finish version++ * BER-395: update changelog --------- Signed-off-by: Nicolas Buquet Co-authored-by: Mauro Romito Co-authored-by: Stefan Ceriu Co-authored-by: Stefan Ceriu Co-authored-by: Valere Co-authored-by: Valere Co-authored-by: Doug Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> Co-authored-by: Nicolas Buquet Co-authored-by: Nicolas Buquet Co-authored-by: Giom Foret Co-authored-by: Mauro <34335419+Velin92@users.noreply.github.com> Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Josh Simmons Co-authored-by: Josh Simmons --- .github/PULL_REQUEST_TEMPLATE.md | 36 +++++- .github/workflows/ci-integration-tests.yml | 4 +- .github/workflows/ci-unit-tests.yml | 4 +- CHANGELOG.md | 9 ++ CHANGES.md | 37 ++++++ CONTRIBUTING.md | 5 - Gemfile | 2 +- Gemfile.lock | 10 +- MatrixSDK.podspec | 2 +- MatrixSDK/Background/MXBackgroundStore.swift | 6 +- .../MXKeysQueryResponse+Extensions.swift | 24 ++++ .../Categories/MXRestClient+Extensions.swift | 71 ++++++++++++ .../Contrib/Swift/JSONModels/MXEvent.swift | 4 +- .../Swift/JSONModels/MXRoomPowerLevels.swift | 4 +- MatrixSDK/Contrib/Swift/MXRestClient.swift | 4 + .../CryptoMachine/MXCryptoRequests.swift | 6 +- .../Data/Store/MXFileStore/MXFileStore.m | 2 +- .../Store/MXMemoryStore/MXMemoryRoomStore.h | 10 ++ .../Store/MXMemoryStore/MXMemoryRoomStore.m | 27 +++++ .../Data/Store/MXMemoryStore/MXMemoryStore.m | 6 + MatrixSDK/Data/Store/MXNoStore/MXNoStore.m | 11 ++ MatrixSDK/Data/Store/MXStore.h | 13 ++- MatrixSDK/JSONModels/MXEvent.h | 2 + MatrixSDK/JSONModels/MXEvent.m | 1 + MatrixSDK/JSONModels/MXJSONModels.h | 19 ++++ MatrixSDK/JSONModels/MXJSONModels.m | 95 ++++++++++++++++ MatrixSDK/JSONModels/MXMatrixVersions.h | 6 + MatrixSDK/JSONModels/MXMatrixVersions.m | 9 +- MatrixSDK/MXEnumConstants.h | 5 + MatrixSDK/MXEnumConstants.m | 1 + MatrixSDK/MXRestClient.h | 29 +++++ MatrixSDK/MXRestClient.m | 107 +++++++++++++++--- MatrixSDK/MXSession.m | 3 +- MatrixSDK/MatrixSDKVersion.m | 2 +- MatrixSDK/Utils/Logs/MXLog.swift | 2 +- MatrixSDK/Utils/MXTools.m | 7 +- MatrixSDK/Utils/Media/MXMediaLoader.h | 8 +- MatrixSDK/Utils/Media/MXMediaLoader.m | 23 +--- MatrixSDK/Utils/Media/MXMediaManager.h | 10 +- MatrixSDK/Utils/Media/MXMediaManager.m | 37 +++--- MatrixSDK/VoIP/CallKit/MXCallKitAdapter.m | 8 ++ MatrixSDKTests/MXSelfSignedHomeserverTests.m | 3 +- Podfile.lock | 2 +- README.rst | 22 ++-- 44 files changed, 587 insertions(+), 111 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a576ac54d4..6ce454d81c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,33 @@ -### Pull Request Checklist +**Context** +- Why do we want/need it? - +**Relevant issues** +- Closes ...(e.g. #138) -* [ ] Pull request is based on the develop branch -* [ ] Pull request contains a changelog file in ./changelog.d. See https://github.com/matrix-org/matrix-ios-sdk/blob/develop/CONTRIBUTING.md#changelog -* [ ] Pull request includes a [sign off](https://github.com/matrix-org/matrix-ios-sdk/blob/develop/CONTRIBUTING.md#sign-off) +**Changes** +- What does it do? +- In summary, what changes are made to the code? + +**Known problems** +- What problems do still arise or are anticipated? +- Which part of the solution do you need help with? + +**Extra attention** +- What do I need to pay extra attention to as a reviewer? + +**Check-list** +- [ ] Acceptance criteria described in the issue are satisfied, or the bug(s) is/are fixed. +- [ ] Documentation present (relevant information is properly documented). +- [ ] Written tests for test suite (optional). +- [ ] CHANGELOG updated. + +**Tested on devices** +- [ ] Minimum supported iOS version. +- [ ] Maximum supported iOS version. +- [ ] Lowest resolution supported. +- [ ] Highest resolution supported. +- [ ] Device with a notch. +- [ ] Device without a notch. + +**Is this issue considered as Done?** +- [ ] It meets our [DoD](https://github.com/nedap/healthcare-mobile/wiki/DoD). diff --git a/.github/workflows/ci-integration-tests.yml b/.github/workflows/ci-integration-tests.yml index 81fd1e95a4..590e2b3552 100644 --- a/.github/workflows/ci-integration-tests.yml +++ b/.github/workflows/ci-integration-tests.yml @@ -88,4 +88,6 @@ jobs: # Upload coverage - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/ci-unit-tests.yml b/.github/workflows/ci-unit-tests.yml index 90a46ffb3d..96e0c752f1 100644 --- a/.github/workflows/ci-unit-tests.yml +++ b/.github/workflows/ci-unit-tests.yml @@ -64,4 +64,6 @@ jobs: path: build/test/MatrixSDK-macOS.xcresult/ - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index b109d8e549..a34ea3a534 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes specific for Berichten Matrix SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [v0.1.4] - 02/09/2024 +##### Added +- BER-395: Merge upstream MatrixSDK v0.27.13. + +##### Fixed + +##### Changed + ## [v0.1.3] - 04/06/2024 ##### Added - BER-359: Merge upstream MatrixSDK v0.27.8. @@ -37,6 +45,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). --- +[v0.1.4]: https://github.com/nedap/matrix-ios-sdk/compare/nedap/0.1.3...nedap/0.1.4 [v0.1.3]: https://github.com/nedap/matrix-ios-sdk/compare/nedap/0.1.2...nedap/0.1.3 [v0.1.2]: https://github.com/nedap/matrix-ios-sdk/compare/nedap/0.1.1...nedap/0.1.2 [v0.1.1]: https://github.com/nedap/matrix-ios-sdk/compare/nedap/0.1.0...nedap/0.1.1 diff --git a/CHANGES.md b/CHANGES.md index 9847a3710f..1121ef1302 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,40 @@ +## Changes in 0.27.13 (2024-08-20) + +🙌 Improvements + +- Add UTC timestamps to console log lines. ([#7472](https://github.com/vector-im/element-ios/issues/7472)) + +📄 Documentation + +- Drop the requirement for "real" or "legally identifiable" name in order to contribute, in line with updated Foundation policy. ([#1875](https://github.com/matrix-org/matrix-ios-sdk/pull/1875)) + + +## Changes in 0.27.12 (2024-07-23) + +🙌 Improvements + +- Expose MXRroomPowerLevels Swift wrappers to Element ([#1869](https://github.com/matrix-org/matrix-ios-sdk/pull/1869)) + +🐛 Bugfixes + +- Fix CallKit audio session late init in VoIP call. ([#1866](https://github.com/matrix-org/matrix-ios-sdk/pull/1866)) + + +## Changes in 0.27.11 (2024-06-18) + +No significant changes. + + +## Changes in 0.27.10 (2024-06-17) + +No significant changes. + + +## Changes in 0.27.9 (2024-06-13) + +No significant changes. + + ## Changes in 0.27.8 (2024-05-29) 🙌 Improvements diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ea09982691..4e1ff78fab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -155,11 +155,6 @@ include the line in your commit or pull request comment: Signed-off-by: Your Name ``` -We accept contributions under a legally identifiable name, such as -your name on government documentation or common-law names (names -claimed by legitimate usage or repute). Unfortunately, we cannot -accept anonymous contributions at this time. - Git allows you to add this signoff automatically when using the `-s` flag to `git commit`, which uses the name and email set in your `user.name` and `user.email` git configs. diff --git a/Gemfile b/Gemfile index 2aa841dabd..10e63f4303 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source "https://rubygems.org" gem "fastlane" -gem "cocoapods", '~>1.14.3' +gem "cocoapods", '~>1.15.2' gem "xcode-install" gem "slather" diff --git a/Gemfile.lock b/Gemfile.lock index 317baa44e3..d531aee810 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -41,10 +41,10 @@ GEM bigdecimal (3.1.4) claide (1.1.0) clamp (1.3.2) - cocoapods (1.14.3) + cocoapods (1.15.2) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.14.3) + cocoapods-core (= 1.15.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -59,7 +59,7 @@ GEM nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.14.3) + cocoapods-core (1.15.2) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -165,7 +165,7 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - ffi (1.16.3) + ffi (1.17.0) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) @@ -296,7 +296,7 @@ PLATFORMS ruby DEPENDENCIES - cocoapods (~> 1.14.3) + cocoapods (~> 1.15.2) fastlane slather xcode-install diff --git a/MatrixSDK.podspec b/MatrixSDK.podspec index 0bc4db2a53..26d99e3df7 100644 --- a/MatrixSDK.podspec +++ b/MatrixSDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MatrixSDK" - s.version = "0.1.3" + s.version = "0.1.4" s.summary = "The iOS SDK to build apps compatible with Matrix (https://www.matrix.org)" s.description = <<-DESC diff --git a/MatrixSDK/Background/MXBackgroundStore.swift b/MatrixSDK/Background/MXBackgroundStore.swift index a171d84c4c..a414eba9a0 100644 --- a/MatrixSDK/Background/MXBackgroundStore.swift +++ b/MatrixSDK/Background/MXBackgroundStore.swift @@ -298,6 +298,11 @@ class MXBackgroundStore: NSObject, MXStore { func isRoomMarked(asUnread roomId: String) -> Bool { return false } + + func removeAllMessagesSent(before limitTs: UInt64, inRoom roomId: String) -> Bool { + // Not sure if this needs to be implemented + false + } } // MARK: - MXRoomSummaryStore @@ -334,5 +339,4 @@ extension MXBackgroundStore: MXRoomSummaryStore { completion([]) } } - } diff --git a/MatrixSDK/Categories/MXKeysQueryResponse+Extensions.swift b/MatrixSDK/Categories/MXKeysQueryResponse+Extensions.swift index 61565fb97f..aba66c39ab 100644 --- a/MatrixSDK/Categories/MXKeysQueryResponse+Extensions.swift +++ b/MatrixSDK/Categories/MXKeysQueryResponse+Extensions.swift @@ -39,3 +39,27 @@ extension MXKeysQueryResponse : MXSummable { return keysQueryResponse as! Self } } + + +extension MXKeysQueryResponseRaw : MXSummable { + + public static func +(lhs: MXKeysQueryResponseRaw, rhs: MXKeysQueryResponseRaw) -> Self { + let keysQueryResponse = MXKeysQueryResponseRaw() + + // Casts to original objc NSDictionary are annoying + // but we want to reuse our implementation of NSDictionary.+ + let deviceKeysMap = (lhs.deviceKeys as NSDictionary? ?? NSDictionary()) + + (rhs.deviceKeys as NSDictionary? ?? NSDictionary()) + keysQueryResponse.deviceKeys = deviceKeysMap as? [String : Any] + + let crossSigningKeys = (lhs.crossSigningKeys as NSDictionary? ?? NSDictionary()) + + (rhs.crossSigningKeys as NSDictionary? ?? NSDictionary()) + keysQueryResponse.crossSigningKeys = crossSigningKeys as? [String: MXCrossSigningInfo] + + let failures = (lhs.failures as NSDictionary? ?? NSDictionary()) + + (rhs.failures as NSDictionary? ?? NSDictionary()) + keysQueryResponse.failures = failures as? [AnyHashable : Any] + + return keysQueryResponse as! Self + } +} diff --git a/MatrixSDK/Categories/MXRestClient+Extensions.swift b/MatrixSDK/Categories/MXRestClient+Extensions.swift index 7252d26b31..37bc63c3ec 100644 --- a/MatrixSDK/Categories/MXRestClient+Extensions.swift +++ b/MatrixSDK/Categories/MXRestClient+Extensions.swift @@ -89,4 +89,75 @@ public extension MXRestClient { return operation } + + /// Download users keys by chunks. + /// + /// - Parameters: + /// - users: list of users to get keys for. + /// - token: sync token to pass in the query request, to help. + /// - chunkSize: max number of users to ask for in one CS API request. + /// - success: A block object called when the operation succeeds. + /// - failure: A block object called when the operation fails. + /// - Returns: a MXHTTPOperation instance. + func downloadKeysByChunkRaw(forUsers users: [String], + token: String?, + chunkSize: Int = 250, + success: @escaping (_ keysQueryResponse: MXKeysQueryResponseRaw) -> Void, + failure: @escaping (_ error: NSError?) -> Void) -> MXHTTPOperation { + + // Do not chunk if not needed + if users.count <= chunkSize { + return self.downloadKeysRaw(forUsers: users, token: token) { response in + switch response { + case .success(let keysQueryResponse): + success(keysQueryResponse) + case .failure(let error): + failure(error as NSError) + } + } + } + + MXLog.debug("[MXRestClient+Extensions] downloadKeysByChunk: \(users.count) users with chunkSize:\(chunkSize)") + + // An arbitrary MXHTTPOperation. It will not cancel requests + // but it will avoid to call callbacks in case of a cancellation is requested + let operation = MXHTTPOperation() + + let group = DispatchGroup() + var responses = [MXResponse]() + users.chunked(into: chunkSize).forEach { chunkedUsers in + group.enter() + self.downloadKeysRaw(forUsers: chunkedUsers, token: token) { response in + switch response { + case .success(let keysQueryResponse): + MXLog.debug("[MXRestClient+Extensions] downloadKeysByChunk: Got intermediate response. Got device keys for %@ users. Got cross-signing keys for %@ users \(String(describing: keysQueryResponse.deviceKeys.keys.count)) \(String(describing: keysQueryResponse.crossSigningKeys.count))") + case .failure(let error): + MXLog.debug("[MXRestClient+Extensions] downloadKeysByChunk: Got intermediate error. Error: \(error)") + } + + responses.append(response) + group.leave() + } + } + + group.notify(queue: self.completionQueue) { + MXLog.debug("[MXRestClient+Extensions] downloadKeysByChunk: Got all responses") + + guard operation.isCancelled == false else { + MXLog.debug("[MXRestClient+Extensions] downloadKeysByChunk: Request was cancelled") + return + } + + // Gather all responses in one + let response = responses.reduce(.success(MXKeysQueryResponseRaw()), +) + switch response { + case .success(let keysQueryResponse): + success(keysQueryResponse) + case .failure(let error): + failure(error as NSError) + } + } + + return operation + } } diff --git a/MatrixSDK/Contrib/Swift/JSONModels/MXEvent.swift b/MatrixSDK/Contrib/Swift/JSONModels/MXEvent.swift index dde0e04ae6..00f137b785 100644 --- a/MatrixSDK/Contrib/Swift/JSONModels/MXEvent.swift +++ b/MatrixSDK/Contrib/Swift/JSONModels/MXEvent.swift @@ -86,6 +86,7 @@ public enum MXEventType: Equatable, Hashable { case beaconInfo case beacon + case roomRetention case custom(String) @@ -141,6 +142,7 @@ public enum MXEventType: Equatable, Hashable { case .taggedEvents: return kMXEventTypeStringTaggedEvents case .spaceChild: return kMXEventTypeStringSpaceChild case .spaceOrder: return kMXEventTypeStringSpaceOrderMSC3230 + case .roomRetention: return kMXEventTypeStringRoomRetention case .pollStart: return kMXEventTypeStringPollStartMSC3381 case .pollResponse: return kMXEventTypeStringPollResponseMSC3381 @@ -157,7 +159,7 @@ public enum MXEventType: Equatable, Hashable { } public init(identifier: String) { - let events: [MXEventType] = [.roomName, .roomTopic, .roomAvatar, .roomMember, .roomCreate, .roomJoinRules, .roomPowerLevels, .roomAliases, .roomCanonicalAlias, .roomEncrypted, .roomEncryption, .roomGuestAccess, .roomHistoryVisibility, .roomKey, .roomForwardedKey, .roomKeyRequest, .roomMessage, .roomMessageFeedback, .roomRedaction, .roomThirdPartyInvite, .roomTag, .presence, .typing, .callInvite, .callCandidates, .callAnswer, .callSelectAnswer, .callHangup, .callReject, .callNegotiate, .callReplaces, .callRejectReplacement, .callAssertedIdentity, .callAssertedIdentityUnstable, .reaction, .receipt, .roomTombStone, .keyVerificationStart, .keyVerificationAccept, .keyVerificationKey, .keyVerificationMac, .keyVerificationCancel, .keyVerificationDone, .secretRequest, .secretSend, .secretStorageDefaultKey, .taggedEvents, .spaceChild, .spaceOrder, .pollStart, .pollResponse, .pollEnd, .beaconInfo, .beacon] + let events: [MXEventType] = [.roomName, .roomTopic, .roomAvatar, .roomMember, .roomCreate, .roomJoinRules, .roomPowerLevels, .roomAliases, .roomCanonicalAlias, .roomEncrypted, .roomEncryption, .roomGuestAccess, .roomHistoryVisibility, .roomKey, .roomForwardedKey, .roomKeyRequest, .roomMessage, .roomMessageFeedback, .roomRedaction, .roomThirdPartyInvite, .roomTag, .presence, .typing, .callInvite, .callCandidates, .callAnswer, .callSelectAnswer, .callHangup, .callReject, .callNegotiate, .callReplaces, .callRejectReplacement, .callAssertedIdentity, .callAssertedIdentityUnstable, .reaction, .receipt, .roomTombStone, .keyVerificationStart, .keyVerificationAccept, .keyVerificationKey, .keyVerificationMac, .keyVerificationCancel, .keyVerificationDone, .secretRequest, .secretSend, .secretStorageDefaultKey, .taggedEvents, .spaceChild, .spaceOrder, .pollStart, .pollResponse, .pollEnd, .beaconInfo, .beacon, .roomRetention] if let type = events.first(where: { $0.identifier == identifier }) { self = type diff --git a/MatrixSDK/Contrib/Swift/JSONModels/MXRoomPowerLevels.swift b/MatrixSDK/Contrib/Swift/JSONModels/MXRoomPowerLevels.swift index 47cd8bbd58..f2a3e30e71 100644 --- a/MatrixSDK/Contrib/Swift/JSONModels/MXRoomPowerLevels.swift +++ b/MatrixSDK/Contrib/Swift/JSONModels/MXRoomPowerLevels.swift @@ -25,7 +25,7 @@ extension MXRoomPowerLevels { - parameter eventType: the type of event. - returns: the required minimum power level. */ - @nonobjc func minimumPowerLevelForSendingMessageEvent(_ eventType: MXEventType) -> Int { + @nonobjc public func minimumPowerLevelForSendingMessageEvent(_ eventType: MXEventType) -> Int { return __minimumPowerLevelForSendingEvent(asMessage: eventType.identifier) } @@ -36,7 +36,7 @@ extension MXRoomPowerLevels { - parameter eventType: the type of event. - returns: the required minimum power level. */ - @nonobjc func minimumPowerLevelForSendingStateEvent(_ eventType: MXEventType) -> Int { + @nonobjc public func minimumPowerLevelForSendingStateEvent(_ eventType: MXEventType) -> Int { return __minimumPowerLevelForSendingEvent(asStateEvent: eventType.identifier) } diff --git a/MatrixSDK/Contrib/Swift/MXRestClient.swift b/MatrixSDK/Contrib/Swift/MXRestClient.swift index 33308654fa..58c958cda8 100644 --- a/MatrixSDK/Contrib/Swift/MXRestClient.swift +++ b/MatrixSDK/Contrib/Swift/MXRestClient.swift @@ -1848,6 +1848,10 @@ public extension MXRestClient { return __downloadKeys(forUsers: userIds, token: token, success: currySuccess(completion), failure: curryFailure(completion)) } + @nonobjc @discardableResult func downloadKeysRaw(forUsers userIds: [String], token: String? = nil, completion: @escaping (_ response: MXResponse) -> Void) -> MXHTTPOperation { + return __downloadKeysRaw(forUsers: userIds, token: token, success: currySuccess(completion), failure: curryFailure(completion)) + } + /** Claim one-time keys. diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift index 5703725543..a721e00972 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift @@ -21,13 +21,13 @@ import MatrixSDKCrypto /// to the native REST API client struct MXCryptoRequests { private let restClient: MXRestClient - private let queryScheduler: MXKeysQueryScheduler + private let queryScheduler: MXKeysQueryScheduler init(restClient: MXRestClient) { self.restClient = restClient self.queryScheduler = .init { users in try await performCallbackRequest { completion in - _ = restClient.downloadKeysByChunk( + _ = restClient.downloadKeysByChunkRaw( forUsers: users, token: nil, success: { @@ -96,7 +96,7 @@ struct MXCryptoRequests { } } - func queryKeys(users: [String]) async throws -> MXKeysQueryResponse { + func queryKeys(users: [String]) async throws -> MXKeysQueryResponseRaw { try await queryScheduler.query(users: Set(users)) } diff --git a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m index 5207df6c6a..33d13627db 100644 --- a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m +++ b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m @@ -29,7 +29,7 @@ #import "MatrixSDKSwiftHeader.h" #import "MXFileRoomSummaryStore.h" -static NSUInteger const kMXFileVersion = 82; // Check getUnreadRoomFromStore if you update this value. Delete this comment after +static NSUInteger const kMXFileVersion = 83; // Check getUnreadRoomFromStore if you update this value. Delete this comment after static NSString *const kMXFileStoreFolder = @"MXFileStore"; static NSString *const kMXFileStoreMedaDataFile = @"MXFileStore"; diff --git a/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryRoomStore.h b/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryRoomStore.h index d085fbfcc1..3ff2312d81 100644 --- a/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryRoomStore.h +++ b/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryRoomStore.h @@ -48,6 +48,16 @@ */ - (void)replaceEvent:(MXEvent*)event; +/** + Remove all the messages sent before a specific timestamp in a room. + The state events are not removed during this operation. We keep them in the timeline. + + @param limitTs the timestamp from which the messages are kept. + + @return YES if at least one event has been removed. + */ +- (BOOL)removeAllMessagesSentBefore:(uint64_t)limitTs; + /** Get an event from this room. diff --git a/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryRoomStore.m b/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryRoomStore.m index 2da23e99d3..d413bc28a8 100644 --- a/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryRoomStore.m +++ b/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryRoomStore.m @@ -197,4 +197,31 @@ - (NSString *)description return [NSString stringWithFormat:@"%tu messages - paginationToken: %@ - hasReachedHomeServerPaginationEnd: %@ - hasLoadedAllRoomMembersForRoom: %@", messages.count, _paginationToken, @(_hasReachedHomeServerPaginationEnd), @(_hasLoadedAllRoomMembersForRoom)]; } +- (BOOL)removeAllMessagesSentBefore:(uint64_t)limitTs +{ + NSUInteger index = 0; + BOOL didChange = NO; + while (index < messages.count) + { + MXEvent *anEvent = [messages objectAtIndex:index]; + if (anEvent.isState) + { + // Keep state event + index ++; + } + else if (anEvent.originServerTs < limitTs) + { + [messages removeObjectAtIndex:index]; + [messagesByEventIds removeObjectForKey:anEvent.eventId]; + didChange = YES; + } + else + { + // Break the loop, we've reached the first non-state event in the timeline which is not expired + break; + } + } + return didChange; +} + @end diff --git a/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryStore.m b/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryStore.m index 969a0bb932..aad34e943b 100644 --- a/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryStore.m +++ b/MatrixSDK/Data/Store/MXMemoryStore/MXMemoryStore.m @@ -83,6 +83,12 @@ - (void)replaceEvent:(MXEvent *)event inRoom:(NSString *)roomId [roomStore replaceEvent:event]; } +- (BOOL)removeAllMessagesSentBefore:(uint64_t)limitTs inRoom:(nonnull NSString *)roomId +{ + MXMemoryRoomStore *roomStore = [self getOrCreateRoomStore:roomId]; + return [roomStore removeAllMessagesSentBefore:limitTs]; +} + - (BOOL)eventExistsWithEventId:(NSString *)eventId inRoom:(NSString *)roomId { return (nil != [self eventWithEventId:eventId inRoom:roomId]); diff --git a/MatrixSDK/Data/Store/MXNoStore/MXNoStore.m b/MatrixSDK/Data/Store/MXNoStore/MXNoStore.m index 99c956e4ec..03b44302fa 100644 --- a/MatrixSDK/Data/Store/MXNoStore/MXNoStore.m +++ b/MatrixSDK/Data/Store/MXNoStore/MXNoStore.m @@ -124,6 +124,17 @@ - (BOOL)eventExistsWithEventId:(NSString *)eventId inRoom:(NSString *)roomId return NO; } +- (BOOL)removeAllMessagesSentBefore:(uint64_t)limitTs inRoom:(nonnull NSString *)roomId +{ + // Only the last message is stored + MXEvent *lastMessage = lastMessages[roomId]; + if (!lastMessage.isState && lastMessage.originServerTs < limitTs) { + lastMessages[roomId] = nil; + return YES; + } + return NO; +} + - (MXEvent *)eventWithEventId:(NSString *)eventId inRoom:(NSString *)roomId { // Events are not stored. So, we cannot find it. diff --git a/MatrixSDK/Data/Store/MXStore.h b/MatrixSDK/Data/Store/MXStore.h index d17982a3e9..c427cb62f0 100644 --- a/MatrixSDK/Data/Store/MXStore.h +++ b/MatrixSDK/Data/Store/MXStore.h @@ -426,6 +426,18 @@ */ - (void)storeOutgoingMessageForRoom:(nonnull NSString*)roomId outgoingMessage:(nonnull MXEvent*)outgoingMessage; +/** + Remove all the messages sent before a specific timestamp in a room. + The state events are not removed during this operation. We keep them in the timeline. + This operation doesn't change the pagination token, and the flag indicating that the SDK has reached the end of pagination. + + @param limitTs the timestamp from which the messages are kept. + @param roomId the id of the room. + + @return YES if at least one event has been removed. + */ +- (BOOL)removeAllMessagesSentBefore:(uint64_t)limitTs inRoom:(nonnull NSString *)roomId; + /** Remove all outgoing messages from a room. @@ -593,5 +605,4 @@ success:(nonnull void (^)(NSString * _Nullable filterId))success failure:(nullable void (^)(NSError * _Nullable error))failure; - @end diff --git a/MatrixSDK/JSONModels/MXEvent.h b/MatrixSDK/JSONModels/MXEvent.h index 2c549b0531..96dd31fc3c 100644 --- a/MatrixSDK/JSONModels/MXEvent.h +++ b/MatrixSDK/JSONModels/MXEvent.h @@ -103,6 +103,7 @@ typedef NS_ENUM(NSInteger, MXEventType) MXEventTypeSpaceOrder, MXEventTypeBeaconInfo, MXEventTypeBeacon, + MXEventTypeRoomRetention, // The event is a custom event. Refer to its `MXEventTypeString` version MXEventTypeCustom = 1000 @@ -163,6 +164,7 @@ FOUNDATION_EXPORT NSString *const kMXEventTypeStringSpaceChild; FOUNDATION_EXPORT NSString *const kMXEventTypeStringSpaceOrder; FOUNDATION_EXPORT NSString *const kMXEventTypeStringSpaceOrderMSC3230; FOUNDATION_EXPORT NSString *const kMXEventTypeStringSpaceOrderKey; +FOUNDATION_EXPORT NSString *const kMXEventTypeStringRoomRetention; // Interactive key verification FOUNDATION_EXPORT NSString *const kMXEventTypeStringKeyVerificationRequest; diff --git a/MatrixSDK/JSONModels/MXEvent.m b/MatrixSDK/JSONModels/MXEvent.m index af7324b967..7f6d898fd1 100644 --- a/MatrixSDK/JSONModels/MXEvent.m +++ b/MatrixSDK/JSONModels/MXEvent.m @@ -115,6 +115,7 @@ NSString *const kMXMessageTypeLocation = @"m.location"; NSString *const kMXMessageTypeFile = @"m.file"; NSString *const kMXMessageTypeServerNotice = @"m.server_notice"; +NSString *const kMXEventTypeStringRoomRetention = @"m.room.retention"; NSString *const kMXMessageTypeKeyVerificationRequest = @"m.key.verification.request"; NSString *const kMXMessageBodyKey = @"body"; diff --git a/MatrixSDK/JSONModels/MXJSONModels.h b/MatrixSDK/JSONModels/MXJSONModels.h index 2a758f1f38..715faa2a9c 100644 --- a/MatrixSDK/JSONModels/MXJSONModels.h +++ b/MatrixSDK/JSONModels/MXJSONModels.h @@ -1125,6 +1125,25 @@ FOUNDATION_EXPORT NSString *const kMXPushRuleScopeStringGlobal; @end +@interface MXKeysQueryResponseRaw : MXJSONModel + + /** + The device keys per devices per users. + */ + @property (nonatomic) NSDictionary *deviceKeys; + + /** + Cross-signing keys per users. + */ + @property (nonatomic) NSDictionary *crossSigningKeys; + + /** + The failures sorted by homeservers. + */ + @property (nonatomic) NSDictionary *failures; + +@end + /** `MXKeysClaimResponse` represents the response to /keys/claim request made by [MXRestClient claimOneTimeKeysForUsersDevices]. diff --git a/MatrixSDK/JSONModels/MXJSONModels.m b/MatrixSDK/JSONModels/MXJSONModels.m index 0052544372..8b97ebd37e 100644 --- a/MatrixSDK/JSONModels/MXJSONModels.m +++ b/MatrixSDK/JSONModels/MXJSONModels.m @@ -1247,6 +1247,101 @@ - (NSDictionary *)JSONDictionary @end +@interface MXKeysQueryResponseRaw () +@end + +@implementation MXKeysQueryResponseRaw + ++ (id)modelFromJSON:(NSDictionary *)JSONDictionary +{ + MXKeysQueryResponseRaw *keysQueryResponse = [[MXKeysQueryResponseRaw alloc] init]; + if (keysQueryResponse) + { + + if ([JSONDictionary[@"device_keys"] isKindOfClass:NSDictionary.class]) + { + keysQueryResponse.deviceKeys = JSONDictionary[@"device_keys"]; + } + + MXJSONModelSetDictionary(keysQueryResponse.failures, JSONDictionary[@"failures"]); + + // Extract cross-signing keys + NSMutableDictionary *crossSigningKeys = [NSMutableDictionary dictionary]; + + // Gather all of them by type by user + NSDictionary*> *allKeys = + @{ + MXCrossSigningKeyType.master: [self extractUserKeysFromJSON:JSONDictionary[@"master_keys"]] ?: @{}, + MXCrossSigningKeyType.selfSigning: [self extractUserKeysFromJSON:JSONDictionary[@"self_signing_keys"]] ?: @{}, + MXCrossSigningKeyType.userSigning: [self extractUserKeysFromJSON:JSONDictionary[@"user_signing_keys"]] ?: @{}, + }; + + // Package them into a `userId -> MXCrossSigningInfo` dictionary + for (NSString *keyType in allKeys) + { + NSDictionary *keys = allKeys[keyType]; + for (NSString *userId in keys) + { + MXCrossSigningInfo *crossSigningInfo = crossSigningKeys[userId]; + if (!crossSigningInfo) + { + crossSigningInfo = [[MXCrossSigningInfo alloc] initWithUserId:userId]; + crossSigningKeys[userId] = crossSigningInfo; + } + + [crossSigningInfo addCrossSigningKey:keys[userId] type:keyType]; + } + } + + keysQueryResponse.crossSigningKeys = crossSigningKeys; + } + + return keysQueryResponse; +} + ++ (NSDictionary*)extractUserKeysFromJSON:(NSDictionary *)keysJSONDictionary +{ + NSMutableDictionary *keys = [NSMutableDictionary dictionary]; + for (NSString *userId in keysJSONDictionary) + { + MXCrossSigningKey *key; + MXJSONModelSetMXJSONModel(key, MXCrossSigningKey, keysJSONDictionary[userId]); + if (key) + { + keys[userId] = key; + } + } + + if (!keys.count) + { + keys = nil; + } + + return keys; +} + +- (NSDictionary *)JSONDictionary +{ + + NSMutableDictionary *master = [[NSMutableDictionary alloc] init]; + NSMutableDictionary *selfSigning = [[NSMutableDictionary alloc] init]; + NSMutableDictionary *userSigning = [[NSMutableDictionary alloc] init]; + for (NSString *userId in self.crossSigningKeys) { + master[userId] = self.crossSigningKeys[userId].masterKeys.JSONDictionary.copy; + selfSigning[userId] = self.crossSigningKeys[userId].selfSignedKeys.JSONDictionary.copy; + userSigning[userId] = self.crossSigningKeys[userId].userSignedKeys.JSONDictionary.copy; + } + + return @{ + @"device_keys": self.deviceKeys.copy ?: @{}, + @"failures": self.failures.copy ?: @{}, + @"master_keys": master.copy ?: @{}, + @"self_signing_keys": selfSigning.copy ?: @{}, + @"user_signing_keys": userSigning.copy ?: @{} + }; +} + +@end @interface MXKeysClaimResponse () /** diff --git a/MatrixSDK/JSONModels/MXMatrixVersions.h b/MatrixSDK/JSONModels/MXMatrixVersions.h index b2a0bb1111..2e3d79ffed 100644 --- a/MatrixSDK/JSONModels/MXMatrixVersions.h +++ b/MatrixSDK/JSONModels/MXMatrixVersions.h @@ -35,6 +35,7 @@ struct MXMatrixClientServerAPIVersionStruct __unsafe_unretained NSString * const v1_1; __unsafe_unretained NSString * const v1_2; __unsafe_unretained NSString * const v1_3; + __unsafe_unretained NSString * const v1_11; }; extern const struct MXMatrixClientServerAPIVersionStruct MXMatrixClientServerAPIVersion; @@ -123,6 +124,11 @@ extern const struct MXMatrixVersionsFeatureStruct MXMatrixVersionsFeature; */ @property (nonatomic, readonly) BOOL supportsRedactionWithRelationsUnstable; +/** + Indicate if the server supports MSC3916 + */ +@property (nonatomic, readonly) BOOL supportsAuthenticatedMedia; + @end NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/JSONModels/MXMatrixVersions.m b/MatrixSDK/JSONModels/MXMatrixVersions.m index 2dd5fb81f0..68f5eb996a 100644 --- a/MatrixSDK/JSONModels/MXMatrixVersions.m +++ b/MatrixSDK/JSONModels/MXMatrixVersions.m @@ -27,7 +27,9 @@ .r0_6_1 = @"r0.6.1", .v1_1 = @"v1.1", .v1_2 = @"v1.2", - .v1_3 = @"v1.3" + .v1_3 = @"v1.3", + // missing versions not considered + .v1_11 = @"v1.11" }; const struct MXMatrixVersionsFeatureStruct MXMatrixVersionsFeature = { @@ -145,6 +147,11 @@ - (BOOL)supportsRedactionWithRelationsUnstable return [self serverSupportsFeature:kJSONKeyMSC3912Unstable]; } +- (BOOL)supportsAuthenticatedMedia +{ + return [self serverSupportsVersion:MXMatrixClientServerAPIVersion.v1_11]; +} + #pragma mark - Private - (BOOL)serverSupportsVersion:(NSString *)version diff --git a/MatrixSDK/MXEnumConstants.h b/MatrixSDK/MXEnumConstants.h index f41f89023d..6151c12625 100644 --- a/MatrixSDK/MXEnumConstants.h +++ b/MatrixSDK/MXEnumConstants.h @@ -33,6 +33,11 @@ FOUNDATION_EXPORT NSString *const kMXContentUriScheme; */ FOUNDATION_EXPORT NSString *const kMXContentPrefixPath; +/** + A constant representing the default prefix of the Matrix authenticated content repository path. + */ +FOUNDATION_EXPORT NSString *const kMXAuthenticatedContentPrefixPath; + /** A constant representing the URI path for as-yet unspecified of the AntiVirus Client-Server HTTP API. */ diff --git a/MatrixSDK/MXEnumConstants.m b/MatrixSDK/MXEnumConstants.m index 88cb32e176..10f20274e2 100644 --- a/MatrixSDK/MXEnumConstants.m +++ b/MatrixSDK/MXEnumConstants.m @@ -23,6 +23,7 @@ */ NSString *const kMXContentUriScheme = @"mxc://"; NSString *const kMXContentPrefixPath = @"_matrix/media/r0"; +NSString *const kMXAuthenticatedContentPrefixPath = @"_matrix/client/v1/media"; /** Prefix used in path of antivirus server API requests. diff --git a/MatrixSDK/MXRestClient.h b/MatrixSDK/MXRestClient.h index 981c3fc992..7952d9b043 100644 --- a/MatrixSDK/MXRestClient.h +++ b/MatrixSDK/MXRestClient.h @@ -229,6 +229,12 @@ extern NSString *const kMXCredentialsNewRefreshTokenDataKey; */ @property (nonatomic) NSString *contentPathPrefix; +/** + The Matrix content repository prefix to use for authenticated access. + By default, it is defined by the constant kMXAuthenticatedContentPrefixPath. + */ +@property (nonatomic) NSString *authenticatedContentPathPrefix; + /** The current trusted certificate (if any). */ @@ -245,6 +251,10 @@ extern NSString *const kMXCredentialsNewRefreshTokenDataKey; */ @property (nonatomic, copy) NSSet *acceptableContentTypes; +/** + Supported server versions of the matrix server, only for internal use of the SDK, use the stored version on the app side. + */ +@property (readonly) BOOL isUsingAuthenticatedMedia; /** Create an instance based on homeserver url. @@ -1583,6 +1593,21 @@ NS_REFINED_FOR_SWIFT; success:(void (^)(void))success failure:(void (^)(NSError *error))failure; +/** + Report a room. + + @param roomId the id of the room. + @param reason the redaction reason (optional). + + @param success A block object called when the operation succeeds. + @param failure A block object called when the operation fails. + + @return a MXHTTPOperation instance. + */ +-(MXHTTPOperation *)reportRoom:(NSString *)roomId + reason:(NSString *)reason + success:(void (^)(void))success + failure:(void (^)(NSError *))failure; /** Report an event. @@ -2485,6 +2510,10 @@ Note: Clients should consider avoiding this endpoint for URLs posted in encrypte success:(void (^)(MXKeysQueryResponse *keysQueryResponse))success failure:(void (^)(NSError *error))failure NS_REFINED_FOR_SWIFT; +- (MXHTTPOperation*)downloadKeysRawForUsers:(NSArray*)userIds + token:(NSString*)token + success:(void (^)(MXKeysQueryResponseRaw *keysQueryResponse))success + failure:(void (^)(NSError *error))failure NS_REFINED_FOR_SWIFT; /** * Claim one-time keys. diff --git a/MatrixSDK/MXRestClient.m b/MatrixSDK/MXRestClient.m index fc73875a27..2691d211f1 100644 --- a/MatrixSDK/MXRestClient.m +++ b/MatrixSDK/MXRestClient.m @@ -142,10 +142,11 @@ @interface MXRestClient () */ dispatch_queue_t processingQueue; } +@property(readwrite) BOOL isUsingAuthenticatedMedia; @end @implementation MXRestClient -@synthesize credentials, apiPathPrefix, contentPathPrefix, completionQueue, antivirusServerPathPrefix; +@synthesize credentials, apiPathPrefix, contentPathPrefix, authenticatedContentPathPrefix, completionQueue, antivirusServerPathPrefix, isUsingAuthenticatedMedia; + (dispatch_queue_t)refreshQueue { @@ -198,6 +199,7 @@ -(id)initWithCredentials:(MXCredentials*)inCredentials apiPathPrefix = kMXAPIPrefixPathR0; antivirusServerPathPrefix = kMXAntivirusAPIPrefixPathUnstable; contentPathPrefix = kMXContentPrefixPath; + authenticatedContentPathPrefix = kMXAuthenticatedContentPrefixPath; credentials = inCredentials; _identityServer = credentials.identityServer; @@ -529,6 +531,7 @@ - (MXHTTPOperation*)supportedMatrixVersions:(void (^)(MXMatrixVersions *matrixVe [self dispatchProcessing:^{ MXJSONModelSetMXJSONModel(matrixVersions, MXMatrixVersions, JSONResponse); } andCompletion:^{ + self->isUsingAuthenticatedMedia = matrixVersions.supportsAuthenticatedMedia; success(matrixVersions); }]; } @@ -3091,6 +3094,29 @@ - (MXHTTPOperation*)redactEvent:(NSString*)eventId } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); + [self dispatchFailure:error inBlock:failure]; + }]; +} + +-(MXHTTPOperation *)reportRoom:(NSString *)roomId + reason:(NSString *)reason + success:(void (^)(void))success + failure:(void (^)(NSError *))failure +{ + NSString *path = [NSString stringWithFormat:@"%@/org.matrix.msc4151/rooms/%@/report", kMXAPIPrefixPathUnstable, roomId]; + + NSDictionary *parameters = @{ @"reason": reason.length > 0 ? reason : @"" }; + + MXWeakify(self); + return [httpClient requestWithMethod:@"POST" + path:path + parameters:parameters + success:^(NSDictionary *JSONResponse) { + MXStrongifyAndReturnIfNil(self); + [self dispatchSuccess:success]; + } + failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); [self dispatchFailure:error inBlock:failure]; }]; } @@ -4475,28 +4501,30 @@ - (MXHTTPOperation *)previewForURL:(NSURL *)url { NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; parameters[@"url"] = [url absoluteString]; + NSString* path = isUsingAuthenticatedMedia ? authenticatedContentPathPrefix : contentPathPrefix; MXWeakify(self); + return [httpClient requestWithMethod:@"GET" - path:[NSString stringWithFormat:@"%@/preview_url", contentPathPrefix] + path:[NSString stringWithFormat:@"%@/preview_url", path] parameters:parameters success:^(NSDictionary *JSONResponse) { - MXStrongifyAndReturnIfNil(self); - - if (success) - { - __block MXURLPreview *urlPreview; - [self dispatchProcessing:^{ - MXJSONModelSetMXJSONModel(urlPreview, MXURLPreview, JSONResponse); - } andCompletion:^{ - success(urlPreview); - }]; - } - } + MXStrongifyAndReturnIfNil(self); + + if (success) + { + __block MXURLPreview *urlPreview; + [self dispatchProcessing:^{ + MXJSONModelSetMXJSONModel(urlPreview, MXURLPreview, JSONResponse); + } andCompletion:^{ + success(urlPreview); + }]; + } + } failure:^(NSError *error) { - MXStrongifyAndReturnIfNil(self); - [self dispatchFailure:error inBlock:failure]; - }]; + MXStrongifyAndReturnIfNil(self); + [self dispatchFailure:error inBlock:failure]; + }]; } #pragma mark - Antivirus server API @@ -4925,6 +4953,51 @@ - (MXHTTPOperation*)downloadKeysForUsers:(NSArray*)userIds }]; } +- (MXHTTPOperation*)downloadKeysRawForUsers:(NSArray*)userIds + token:(NSString *)token + success:(void (^)(MXKeysQueryResponseRaw *keysQueryResponse))success + failure:(void (^)(NSError *error))failure +{ + NSString *path = [NSString stringWithFormat:@"%@/keys/query", kMXAPIPrefixPathR0]; + + NSMutableDictionary *downloadQuery = [NSMutableDictionary dictionary]; + for (NSString *userID in userIds) + { + downloadQuery[userID] = @[]; + } + + NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithDictionary:@{ + @"device_keys": downloadQuery + }]; + + if (token) + { + parameters[@"token"] = token; + } + + MXWeakify(self); + return [httpClient requestWithMethod:@"POST" + path: path + parameters:parameters + success:^(NSDictionary *JSONResponse) { + MXStrongifyAndReturnIfNil(self); + + if (success) + { + __block MXKeysQueryResponseRaw *keysQueryResponse; + [self dispatchProcessing:^{ + MXJSONModelSetMXJSONModel(keysQueryResponse, MXKeysQueryResponseRaw, JSONResponse); + } andCompletion:^{ + success(keysQueryResponse); + }]; + } + } + failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + [self dispatchFailure:error inBlock:failure]; + }]; +} + - (MXHTTPOperation *)claimOneTimeKeysForUsersDevices:(MXUsersDevicesMap *)usersDevicesKeyTypesMap success:(void (^)(MXKeysClaimResponse *))success failure:(void (^)(NSError *))failure { NSString *path = [NSString stringWithFormat:@"%@/keys/claim", kMXAPIPrefixPathR0]; diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index 1002855ba1..09f2fca11e 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -234,8 +234,7 @@ - (id)initWithMatrixRestClient:(MXRestClient*)mxRestClient { matrixRestClient = mxRestClient; _threePidAddManager = [[MX3PidAddManager alloc] initWithMatrixSession:self]; - // Modified by Nedap. Pass access token to load the image (BER-229) - mediaManager = [[MXMediaManager alloc] initWithHomeServer:matrixRestClient.homeserver andAccessToken:matrixRestClient.credentials.accessToken]; + mediaManager = [[MXMediaManager alloc] initWithRestClient:matrixRestClient]; rooms = [NSMutableDictionary dictionary]; roomSummaries = [NSMutableDictionary dictionary]; _roomSummaryUpdateDelegate = [MXRoomSummaryUpdater roomSummaryUpdaterForSession:self]; diff --git a/MatrixSDK/MatrixSDKVersion.m b/MatrixSDK/MatrixSDKVersion.m index 705e2e1b0d..c48d07bcaa 100644 --- a/MatrixSDK/MatrixSDKVersion.m +++ b/MatrixSDK/MatrixSDKVersion.m @@ -16,4 +16,4 @@ #import -NSString *const MatrixSDKVersion = @"0.27.8"; +NSString *const MatrixSDKVersion = @"0.27.13"; diff --git a/MatrixSDK/Utils/Logs/MXLog.swift b/MatrixSDK/Utils/Logs/MXLog.swift index c36bbc446d..615d1caa8d 100644 --- a/MatrixSDK/Utils/Logs/MXLog.swift +++ b/MatrixSDK/Utils/Logs/MXLog.swift @@ -192,7 +192,7 @@ private var logger: SwiftyBeaver.Type = { let consoleDestination = ConsoleDestination() consoleDestination.useNSLog = true consoleDestination.asynchronously = false - consoleDestination.format = "$C$M $X$c" // Format is `Color Message Context`, see https://docs.swiftybeaver.com/article/20-custom-format + consoleDestination.format = "$DHH:mm:ss.SSS$d$Z $C$M $X$c" // Format is `Time Color Message Context`, see https://docs.swiftybeaver.com/article/20-custom-format consoleDestination.levelColor.verbose = "" consoleDestination.levelColor.debug = "" consoleDestination.levelColor.info = "" diff --git a/MatrixSDK/Utils/MXTools.m b/MatrixSDK/Utils/MXTools.m index 22435cd7dc..4377c99152 100644 --- a/MatrixSDK/Utils/MXTools.m +++ b/MatrixSDK/Utils/MXTools.m @@ -140,7 +140,9 @@ + (void)initialize @(MXEventTypePollResponse) : kMXEventTypeStringPollResponseMSC3381, @(MXEventTypePollEnd) : kMXEventTypeStringPollEndMSC3381, @(MXEventTypeBeaconInfo) : kMXEventTypeStringBeaconInfoMSC3672, - @(MXEventTypeBeacon) : kMXEventTypeStringBeaconMSC3672 + @(MXEventTypeBeacon) : kMXEventTypeStringBeaconMSC3672, + + @(MXEventTypeRoomRetention): kMXEventTypeStringRoomRetention }; eventTypeMapStringToEnum = @{ @@ -215,7 +217,8 @@ + (void)initialize kMXEventTypeStringBeaconInfoMSC3672 : @(MXEventTypeBeaconInfo), kMXEventTypeStringBeaconInfo : @(MXEventTypeBeaconInfo), kMXEventTypeStringBeaconMSC3672 : @(MXEventTypeBeacon), - kMXEventTypeStringBeacon : @(MXEventTypeBeacon) + kMXEventTypeStringBeacon : @(MXEventTypeBeacon), + kMXEventTypeStringRoomRetention: @(MXEventTypeRoomRetention), }; isEmailAddressRegex = [NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"^%@$", kMXToolsRegexStringForEmailAddress] diff --git a/MatrixSDK/Utils/Media/MXMediaLoader.h b/MatrixSDK/Utils/Media/MXMediaLoader.h index a5b7a1b1ca..c8fad9e56e 100644 --- a/MatrixSDK/Utils/Media/MXMediaLoader.h +++ b/MatrixSDK/Utils/Media/MXMediaLoader.h @@ -180,13 +180,7 @@ extern NSString *const kMXMediaUploadIdPrefix; @property (readonly) CGFloat uploadInitialRange; @property (readonly) CGFloat uploadRange; -// Modified by Nedap. Init with access token to set the authorization token on media requests (BER-229) -/** - Init 'MXMediaLoader' instance with the access token. - - @param accessToken the server access token. - */ -- (id)initWithAccessToken:(NSString*)accessToken; +- (id)initWithAccessToken:(NSString *) accessToken; /** Cancel the operation. diff --git a/MatrixSDK/Utils/Media/MXMediaLoader.m b/MatrixSDK/Utils/Media/MXMediaLoader.m index b3539eb770..572f934d98 100644 --- a/MatrixSDK/Utils/Media/MXMediaLoader.m +++ b/MatrixSDK/Utils/Media/MXMediaLoader.m @@ -40,10 +40,10 @@ NSString *const kMXMediaUploadIdPrefix = @"upload-"; -// Modified by Nedap. Store accessToken to set the authorization token on media requests (BER-229) + @interface MXMediaLoader() -@property (nonatomic) NSString *accessToken; +@property (nonatomic, readonly) NSString* accessToken; @end @@ -51,20 +51,11 @@ @implementation MXMediaLoader @synthesize statisticsDict; -- (id)init +- (id)initWithAccessToken:(NSString *) accessToken { if (self = [super init]) { _state = MXMediaLoaderStateIdle; - } - return self; -} - -// Modified by Nedap. Init with access token to set the authorization token on media requests (BER-229) -- (id)initWithAccessToken:(NSString *)accessToken -{ - if (self = [self init]) - { _accessToken = accessToken; } return self; @@ -165,11 +156,7 @@ - (void)downloadMediaFromURL:(NSString *)url [request setValue:value forHTTPHeaderField:key]; }]; - // Modified by Nedap. Set the authorization token on requests (BER-229) - if (self.accessToken) { - [request setValue:[NSString stringWithFormat:@"Bearer %@", self.accessToken] forHTTPHeaderField:@"Authorization"]; - } - + [request setValue: [NSString stringWithFormat:@"Bearer %@", _accessToken] forHTTPHeaderField: @"Authorization"]; if (data) { // Use an HTTP POST method to send this data as JSON object. @@ -426,7 +413,7 @@ - (id)initForUploadWithMatrixSession:(MXSession*)matrixSession initialRange:(CGF { // Create a unique upload Id _uploadId = [NSString stringWithFormat:@"%@%@", kMXMediaUploadIdPrefix, [[NSProcessInfo processInfo] globallyUniqueString]]; - + _accessToken = matrixSession.matrixRestClient.credentials.accessToken; mxSession = matrixSession; _uploadInitialRange = initialRange; _uploadRange = range; diff --git a/MatrixSDK/Utils/Media/MXMediaManager.h b/MatrixSDK/Utils/Media/MXMediaManager.h index e60d4c4d1d..f608655f86 100644 --- a/MatrixSDK/Utils/Media/MXMediaManager.h +++ b/MatrixSDK/Utils/Media/MXMediaManager.h @@ -19,6 +19,7 @@ #import #import "MXMediaLoader.h" #import "MXEnumConstants.h" +#import "MXRestClient.h" #if TARGET_OS_IPHONE #import @@ -50,16 +51,15 @@ extern NSString *const kMXMediaManagerDefaultCacheFolder; Create an instance based on a homeserver url. This homeserver URL is required to resolve the Matrix Content URI (in the form of "mxc://..."). - @param homeserverURL the homeserver URL. - @param accessToken the server access token. + @param restClient the REST client. @return a MXMediaManager instance. */ -- (id)initWithHomeServer:(NSString *)homeserverURL andAccessToken:(NSString*)accessToken; +- (id)initWithRestClient:(MXRestClient *)restClient; /** - The homeserver URL. + The rest client.. */ -@property (nonatomic, readonly) NSString *homeserverURL; +@property (nonatomic, readonly) MXRestClient *restClient; /** Antivirus scanner used to scan medias. diff --git a/MatrixSDK/Utils/Media/MXMediaManager.m b/MatrixSDK/Utils/Media/MXMediaManager.m index 1d1d8d7556..e3d9d9f319 100644 --- a/MatrixSDK/Utils/Media/MXMediaManager.m +++ b/MatrixSDK/Utils/Media/MXMediaManager.m @@ -50,24 +50,15 @@ // avoid listing files because it is useless static NSUInteger storageCacheSize = 0; -// Modified by Nedap. Store the access token to pass the authorization token to media loader (BER-229) -@interface MXMediaManager() - -@property (nonatomic) NSString *accessToken; - -@end - @implementation MXMediaManager -// Modified by Nedap. Init with access token to pass the authorization token to media loader (BER-229) -- (id)initWithHomeServer:(NSString *)homeserverURL andAccessToken:(NSString *)accessToken +- (id)initWithRestClient:(MXRestClient *)restClient { self = [super init]; if (self) { - _homeserverURL = homeserverURL; + _restClient = restClient; _scanManager = nil; - _accessToken = accessToken; } return self; } @@ -388,7 +379,11 @@ - (NSString*)urlOfContent:(NSString*)mxContentURI } else { - mxMediaPrefix = [NSString stringWithFormat:@"%@/%@/download/", _homeserverURL, kMXContentPrefixPath]; + mxMediaPrefix = [NSString stringWithFormat:@"%@/%@/download/", _restClient.homeserver, kMXContentPrefixPath]; + if (_restClient.isUsingAuthenticatedMedia) + { + mxMediaPrefix = [NSString stringWithFormat:@"%@/%@/download/", _restClient.homeserver, kMXAuthenticatedContentPrefixPath]; + } } contentURL = [mxContentURI stringByReplacingOccurrencesOfString:kMXContentUriScheme withString:mxMediaPrefix]; @@ -427,7 +422,11 @@ - (NSString*)urlOfContentThumbnail:(NSString*)mxContentURI } else { - mxThumbnailPrefix = [NSString stringWithFormat:@"%@/%@/thumbnail/", _homeserverURL, kMXContentPrefixPath]; + mxThumbnailPrefix = [NSString stringWithFormat:@"%@/%@/thumbnail/", _restClient.homeserver, kMXContentPrefixPath]; + if (_restClient.isUsingAuthenticatedMedia) + { + mxThumbnailPrefix = [NSString stringWithFormat:@"%@/%@/thumbnail/", _restClient.homeserver, kMXAuthenticatedContentPrefixPath]; + } } NSString *thumbnailURL = [mxContentURI stringByReplacingOccurrencesOfString:kMXContentUriScheme withString:mxThumbnailPrefix]; @@ -459,7 +458,8 @@ - (NSString*)urlOfContentThumbnail:(NSString*)mxContentURI - (NSString *)urlOfIdenticon:(NSString *)identiconString { - return [NSString stringWithFormat:@"%@/%@/identicon/%@", _homeserverURL, kMXContentPrefixPath, [identiconString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]]; + // Deprecated API, not need to use authenticated for this. + return [NSString stringWithFormat:@"%@/%@/identicon/%@", _restClient.homeserver, kMXContentPrefixPath, [identiconString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]]; } @@ -508,9 +508,9 @@ - (MXMediaLoader*)downloadMediaFromMatrixContentURI:(NSString *)mxContentURI return [MXMediaManager downloadMedia:mediaURL withData:nil parameters:params - accessToken:self.accessToken andIdentifier:downloadId saveAtFilePath:filePath + accessToken: _restClient.credentials.accessToken scanManager:_scanManager success:success failure:failure]; @@ -555,9 +555,9 @@ - (MXMediaLoader*)downloadThumbnailFromMatrixContentURI:(NSString *)mxContentURI return [MXMediaManager downloadMedia:mediaURL withData:nil parameters:params - accessToken:self.accessToken andIdentifier:downloadId saveAtFilePath:filePath + accessToken: _restClient.credentials.accessToken scanManager:_scanManager success:success failure:failure]; @@ -568,9 +568,9 @@ - (MXMediaLoader*)downloadThumbnailFromMatrixContentURI:(NSString *)mxContentURI + (MXMediaLoader*)downloadMedia:(NSString *)mediaURL withData:(NSDictionary *)data parameters:(NSDictionary *)params - accessToken:(NSString *)accessToken andIdentifier:(NSString *)downloadId saveAtFilePath:(NSString *)filePath + accessToken:(NSString *)accessToken scanManager:(MXScanManager *)scanManager success:(void (^)(NSString *outputFilePath))success failure:(void (^)(NSError *error))failure @@ -618,7 +618,6 @@ + (MXMediaLoader*)downloadMedia:(NSString *)mediaURL else { // Create a media loader to download data - // Modified by Nedap. Init with access token to set the authorization token on media requests (BER-229) mediaLoader = [[MXMediaLoader alloc] initWithAccessToken:accessToken]; // Report this loader if (!downloadTable) @@ -736,9 +735,9 @@ - (MXMediaLoader*)downloadEncryptedMediaFromMatrixContentFile:(MXEncryptedConten return [MXMediaManager downloadMedia:downloadMediaURL withData:dataToPost parameters:nil - accessToken:nil andIdentifier:downloadId saveAtFilePath:filePath + accessToken: _restClient.credentials.accessToken scanManager:_scanManager success:success failure:failure]; diff --git a/MatrixSDK/VoIP/CallKit/MXCallKitAdapter.m b/MatrixSDK/VoIP/CallKit/MXCallKitAdapter.m index 84ea69a403..6fbb55d98a 100644 --- a/MatrixSDK/VoIP/CallKit/MXCallKitAdapter.m +++ b/MatrixSDK/VoIP/CallKit/MXCallKitAdapter.m @@ -226,6 +226,14 @@ - (void)reportIncomingCall:(MXCall *)call { update.supportsUngrouping = NO; update.supportsDTMF = NO; + // If the user tap the "Answer" button from Element's timeline, very often, he can't hear the other user. + // It's because the audio session is not configured at the beginiing of the call. + // It's a flaw in CallKit implementation. + // The audio session need to be configured earlier, like here. + // + // See https://developer.apple.com/forums/thread/64544 (7th post from Apple Engineer) + [self.audioSessionConfigurator configureAudioSessionForVideoCall:call.isVideoCall]; + [self.provider reportNewIncomingCallWithUUID:callUUID update:update completion:^(NSError * _Nullable error) { if (error) { diff --git a/MatrixSDKTests/MXSelfSignedHomeserverTests.m b/MatrixSDKTests/MXSelfSignedHomeserverTests.m index feb0a5d6b7..10a73ed72a 100644 --- a/MatrixSDKTests/MXSelfSignedHomeserverTests.m +++ b/MatrixSDKTests/MXSelfSignedHomeserverTests.m @@ -288,8 +288,7 @@ - (void)testMediaWithNotTrustedCertificate NSString *contentURL = event.content[@"url"]; XCTAssert(contentURL); - // Modified by Nedap. Init with access token to set the authorization token on media requests (BER-229) - MXMediaManager *mediaManager = [[MXMediaManager alloc] initWithHomeServer:mxSession.matrixRestClient.homeserver andAccessToken:mxSession.matrixRestClient.credentials.accessToken]; + MXMediaManager *mediaManager = [[MXMediaManager alloc] initWithRestClient:mxSession.matrixRestClient]; XCTAssert(mediaManager); [mxSession close]; diff --git a/Podfile.lock b/Podfile.lock index a10fdb8f1e..29a750b881 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -73,4 +73,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 37ab0de0200808bcd3335a637e31736df60fc62e -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/README.rst b/README.rst index 8799f5c9b8..5ca2d1d085 100644 --- a/README.rst +++ b/README.rst @@ -9,6 +9,7 @@ .. image:: https://img.shields.io/badge/License-Apache%202.0-yellowgreen.svg?style=flat-square :target: https://opensource.org/licenses/Apache-2.0 +============== Matrix iOS SDK ============== @@ -20,6 +21,18 @@ This SDK implements an interface to communicate with the Matrix Client/Server API which is defined at http://matrix.org/docs/api/client-server/. +Pod Deprecation +=============== + +The SDK is no longer published directly to Cocopods following recent linting issues +with Xcode 14.3 and greater: `CocoaPods/CocoaPods#11839 `_. +This deprecation *only* covers the published pod, the SDK is still being maintained. + +It is however worth noting that we're now primarily focussed on the `Matrix Rust SDK `_ +and its respective FFI bindings which are available as a `Swift package `_. +This would likely be a more sensible choice for anyone starting a new project using Matrix on Apple platforms. + + Use the SDK in your app ======================= @@ -29,15 +42,10 @@ In order to set this up:: sudo gem install cocoapods pod setup -The best way to add the last release of the Matrix SDK to your application -project is to add the MatrixSDK dependency to your Podfile:: - - pod 'MatrixSDK' +The best way to add the Matrix SDK to your application is to add the MatrixSDK repo to your Podfile:: -If you want to use the develop version of the SDK, use instead: + pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :tag => 'vX.Y.Z' - pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', - :branch => 'develop' Options =======